1 //
2 // Copyright 2021 gRPC authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include "src/core/lib/transport/parsed_metadata.h"
18
19 #include <memory>
20
21 #include "absl/strings/numbers.h"
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24
25 #include <grpc/support/log.h>
26
27 #include "src/core/lib/transport/metadata_batch.h"
28 #include "test/core/util/test_config.h"
29
30 namespace grpc_core {
31 namespace testing {
32
33 struct CharTrait {
34 using MementoType = char;
keygrpc_core::testing::CharTrait35 static absl::string_view key() { return "key"; }
test_mementogrpc_core::testing::CharTrait36 static char test_memento() { return 'a'; }
test_valuegrpc_core::testing::CharTrait37 static char test_value() { return 'a'; }
test_memento_transport_sizegrpc_core::testing::CharTrait38 static size_t test_memento_transport_size() { return 34; }
MementoToValuegrpc_core::testing::CharTrait39 static char MementoToValue(char memento) { return memento; }
ParseMementogrpc_core::testing::CharTrait40 static char ParseMemento(Slice slice, bool, MetadataParseErrorFn) {
41 return slice[0];
42 }
DisplayValuegrpc_core::testing::CharTrait43 static std::string DisplayValue(char value) { return std::string(1, value); }
DisplayMementogrpc_core::testing::CharTrait44 static std::string DisplayMemento(MementoType memento) {
45 return DisplayValue(memento);
46 }
47 };
48
49 struct Int32Trait {
50 using MementoType = int32_t;
keygrpc_core::testing::Int32Trait51 static absl::string_view key() { return "key2"; }
test_mementogrpc_core::testing::Int32Trait52 static int32_t test_memento() { return -1; }
test_valuegrpc_core::testing::Int32Trait53 static int32_t test_value() { return -1; }
test_memento_transport_sizegrpc_core::testing::Int32Trait54 static size_t test_memento_transport_size() { return 478; }
MementoToValuegrpc_core::testing::Int32Trait55 static int32_t MementoToValue(int32_t memento) { return memento; }
ParseMementogrpc_core::testing::Int32Trait56 static int32_t ParseMemento(Slice slice, bool, MetadataParseErrorFn) {
57 int32_t out;
58 GPR_ASSERT(absl::SimpleAtoi(slice.as_string_view(), &out));
59 return out;
60 }
DisplayValuegrpc_core::testing::Int32Trait61 static std::string DisplayValue(int32_t value) {
62 return std::to_string(value);
63 }
DisplayMementogrpc_core::testing::Int32Trait64 static std::string DisplayMemento(MementoType memento) {
65 return DisplayValue(memento);
66 }
67 };
68
69 struct Int64Trait {
70 using MementoType = int64_t;
keygrpc_core::testing::Int64Trait71 static absl::string_view key() { return "key3"; }
test_mementogrpc_core::testing::Int64Trait72 static int64_t test_memento() { return 83481847284179298; }
test_valuegrpc_core::testing::Int64Trait73 static int64_t test_value() { return -83481847284179298; }
test_memento_transport_sizegrpc_core::testing::Int64Trait74 static size_t test_memento_transport_size() { return 87; }
MementoToValuegrpc_core::testing::Int64Trait75 static int64_t MementoToValue(int64_t memento) { return -memento; }
ParseMementogrpc_core::testing::Int64Trait76 static int64_t ParseMemento(Slice slice, bool, MetadataParseErrorFn) {
77 int64_t out;
78 GPR_ASSERT(absl::SimpleAtoi(slice.as_string_view(), &out));
79 return out;
80 }
DisplayValuegrpc_core::testing::Int64Trait81 static std::string DisplayValue(int64_t value) {
82 return std::to_string(value);
83 }
DisplayMementogrpc_core::testing::Int64Trait84 static std::string DisplayMemento(MementoType memento) {
85 return DisplayValue(memento);
86 }
87 };
88
89 struct IntptrTrait {
90 using MementoType = intptr_t;
keygrpc_core::testing::IntptrTrait91 static absl::string_view key() { return "key4"; }
test_mementogrpc_core::testing::IntptrTrait92 static intptr_t test_memento() { return 8374298; }
test_valuegrpc_core::testing::IntptrTrait93 static intptr_t test_value() { return test_memento() / 2; }
test_memento_transport_sizegrpc_core::testing::IntptrTrait94 static size_t test_memento_transport_size() { return 800; }
MementoToValuegrpc_core::testing::IntptrTrait95 static intptr_t MementoToValue(intptr_t memento) { return memento / 2; }
ParseMementogrpc_core::testing::IntptrTrait96 static intptr_t ParseMemento(Slice slice, bool, MetadataParseErrorFn) {
97 intptr_t out;
98 GPR_ASSERT(absl::SimpleAtoi(slice.as_string_view(), &out));
99 return out;
100 }
DisplayValuegrpc_core::testing::IntptrTrait101 static std::string DisplayValue(intptr_t value) {
102 return std::to_string(value);
103 }
DisplayMementogrpc_core::testing::IntptrTrait104 static std::string DisplayMemento(MementoType memento) {
105 return DisplayValue(memento);
106 }
107 };
108
109 struct StringTrait {
110 using MementoType = std::string;
keygrpc_core::testing::StringTrait111 static absl::string_view key() { return "key5-bin"; }
test_mementogrpc_core::testing::StringTrait112 static std::string test_memento() { return "hello"; }
test_valuegrpc_core::testing::StringTrait113 static std::string test_value() { return "hi hello"; }
test_memento_transport_sizegrpc_core::testing::StringTrait114 static size_t test_memento_transport_size() { return 599; }
MementoToValuegrpc_core::testing::StringTrait115 static std::string MementoToValue(std::string memento) {
116 return "hi " + memento;
117 }
ParseMementogrpc_core::testing::StringTrait118 static std::string ParseMemento(Slice slice, bool, MetadataParseErrorFn) {
119 auto view = slice.as_string_view();
120 return std::string(view.begin(), view.end());
121 }
DisplayValuegrpc_core::testing::StringTrait122 static std::string DisplayValue(const std::string& value) { return value; }
DisplayMementogrpc_core::testing::StringTrait123 static std::string DisplayMemento(MementoType memento) {
124 return DisplayValue(memento);
125 }
126 };
127
128 class FakeContainer {
129 public:
Set(CharTrait,char x)130 void Set(CharTrait, char x) { SetChar(x); }
Set(Int32Trait,int32_t x)131 void Set(Int32Trait, int32_t x) { SetInt32(x); }
Set(Int64Trait,int64_t x)132 void Set(Int64Trait, int64_t x) { SetInt64(x); }
Set(IntptrTrait,intptr_t x)133 void Set(IntptrTrait, intptr_t x) { SetIntptr(x); }
Set(StringTrait,std::string x)134 void Set(StringTrait, std::string x) { SetString(x); }
135
Set(const ParsedMetadata<FakeContainer> & metadata)136 void Set(const ParsedMetadata<FakeContainer>& metadata) {
137 metadata.SetOnContainer(this);
138 }
139
140 MOCK_METHOD1(SetChar, void(char));
141 MOCK_METHOD1(SetInt32, void(int32_t));
142 MOCK_METHOD1(SetInt64, void(int64_t));
143 MOCK_METHOD1(SetIntptr, void(intptr_t));
144 MOCK_METHOD1(SetString, void(std::string));
145 };
146
147 using FakeParsedMetadata = ::grpc_core::ParsedMetadata<FakeContainer>;
148
TEST(ParsedMetadataTest,Noop)149 TEST(ParsedMetadataTest, Noop) { FakeParsedMetadata(); }
150
TEST(ParsedMetadataTest,DebugString)151 TEST(ParsedMetadataTest, DebugString) {
152 FakeParsedMetadata parsed(CharTrait(), 'x', 36);
153 EXPECT_EQ(parsed.DebugString(), "key: x");
154 }
155
TEST(ParsedMetadataTest,IsNotBinary)156 TEST(ParsedMetadataTest, IsNotBinary) {
157 FakeParsedMetadata parsed(CharTrait(), 'x', 36);
158 EXPECT_FALSE(parsed.is_binary_header());
159 }
160
TEST(ParsedMetadataTest,IsBinary)161 TEST(ParsedMetadataTest, IsBinary) {
162 FakeParsedMetadata parsed(StringTrait(), "s", 36);
163 EXPECT_TRUE(parsed.is_binary_header());
164 }
165
TEST(ParsedMetadataTest,Set)166 TEST(ParsedMetadataTest, Set) {
167 FakeContainer c;
168 FakeParsedMetadata p(CharTrait(), 'x', 36);
169 EXPECT_CALL(c, SetChar('x')).Times(1);
170 c.Set(p);
171 p = FakeParsedMetadata(Int32Trait(), -1, 478);
172 EXPECT_CALL(c, SetInt32(-1)).Times(1);
173 c.Set(p);
174 p = FakeParsedMetadata(Int64Trait(), 83481847284179298, 87);
175 EXPECT_CALL(c, SetInt64(-83481847284179298)).Times(1);
176 c.Set(p);
177 p = FakeParsedMetadata(IntptrTrait(), 8374298, 800);
178 EXPECT_CALL(c, SetIntptr(4187149)).Times(1);
179 c.Set(p);
180 p = FakeParsedMetadata(StringTrait(), "hello", 599);
181 EXPECT_CALL(c, SetString("hi hello")).Times(1);
182 c.Set(p);
183 }
184
185 template <typename T>
186 class TraitSpecializedTest : public ::testing::Test {};
187
188 TYPED_TEST_SUITE_P(TraitSpecializedTest);
189
TYPED_TEST_P(TraitSpecializedTest,Noop)190 TYPED_TEST_P(TraitSpecializedTest, Noop) {
191 FakeParsedMetadata(TypeParam(), TypeParam::test_memento(),
192 TypeParam::test_memento_transport_size());
193 }
194
TYPED_TEST_P(TraitSpecializedTest,CanMove)195 TYPED_TEST_P(TraitSpecializedTest, CanMove) {
196 FakeParsedMetadata a(TypeParam(), TypeParam::test_memento(),
197 TypeParam::test_memento_transport_size());
198 FakeParsedMetadata b = std::move(a);
199 a = std::move(b);
200 }
201
TYPED_TEST_P(TraitSpecializedTest,DebugString)202 TYPED_TEST_P(TraitSpecializedTest, DebugString) {
203 FakeParsedMetadata p(TypeParam(), TypeParam::test_memento(),
204 TypeParam::test_memento_transport_size());
205 EXPECT_EQ(p.DebugString(),
206 absl::StrCat(TypeParam::key(), ": ",
207 TypeParam::DisplayValue(TypeParam::test_memento())));
208 }
209
TYPED_TEST_P(TraitSpecializedTest,TransportSize)210 TYPED_TEST_P(TraitSpecializedTest, TransportSize) {
211 FakeParsedMetadata p(TypeParam(), TypeParam::test_memento(),
212 TypeParam::test_memento_transport_size());
213 EXPECT_EQ(p.transport_size(), TypeParam::test_memento_transport_size());
214 }
215
216 REGISTER_TYPED_TEST_SUITE_P(TraitSpecializedTest, Noop, CanMove, DebugString,
217 TransportSize);
218
219 using InterestingTraits = ::testing::Types<CharTrait, Int32Trait, Int64Trait,
220 IntptrTrait, StringTrait>;
221 INSTANTIATE_TYPED_TEST_SUITE_P(My, TraitSpecializedTest, InterestingTraits);
222
TEST(KeyValueTest,Simple)223 TEST(KeyValueTest, Simple) {
224 using PM = ParsedMetadata<grpc_metadata_batch>;
225 using PMPtr = std::unique_ptr<PM>;
226 PMPtr p =
227 std::make_unique<PM>(PM::FromSlicePair{}, Slice::FromCopiedString("key"),
228 Slice::FromCopiedString("value"), 40);
229 EXPECT_EQ(p->DebugString(), "key: value");
230 EXPECT_EQ(p->transport_size(), 40);
231 PM p2 = p->WithNewValue(Slice::FromCopiedString("some_other_value"), true,
232 strlen("some_other_value"),
233 [](absl::string_view msg, const Slice& value) {
234 ASSERT_TRUE(false)
235 << "Should not be called: msg=" << msg
236 << ", value=" << value.as_string_view();
237 });
238 EXPECT_EQ(p->DebugString(), "key: value");
239 EXPECT_EQ(p2.DebugString(), "key: some_other_value");
240 EXPECT_EQ(p2.transport_size(), 51);
241 p.reset();
242 EXPECT_EQ(p2.DebugString(), "key: some_other_value");
243 EXPECT_EQ(p2.transport_size(), 51);
244 PM p3 = std::move(p2);
245 EXPECT_EQ(p3.DebugString(), "key: some_other_value");
246 EXPECT_EQ(p3.transport_size(), 51);
247 }
248
TEST(KeyValueTest,LongKey)249 TEST(KeyValueTest, LongKey) {
250 using PM = ParsedMetadata<grpc_metadata_batch>;
251 using PMPtr = std::unique_ptr<PM>;
252 PMPtr p = std::make_unique<PM>(PM::FromSlicePair{},
253 Slice::FromCopiedString(std::string(60, 'a')),
254 Slice::FromCopiedString("value"), 60 + 5 + 32);
255 EXPECT_EQ(
256 p->DebugString(),
257 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: value");
258 EXPECT_EQ(p->transport_size(), 97);
259 PM p2 = p->WithNewValue(Slice::FromCopiedString("some_other_value"), true,
260 strlen("some_other_value"),
261 [](absl::string_view msg, const Slice& value) {
262 ASSERT_TRUE(false)
263 << "Should not be called: msg=" << msg
264 << ", value=" << value.as_string_view();
265 });
266 EXPECT_EQ(
267 p->DebugString(),
268 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: value");
269 EXPECT_EQ(p2.DebugString(),
270 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: "
271 "some_other_value");
272 EXPECT_EQ(p2.transport_size(), 108);
273 p.reset();
274 EXPECT_EQ(p2.DebugString(),
275 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: "
276 "some_other_value");
277 EXPECT_EQ(p2.transport_size(), 108);
278 PM p3 = std::move(p2);
279 EXPECT_EQ(p3.DebugString(),
280 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: "
281 "some_other_value");
282 EXPECT_EQ(p3.transport_size(), 108);
283 }
284
285 } // namespace testing
286 } // namespace grpc_core
287
main(int argc,char ** argv)288 int main(int argc, char** argv) {
289 testing::InitGoogleTest(&argc, argv);
290 grpc::testing::TestEnvironment env(&argc, argv);
291 return RUN_ALL_TESTS();
292 };
293