blob: aefe2c1e6921bde723841b1a308a3d282a85f539 [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#include <gtest/gtest.h>
#include <string>
#include "brpc/policy/mysql/mysql_auth_packet.h"
#include "butil/strings/string_piece.h"
namespace {
using brpc::policy::mysql::DecodeLengthEncodedInt;
using brpc::policy::mysql::DecodeLengthEncodedString;
using brpc::policy::mysql::DecodeNullTerminatedString;
using brpc::policy::mysql::DecodePacketHeader;
using brpc::policy::mysql::EncodeLengthEncodedInt;
using brpc::policy::mysql::EncodeLengthEncodedString;
using brpc::policy::mysql::EncodePacketHeader;
using brpc::policy::mysql::PacketHeader;
using brpc::policy::mysql::kMaxPayloadLen;
using brpc::policy::mysql::kPacketHeaderLen;
// ----------------------------------------------------------------------
// length-encoded integer
// ----------------------------------------------------------------------
TEST(LenencIntTest, Decode_1Byte_Zero) {
const char buf[] = {0x00};
uint64_t v = 0xdead;
EXPECT_EQ(DecodeLengthEncodedInt(butil::StringPiece(buf, 1), &v), 1u);
EXPECT_EQ(v, 0u);
}
TEST(LenencIntTest, Decode_1Byte_Max250) {
const char buf[] = {static_cast<char>(0xfa)};
uint64_t v = 0;
EXPECT_EQ(DecodeLengthEncodedInt(butil::StringPiece(buf, 1), &v), 1u);
EXPECT_EQ(v, 0xfau);
}
TEST(LenencIntTest, Decode_2Byte_251) {
const char buf[] = {static_cast<char>(0xfc), static_cast<char>(0xfb), 0x00};
uint64_t v = 0;
EXPECT_EQ(DecodeLengthEncodedInt(butil::StringPiece(buf, 3), &v), 3u);
EXPECT_EQ(v, 251u);
}
TEST(LenencIntTest, Decode_2Byte_Max65535) {
const char buf[] = {static_cast<char>(0xfc),
static_cast<char>(0xff),
static_cast<char>(0xff)};
uint64_t v = 0;
EXPECT_EQ(DecodeLengthEncodedInt(butil::StringPiece(buf, 3), &v), 3u);
EXPECT_EQ(v, 0xffffu);
}
TEST(LenencIntTest, Decode_3Byte) {
const char buf[] = {static_cast<char>(0xfd), 0x01, 0x02, 0x03};
uint64_t v = 0;
EXPECT_EQ(DecodeLengthEncodedInt(butil::StringPiece(buf, 4), &v), 4u);
EXPECT_EQ(v, 0x030201u);
}
TEST(LenencIntTest, Decode_8Byte) {
const char buf[] = {static_cast<char>(0xfe),
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
uint64_t v = 0;
EXPECT_EQ(DecodeLengthEncodedInt(butil::StringPiece(buf, 9), &v), 9u);
EXPECT_EQ(v, 0x0807060504030201ULL);
}
TEST(LenencIntTest, Decode_ReservedFF_ReturnsZero) {
const char buf[] = {static_cast<char>(0xff)};
uint64_t v = 0;
EXPECT_EQ(DecodeLengthEncodedInt(butil::StringPiece(buf, 1), &v), 0u);
}
TEST(LenencIntTest, Decode_Truncated_ReturnsZero) {
const char buf[] = {static_cast<char>(0xfc), 0x01}; // missing 1 byte
uint64_t v = 0;
EXPECT_EQ(DecodeLengthEncodedInt(butil::StringPiece(buf, 2), &v), 0u);
EXPECT_EQ(DecodeLengthEncodedInt(butil::StringPiece(buf, 0), &v), 0u);
}
TEST(LenencIntTest, Decode_NullMarkerFB_ReportsNull) {
const char buf[] = {static_cast<char>(0xfb)};
uint64_t v = 0xdead;
bool is_null = false;
// 0xFB is the NULL marker: 1 byte consumed, value NULL, *out defined to 0.
EXPECT_EQ(DecodeLengthEncodedInt(butil::StringPiece(buf, 1), &v, &is_null),
1u);
EXPECT_TRUE(is_null);
EXPECT_EQ(v, 0u);
}
TEST(LenencIntTest, Decode_NonNull_SetsIsNullFalse) {
const char buf[] = {0x05};
uint64_t v = 0;
bool is_null = true;
EXPECT_EQ(DecodeLengthEncodedInt(butil::StringPiece(buf, 1), &v, &is_null),
1u);
EXPECT_FALSE(is_null);
EXPECT_EQ(v, 5u);
}
TEST(LenencIntTest, Decode_Failure_DefinesOutAndIsNull) {
// Reserved 0xFF marker -> failure; *out reset to 0, *is_null to false even
// though both held stale values, so a careless caller can't read garbage.
const char buf[] = {static_cast<char>(0xff)};
uint64_t v = 0xdead;
bool is_null = true;
EXPECT_EQ(DecodeLengthEncodedInt(butil::StringPiece(buf, 1), &v, &is_null),
0u);
EXPECT_FALSE(is_null);
EXPECT_EQ(v, 0u);
}
TEST(LenencIntTest, Decode_NullMarker_WithoutIsNullArg) {
// |is_null| is optional; 0xFB without it must not crash and still
// consumes the single marker byte.
const char buf[] = {static_cast<char>(0xfb)};
uint64_t v = 0xdead;
EXPECT_EQ(DecodeLengthEncodedInt(butil::StringPiece(buf, 1), &v), 1u);
EXPECT_EQ(v, 0u);
}
TEST(LenencIntTest, Encode_RoundTrip_AllRanges) {
const uint64_t values[] = {
0, 1, 250, 251, 0xffff, 0x10000, 0xffffff, 0x1000000, 0xffffffffULL
};
for (uint64_t v : values) {
std::string buf;
EncodeLengthEncodedInt(v, &buf);
uint64_t decoded = 0;
EXPECT_GT(DecodeLengthEncodedInt(buf, &decoded), 0u);
EXPECT_EQ(decoded, v);
}
}
// ----------------------------------------------------------------------
// length-encoded string
// ----------------------------------------------------------------------
TEST(LenencStringTest, Empty) {
std::string buf;
EncodeLengthEncodedString(butil::StringPiece(""), &buf);
EXPECT_EQ(buf, std::string("\0", 1));
std::string out;
EXPECT_EQ(DecodeLengthEncodedString(buf, &out), 1u);
EXPECT_TRUE(out.empty());
}
TEST(LenencStringTest, ShortString_RoundTrip) {
std::string buf;
EncodeLengthEncodedString(butil::StringPiece("hello"), &buf);
EXPECT_EQ(buf.size(), 6u);
std::string out;
EXPECT_EQ(DecodeLengthEncodedString(buf, &out), 6u);
EXPECT_EQ(out, "hello");
}
TEST(LenencStringTest, ContainsNul_RoundTrip) {
std::string buf;
const std::string value("a\0b\0c", 5);
EncodeLengthEncodedString(butil::StringPiece(value), &buf);
std::string out;
EXPECT_EQ(DecodeLengthEncodedString(buf, &out), 6u);
EXPECT_EQ(out, value);
}
TEST(LenencStringTest, TruncatedPayload_ReturnsZero) {
// Encoded length says 10 but only 3 bytes available.
std::string buf;
buf.push_back(0x0a);
buf.append("abc");
std::string out;
EXPECT_EQ(DecodeLengthEncodedString(buf, &out), 0u);
}
TEST(LenencStringTest, NullMarkerFB_ReportsNull) {
// A length-encoded string whose leading lenenc-int is 0xFB is NULL,
// distinct from the empty string (lenenc 0x00). Only the marker byte is
// consumed and out_value is cleared.
const char buf[] = {static_cast<char>(0xfb), 'x', 'y'};
std::string out = "stale";
bool is_null = false;
EXPECT_EQ(DecodeLengthEncodedString(butil::StringPiece(buf, 3), &out,
&is_null),
1u);
EXPECT_TRUE(is_null);
EXPECT_TRUE(out.empty());
}
TEST(LenencStringTest, NonNull_SetsIsNullFalse) {
std::string buf;
EncodeLengthEncodedString(butil::StringPiece("hi"), &buf);
std::string out;
bool is_null = true;
EXPECT_EQ(DecodeLengthEncodedString(buf, &out, &is_null), 3u);
EXPECT_FALSE(is_null);
EXPECT_EQ(out, "hi");
}
TEST(LenencStringTest, EmptyIsNotNull) {
// Empty string (lenenc 0x00) must NOT be reported as NULL.
std::string buf;
EncodeLengthEncodedString(butil::StringPiece(""), &buf);
std::string out = "stale";
bool is_null = true;
EXPECT_EQ(DecodeLengthEncodedString(buf, &out, &is_null), 1u);
EXPECT_FALSE(is_null);
EXPECT_TRUE(out.empty());
}
// ----------------------------------------------------------------------
// packet header
// ----------------------------------------------------------------------
TEST(PacketHeaderTest, RoundTrip_TypicalSizes) {
const uint32_t sizes[] = {0u, 1u, 0xffu, 0x100u, 0xffffu, 0x10000u, 0x123456u};
for (uint32_t s : sizes) {
PacketHeader in = {s, 7};
std::string buf;
EncodePacketHeader(in, &buf);
ASSERT_EQ(buf.size(), kPacketHeaderLen);
PacketHeader out;
ASSERT_TRUE(DecodePacketHeader(buf, &out));
EXPECT_EQ(out.payload_len, s);
EXPECT_EQ(out.seq, 7u);
}
}
TEST(PacketHeaderTest, MaxPayloadLength) {
PacketHeader in = {kMaxPayloadLen, 0};
std::string buf;
EncodePacketHeader(in, &buf);
PacketHeader out;
ASSERT_TRUE(DecodePacketHeader(buf, &out));
EXPECT_EQ(out.payload_len, kMaxPayloadLen);
}
TEST(PacketHeaderTest, SequenceWraparound) {
PacketHeader in = {0, 255};
std::string buf;
EncodePacketHeader(in, &buf);
PacketHeader out;
ASSERT_TRUE(DecodePacketHeader(buf, &out));
EXPECT_EQ(out.seq, 255u);
}
TEST(PacketHeaderTest, Decode_TruncatedReturnsFalse) {
PacketHeader out;
EXPECT_FALSE(DecodePacketHeader(butil::StringPiece("\x00\x00\x00", 3), &out));
EXPECT_FALSE(DecodePacketHeader(butil::StringPiece("", 0), &out));
}
// ----------------------------------------------------------------------
// NUL-terminated string
// ----------------------------------------------------------------------
TEST(NullTermStringTest, HappyPath) {
const char buf[] = "hello\0extra";
std::string out;
EXPECT_EQ(DecodeNullTerminatedString(
butil::StringPiece(buf, sizeof(buf) - 1), &out),
6u);
EXPECT_EQ(out, "hello");
}
TEST(NullTermStringTest, EmptyString) {
const char buf[] = "\0rest";
std::string out;
EXPECT_EQ(DecodeNullTerminatedString(
butil::StringPiece(buf, sizeof(buf) - 1), &out),
1u);
EXPECT_TRUE(out.empty());
}
TEST(NullTermStringTest, NoNul_ReturnsZero) {
std::string out;
EXPECT_EQ(DecodeNullTerminatedString(butil::StringPiece("abc"), &out), 0u);
}
} // namespace