1 //
2 //
3 // Copyright 2023 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #include "src/cpp/ext/csm/metadata_exchange.h"
20
21 #include "absl/functional/any_invocable.h"
22 #include "gmock/gmock.h"
23 #include "google/cloud/opentelemetry/resource_detector.h"
24 #include "gtest/gtest.h"
25 #include "opentelemetry/metrics/provider.h"
26 #include "opentelemetry/sdk/metrics/meter_provider.h"
27 #include "opentelemetry/sdk/metrics/metric_reader.h"
28
29 #include <grpcpp/ext/otel_plugin.h>
30 #include <grpcpp/grpcpp.h>
31
32 #include "src/core/lib/channel/call_tracer.h"
33 #include "src/core/lib/config/core_configuration.h"
34 #include "src/core/lib/gpr/tmpfile.h"
35 #include "src/core/lib/gprpp/env.h"
36 #include "src/cpp/ext/csm/csm_observability.h"
37 #include "src/cpp/ext/otel/otel_plugin.h"
38 #include "test/core/util/test_config.h"
39 #include "test/cpp/end2end/test_service_impl.h"
40 #include "test/cpp/ext/otel/otel_test_library.h"
41
42 namespace grpc {
43 namespace testing {
44 namespace {
45
46 using OptionalLabelKey =
47 grpc_core::ClientCallTracer::CallAttemptTracer::OptionalLabelKey;
48 using ::testing::ElementsAre;
49 using ::testing::Pair;
50
TestGkeResource()51 opentelemetry::sdk::resource::Resource TestGkeResource() {
52 opentelemetry::sdk::common::AttributeMap attributes;
53 attributes.SetAttribute("cloud.platform", "gcp_kubernetes_engine");
54 attributes.SetAttribute("k8s.pod.name", "pod");
55 attributes.SetAttribute("k8s.container.name", "container");
56 attributes.SetAttribute("k8s.namespace.name", "namespace");
57 attributes.SetAttribute("k8s.cluster.name", "cluster");
58 attributes.SetAttribute("cloud.region", "region");
59 attributes.SetAttribute("cloud.account.id", "id");
60 return opentelemetry::sdk::resource::Resource::Create(attributes);
61 }
62
TestGceResource()63 opentelemetry::sdk::resource::Resource TestGceResource() {
64 opentelemetry::sdk::common::AttributeMap attributes;
65 attributes.SetAttribute("cloud.platform", "gcp_compute_engine");
66 attributes.SetAttribute("cloud.availability_zone", "zone");
67 attributes.SetAttribute("cloud.account.id", "id");
68 return opentelemetry::sdk::resource::Resource::Create(attributes);
69 }
70
TestUnknownResource()71 opentelemetry::sdk::resource::Resource TestUnknownResource() {
72 opentelemetry::sdk::common::AttributeMap attributes;
73 attributes.SetAttribute("cloud.platform", "random");
74 return opentelemetry::sdk::resource::Resource::Create(attributes);
75 }
76
77 class TestScenario {
78 public:
79 enum class ResourceType : std::uint8_t { kGke, kGce, kUnknown };
80 enum class XdsBootstrapSource : std::uint8_t { kFromFile, kFromConfig };
81
TestScenario(ResourceType type,XdsBootstrapSource bootstrap_source)82 explicit TestScenario(ResourceType type, XdsBootstrapSource bootstrap_source)
83 : type_(type), bootstrap_source_(bootstrap_source) {}
84
GetTestResource() const85 opentelemetry::sdk::resource::Resource GetTestResource() const {
86 switch (type_) {
87 case ResourceType::kGke:
88 return TestGkeResource();
89 case ResourceType::kGce:
90 return TestGceResource();
91 case ResourceType::kUnknown:
92 return TestUnknownResource();
93 }
94 }
95
Name(const::testing::TestParamInfo<TestScenario> & info)96 static std::string Name(const ::testing::TestParamInfo<TestScenario>& info) {
97 std::string ret_val;
98 switch (info.param.type_) {
99 case ResourceType::kGke:
100 ret_val += "Gke";
101 break;
102 case ResourceType::kGce:
103 ret_val += "Gce";
104 break;
105 case ResourceType::kUnknown:
106 ret_val += "Unknown";
107 break;
108 }
109 switch (info.param.bootstrap_source_) {
110 case TestScenario::XdsBootstrapSource::kFromFile:
111 ret_val += "BootstrapFromFile";
112 break;
113 case TestScenario::XdsBootstrapSource::kFromConfig:
114 ret_val += "BootstrapFromConfig";
115 break;
116 }
117 return ret_val;
118 }
119
type() const120 ResourceType type() const { return type_; }
121
bootstrap_source() const122 XdsBootstrapSource bootstrap_source() const { return bootstrap_source_; }
123
124 private:
125 ResourceType type_;
126 XdsBootstrapSource bootstrap_source_;
127 };
128
129 // A PluginOption that injects `ServiceMeshLabelsInjector`. (This is different
130 // from CsmOpenTelemetryPluginOption since it does not restrict itself to just
131 // CSM channels and servers.)
132 class MeshLabelsPluginOption
133 : public grpc::internal::InternalOpenTelemetryPluginOption {
134 public:
MeshLabelsPluginOption(const opentelemetry::sdk::common::AttributeMap & map)135 explicit MeshLabelsPluginOption(
136 const opentelemetry::sdk::common::AttributeMap& map)
137 : labels_injector_(
138 std::make_unique<grpc::internal::ServiceMeshLabelsInjector>(map)) {}
139
IsActiveOnClientChannel(absl::string_view) const140 bool IsActiveOnClientChannel(absl::string_view /*target*/) const override {
141 return true;
142 }
143
IsActiveOnServer(const grpc_core::ChannelArgs &) const144 bool IsActiveOnServer(const grpc_core::ChannelArgs& /*args*/) const override {
145 return true;
146 }
147
labels_injector() const148 const grpc::internal::LabelsInjector* labels_injector() const override {
149 return labels_injector_.get();
150 }
151
152 private:
153 std::unique_ptr<grpc::internal::ServiceMeshLabelsInjector> labels_injector_;
154 };
155
156 class MetadataExchangeTest
157 : public OpenTelemetryPluginEnd2EndTest,
158 public ::testing::WithParamInterface<TestScenario> {
159 protected:
Init(const std::vector<absl::string_view> & metric_names,bool enable_client_side_injector=true,std::map<grpc_core::ClientCallTracer::CallAttemptTracer::OptionalLabelKey,grpc_core::RefCountedStringValue> labels_to_inject={})160 void Init(
161 const std::vector<absl::string_view>& metric_names,
162 bool enable_client_side_injector = true,
163 std::map<grpc_core::ClientCallTracer::CallAttemptTracer::OptionalLabelKey,
164 grpc_core::RefCountedStringValue>
165 labels_to_inject = {}) {
166 const char* kBootstrap =
167 "{\"node\": {\"id\": "
168 "\"projects/1234567890/networks/mesh:mesh-id/nodes/"
169 "01234567-89ab-4def-8123-456789abcdef\"}}";
170 switch (GetParam().bootstrap_source()) {
171 case TestScenario::XdsBootstrapSource::kFromFile: {
172 ASSERT_EQ(bootstrap_file_name_, nullptr);
173 FILE* bootstrap_file =
174 gpr_tmpfile("xds_bootstrap", &bootstrap_file_name_);
175 fputs(kBootstrap, bootstrap_file);
176 fclose(bootstrap_file);
177 grpc_core::SetEnv("GRPC_XDS_BOOTSTRAP", bootstrap_file_name_);
178 break;
179 }
180 case TestScenario::XdsBootstrapSource::kFromConfig:
181 grpc_core::SetEnv("GRPC_XDS_BOOTSTRAP_CONFIG", kBootstrap);
182 break;
183 }
184 OpenTelemetryPluginEnd2EndTest::Init(std::move(
185 Options()
186 .set_metric_names(metric_names)
187 .add_plugin_option(std::make_unique<MeshLabelsPluginOption>(
188 GetParam().GetTestResource().GetAttributes()))
189 .set_labels_to_inject(std::move(labels_to_inject))
190 .set_channel_scope_filter(
191 [enable_client_side_injector](
__anond9016ec40202( const OpenTelemetryPluginBuilder::ChannelScope& ) 192 const OpenTelemetryPluginBuilder::ChannelScope& /*scope*/) {
193 return enable_client_side_injector;
194 })));
195 }
196
~MetadataExchangeTest()197 ~MetadataExchangeTest() override {
198 grpc_core::UnsetEnv("GRPC_XDS_BOOTSTRAP_CONFIG");
199 grpc_core::UnsetEnv("GRPC_XDS_BOOTSTRAP");
200 if (bootstrap_file_name_ != nullptr) {
201 remove(bootstrap_file_name_);
202 gpr_free(bootstrap_file_name_);
203 }
204 }
205
VerifyServiceMeshAttributes(const std::map<std::string,opentelemetry::sdk::common::OwnedAttributeValue> & attributes,bool is_client)206 void VerifyServiceMeshAttributes(
207 const std::map<std::string,
208 opentelemetry::sdk::common::OwnedAttributeValue>&
209 attributes,
210 bool is_client) {
211 EXPECT_EQ(
212 absl::get<std::string>(attributes.at("csm.workload_canonical_service")),
213 "canonical_service");
214 EXPECT_EQ(absl::get<std::string>(attributes.at("csm.mesh_id")), "mesh-id");
215 EXPECT_EQ(absl::get<std::string>(
216 attributes.at("csm.remote_workload_canonical_service")),
217 "canonical_service");
218 if (is_client) {
219 EXPECT_EQ(absl::get<std::string>(attributes.at("csm.service_name")),
220 "unknown");
221 EXPECT_EQ(
222 absl::get<std::string>(attributes.at("csm.service_namespace_name")),
223 "unknown");
224 } else {
225 // The CSM optional labels should not be present in server metrics.
226 EXPECT_THAT(attributes, ::testing::Not(::testing::Contains(
227 ::testing::Key("csm.service_name"))));
228 EXPECT_THAT(attributes, ::testing::Not(::testing::Contains(::testing::Key(
229 "csm.service_namespace_name"))));
230 }
231 switch (GetParam().type()) {
232 case TestScenario::ResourceType::kGke:
233 EXPECT_EQ(
234 absl::get<std::string>(attributes.at("csm.remote_workload_type")),
235 "gcp_kubernetes_engine");
236 EXPECT_EQ(
237 absl::get<std::string>(attributes.at("csm.remote_workload_name")),
238 "workload");
239 EXPECT_EQ(absl::get<std::string>(
240 attributes.at("csm.remote_workload_namespace_name")),
241 "namespace");
242 EXPECT_EQ(absl::get<std::string>(
243 attributes.at("csm.remote_workload_cluster_name")),
244 "cluster");
245 EXPECT_EQ(absl::get<std::string>(
246 attributes.at("csm.remote_workload_location")),
247 "region");
248 EXPECT_EQ(absl::get<std::string>(
249 attributes.at("csm.remote_workload_project_id")),
250 "id");
251 break;
252 case TestScenario::ResourceType::kGce:
253 EXPECT_EQ(
254 absl::get<std::string>(attributes.at("csm.remote_workload_type")),
255 "gcp_compute_engine");
256 EXPECT_EQ(
257 absl::get<std::string>(attributes.at("csm.remote_workload_name")),
258 "workload");
259 EXPECT_EQ(absl::get<std::string>(
260 attributes.at("csm.remote_workload_location")),
261 "zone");
262 EXPECT_EQ(absl::get<std::string>(
263 attributes.at("csm.remote_workload_project_id")),
264 "id");
265 break;
266 case TestScenario::ResourceType::kUnknown:
267 EXPECT_EQ(
268 absl::get<std::string>(attributes.at("csm.remote_workload_type")),
269 "random");
270 break;
271 }
272 }
273
VerifyNoServiceMeshAttributes(const std::map<std::string,opentelemetry::sdk::common::OwnedAttributeValue> & attributes)274 void VerifyNoServiceMeshAttributes(
275 const std::map<std::string,
276 opentelemetry::sdk::common::OwnedAttributeValue>&
277 attributes) {
278 EXPECT_EQ(attributes.find("csm.remote_workload_type"), attributes.end());
279 }
280
281 private:
282 char* bootstrap_file_name_ = nullptr;
283 };
284
285 // Verify that grpc.client.attempt.started does not get service mesh attributes
TEST_P(MetadataExchangeTest,ClientAttemptStarted)286 TEST_P(MetadataExchangeTest, ClientAttemptStarted) {
287 Init(/*metric_names=*/{
288 grpc::OpenTelemetryPluginBuilder::kClientAttemptStartedInstrumentName});
289 SendRPC();
290 const char* kMetricName = "grpc.client.attempt.started";
291 auto data = ReadCurrentMetricsData(
292 [&](const absl::flat_hash_map<
293 std::string,
294 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
295 data) { return !data.contains(kMetricName); });
296 ASSERT_EQ(data[kMetricName].size(), 1);
297 auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
298 &data[kMetricName][0].point_data);
299 ASSERT_NE(point_data, nullptr);
300 auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
301 ASSERT_NE(client_started_value, nullptr);
302 EXPECT_EQ(*client_started_value, 1);
303 const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
304 EXPECT_EQ(absl::get<std::string>(attributes.at("grpc.method")), kMethodName);
305 EXPECT_EQ(absl::get<std::string>(attributes.at("grpc.target")),
306 canonical_server_address_);
307 VerifyNoServiceMeshAttributes(attributes);
308 }
309
TEST_P(MetadataExchangeTest,ClientAttemptDuration)310 TEST_P(MetadataExchangeTest, ClientAttemptDuration) {
311 Init(/*metric_names=*/{
312 grpc::OpenTelemetryPluginBuilder::kClientAttemptDurationInstrumentName});
313 SendRPC();
314 const char* kMetricName = "grpc.client.attempt.duration";
315 auto data = ReadCurrentMetricsData(
316 [&](const absl::flat_hash_map<
317 std::string,
318 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
319 data) { return !data.contains(kMetricName); });
320 ASSERT_EQ(data[kMetricName].size(), 1);
321 auto point_data =
322 absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
323 &data[kMetricName][0].point_data);
324 ASSERT_NE(point_data, nullptr);
325 ASSERT_EQ(point_data->count_, 1);
326 const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
327 EXPECT_EQ(absl::get<std::string>(attributes.at("grpc.method")), kMethodName);
328 EXPECT_EQ(absl::get<std::string>(attributes.at("grpc.target")),
329 canonical_server_address_);
330 EXPECT_EQ(absl::get<std::string>(attributes.at("grpc.status")), "OK");
331 VerifyServiceMeshAttributes(attributes, /*is_client=*/true);
332 }
333
334 // Verify that grpc.server.call.started does not get service mesh attributes
TEST_P(MetadataExchangeTest,ServerCallStarted)335 TEST_P(MetadataExchangeTest, ServerCallStarted) {
336 Init(
337 /*metric_names=*/{
338 grpc::OpenTelemetryPluginBuilder::kServerCallStartedInstrumentName});
339 SendRPC();
340 const char* kMetricName = "grpc.server.call.started";
341 auto data = ReadCurrentMetricsData(
342 [&](const absl::flat_hash_map<
343 std::string,
344 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
345 data) { return !data.contains(kMetricName); });
346 ASSERT_EQ(data[kMetricName].size(), 1);
347 auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
348 &data[kMetricName][0].point_data);
349 ASSERT_NE(point_data, nullptr);
350 ASSERT_EQ(absl::get<int64_t>(point_data->value_), 1);
351 const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
352 EXPECT_EQ(absl::get<std::string>(attributes.at("grpc.method")), kMethodName);
353 VerifyNoServiceMeshAttributes(attributes);
354 }
355
TEST_P(MetadataExchangeTest,ServerCallDuration)356 TEST_P(MetadataExchangeTest, ServerCallDuration) {
357 Init(
358 /*metric_names=*/{
359 grpc::OpenTelemetryPluginBuilder::kServerCallDurationInstrumentName});
360 SendRPC();
361 const char* kMetricName = "grpc.server.call.duration";
362 auto data = ReadCurrentMetricsData(
363 [&](const absl::flat_hash_map<
364 std::string,
365 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
366 data) { return !data.contains(kMetricName); });
367 ASSERT_EQ(data[kMetricName].size(), 1);
368 auto point_data =
369 absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
370 &data[kMetricName][0].point_data);
371 ASSERT_NE(point_data, nullptr);
372 ASSERT_EQ(point_data->count_, 1);
373 const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
374 EXPECT_EQ(absl::get<std::string>(attributes.at("grpc.method")), kMethodName);
375 EXPECT_EQ(absl::get<std::string>(attributes.at("grpc.status")), "OK");
376 VerifyServiceMeshAttributes(attributes, /*is_client=*/false);
377 }
378
379 // Test that the server records unknown when the client does not send metadata
TEST_P(MetadataExchangeTest,ClientDoesNotSendMetadata)380 TEST_P(MetadataExchangeTest, ClientDoesNotSendMetadata) {
381 Init(
382 /*metric_names=*/{grpc::OpenTelemetryPluginBuilder::
383 kServerCallDurationInstrumentName},
384 /*enable_client_side_injector=*/false);
385 SendRPC();
386 const char* kMetricName = "grpc.server.call.duration";
387 auto data = ReadCurrentMetricsData(
388 [&](const absl::flat_hash_map<
389 std::string,
390 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
391 data) { return !data.contains(kMetricName); });
392 ASSERT_EQ(data[kMetricName].size(), 1);
393 auto point_data =
394 absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
395 &data[kMetricName][0].point_data);
396 ASSERT_NE(point_data, nullptr);
397 ASSERT_EQ(point_data->count_, 1);
398 const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
399 EXPECT_EQ(absl::get<std::string>(attributes.at("grpc.method")), kMethodName);
400 EXPECT_EQ(absl::get<std::string>(attributes.at("grpc.status")), "OK");
401 EXPECT_EQ(
402 absl::get<std::string>(attributes.at("csm.workload_canonical_service")),
403 "canonical_service");
404 EXPECT_EQ(absl::get<std::string>(attributes.at("csm.mesh_id")), "mesh-id");
405 EXPECT_EQ(absl::get<std::string>(attributes.at("csm.remote_workload_type")),
406 "unknown");
407 }
408
TEST_P(MetadataExchangeTest,VerifyCsmServiceLabels)409 TEST_P(MetadataExchangeTest, VerifyCsmServiceLabels) {
410 Init(/*metric_names=*/{grpc::OpenTelemetryPluginBuilder::
411 kClientAttemptDurationInstrumentName},
412 /*enable_client_side_injector=*/true,
413 // Injects CSM service labels to be recorded in the call.
414 {{OptionalLabelKey::kXdsServiceName,
415 grpc_core::RefCountedStringValue("myservice")},
416 {OptionalLabelKey::kXdsServiceNamespace,
417 grpc_core::RefCountedStringValue("mynamespace")}});
418 SendRPC();
419 const char* kMetricName = "grpc.client.attempt.duration";
420 auto data = ReadCurrentMetricsData(
421 [&](const absl::flat_hash_map<
422 std::string,
423 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
424 data) { return !data.contains(kMetricName); });
425 ASSERT_EQ(data[kMetricName].size(), 1);
426 const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
427 EXPECT_EQ(absl::get<std::string>(attributes.at("csm.service_name")),
428 "myservice");
429 EXPECT_EQ(absl::get<std::string>(attributes.at("csm.service_namespace_name")),
430 "mynamespace");
431 }
432
433 // Creates a serialized slice with labels for metadata exchange based on \a
434 // resource.
RemoteMetadataSliceFromResource(const opentelemetry::sdk::resource::Resource & resource)435 grpc_core::Slice RemoteMetadataSliceFromResource(
436 const opentelemetry::sdk::resource::Resource& resource) {
437 return grpc::internal::ServiceMeshLabelsInjector(resource.GetAttributes())
438 .TestOnlySerializedLabels()
439 .Ref();
440 }
441
LabelsFromIterable(grpc::internal::MeshLabelsIterable * iterable)442 std::vector<std::pair<absl::string_view, absl::string_view>> LabelsFromIterable(
443 grpc::internal::MeshLabelsIterable* iterable) {
444 std::vector<std::pair<absl::string_view, absl::string_view>> labels;
445 while (true) {
446 auto label = iterable->Next();
447 if (!label.has_value()) break;
448 labels.push_back(*std::move(label));
449 }
450 EXPECT_EQ(labels.size(), iterable->Size());
451 return labels;
452 }
453
PrettyPrintLabels(const std::vector<std::pair<absl::string_view,absl::string_view>> & labels)454 std::string PrettyPrintLabels(
455 const std::vector<std::pair<absl::string_view, absl::string_view>>&
456 labels) {
457 std::vector<std::string> strings;
458 strings.reserve(labels.size());
459 for (const auto& pair : labels) {
460 strings.push_back(
461 absl::StrFormat("{\"%s\" : \"%s\"}", pair.first, pair.second));
462 }
463 return absl::StrJoin(strings, ", ");
464 }
465
TEST(MeshLabelsIterableTest,NoRemoteMetadata)466 TEST(MeshLabelsIterableTest, NoRemoteMetadata) {
467 std::vector<std::pair<absl::string_view, std::string>> local_labels = {
468 {"csm.workload_canonical_service", "canonical_service"},
469 {"csm.mesh_id", "mesh"}};
470 grpc::internal::MeshLabelsIterable iterable(local_labels, grpc_core::Slice());
471 auto labels = LabelsFromIterable(&iterable);
472 EXPECT_FALSE(iterable.GotRemoteLabels());
473 EXPECT_THAT(
474 labels,
475 ElementsAre(Pair("csm.workload_canonical_service", "canonical_service"),
476 Pair("csm.mesh_id", "mesh"),
477 Pair("csm.remote_workload_type", "unknown"),
478 Pair("csm.remote_workload_canonical_service", "unknown")))
479 << PrettyPrintLabels(labels);
480 }
481
TEST(MeshLabelsIterableTest,RemoteGceTypeMetadata)482 TEST(MeshLabelsIterableTest, RemoteGceTypeMetadata) {
483 std::vector<std::pair<absl::string_view, std::string>> local_labels = {
484 {"csm.workload_canonical_service", "canonical_service"},
485 {"csm.mesh_id", "mesh"}};
486 grpc::internal::MeshLabelsIterable iterable(
487 local_labels, RemoteMetadataSliceFromResource(TestGceResource()));
488 auto labels = LabelsFromIterable(&iterable);
489 EXPECT_TRUE(iterable.GotRemoteLabels());
490 EXPECT_THAT(
491 labels,
492 ElementsAre(
493 Pair("csm.workload_canonical_service", "canonical_service"),
494 Pair("csm.mesh_id", "mesh"),
495 Pair("csm.remote_workload_type", "gcp_compute_engine"),
496 Pair("csm.remote_workload_canonical_service", "canonical_service"),
497 Pair("csm.remote_workload_name", "workload"),
498 Pair("csm.remote_workload_location", "zone"),
499 Pair("csm.remote_workload_project_id", "id")))
500 << PrettyPrintLabels(labels);
501 }
502
TEST(MeshLabelsIterableTest,RemoteGkeTypeMetadata)503 TEST(MeshLabelsIterableTest, RemoteGkeTypeMetadata) {
504 std::vector<std::pair<absl::string_view, std::string>> local_labels = {
505 {"csm.workload_canonical_service", "canonical_service"},
506 {"csm.mesh_id", "mesh"}};
507 grpc::internal::MeshLabelsIterable iterable(
508 local_labels, RemoteMetadataSliceFromResource(TestGkeResource()));
509 auto labels = LabelsFromIterable(&iterable);
510 EXPECT_TRUE(iterable.GotRemoteLabels());
511 EXPECT_THAT(
512 labels,
513 ElementsAre(
514 Pair("csm.workload_canonical_service", "canonical_service"),
515 Pair("csm.mesh_id", "mesh"),
516 Pair("csm.remote_workload_type", "gcp_kubernetes_engine"),
517 Pair("csm.remote_workload_canonical_service", "canonical_service"),
518 Pair("csm.remote_workload_name", "workload"),
519 Pair("csm.remote_workload_namespace_name", "namespace"),
520 Pair("csm.remote_workload_cluster_name", "cluster"),
521 Pair("csm.remote_workload_location", "region"),
522 Pair("csm.remote_workload_project_id", "id")))
523 << PrettyPrintLabels(labels);
524 }
525
TEST(MeshLabelsIterableTest,RemoteUnknownTypeMetadata)526 TEST(MeshLabelsIterableTest, RemoteUnknownTypeMetadata) {
527 std::vector<std::pair<absl::string_view, std::string>> local_labels = {
528 {"csm.workload_canonical_service", "canonical_service"},
529 {"csm.mesh_id", "mesh"}};
530 grpc::internal::MeshLabelsIterable iterable(
531 local_labels, RemoteMetadataSliceFromResource(TestUnknownResource()));
532 auto labels = LabelsFromIterable(&iterable);
533 EXPECT_TRUE(iterable.GotRemoteLabels());
534 EXPECT_THAT(
535 labels,
536 ElementsAre(
537 Pair("csm.workload_canonical_service", "canonical_service"),
538 Pair("csm.mesh_id", "mesh"),
539 Pair("csm.remote_workload_type", "random"),
540 Pair("csm.remote_workload_canonical_service", "canonical_service")))
541 << PrettyPrintLabels(labels);
542 }
543
TEST(MeshLabelsIterableTest,TestResetIteratorPosition)544 TEST(MeshLabelsIterableTest, TestResetIteratorPosition) {
545 std::vector<std::pair<absl::string_view, std::string>> local_labels = {
546 {"csm.workload_canonical_service", "canonical_service"},
547 {"csm.mesh_id", "mesh"}};
548 grpc::internal::MeshLabelsIterable iterable(local_labels, grpc_core::Slice());
549 auto labels = LabelsFromIterable(&iterable);
550 auto expected_labels_matcher = ElementsAre(
551 Pair("csm.workload_canonical_service", "canonical_service"),
552 Pair("csm.mesh_id", "mesh"), Pair("csm.remote_workload_type", "unknown"),
553 Pair("csm.remote_workload_canonical_service", "unknown"));
554 EXPECT_THAT(labels, expected_labels_matcher) << PrettyPrintLabels(labels);
555 // Resetting the iterable should return the entire list again.
556 iterable.ResetIteratorPosition();
557 labels = LabelsFromIterable(&iterable);
558 EXPECT_THAT(labels, expected_labels_matcher) << PrettyPrintLabels(labels);
559 }
560
561 INSTANTIATE_TEST_SUITE_P(
562 MetadataExchange, MetadataExchangeTest,
563 ::testing::Values(
564 TestScenario(TestScenario::ResourceType::kGke,
565 TestScenario::XdsBootstrapSource::kFromConfig),
566 TestScenario(TestScenario::ResourceType::kGke,
567 TestScenario::XdsBootstrapSource::kFromFile),
568 TestScenario(TestScenario::ResourceType::kGce,
569 TestScenario::XdsBootstrapSource::kFromConfig),
570 TestScenario(TestScenario::ResourceType::kGce,
571 TestScenario::XdsBootstrapSource::kFromFile),
572 TestScenario(TestScenario::ResourceType::kUnknown,
573 TestScenario::XdsBootstrapSource::kFromConfig),
574 TestScenario(TestScenario::ResourceType::kUnknown,
575 TestScenario::XdsBootstrapSource::kFromFile)),
576 &TestScenario::Name);
577
578 } // namespace
579 } // namespace testing
580 } // namespace grpc
581
main(int argc,char ** argv)582 int main(int argc, char** argv) {
583 grpc::testing::TestEnvironment env(&argc, argv);
584 ::testing::InitGoogleTest(&argc, argv);
585 grpc_core::SetEnv("CSM_WORKLOAD_NAME", "workload");
586 grpc_core::SetEnv("CSM_CANONICAL_SERVICE_NAME", "canonical_service");
587 return RUN_ALL_TESTS();
588 }
589