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 <stdlib.h>
18
19 #include <memory>
20 #include <string>
21 #include <vector>
22
23 #include "absl/strings/match.h"
24 #include "absl/strings/str_cat.h"
25 #include "absl/strings/str_split.h"
26 #include "absl/types/optional.h"
27 #include "gtest/gtest.h"
28
29 #include <grpc/event_engine/memory_allocator.h>
30
31 #include "src/core/lib/gprpp/ref_counted_ptr.h"
32 #include "src/core/lib/gprpp/time.h"
33 #include "src/core/lib/resource_quota/arena.h"
34 #include "src/core/lib/resource_quota/memory_quota.h"
35 #include "src/core/lib/resource_quota/resource_quota.h"
36 #include "src/core/lib/slice/slice.h"
37 #include "src/core/lib/transport/metadata_batch.h"
38 #include "test/core/util/test_config.h"
39
40 namespace grpc_core {
41 namespace testing {
42
43 struct EmptyMetadataMap : public MetadataMap<EmptyMetadataMap> {
44 using MetadataMap<EmptyMetadataMap>::MetadataMap;
45 };
46
47 struct TimeoutOnlyMetadataMap
48 : public MetadataMap<TimeoutOnlyMetadataMap, GrpcTimeoutMetadata> {
49 using MetadataMap<TimeoutOnlyMetadataMap, GrpcTimeoutMetadata>::MetadataMap;
50 };
51
52 struct StreamNetworkStateMetadataMap
53 : public MetadataMap<StreamNetworkStateMetadataMap,
54 GrpcStreamNetworkState> {
55 using MetadataMap<StreamNetworkStateMetadataMap,
56 GrpcStreamNetworkState>::MetadataMap;
57 };
58
59 class MetadataMapTest : public ::testing::Test {
60 protected:
61 MemoryAllocator memory_allocator_ = MemoryAllocator(
62 ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator("test"));
63 };
64
TEST_F(MetadataMapTest,Noop)65 TEST_F(MetadataMapTest, Noop) {
66 auto arena = MakeScopedArena(1024, &memory_allocator_);
67 EmptyMetadataMap();
68 }
69
TEST_F(MetadataMapTest,NoopWithDeadline)70 TEST_F(MetadataMapTest, NoopWithDeadline) {
71 auto arena = MakeScopedArena(1024, &memory_allocator_);
72 TimeoutOnlyMetadataMap();
73 }
74
TEST_F(MetadataMapTest,SimpleOps)75 TEST_F(MetadataMapTest, SimpleOps) {
76 auto arena = MakeScopedArena(1024, &memory_allocator_);
77 TimeoutOnlyMetadataMap map;
78 EXPECT_EQ(map.get_pointer(GrpcTimeoutMetadata()), nullptr);
79 EXPECT_EQ(map.get(GrpcTimeoutMetadata()), absl::nullopt);
80 map.Set(GrpcTimeoutMetadata(),
81 Timestamp::FromMillisecondsAfterProcessEpoch(1234));
82 EXPECT_NE(map.get_pointer(GrpcTimeoutMetadata()), nullptr);
83 EXPECT_EQ(*map.get_pointer(GrpcTimeoutMetadata()),
84 Timestamp::FromMillisecondsAfterProcessEpoch(1234));
85 EXPECT_EQ(map.get(GrpcTimeoutMetadata()),
86 Timestamp::FromMillisecondsAfterProcessEpoch(1234));
87 map.Remove(GrpcTimeoutMetadata());
88 EXPECT_EQ(map.get_pointer(GrpcTimeoutMetadata()), nullptr);
89 EXPECT_EQ(map.get(GrpcTimeoutMetadata()), absl::nullopt);
90 }
91
92 // Target for MetadataMap::Encode.
93 // Writes down some string representation of what it receives, so we can
94 // EXPECT_EQ it later.
95 class FakeEncoder {
96 public:
output()97 std::string output() { return output_; }
98
Encode(const Slice & key,const Slice & value)99 void Encode(const Slice& key, const Slice& value) {
100 output_ += absl::StrCat("UNKNOWN METADATUM: key=", key.as_string_view(),
101 " value=", value.as_string_view(), "\n");
102 }
103
Encode(GrpcTimeoutMetadata,Timestamp deadline)104 void Encode(GrpcTimeoutMetadata, Timestamp deadline) {
105 output_ += absl::StrCat("grpc-timeout: deadline=",
106 deadline.milliseconds_after_process_epoch(), "\n");
107 }
108
109 private:
110 std::string output_;
111 };
112
TEST_F(MetadataMapTest,EmptyEncodeTest)113 TEST_F(MetadataMapTest, EmptyEncodeTest) {
114 FakeEncoder encoder;
115 auto arena = MakeScopedArena(1024, &memory_allocator_);
116 TimeoutOnlyMetadataMap map;
117 map.Encode(&encoder);
118 EXPECT_EQ(encoder.output(), "");
119 }
120
TEST_F(MetadataMapTest,TimeoutEncodeTest)121 TEST_F(MetadataMapTest, TimeoutEncodeTest) {
122 FakeEncoder encoder;
123 auto arena = MakeScopedArena(1024, &memory_allocator_);
124 TimeoutOnlyMetadataMap map;
125 map.Set(GrpcTimeoutMetadata(),
126 Timestamp::FromMillisecondsAfterProcessEpoch(1234));
127 map.Encode(&encoder);
128 EXPECT_EQ(encoder.output(), "grpc-timeout: deadline=1234\n");
129 }
130
TEST_F(MetadataMapTest,NonEncodableTrait)131 TEST_F(MetadataMapTest, NonEncodableTrait) {
132 struct EncoderWithNoTraitEncodeFunctions {
133 void Encode(const Slice&, const Slice&) {
134 abort(); // should not be called
135 }
136 };
137 auto arena = MakeScopedArena(1024, &memory_allocator_);
138 StreamNetworkStateMetadataMap map;
139 map.Set(GrpcStreamNetworkState(), GrpcStreamNetworkState::kNotSentOnWire);
140 EXPECT_EQ(map.get(GrpcStreamNetworkState()),
141 GrpcStreamNetworkState::kNotSentOnWire);
142 EncoderWithNoTraitEncodeFunctions encoder;
143 map.Encode(&encoder);
144 EXPECT_EQ(map.DebugString(), "GrpcStreamNetworkState: not sent on wire");
145 }
146
TEST(DebugStringBuilderTest,OneAddAfterRedaction)147 TEST(DebugStringBuilderTest, OneAddAfterRedaction) {
148 metadata_detail::DebugStringBuilder b;
149 b.AddAfterRedaction(ContentTypeMetadata::key(), "AddValue01");
150 EXPECT_EQ(b.TakeOutput(),
151 absl::StrCat(ContentTypeMetadata::key(), ": AddValue01"));
152 }
153
GetAllowList()154 std::vector<std::string> GetAllowList() {
155 return {
156 // clang-format off
157 std::string(ContentTypeMetadata::key()),
158 std::string(EndpointLoadMetricsBinMetadata::key()),
159 std::string(GrpcAcceptEncodingMetadata::key()),
160 std::string(GrpcEncodingMetadata::key()),
161 std::string(GrpcInternalEncodingRequest::key()),
162 std::string(GrpcLbClientStatsMetadata::key()),
163 std::string(GrpcMessageMetadata::key()),
164 std::string(GrpcPreviousRpcAttemptsMetadata::key()),
165 std::string(GrpcRetryPushbackMsMetadata::key()),
166 std::string(GrpcServerStatsBinMetadata::key()),
167 std::string(GrpcStatusMetadata::key()),
168 std::string(GrpcTagsBinMetadata::key()),
169 std::string(GrpcTimeoutMetadata::key()),
170 std::string(GrpcTraceBinMetadata::key()),
171 std::string(HostMetadata::key()),
172 std::string(HttpAuthorityMetadata::key()),
173 std::string(HttpMethodMetadata::key()),
174 std::string(HttpPathMetadata::key()),
175 std::string(HttpSchemeMetadata::key()),
176 std::string(HttpStatusMetadata::key()),
177 std::string(LbCostBinMetadata::key()),
178 std::string(LbTokenMetadata::key()),
179 std::string(TeMetadata::key()),
180 std::string(UserAgentMetadata::key()),
181 std::string(XEnvoyPeerMetadata::key()),
182 std::string(GrpcCallWasCancelled::DebugKey()),
183 std::string(GrpcRegisteredMethod::DebugKey()),
184 std::string(GrpcStatusContext::DebugKey()),
185 std::string(GrpcStatusFromWire::DebugKey()),
186 std::string(GrpcStreamNetworkState::DebugKey()),
187 std::string(GrpcTarPit::DebugKey()),
188 std::string(GrpcTrailersOnly::DebugKey()),
189 std::string(PeerString::DebugKey()),
190 std::string(WaitForReady::DebugKey())
191 // clang-format on
192 };
193 }
194
TEST(DebugStringBuilderTest,TestAllAllowListed)195 TEST(DebugStringBuilderTest, TestAllAllowListed) {
196 metadata_detail::DebugStringBuilder builder_add_allow_list;
197 const std::vector<std::string> allow_list_keys = GetAllowList();
198
199 for (const std::string& curr_key : allow_list_keys) {
200 builder_add_allow_list.AddAfterRedaction(curr_key, curr_key);
201 }
202
203 // All values which are allow listed should be added as is.
204 EXPECT_EQ(builder_add_allow_list.TakeOutput(),
205 "content-type: content-type, "
206 "endpoint-load-metrics-bin: endpoint-load-metrics-bin, "
207 "grpc-accept-encoding: grpc-accept-encoding, "
208 "grpc-encoding: grpc-encoding, "
209 "grpc-internal-encoding-request: grpc-internal-encoding-request, "
210 "grpclb_client_stats: grpclb_client_stats, "
211 "grpc-message: grpc-message, "
212 "grpc-previous-rpc-attempts: grpc-previous-rpc-attempts, "
213 "grpc-retry-pushback-ms: grpc-retry-pushback-ms, "
214 "grpc-server-stats-bin: grpc-server-stats-bin, "
215 "grpc-status: grpc-status, "
216 "grpc-tags-bin: grpc-tags-bin, "
217 "grpc-timeout: grpc-timeout, "
218 "grpc-trace-bin: grpc-trace-bin, "
219 "host: host, :authority: :authority, "
220 ":method: :method, "
221 ":path: :path, "
222 ":scheme: :scheme, "
223 ":status: :status, "
224 "lb-cost-bin: lb-cost-bin, "
225 "lb-token: lb-token, "
226 "te: te, "
227 "user-agent: user-agent, "
228 "x-envoy-peer-metadata: x-envoy-peer-metadata, "
229 "GrpcCallWasCancelled: GrpcCallWasCancelled, "
230 "GrpcRegisteredMethod: GrpcRegisteredMethod, "
231 "GrpcStatusContext: GrpcStatusContext, "
232 "GrpcStatusFromWire: GrpcStatusFromWire, "
233 "GrpcStreamNetworkState: GrpcStreamNetworkState, "
234 "GrpcTarPit: GrpcTarPit, "
235 "GrpcTrailersOnly: GrpcTrailersOnly, "
236 "PeerString: PeerString, "
237 "WaitForReady: WaitForReady");
238 }
239
TEST(DebugStringBuilderTest,TestAllRedacted)240 TEST(DebugStringBuilderTest, TestAllRedacted) {
241 metadata_detail::DebugStringBuilder builder_add_redacted;
242 const std::vector<std::string> allow_list_keys = GetAllowList();
243
244 for (const std::string& curr_key : allow_list_keys) {
245 builder_add_redacted.AddAfterRedaction(curr_key + "1234", curr_key);
246 }
247
248 // All values which are not allow listed should be redacted
249 std::vector<std::string> redacted_output =
250 absl::StrSplit(builder_add_redacted.TakeOutput(), ',');
251 int i = 0;
252 for (std::string& curr_row : redacted_output) {
253 std::string redacted_str = absl::StrCat(
254 allow_list_keys[i++].size(), " bytes redacted by allow listing.");
255 EXPECT_EQ(absl::StrContains(curr_row, redacted_str), true);
256 }
257 }
258
259 } // namespace testing
260 } // namespace grpc_core
261
main(int argc,char ** argv)262 int main(int argc, char** argv) {
263 testing::InitGoogleTest(&argc, argv);
264 grpc::testing::TestEnvironment env(&argc, argv);
265 return RUN_ALL_TESTS();
266 };
267