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 <gmock/gmock.h>
20 #include <gtest/gtest.h>
21 
22 #include "src/core/lib/slice/slice_internal.h"
23 #include "test/core/util/test_config.h"
24 
25 namespace grpc_core {
26 namespace testing {
27 
28 struct CharTrait {
29   using MementoType = char;
keygrpc_core::testing::CharTrait30   static const char* key() { return "key"; }
test_mementogrpc_core::testing::CharTrait31   static char test_memento() { return 'a'; }
test_valuegrpc_core::testing::CharTrait32   static char test_value() { return 'a'; }
test_memento_transport_sizegrpc_core::testing::CharTrait33   static size_t test_memento_transport_size() { return 34; }
MementoToValuegrpc_core::testing::CharTrait34   static char MementoToValue(char memento) { return memento; }
ParseMementogrpc_core::testing::CharTrait35   static char ParseMemento(const grpc_slice& slice) {
36     return *GRPC_SLICE_START_PTR(slice);
37   }
DisplayValuegrpc_core::testing::CharTrait38   static std::string DisplayValue(char value) { return std::string(1, value); }
39 };
40 
41 struct Int32Trait {
42   using MementoType = int32_t;
keygrpc_core::testing::Int32Trait43   static const char* key() { return "key2"; }
test_mementogrpc_core::testing::Int32Trait44   static int32_t test_memento() { return -1; }
test_valuegrpc_core::testing::Int32Trait45   static int32_t test_value() { return -1; }
test_memento_transport_sizegrpc_core::testing::Int32Trait46   static size_t test_memento_transport_size() { return 478; }
MementoToValuegrpc_core::testing::Int32Trait47   static int32_t MementoToValue(int32_t memento) { return memento; }
ParseMementogrpc_core::testing::Int32Trait48   static int32_t ParseMemento(const grpc_slice& slice) {
49     int32_t out;
50     GPR_ASSERT(absl::SimpleAtoi(StringViewFromSlice(slice), &out));
51     return out;
52   }
DisplayValuegrpc_core::testing::Int32Trait53   static std::string DisplayValue(int32_t value) {
54     return std::to_string(value);
55   }
56 };
57 
58 struct Int64Trait {
59   using MementoType = int64_t;
keygrpc_core::testing::Int64Trait60   static const char* key() { return "key3"; }
test_mementogrpc_core::testing::Int64Trait61   static int64_t test_memento() { return 83481847284179298; }
test_valuegrpc_core::testing::Int64Trait62   static int64_t test_value() { return -83481847284179298; }
test_memento_transport_sizegrpc_core::testing::Int64Trait63   static size_t test_memento_transport_size() { return 87; }
MementoToValuegrpc_core::testing::Int64Trait64   static int64_t MementoToValue(int64_t memento) { return -memento; }
ParseMementogrpc_core::testing::Int64Trait65   static int64_t ParseMemento(const grpc_slice& slice) {
66     int64_t out;
67     GPR_ASSERT(absl::SimpleAtoi(StringViewFromSlice(slice), &out));
68     return out;
69   }
DisplayValuegrpc_core::testing::Int64Trait70   static std::string DisplayValue(int64_t value) {
71     return std::to_string(value);
72   }
73 };
74 
75 struct IntptrTrait {
76   using MementoType = intptr_t;
keygrpc_core::testing::IntptrTrait77   static const char* key() { return "key4"; }
test_mementogrpc_core::testing::IntptrTrait78   static intptr_t test_memento() { return 8374298; }
test_valuegrpc_core::testing::IntptrTrait79   static intptr_t test_value() { return test_memento() / 2; }
test_memento_transport_sizegrpc_core::testing::IntptrTrait80   static size_t test_memento_transport_size() { return 800; }
MementoToValuegrpc_core::testing::IntptrTrait81   static intptr_t MementoToValue(intptr_t memento) { return memento / 2; }
ParseMementogrpc_core::testing::IntptrTrait82   static intptr_t ParseMemento(const grpc_slice& slice) {
83     intptr_t out;
84     GPR_ASSERT(absl::SimpleAtoi(StringViewFromSlice(slice), &out));
85     return out;
86   }
DisplayValuegrpc_core::testing::IntptrTrait87   static std::string DisplayValue(intptr_t value) {
88     return std::to_string(value);
89   }
90 };
91 
92 struct StringTrait {
93   using MementoType = std::string;
keygrpc_core::testing::StringTrait94   static const char* key() { return "key5-bin"; }
test_mementogrpc_core::testing::StringTrait95   static std::string test_memento() { return "hello"; }
test_valuegrpc_core::testing::StringTrait96   static std::string test_value() { return "hi hello"; }
test_memento_transport_sizegrpc_core::testing::StringTrait97   static size_t test_memento_transport_size() { return 599; }
MementoToValuegrpc_core::testing::StringTrait98   static std::string MementoToValue(std::string memento) {
99     return "hi " + memento;
100   }
ParseMementogrpc_core::testing::StringTrait101   static std::string ParseMemento(const grpc_slice& slice) {
102     auto view = StringViewFromSlice(slice);
103     return std::string(view.begin(), view.end());
104   }
DisplayValuegrpc_core::testing::StringTrait105   static std::string DisplayValue(const std::string& value) { return value; }
106 };
107 
108 class FakeContainer {
109  public:
Set(CharTrait,char x)110   void Set(CharTrait, char x) { SetChar(x); }
Set(Int32Trait,int32_t x)111   void Set(Int32Trait, int32_t x) { SetInt32(x); }
Set(Int64Trait,int64_t x)112   void Set(Int64Trait, int64_t x) { SetInt64(x); }
Set(IntptrTrait,intptr_t x)113   void Set(IntptrTrait, intptr_t x) { SetIntptr(x); }
Set(StringTrait,std::string x)114   void Set(StringTrait, std::string x) { SetString(x); }
115 
Set(const::grpc_core::ParsedMetadata<FakeContainer> & metadata)116   void Set(const ::grpc_core::ParsedMetadata<FakeContainer>& metadata) {
117     EXPECT_EQ(GRPC_ERROR_NONE, metadata.SetOnContainer(this));
118   }
119 
120   MOCK_METHOD1(SetChar, void(char));
121   MOCK_METHOD1(SetInt32, void(int32_t));
122   MOCK_METHOD1(SetInt64, void(int64_t));
123   MOCK_METHOD1(SetIntptr, void(intptr_t));
124   MOCK_METHOD1(SetString, void(std::string));
125 };
126 
127 using ParsedMetadata = ::grpc_core::ParsedMetadata<FakeContainer>;
128 
TEST(ParsedMetadataTest,Noop)129 TEST(ParsedMetadataTest, Noop) { ParsedMetadata(); }
130 
TEST(ParsedMetadataTest,DebugString)131 TEST(ParsedMetadataTest, DebugString) {
132   ParsedMetadata parsed(CharTrait(), 'x', 36);
133   EXPECT_EQ(parsed.DebugString(), "key: x");
134 }
135 
TEST(ParsedMetadataTest,IsNotBinary)136 TEST(ParsedMetadataTest, IsNotBinary) {
137   ParsedMetadata parsed(CharTrait(), 'x', 36);
138   EXPECT_FALSE(parsed.is_binary_header());
139 }
140 
TEST(ParsedMetadataTest,IsBinary)141 TEST(ParsedMetadataTest, IsBinary) {
142   ParsedMetadata parsed(StringTrait(), "s", 36);
143   EXPECT_TRUE(parsed.is_binary_header());
144 }
145 
TEST(ParsedMetadataTest,Set)146 TEST(ParsedMetadataTest, Set) {
147   FakeContainer c;
148   ParsedMetadata p(CharTrait(), 'x', 36);
149   EXPECT_CALL(c, SetChar('x')).Times(1);
150   c.Set(p);
151   p = ParsedMetadata(Int32Trait(), -1, 478);
152   EXPECT_CALL(c, SetInt32(-1)).Times(1);
153   c.Set(p);
154   p = ParsedMetadata(Int64Trait(), 83481847284179298, 87);
155   EXPECT_CALL(c, SetInt64(-83481847284179298)).Times(1);
156   c.Set(p);
157   p = ParsedMetadata(IntptrTrait(), 8374298, 800);
158   EXPECT_CALL(c, SetIntptr(4187149)).Times(1);
159   c.Set(p);
160   p = ParsedMetadata(StringTrait(), "hello", 599);
161   EXPECT_CALL(c, SetString("hi hello")).Times(1);
162   c.Set(p);
163 }
164 
165 template <typename T>
166 class TraitSpecializedTest : public ::testing::Test {};
167 
168 TYPED_TEST_SUITE_P(TraitSpecializedTest);
169 
TYPED_TEST_P(TraitSpecializedTest,Noop)170 TYPED_TEST_P(TraitSpecializedTest, Noop) {
171   ParsedMetadata(TypeParam(), TypeParam::test_memento(),
172                  TypeParam::test_memento_transport_size());
173 }
174 
TYPED_TEST_P(TraitSpecializedTest,CanMove)175 TYPED_TEST_P(TraitSpecializedTest, CanMove) {
176   ParsedMetadata a(TypeParam(), TypeParam::test_memento(),
177                    TypeParam::test_memento_transport_size());
178   ParsedMetadata b = std::move(a);
179   a = std::move(b);
180 }
181 
TYPED_TEST_P(TraitSpecializedTest,DebugString)182 TYPED_TEST_P(TraitSpecializedTest, DebugString) {
183   ParsedMetadata p(TypeParam(), TypeParam::test_memento(),
184                    TypeParam::test_memento_transport_size());
185   EXPECT_EQ(p.DebugString(),
186             absl::StrCat(TypeParam::key(), ": ",
187                          TypeParam::DisplayValue(TypeParam::test_memento())));
188 }
189 
TYPED_TEST_P(TraitSpecializedTest,TransportSize)190 TYPED_TEST_P(TraitSpecializedTest, TransportSize) {
191   ParsedMetadata p(TypeParam(), TypeParam::test_memento(),
192                    TypeParam::test_memento_transport_size());
193   EXPECT_EQ(p.transport_size(), TypeParam::test_memento_transport_size());
194 }
195 
196 REGISTER_TYPED_TEST_SUITE_P(TraitSpecializedTest, Noop, CanMove, DebugString,
197                             TransportSize);
198 
199 using InterestingTraits = ::testing::Types<CharTrait, Int32Trait, Int64Trait,
200                                            IntptrTrait, StringTrait>;
201 INSTANTIATE_TYPED_TEST_SUITE_P(My, TraitSpecializedTest, InterestingTraits);
202 
203 }  // namespace testing
204 }  // namespace grpc_core
205 
main(int argc,char ** argv)206 int main(int argc, char** argv) {
207   testing::InitGoogleTest(&argc, argv);
208   grpc::testing::TestEnvironment env(argc, argv);
209   return RUN_ALL_TESTS();
210 };
211