xref: /aosp_15_r20/external/grpc-grpc/test/core/xds/xds_endpoint_resource_type_test.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1 //
2 // Copyright 2022 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 <stdint.h>
18 
19 #include <limits>
20 #include <map>
21 #include <memory>
22 #include <string>
23 #include <utility>
24 #include <vector>
25 
26 #include <google/protobuf/wrappers.pb.h>
27 
28 #include "absl/status/status.h"
29 #include "absl/status/statusor.h"
30 #include "absl/strings/str_format.h"
31 #include "absl/types/optional.h"
32 #include "gtest/gtest.h"
33 #include "upb/mem/arena.hpp"
34 #include "upb/reflection/def.hpp"
35 
36 #include <grpc/grpc.h>
37 
38 #include "src/core/ext/xds/xds_bootstrap.h"
39 #include "src/core/ext/xds/xds_bootstrap_grpc.h"
40 #include "src/core/ext/xds/xds_client.h"
41 #include "src/core/ext/xds/xds_client_stats.h"
42 #include "src/core/ext/xds/xds_endpoint.h"
43 #include "src/core/ext/xds/xds_health_status.h"
44 #include "src/core/ext/xds/xds_resource_type.h"
45 #include "src/core/lib/address_utils/sockaddr_utils.h"
46 #include "src/core/lib/channel/channel_args.h"
47 #include "src/core/lib/debug/trace.h"
48 #include "src/core/lib/gprpp/crash.h"
49 #include "src/core/lib/gprpp/ref_counted_ptr.h"
50 #include "src/core/lib/iomgr/error.h"
51 #include "src/core/lib/iomgr/resolved_address.h"
52 #include "src/core/resolver/endpoint_addresses.h"
53 #include "src/proto/grpc/testing/xds/v3/address.pb.h"
54 #include "src/proto/grpc/testing/xds/v3/base.pb.h"
55 #include "src/proto/grpc/testing/xds/v3/endpoint.pb.h"
56 #include "src/proto/grpc/testing/xds/v3/health_check.pb.h"
57 #include "src/proto/grpc/testing/xds/v3/percent.pb.h"
58 #include "test/core/util/scoped_env_var.h"
59 #include "test/core/util/test_config.h"
60 
61 using envoy::config::endpoint::v3::ClusterLoadAssignment;
62 
63 namespace grpc_core {
64 namespace testing {
65 namespace {
66 
67 TraceFlag xds_endpoint_resource_type_test_trace(
68     true, "xds_endpoint_resource_type_test");
69 
70 class XdsEndpointTest : public ::testing::Test {
71  protected:
XdsEndpointTest()72   XdsEndpointTest()
73       : xds_client_(MakeXdsClient()),
74         decode_context_{xds_client_.get(),
75                         *xds_client_->bootstrap().servers().front(),
76                         &xds_endpoint_resource_type_test_trace,
77                         upb_def_pool_.ptr(), upb_arena_.ptr()} {}
78 
MakeXdsClient()79   static RefCountedPtr<XdsClient> MakeXdsClient() {
80     grpc_error_handle error;
81     auto bootstrap = GrpcXdsBootstrap::Create(
82         "{\n"
83         "  \"xds_servers\": [\n"
84         "    {\n"
85         "      \"server_uri\": \"xds.example.com\",\n"
86         "      \"channel_creds\": [\n"
87         "        {\"type\": \"google_default\"}\n"
88         "      ]\n"
89         "    }\n"
90         "  ]\n"
91         "}");
92     if (!bootstrap.ok()) {
93       Crash(absl::StrFormat("Error parsing bootstrap: %s",
94                             bootstrap.status().ToString().c_str()));
95     }
96     return MakeRefCounted<XdsClient>(std::move(*bootstrap),
97                                      /*transport_factory=*/nullptr,
98                                      /*event_engine=*/nullptr,
99                                      /*metrics_reporter=*/nullptr, "foo agent",
100                                      "foo version");
101   }
102 
103   RefCountedPtr<XdsClient> xds_client_;
104   upb::DefPool upb_def_pool_;
105   upb::Arena upb_arena_;
106   XdsResourceType::DecodeContext decode_context_;
107 };
108 
TEST_F(XdsEndpointTest,Definition)109 TEST_F(XdsEndpointTest, Definition) {
110   auto* resource_type = XdsEndpointResourceType::Get();
111   ASSERT_NE(resource_type, nullptr);
112   EXPECT_EQ(resource_type->type_url(),
113             "envoy.config.endpoint.v3.ClusterLoadAssignment");
114   EXPECT_FALSE(resource_type->AllResourcesRequiredInSotW());
115 }
116 
TEST_F(XdsEndpointTest,UnparseableProto)117 TEST_F(XdsEndpointTest, UnparseableProto) {
118   std::string serialized_resource("\0", 1);
119   auto* resource_type = XdsEndpointResourceType::Get();
120   auto decode_result =
121       resource_type->Decode(decode_context_, serialized_resource);
122   EXPECT_EQ(decode_result.resource.status().code(),
123             absl::StatusCode::kInvalidArgument);
124   EXPECT_EQ(decode_result.resource.status().message(),
125             "Can't parse ClusterLoadAssignment resource.")
126       << decode_result.resource.status();
127 }
128 
TEST_F(XdsEndpointTest,MinimumValidConfig)129 TEST_F(XdsEndpointTest, MinimumValidConfig) {
130   ClusterLoadAssignment cla;
131   cla.set_cluster_name("foo");
132   auto* locality = cla.add_endpoints();
133   locality->mutable_load_balancing_weight()->set_value(1);
134   auto* locality_name = locality->mutable_locality();
135   locality_name->set_region("myregion");
136   locality_name->set_zone("myzone");
137   locality_name->set_sub_zone("mysubzone");
138   auto* socket_address = locality->add_lb_endpoints()
139                              ->mutable_endpoint()
140                              ->mutable_address()
141                              ->mutable_socket_address();
142   socket_address->set_address("127.0.0.1");
143   socket_address->set_port_value(443);
144   std::string serialized_resource;
145   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
146   auto* resource_type = XdsEndpointResourceType::Get();
147   auto decode_result =
148       resource_type->Decode(decode_context_, serialized_resource);
149   ASSERT_TRUE(decode_result.resource.ok()) << decode_result.resource.status();
150   ASSERT_TRUE(decode_result.name.has_value());
151   EXPECT_EQ(*decode_result.name, "foo");
152   auto& resource =
153       static_cast<const XdsEndpointResource&>(**decode_result.resource);
154   ASSERT_EQ(resource.priorities.size(), 1);
155   const auto& priority = resource.priorities[0];
156   ASSERT_EQ(priority.localities.size(), 1);
157   const auto& p = *priority.localities.begin();
158   ASSERT_EQ(p.first, p.second.name.get());
159   EXPECT_EQ(p.first->region(), "myregion");
160   EXPECT_EQ(p.first->zone(), "myzone");
161   EXPECT_EQ(p.first->sub_zone(), "mysubzone");
162   EXPECT_EQ(p.second.lb_weight, 1);
163   ASSERT_EQ(p.second.endpoints.size(), 1);
164   const auto& address = p.second.endpoints.front();
165   auto addr = grpc_sockaddr_to_string(&address.address(), /*normalize=*/false);
166   ASSERT_TRUE(addr.ok()) << addr.status();
167   EXPECT_EQ(*addr, "127.0.0.1:443");
168   EXPECT_EQ(address.args(), ChannelArgs()
169                                 .Set(GRPC_ARG_ADDRESS_WEIGHT, 1)
170                                 .Set(GRPC_ARG_XDS_HEALTH_STATUS,
171                                      XdsHealthStatus::HealthStatus::kUnknown));
172   EXPECT_EQ(resource.drop_config, nullptr);
173 }
174 
TEST_F(XdsEndpointTest,EndpointWeight)175 TEST_F(XdsEndpointTest, EndpointWeight) {
176   ClusterLoadAssignment cla;
177   cla.set_cluster_name("foo");
178   auto* locality = cla.add_endpoints();
179   locality->mutable_load_balancing_weight()->set_value(1);
180   auto* locality_name = locality->mutable_locality();
181   locality_name->set_region("myregion");
182   locality_name->set_zone("myzone");
183   locality_name->set_sub_zone("mysubzone");
184   auto* endpoint = locality->add_lb_endpoints();
185   endpoint->mutable_load_balancing_weight()->set_value(3);
186   auto* socket_address =
187       endpoint->mutable_endpoint()->mutable_address()->mutable_socket_address();
188   socket_address->set_address("127.0.0.1");
189   socket_address->set_port_value(443);
190   std::string serialized_resource;
191   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
192   auto* resource_type = XdsEndpointResourceType::Get();
193   auto decode_result =
194       resource_type->Decode(decode_context_, serialized_resource);
195   ASSERT_TRUE(decode_result.resource.ok()) << decode_result.resource.status();
196   ASSERT_TRUE(decode_result.name.has_value());
197   EXPECT_EQ(*decode_result.name, "foo");
198   auto& resource =
199       static_cast<const XdsEndpointResource&>(**decode_result.resource);
200   ASSERT_EQ(resource.priorities.size(), 1);
201   const auto& priority = resource.priorities[0];
202   ASSERT_EQ(priority.localities.size(), 1);
203   const auto& p = *priority.localities.begin();
204   ASSERT_EQ(p.first, p.second.name.get());
205   EXPECT_EQ(p.first->region(), "myregion");
206   EXPECT_EQ(p.first->zone(), "myzone");
207   EXPECT_EQ(p.first->sub_zone(), "mysubzone");
208   EXPECT_EQ(p.second.lb_weight, 1);
209   ASSERT_EQ(p.second.endpoints.size(), 1);
210   const auto& address = p.second.endpoints.front();
211   auto addr = grpc_sockaddr_to_string(&address.address(), /*normalize=*/false);
212   ASSERT_TRUE(addr.ok()) << addr.status();
213   EXPECT_EQ(*addr, "127.0.0.1:443");
214   EXPECT_EQ(address.args(), ChannelArgs()
215                                 .Set(GRPC_ARG_ADDRESS_WEIGHT, 3)
216                                 .Set(GRPC_ARG_XDS_HEALTH_STATUS,
217                                      XdsHealthStatus::HealthStatus::kUnknown));
218   EXPECT_EQ(resource.drop_config, nullptr);
219 }
220 
TEST_F(XdsEndpointTest,IgnoresLocalityWithNoWeight)221 TEST_F(XdsEndpointTest, IgnoresLocalityWithNoWeight) {
222   ClusterLoadAssignment cla;
223   cla.set_cluster_name("foo");
224   auto* locality = cla.add_endpoints();
225   auto* locality_name = locality->mutable_locality();
226   locality_name->set_region("myregion");
227   locality_name->set_zone("myzone");
228   locality_name->set_sub_zone("mysubzone");
229   auto* socket_address = locality->add_lb_endpoints()
230                              ->mutable_endpoint()
231                              ->mutable_address()
232                              ->mutable_socket_address();
233   socket_address->set_address("127.0.0.1");
234   socket_address->set_port_value(443);
235   locality = cla.add_endpoints();
236   *locality = cla.endpoints(0);
237   locality->mutable_load_balancing_weight()->set_value(1);
238   std::string serialized_resource;
239   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
240   auto* resource_type = XdsEndpointResourceType::Get();
241   auto decode_result =
242       resource_type->Decode(decode_context_, serialized_resource);
243   ASSERT_TRUE(decode_result.resource.ok()) << decode_result.resource.status();
244   ASSERT_TRUE(decode_result.name.has_value());
245   EXPECT_EQ(*decode_result.name, "foo");
246   auto& resource =
247       static_cast<const XdsEndpointResource&>(**decode_result.resource);
248   ASSERT_EQ(resource.priorities.size(), 1);
249   const auto& priority = resource.priorities[0];
250   ASSERT_EQ(priority.localities.size(), 1);
251   const auto& p = *priority.localities.begin();
252   ASSERT_EQ(p.first, p.second.name.get());
253   EXPECT_EQ(p.first->region(), "myregion");
254   EXPECT_EQ(p.first->zone(), "myzone");
255   EXPECT_EQ(p.first->sub_zone(), "mysubzone");
256   EXPECT_EQ(p.second.lb_weight, 1);
257   ASSERT_EQ(p.second.endpoints.size(), 1);
258   const auto& address = p.second.endpoints.front();
259   auto addr = grpc_sockaddr_to_string(&address.address(), /*normalize=*/false);
260   ASSERT_TRUE(addr.ok()) << addr.status();
261   EXPECT_EQ(*addr, "127.0.0.1:443");
262   EXPECT_EQ(address.args(), ChannelArgs()
263                                 .Set(GRPC_ARG_ADDRESS_WEIGHT, 1)
264                                 .Set(GRPC_ARG_XDS_HEALTH_STATUS,
265                                      XdsHealthStatus::HealthStatus::kUnknown));
266   EXPECT_EQ(resource.drop_config, nullptr);
267 }
268 
TEST_F(XdsEndpointTest,IgnoresLocalityWithZeroWeight)269 TEST_F(XdsEndpointTest, IgnoresLocalityWithZeroWeight) {
270   ClusterLoadAssignment cla;
271   cla.set_cluster_name("foo");
272   auto* locality = cla.add_endpoints();
273   locality->mutable_load_balancing_weight()->set_value(0);
274   auto* locality_name = locality->mutable_locality();
275   locality_name->set_region("myregion");
276   locality_name->set_zone("myzone");
277   locality_name->set_sub_zone("mysubzone");
278   auto* socket_address = locality->add_lb_endpoints()
279                              ->mutable_endpoint()
280                              ->mutable_address()
281                              ->mutable_socket_address();
282   socket_address->set_address("127.0.0.1");
283   socket_address->set_port_value(443);
284   locality = cla.add_endpoints();
285   *locality = cla.endpoints(0);
286   locality->mutable_load_balancing_weight()->set_value(1);
287   std::string serialized_resource;
288   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
289   auto* resource_type = XdsEndpointResourceType::Get();
290   auto decode_result =
291       resource_type->Decode(decode_context_, serialized_resource);
292   ASSERT_TRUE(decode_result.resource.ok()) << decode_result.resource.status();
293   ASSERT_TRUE(decode_result.name.has_value());
294   EXPECT_EQ(*decode_result.name, "foo");
295   auto& resource =
296       static_cast<const XdsEndpointResource&>(**decode_result.resource);
297   ASSERT_EQ(resource.priorities.size(), 1);
298   const auto& priority = resource.priorities[0];
299   ASSERT_EQ(priority.localities.size(), 1);
300   const auto& p = *priority.localities.begin();
301   ASSERT_EQ(p.first, p.second.name.get());
302   EXPECT_EQ(p.first->region(), "myregion");
303   EXPECT_EQ(p.first->zone(), "myzone");
304   EXPECT_EQ(p.first->sub_zone(), "mysubzone");
305   EXPECT_EQ(p.second.lb_weight, 1);
306   ASSERT_EQ(p.second.endpoints.size(), 1);
307   const auto& address = p.second.endpoints.front();
308   auto addr = grpc_sockaddr_to_string(&address.address(), /*normalize=*/false);
309   ASSERT_TRUE(addr.ok()) << addr.status();
310   EXPECT_EQ(*addr, "127.0.0.1:443");
311   EXPECT_EQ(address.args(), ChannelArgs()
312                                 .Set(GRPC_ARG_ADDRESS_WEIGHT, 1)
313                                 .Set(GRPC_ARG_XDS_HEALTH_STATUS,
314                                      XdsHealthStatus::HealthStatus::kUnknown));
315   EXPECT_EQ(resource.drop_config, nullptr);
316 }
317 
TEST_F(XdsEndpointTest,LocalityWithNoEndpoints)318 TEST_F(XdsEndpointTest, LocalityWithNoEndpoints) {
319   ClusterLoadAssignment cla;
320   cla.set_cluster_name("foo");
321   auto* locality = cla.add_endpoints();
322   locality->mutable_load_balancing_weight()->set_value(1);
323   auto* locality_name = locality->mutable_locality();
324   locality_name->set_region("myregion");
325   locality_name->set_zone("myzone");
326   locality_name->set_sub_zone("mysubzone");
327   std::string serialized_resource;
328   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
329   auto* resource_type = XdsEndpointResourceType::Get();
330   auto decode_result =
331       resource_type->Decode(decode_context_, serialized_resource);
332   ASSERT_TRUE(decode_result.resource.ok()) << decode_result.resource.status();
333   ASSERT_TRUE(decode_result.name.has_value());
334   EXPECT_EQ(*decode_result.name, "foo");
335   auto& resource =
336       static_cast<const XdsEndpointResource&>(**decode_result.resource);
337   ASSERT_EQ(resource.priorities.size(), 1);
338   const auto& priority = resource.priorities[0];
339   ASSERT_EQ(priority.localities.size(), 1);
340   const auto& p = *priority.localities.begin();
341   ASSERT_EQ(p.first, p.second.name.get());
342   EXPECT_EQ(p.first->region(), "myregion");
343   EXPECT_EQ(p.first->zone(), "myzone");
344   EXPECT_EQ(p.first->sub_zone(), "mysubzone");
345   EXPECT_EQ(p.second.lb_weight, 1);
346   EXPECT_EQ(p.second.endpoints.size(), 0);
347   EXPECT_EQ(resource.drop_config, nullptr);
348 }
349 
TEST_F(XdsEndpointTest,NoLocality)350 TEST_F(XdsEndpointTest, NoLocality) {
351   ClusterLoadAssignment cla;
352   cla.set_cluster_name("foo");
353   auto* locality = cla.add_endpoints();
354   locality->mutable_load_balancing_weight()->set_value(1);
355   auto* socket_address = locality->add_lb_endpoints()
356                              ->mutable_endpoint()
357                              ->mutable_address()
358                              ->mutable_socket_address();
359   socket_address->set_address("127.0.0.1");
360   socket_address->set_port_value(443);
361   std::string serialized_resource;
362   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
363   auto* resource_type = XdsEndpointResourceType::Get();
364   auto decode_result =
365       resource_type->Decode(decode_context_, serialized_resource);
366   ASSERT_TRUE(decode_result.name.has_value());
367   EXPECT_EQ(*decode_result.name, "foo");
368   EXPECT_EQ(decode_result.resource.status().code(),
369             absl::StatusCode::kInvalidArgument);
370   EXPECT_EQ(decode_result.resource.status().message(),
371             "errors parsing EDS resource: ["
372             "field:endpoints[0].locality error:field not present]")
373       << decode_result.resource.status();
374 }
375 
TEST_F(XdsEndpointTest,InvalidPort)376 TEST_F(XdsEndpointTest, InvalidPort) {
377   ClusterLoadAssignment cla;
378   cla.set_cluster_name("foo");
379   auto* locality = cla.add_endpoints();
380   locality->mutable_load_balancing_weight()->set_value(1);
381   auto* locality_name = locality->mutable_locality();
382   locality_name->set_region("myregion");
383   locality_name->set_zone("myzone");
384   locality_name->set_sub_zone("mysubzone");
385   auto* socket_address = locality->add_lb_endpoints()
386                              ->mutable_endpoint()
387                              ->mutable_address()
388                              ->mutable_socket_address();
389   socket_address->set_address("127.0.0.1");
390   socket_address->set_port_value(65537);
391   std::string serialized_resource;
392   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
393   auto* resource_type = XdsEndpointResourceType::Get();
394   auto decode_result =
395       resource_type->Decode(decode_context_, serialized_resource);
396   ASSERT_TRUE(decode_result.name.has_value());
397   EXPECT_EQ(*decode_result.name, "foo");
398   EXPECT_EQ(decode_result.resource.status().code(),
399             absl::StatusCode::kInvalidArgument);
400   EXPECT_EQ(decode_result.resource.status().message(),
401             "errors parsing EDS resource: ["
402             "field:endpoints[0].lb_endpoints[0].endpoint.address"
403             ".socket_address.port_value error:invalid port]")
404       << decode_result.resource.status();
405 }
406 
TEST_F(XdsEndpointTest,InvalidAddress)407 TEST_F(XdsEndpointTest, InvalidAddress) {
408   ClusterLoadAssignment cla;
409   cla.set_cluster_name("foo");
410   auto* locality = cla.add_endpoints();
411   locality->mutable_load_balancing_weight()->set_value(1);
412   auto* locality_name = locality->mutable_locality();
413   locality_name->set_region("myregion");
414   locality_name->set_zone("myzone");
415   locality_name->set_sub_zone("mysubzone");
416   auto* socket_address = locality->add_lb_endpoints()
417                              ->mutable_endpoint()
418                              ->mutable_address()
419                              ->mutable_socket_address();
420   socket_address->set_address("not_an_ip_address");
421   socket_address->set_port_value(443);
422   std::string serialized_resource;
423   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
424   auto* resource_type = XdsEndpointResourceType::Get();
425   auto decode_result =
426       resource_type->Decode(decode_context_, serialized_resource);
427   ASSERT_TRUE(decode_result.name.has_value());
428   EXPECT_EQ(*decode_result.name, "foo");
429   EXPECT_EQ(decode_result.resource.status().code(),
430             absl::StatusCode::kInvalidArgument);
431   EXPECT_EQ(decode_result.resource.status().message(),
432             "errors parsing EDS resource: ["
433             "field:endpoints[0].lb_endpoints[0].endpoint.address"
434             ".socket_address error:"
435             "Failed to parse address:not_an_ip_address:443]")
436       << decode_result.resource.status();
437 }
438 
TEST_F(XdsEndpointTest,MissingSocketAddress)439 TEST_F(XdsEndpointTest, MissingSocketAddress) {
440   ClusterLoadAssignment cla;
441   cla.set_cluster_name("foo");
442   auto* locality = cla.add_endpoints();
443   locality->mutable_load_balancing_weight()->set_value(1);
444   auto* locality_name = locality->mutable_locality();
445   locality_name->set_region("myregion");
446   locality_name->set_zone("myzone");
447   locality_name->set_sub_zone("mysubzone");
448   locality->add_lb_endpoints()->mutable_endpoint()->mutable_address();
449   std::string serialized_resource;
450   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
451   auto* resource_type = XdsEndpointResourceType::Get();
452   auto decode_result =
453       resource_type->Decode(decode_context_, serialized_resource);
454   ASSERT_TRUE(decode_result.name.has_value());
455   EXPECT_EQ(*decode_result.name, "foo");
456   EXPECT_EQ(decode_result.resource.status().code(),
457             absl::StatusCode::kInvalidArgument);
458   EXPECT_EQ(decode_result.resource.status().message(),
459             "errors parsing EDS resource: ["
460             "field:endpoints[0].lb_endpoints[0].endpoint.address"
461             ".socket_address error:field not present]")
462       << decode_result.resource.status();
463 }
464 
TEST_F(XdsEndpointTest,MissingAddress)465 TEST_F(XdsEndpointTest, MissingAddress) {
466   ClusterLoadAssignment cla;
467   cla.set_cluster_name("foo");
468   auto* locality = cla.add_endpoints();
469   locality->mutable_load_balancing_weight()->set_value(1);
470   auto* locality_name = locality->mutable_locality();
471   locality_name->set_region("myregion");
472   locality_name->set_zone("myzone");
473   locality_name->set_sub_zone("mysubzone");
474   locality->add_lb_endpoints()->mutable_endpoint();
475   std::string serialized_resource;
476   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
477   auto* resource_type = XdsEndpointResourceType::Get();
478   auto decode_result =
479       resource_type->Decode(decode_context_, serialized_resource);
480   ASSERT_TRUE(decode_result.name.has_value());
481   EXPECT_EQ(*decode_result.name, "foo");
482   EXPECT_EQ(decode_result.resource.status().code(),
483             absl::StatusCode::kInvalidArgument);
484   EXPECT_EQ(decode_result.resource.status().message(),
485             "errors parsing EDS resource: ["
486             "field:endpoints[0].lb_endpoints[0].endpoint.address "
487             "error:field not present]")
488       << decode_result.resource.status();
489 }
490 
TEST_F(XdsEndpointTest,MultipleAddressesPerEndpoint)491 TEST_F(XdsEndpointTest, MultipleAddressesPerEndpoint) {
492   testing::ScopedExperimentalEnvVar env(
493       "GRPC_EXPERIMENTAL_XDS_DUALSTACK_ENDPOINTS");
494   ClusterLoadAssignment cla;
495   cla.set_cluster_name("foo");
496   auto* locality = cla.add_endpoints();
497   locality->mutable_load_balancing_weight()->set_value(1);
498   auto* locality_name = locality->mutable_locality();
499   locality_name->set_region("myregion");
500   locality_name->set_zone("myzone");
501   locality_name->set_sub_zone("mysubzone");
502   auto* ep = locality->add_lb_endpoints()->mutable_endpoint();
503   auto* socket_address = ep->mutable_address()->mutable_socket_address();
504   socket_address->set_address("127.0.0.1");
505   socket_address->set_port_value(443);
506   socket_address = ep->add_additional_addresses()
507                        ->mutable_address()
508                        ->mutable_socket_address();
509   socket_address->set_address("127.0.0.1");
510   socket_address->set_port_value(444);
511   std::string serialized_resource;
512   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
513   auto* resource_type = XdsEndpointResourceType::Get();
514   auto decode_result =
515       resource_type->Decode(decode_context_, serialized_resource);
516   ASSERT_TRUE(decode_result.resource.ok()) << decode_result.resource.status();
517   ASSERT_TRUE(decode_result.name.has_value());
518   EXPECT_EQ(*decode_result.name, "foo");
519   auto& resource =
520       static_cast<const XdsEndpointResource&>(**decode_result.resource);
521   ASSERT_EQ(resource.priorities.size(), 1);
522   const auto& priority = resource.priorities[0];
523   ASSERT_EQ(priority.localities.size(), 1);
524   const auto& p = *priority.localities.begin();
525   ASSERT_EQ(p.first, p.second.name.get());
526   EXPECT_EQ(p.first->region(), "myregion");
527   EXPECT_EQ(p.first->zone(), "myzone");
528   EXPECT_EQ(p.first->sub_zone(), "mysubzone");
529   EXPECT_EQ(p.second.lb_weight, 1);
530   ASSERT_EQ(p.second.endpoints.size(), 1);
531   const auto& endpoint = p.second.endpoints.front();
532   ASSERT_EQ(endpoint.addresses().size(), 2);
533   auto addr =
534       grpc_sockaddr_to_string(&endpoint.addresses()[0], /*normalize=*/false);
535   ASSERT_TRUE(addr.ok()) << addr.status();
536   EXPECT_EQ(*addr, "127.0.0.1:443");
537   addr = grpc_sockaddr_to_string(&endpoint.addresses()[1], /*normalize=*/false);
538   ASSERT_TRUE(addr.ok()) << addr.status();
539   EXPECT_EQ(*addr, "127.0.0.1:444");
540   EXPECT_EQ(endpoint.args(), ChannelArgs()
541                                  .Set(GRPC_ARG_ADDRESS_WEIGHT, 1)
542                                  .Set(GRPC_ARG_XDS_HEALTH_STATUS,
543                                       XdsHealthStatus::HealthStatus::kUnknown));
544   EXPECT_EQ(resource.drop_config, nullptr);
545 }
546 
TEST_F(XdsEndpointTest,AdditionalAddressesMissingAddress)547 TEST_F(XdsEndpointTest, AdditionalAddressesMissingAddress) {
548   testing::ScopedExperimentalEnvVar env(
549       "GRPC_EXPERIMENTAL_XDS_DUALSTACK_ENDPOINTS");
550   ClusterLoadAssignment cla;
551   cla.set_cluster_name("foo");
552   auto* locality = cla.add_endpoints();
553   locality->mutable_load_balancing_weight()->set_value(1);
554   auto* locality_name = locality->mutable_locality();
555   locality_name->set_region("myregion");
556   locality_name->set_zone("myzone");
557   locality_name->set_sub_zone("mysubzone");
558   auto* ep = locality->add_lb_endpoints()->mutable_endpoint();
559   auto* socket_address = ep->mutable_address()->mutable_socket_address();
560   socket_address->set_address("127.0.0.1");
561   socket_address->set_port_value(443);
562   ep->add_additional_addresses();
563   std::string serialized_resource;
564   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
565   auto* resource_type = XdsEndpointResourceType::Get();
566   auto decode_result =
567       resource_type->Decode(decode_context_, serialized_resource);
568   ASSERT_TRUE(decode_result.name.has_value());
569   EXPECT_EQ(*decode_result.name, "foo");
570   EXPECT_EQ(decode_result.resource.status().code(),
571             absl::StatusCode::kInvalidArgument);
572   EXPECT_EQ(decode_result.resource.status().message(),
573             "errors parsing EDS resource: ["
574             "field:endpoints[0].lb_endpoints[0].endpoint"
575             ".additional_addresses[0].address error:field not present]")
576       << decode_result.resource.status();
577 }
578 
TEST_F(XdsEndpointTest,AdditionalAddressesMissingSocketAddress)579 TEST_F(XdsEndpointTest, AdditionalAddressesMissingSocketAddress) {
580   testing::ScopedExperimentalEnvVar env(
581       "GRPC_EXPERIMENTAL_XDS_DUALSTACK_ENDPOINTS");
582   ClusterLoadAssignment cla;
583   cla.set_cluster_name("foo");
584   auto* locality = cla.add_endpoints();
585   locality->mutable_load_balancing_weight()->set_value(1);
586   auto* locality_name = locality->mutable_locality();
587   locality_name->set_region("myregion");
588   locality_name->set_zone("myzone");
589   locality_name->set_sub_zone("mysubzone");
590   auto* ep = locality->add_lb_endpoints()->mutable_endpoint();
591   auto* socket_address = ep->mutable_address()->mutable_socket_address();
592   socket_address->set_address("127.0.0.1");
593   socket_address->set_port_value(443);
594   ep->add_additional_addresses()->mutable_address();
595   std::string serialized_resource;
596   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
597   auto* resource_type = XdsEndpointResourceType::Get();
598   auto decode_result =
599       resource_type->Decode(decode_context_, serialized_resource);
600   ASSERT_TRUE(decode_result.name.has_value());
601   EXPECT_EQ(*decode_result.name, "foo");
602   EXPECT_EQ(decode_result.resource.status().code(),
603             absl::StatusCode::kInvalidArgument);
604   EXPECT_EQ(decode_result.resource.status().message(),
605             "errors parsing EDS resource: ["
606             "field:endpoints[0].lb_endpoints[0].endpoint"
607             ".additional_addresses[0].address.socket_address "
608             "error:field not present]")
609       << decode_result.resource.status();
610 }
611 
TEST_F(XdsEndpointTest,AdditionalAddressesInvalidPort)612 TEST_F(XdsEndpointTest, AdditionalAddressesInvalidPort) {
613   testing::ScopedExperimentalEnvVar env(
614       "GRPC_EXPERIMENTAL_XDS_DUALSTACK_ENDPOINTS");
615   ClusterLoadAssignment cla;
616   cla.set_cluster_name("foo");
617   auto* locality = cla.add_endpoints();
618   locality->mutable_load_balancing_weight()->set_value(1);
619   auto* locality_name = locality->mutable_locality();
620   locality_name->set_region("myregion");
621   locality_name->set_zone("myzone");
622   locality_name->set_sub_zone("mysubzone");
623   auto* ep = locality->add_lb_endpoints()->mutable_endpoint();
624   auto* socket_address = ep->mutable_address()->mutable_socket_address();
625   socket_address->set_address("127.0.0.1");
626   socket_address->set_port_value(443);
627   socket_address = ep->add_additional_addresses()
628                        ->mutable_address()
629                        ->mutable_socket_address();
630   socket_address->set_address("127.0.0.1");
631   socket_address->set_port_value(65537);
632   std::string serialized_resource;
633   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
634   auto* resource_type = XdsEndpointResourceType::Get();
635   auto decode_result =
636       resource_type->Decode(decode_context_, serialized_resource);
637   ASSERT_TRUE(decode_result.name.has_value());
638   EXPECT_EQ(*decode_result.name, "foo");
639   EXPECT_EQ(decode_result.resource.status().code(),
640             absl::StatusCode::kInvalidArgument);
641   EXPECT_EQ(decode_result.resource.status().message(),
642             "errors parsing EDS resource: ["
643             "field:endpoints[0].lb_endpoints[0].endpoint"
644             ".additional_addresses[0].address.socket_address.port_value "
645             "error:invalid port]")
646       << decode_result.resource.status();
647 }
648 
TEST_F(XdsEndpointTest,AdditionalAddressesInvalidAddress)649 TEST_F(XdsEndpointTest, AdditionalAddressesInvalidAddress) {
650   testing::ScopedExperimentalEnvVar env(
651       "GRPC_EXPERIMENTAL_XDS_DUALSTACK_ENDPOINTS");
652   ClusterLoadAssignment cla;
653   cla.set_cluster_name("foo");
654   auto* locality = cla.add_endpoints();
655   locality->mutable_load_balancing_weight()->set_value(1);
656   auto* locality_name = locality->mutable_locality();
657   locality_name->set_region("myregion");
658   locality_name->set_zone("myzone");
659   locality_name->set_sub_zone("mysubzone");
660   auto* ep = locality->add_lb_endpoints()->mutable_endpoint();
661   auto* socket_address = ep->mutable_address()->mutable_socket_address();
662   socket_address->set_address("127.0.0.1");
663   socket_address->set_port_value(443);
664   socket_address = ep->add_additional_addresses()
665                        ->mutable_address()
666                        ->mutable_socket_address();
667   socket_address->set_address("not_an_ip_address");
668   socket_address->set_port_value(444);
669   std::string serialized_resource;
670   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
671   auto* resource_type = XdsEndpointResourceType::Get();
672   auto decode_result =
673       resource_type->Decode(decode_context_, serialized_resource);
674   ASSERT_TRUE(decode_result.name.has_value());
675   EXPECT_EQ(*decode_result.name, "foo");
676   EXPECT_EQ(decode_result.resource.status().code(),
677             absl::StatusCode::kInvalidArgument);
678   EXPECT_EQ(decode_result.resource.status().message(),
679             "errors parsing EDS resource: ["
680             "field:endpoints[0].lb_endpoints[0].endpoint"
681             ".additional_addresses[0].address.socket_address error:"
682             "Failed to parse address:not_an_ip_address:444]")
683       << decode_result.resource.status();
684 }
685 
TEST_F(XdsEndpointTest,IgnoresMultipleAddressesPerEndpointWhenNotEnabled)686 TEST_F(XdsEndpointTest, IgnoresMultipleAddressesPerEndpointWhenNotEnabled) {
687   ClusterLoadAssignment cla;
688   cla.set_cluster_name("foo");
689   auto* locality = cla.add_endpoints();
690   locality->mutable_load_balancing_weight()->set_value(1);
691   auto* locality_name = locality->mutable_locality();
692   locality_name->set_region("myregion");
693   locality_name->set_zone("myzone");
694   locality_name->set_sub_zone("mysubzone");
695   auto* ep = locality->add_lb_endpoints()->mutable_endpoint();
696   auto* socket_address = ep->mutable_address()->mutable_socket_address();
697   socket_address->set_address("127.0.0.1");
698   socket_address->set_port_value(443);
699   socket_address = ep->add_additional_addresses()
700                        ->mutable_address()
701                        ->mutable_socket_address();
702   socket_address->set_address("127.0.0.1");
703   socket_address->set_port_value(444);
704   std::string serialized_resource;
705   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
706   auto* resource_type = XdsEndpointResourceType::Get();
707   auto decode_result =
708       resource_type->Decode(decode_context_, serialized_resource);
709   ASSERT_TRUE(decode_result.resource.ok()) << decode_result.resource.status();
710   ASSERT_TRUE(decode_result.name.has_value());
711   EXPECT_EQ(*decode_result.name, "foo");
712   auto& resource =
713       static_cast<const XdsEndpointResource&>(**decode_result.resource);
714   ASSERT_EQ(resource.priorities.size(), 1);
715   const auto& priority = resource.priorities[0];
716   ASSERT_EQ(priority.localities.size(), 1);
717   const auto& p = *priority.localities.begin();
718   ASSERT_EQ(p.first, p.second.name.get());
719   EXPECT_EQ(p.first->region(), "myregion");
720   EXPECT_EQ(p.first->zone(), "myzone");
721   EXPECT_EQ(p.first->sub_zone(), "mysubzone");
722   EXPECT_EQ(p.second.lb_weight, 1);
723   ASSERT_EQ(p.second.endpoints.size(), 1);
724   const auto& endpoint = p.second.endpoints.front();
725   ASSERT_EQ(endpoint.addresses().size(), 1);
726   auto addr =
727       grpc_sockaddr_to_string(&endpoint.addresses()[0], /*normalize=*/false);
728   ASSERT_TRUE(addr.ok()) << addr.status();
729   EXPECT_EQ(*addr, "127.0.0.1:443");
730   EXPECT_EQ(endpoint.args(), ChannelArgs()
731                                  .Set(GRPC_ARG_ADDRESS_WEIGHT, 1)
732                                  .Set(GRPC_ARG_XDS_HEALTH_STATUS,
733                                       XdsHealthStatus::HealthStatus::kUnknown));
734   EXPECT_EQ(resource.drop_config, nullptr);
735 }
736 
TEST_F(XdsEndpointTest,MissingEndpoint)737 TEST_F(XdsEndpointTest, MissingEndpoint) {
738   ClusterLoadAssignment cla;
739   cla.set_cluster_name("foo");
740   auto* locality = cla.add_endpoints();
741   locality->mutable_load_balancing_weight()->set_value(1);
742   auto* locality_name = locality->mutable_locality();
743   locality_name->set_region("myregion");
744   locality_name->set_zone("myzone");
745   locality_name->set_sub_zone("mysubzone");
746   locality->add_lb_endpoints();
747   std::string serialized_resource;
748   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
749   auto* resource_type = XdsEndpointResourceType::Get();
750   auto decode_result =
751       resource_type->Decode(decode_context_, serialized_resource);
752   ASSERT_TRUE(decode_result.name.has_value());
753   EXPECT_EQ(*decode_result.name, "foo");
754   EXPECT_EQ(decode_result.resource.status().code(),
755             absl::StatusCode::kInvalidArgument);
756   EXPECT_EQ(decode_result.resource.status().message(),
757             "errors parsing EDS resource: ["
758             "field:endpoints[0].lb_endpoints[0].endpoint "
759             "error:field not present]")
760       << decode_result.resource.status();
761 }
762 
TEST_F(XdsEndpointTest,EndpointWeightZero)763 TEST_F(XdsEndpointTest, EndpointWeightZero) {
764   ClusterLoadAssignment cla;
765   cla.set_cluster_name("foo");
766   auto* locality = cla.add_endpoints();
767   locality->mutable_load_balancing_weight()->set_value(1);
768   auto* locality_name = locality->mutable_locality();
769   locality_name->set_region("myregion");
770   locality_name->set_zone("myzone");
771   locality_name->set_sub_zone("mysubzone");
772   auto* endpoint = locality->add_lb_endpoints();
773   endpoint->mutable_load_balancing_weight()->set_value(0);
774   auto* socket_address =
775       endpoint->mutable_endpoint()->mutable_address()->mutable_socket_address();
776   socket_address->set_address("127.0.0.1");
777   socket_address->set_port_value(443);
778   std::string serialized_resource;
779   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
780   auto* resource_type = XdsEndpointResourceType::Get();
781   auto decode_result =
782       resource_type->Decode(decode_context_, serialized_resource);
783   ASSERT_TRUE(decode_result.name.has_value());
784   EXPECT_EQ(*decode_result.name, "foo");
785   EXPECT_EQ(decode_result.resource.status().code(),
786             absl::StatusCode::kInvalidArgument);
787   EXPECT_EQ(decode_result.resource.status().message(),
788             "errors parsing EDS resource: ["
789             "field:endpoints[0].lb_endpoints[0].load_balancing_weight "
790             "error:must be greater than 0]")
791       << decode_result.resource.status();
792 }
793 
TEST_F(XdsEndpointTest,DuplicateLocalityName)794 TEST_F(XdsEndpointTest, DuplicateLocalityName) {
795   ClusterLoadAssignment cla;
796   cla.set_cluster_name("foo");
797   auto* locality = cla.add_endpoints();
798   locality->mutable_load_balancing_weight()->set_value(1);
799   auto* locality_name = locality->mutable_locality();
800   locality_name->set_region("myregion");
801   locality_name->set_zone("myzone");
802   locality_name->set_sub_zone("mysubzone");
803   auto* socket_address = locality->add_lb_endpoints()
804                              ->mutable_endpoint()
805                              ->mutable_address()
806                              ->mutable_socket_address();
807   socket_address->set_address("127.0.0.1");
808   socket_address->set_port_value(443);
809   locality = cla.add_endpoints();
810   locality->mutable_load_balancing_weight()->set_value(1);
811   locality_name = locality->mutable_locality();
812   locality_name->set_region("myregion");
813   locality_name->set_zone("myzone");
814   locality_name->set_sub_zone("mysubzone");
815   socket_address = locality->add_lb_endpoints()
816                        ->mutable_endpoint()
817                        ->mutable_address()
818                        ->mutable_socket_address();
819   socket_address->set_address("127.0.0.2");
820   socket_address->set_port_value(443);
821   std::string serialized_resource;
822   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
823   auto* resource_type = XdsEndpointResourceType::Get();
824   auto decode_result =
825       resource_type->Decode(decode_context_, serialized_resource);
826   ASSERT_TRUE(decode_result.name.has_value());
827   EXPECT_EQ(*decode_result.name, "foo");
828   EXPECT_EQ(decode_result.resource.status().code(),
829             absl::StatusCode::kInvalidArgument);
830   EXPECT_EQ(decode_result.resource.status().message(),
831             "errors parsing EDS resource: ["
832             "field:endpoints[1] error:duplicate locality {region=\"myregion\", "
833             "zone=\"myzone\", sub_zone=\"mysubzone\"} found in priority 0]")
834       << decode_result.resource.status();
835 }
836 
TEST_F(XdsEndpointTest,SparsePriorityList)837 TEST_F(XdsEndpointTest, SparsePriorityList) {
838   ClusterLoadAssignment cla;
839   cla.set_cluster_name("foo");
840   auto* locality = cla.add_endpoints();
841   locality->mutable_load_balancing_weight()->set_value(1);
842   auto* locality_name = locality->mutable_locality();
843   locality_name->set_region("myregion");
844   locality_name->set_zone("myzone");
845   locality_name->set_sub_zone("mysubzone");
846   auto* socket_address = locality->add_lb_endpoints()
847                              ->mutable_endpoint()
848                              ->mutable_address()
849                              ->mutable_socket_address();
850   socket_address->set_address("127.0.0.1");
851   socket_address->set_port_value(443);
852   locality->set_priority(1);
853   locality = cla.add_endpoints();
854   locality->mutable_load_balancing_weight()->set_value(1);
855   locality_name = locality->mutable_locality();
856   locality_name->set_region("myregion2");
857   locality_name->set_zone("myzone");
858   locality_name->set_sub_zone("mysubzone");
859   socket_address = locality->add_lb_endpoints()
860                        ->mutable_endpoint()
861                        ->mutable_address()
862                        ->mutable_socket_address();
863   socket_address->set_address("127.0.0.2");
864   socket_address->set_port_value(443);
865   locality->set_priority(3);
866   std::string serialized_resource;
867   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
868   auto* resource_type = XdsEndpointResourceType::Get();
869   auto decode_result =
870       resource_type->Decode(decode_context_, serialized_resource);
871   ASSERT_TRUE(decode_result.name.has_value());
872   EXPECT_EQ(*decode_result.name, "foo");
873   EXPECT_EQ(decode_result.resource.status().code(),
874             absl::StatusCode::kInvalidArgument);
875   EXPECT_EQ(decode_result.resource.status().message(),
876             "errors parsing EDS resource: ["
877             "field:endpoints errors:[priority 0 empty; priority 2 empty]]")
878       << decode_result.resource.status();
879 }
880 
TEST_F(XdsEndpointTest,LocalityWeightsWithinPriorityExceedUint32Max)881 TEST_F(XdsEndpointTest, LocalityWeightsWithinPriorityExceedUint32Max) {
882   ClusterLoadAssignment cla;
883   cla.set_cluster_name("foo");
884   // First locality has weight of 1.
885   auto* locality = cla.add_endpoints();
886   locality->mutable_load_balancing_weight()->set_value(1);
887   auto* locality_name = locality->mutable_locality();
888   locality_name->set_region("myregion");
889   locality_name->set_zone("myzone");
890   locality_name->set_sub_zone("mysubzone");
891   auto* socket_address = locality->add_lb_endpoints()
892                              ->mutable_endpoint()
893                              ->mutable_address()
894                              ->mutable_socket_address();
895   socket_address->set_address("127.0.0.1");
896   socket_address->set_port_value(443);
897   locality->set_priority(0);
898   // Second locality has weight of uint32 max.
899   locality = cla.add_endpoints();
900   locality->mutable_load_balancing_weight()->set_value(
901       std::numeric_limits<uint32_t>::max());
902   locality_name = locality->mutable_locality();
903   locality_name->set_region("myregion2");
904   locality_name->set_zone("myzone");
905   locality_name->set_sub_zone("mysubzone");
906   socket_address = locality->add_lb_endpoints()
907                        ->mutable_endpoint()
908                        ->mutable_address()
909                        ->mutable_socket_address();
910   socket_address->set_address("127.0.0.2");
911   socket_address->set_port_value(443);
912   locality->set_priority(0);
913   std::string serialized_resource;
914   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
915   auto* resource_type = XdsEndpointResourceType::Get();
916   auto decode_result =
917       resource_type->Decode(decode_context_, serialized_resource);
918   ASSERT_TRUE(decode_result.name.has_value());
919   EXPECT_EQ(*decode_result.name, "foo");
920   EXPECT_EQ(decode_result.resource.status().code(),
921             absl::StatusCode::kInvalidArgument);
922   EXPECT_EQ(decode_result.resource.status().message(),
923             "errors parsing EDS resource: ["
924             "field:endpoints error:sum of locality weights for priority 0 "
925             "exceeds uint32 max]")
926       << decode_result.resource.status();
927 }
928 
TEST_F(XdsEndpointTest,DuplicateAddresses)929 TEST_F(XdsEndpointTest, DuplicateAddresses) {
930   ClusterLoadAssignment cla;
931   cla.set_cluster_name("foo");
932   auto* locality = cla.add_endpoints();
933   locality->mutable_load_balancing_weight()->set_value(1);
934   auto* locality_name = locality->mutable_locality();
935   locality_name->set_region("myregion");
936   locality_name->set_zone("myzone");
937   locality_name->set_sub_zone("mysubzone");
938   auto* socket_address = locality->add_lb_endpoints()
939                              ->mutable_endpoint()
940                              ->mutable_address()
941                              ->mutable_socket_address();
942   socket_address->set_address("127.0.0.1");
943   socket_address->set_port_value(443);
944   locality->set_priority(0);
945   locality = cla.add_endpoints();
946   locality->mutable_load_balancing_weight()->set_value(1);
947   locality_name = locality->mutable_locality();
948   locality_name->set_region("myregion2");
949   locality_name->set_zone("myzone");
950   locality_name->set_sub_zone("mysubzone");
951   socket_address = locality->add_lb_endpoints()
952                        ->mutable_endpoint()
953                        ->mutable_address()
954                        ->mutable_socket_address();
955   socket_address->set_address("127.0.0.1");
956   socket_address->set_port_value(443);
957   locality->set_priority(0);
958   std::string serialized_resource;
959   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
960   auto* resource_type = XdsEndpointResourceType::Get();
961   auto decode_result =
962       resource_type->Decode(decode_context_, serialized_resource);
963   ASSERT_TRUE(decode_result.name.has_value());
964   EXPECT_EQ(*decode_result.name, "foo");
965   EXPECT_EQ(decode_result.resource.status().code(),
966             absl::StatusCode::kInvalidArgument);
967   EXPECT_EQ(decode_result.resource.status().message(),
968             "errors parsing EDS resource: ["
969             "field:endpoints[1].lb_endpoints[0] "
970             "error:duplicate endpoint address \"ipv4:127.0.0.1:443\"]")
971       << decode_result.resource.status();
972 }
973 
TEST_F(XdsEndpointTest,DropConfig)974 TEST_F(XdsEndpointTest, DropConfig) {
975   ClusterLoadAssignment cla;
976   cla.set_cluster_name("foo");
977   auto* locality = cla.add_endpoints();
978   locality->mutable_load_balancing_weight()->set_value(1);
979   auto* locality_name = locality->mutable_locality();
980   locality_name->set_region("myregion");
981   locality_name->set_zone("myzone");
982   locality_name->set_sub_zone("mysubzone");
983   auto* socket_address = locality->add_lb_endpoints()
984                              ->mutable_endpoint()
985                              ->mutable_address()
986                              ->mutable_socket_address();
987   socket_address->set_address("127.0.0.1");
988   socket_address->set_port_value(443);
989   auto* drop_overload = cla.mutable_policy()->add_drop_overloads();
990   drop_overload->set_category("lb_drop");
991   drop_overload->mutable_drop_percentage()->set_numerator(50);
992   drop_overload = cla.mutable_policy()->add_drop_overloads();
993   drop_overload->set_category("lb_overload");
994   drop_overload->mutable_drop_percentage()->set_numerator(2500);
995   drop_overload->mutable_drop_percentage()->set_denominator(
996       envoy::type::v3::FractionalPercent::TEN_THOUSAND);
997   drop_overload = cla.mutable_policy()->add_drop_overloads();
998   drop_overload->set_category("why_not");
999   drop_overload->mutable_drop_percentage()->set_numerator(750000);
1000   drop_overload->mutable_drop_percentage()->set_denominator(
1001       envoy::type::v3::FractionalPercent::MILLION);
1002   std::string serialized_resource;
1003   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
1004   auto* resource_type = XdsEndpointResourceType::Get();
1005   auto decode_result =
1006       resource_type->Decode(decode_context_, serialized_resource);
1007   ASSERT_TRUE(decode_result.resource.ok()) << decode_result.resource.status();
1008   ASSERT_TRUE(decode_result.name.has_value());
1009   EXPECT_EQ(*decode_result.name, "foo");
1010   auto& resource =
1011       static_cast<const XdsEndpointResource&>(**decode_result.resource);
1012   ASSERT_NE(resource.drop_config, nullptr);
1013   const auto& drop_list = resource.drop_config->drop_category_list();
1014   ASSERT_EQ(drop_list.size(), 3);
1015   EXPECT_EQ(drop_list[0].name, "lb_drop");
1016   EXPECT_EQ(drop_list[0].parts_per_million, 500000);
1017   EXPECT_EQ(drop_list[1].name, "lb_overload");
1018   EXPECT_EQ(drop_list[1].parts_per_million, 250000);
1019   EXPECT_EQ(drop_list[2].name, "why_not");
1020   EXPECT_EQ(drop_list[2].parts_per_million, 750000);
1021 }
1022 
TEST_F(XdsEndpointTest,CapsDropPercentageAt100)1023 TEST_F(XdsEndpointTest, CapsDropPercentageAt100) {
1024   ClusterLoadAssignment cla;
1025   cla.set_cluster_name("foo");
1026   auto* locality = cla.add_endpoints();
1027   locality->mutable_load_balancing_weight()->set_value(1);
1028   auto* locality_name = locality->mutable_locality();
1029   locality_name->set_region("myregion");
1030   locality_name->set_zone("myzone");
1031   locality_name->set_sub_zone("mysubzone");
1032   auto* socket_address = locality->add_lb_endpoints()
1033                              ->mutable_endpoint()
1034                              ->mutable_address()
1035                              ->mutable_socket_address();
1036   socket_address->set_address("127.0.0.1");
1037   socket_address->set_port_value(443);
1038   auto* drop_overload = cla.mutable_policy()->add_drop_overloads();
1039   drop_overload->set_category("lb_drop");
1040   drop_overload->mutable_drop_percentage()->set_numerator(10000001);
1041   std::string serialized_resource;
1042   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
1043   auto* resource_type = XdsEndpointResourceType::Get();
1044   auto decode_result =
1045       resource_type->Decode(decode_context_, serialized_resource);
1046   ASSERT_TRUE(decode_result.resource.ok()) << decode_result.resource.status();
1047   ASSERT_TRUE(decode_result.name.has_value());
1048   EXPECT_EQ(*decode_result.name, "foo");
1049   auto& resource =
1050       static_cast<const XdsEndpointResource&>(**decode_result.resource);
1051   ASSERT_NE(resource.drop_config, nullptr);
1052   const auto& drop_list = resource.drop_config->drop_category_list();
1053   ASSERT_EQ(drop_list.size(), 1);
1054   EXPECT_EQ(drop_list[0].name, "lb_drop");
1055   EXPECT_EQ(drop_list[0].parts_per_million, 1000000);
1056   EXPECT_TRUE(resource.drop_config->drop_all());
1057 }
1058 
TEST_F(XdsEndpointTest,MissingDropCategoryName)1059 TEST_F(XdsEndpointTest, MissingDropCategoryName) {
1060   ClusterLoadAssignment cla;
1061   cla.set_cluster_name("foo");
1062   auto* locality = cla.add_endpoints();
1063   locality->mutable_load_balancing_weight()->set_value(1);
1064   auto* locality_name = locality->mutable_locality();
1065   locality_name->set_region("myregion");
1066   locality_name->set_zone("myzone");
1067   locality_name->set_sub_zone("mysubzone");
1068   auto* socket_address = locality->add_lb_endpoints()
1069                              ->mutable_endpoint()
1070                              ->mutable_address()
1071                              ->mutable_socket_address();
1072   socket_address->set_address("127.0.0.1");
1073   socket_address->set_port_value(443);
1074   auto* drop_overload = cla.mutable_policy()->add_drop_overloads();
1075   drop_overload->mutable_drop_percentage()->set_numerator(50);
1076   std::string serialized_resource;
1077   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
1078   auto* resource_type = XdsEndpointResourceType::Get();
1079   auto decode_result =
1080       resource_type->Decode(decode_context_, serialized_resource);
1081   ASSERT_TRUE(decode_result.name.has_value());
1082   EXPECT_EQ(*decode_result.name, "foo");
1083   EXPECT_EQ(decode_result.resource.status().code(),
1084             absl::StatusCode::kInvalidArgument);
1085   EXPECT_EQ(decode_result.resource.status().message(),
1086             "errors parsing EDS resource: ["
1087             "field:policy.drop_overloads[0].category "
1088             "error:empty drop category name]")
1089       << decode_result.resource.status();
1090 }
1091 
TEST_F(XdsEndpointTest,MissingDropPercentage)1092 TEST_F(XdsEndpointTest, MissingDropPercentage) {
1093   ClusterLoadAssignment cla;
1094   cla.set_cluster_name("foo");
1095   auto* locality = cla.add_endpoints();
1096   locality->mutable_load_balancing_weight()->set_value(1);
1097   auto* locality_name = locality->mutable_locality();
1098   locality_name->set_region("myregion");
1099   locality_name->set_zone("myzone");
1100   locality_name->set_sub_zone("mysubzone");
1101   auto* socket_address = locality->add_lb_endpoints()
1102                              ->mutable_endpoint()
1103                              ->mutable_address()
1104                              ->mutable_socket_address();
1105   socket_address->set_address("127.0.0.1");
1106   socket_address->set_port_value(443);
1107   auto* drop_overload = cla.mutable_policy()->add_drop_overloads();
1108   drop_overload->set_category("lb_drop");
1109   std::string serialized_resource;
1110   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
1111   auto* resource_type = XdsEndpointResourceType::Get();
1112   auto decode_result =
1113       resource_type->Decode(decode_context_, serialized_resource);
1114   ASSERT_TRUE(decode_result.name.has_value());
1115   EXPECT_EQ(*decode_result.name, "foo");
1116   EXPECT_EQ(decode_result.resource.status().code(),
1117             absl::StatusCode::kInvalidArgument);
1118   EXPECT_EQ(decode_result.resource.status().message(),
1119             "errors parsing EDS resource: ["
1120             "field:policy.drop_overloads[0].drop_percentage "
1121             "error:field not present]")
1122       << decode_result.resource.status();
1123 }
1124 
TEST_F(XdsEndpointTest,DropPercentageInvalidDenominator)1125 TEST_F(XdsEndpointTest, DropPercentageInvalidDenominator) {
1126   ClusterLoadAssignment cla;
1127   cla.set_cluster_name("foo");
1128   auto* locality = cla.add_endpoints();
1129   locality->mutable_load_balancing_weight()->set_value(1);
1130   auto* locality_name = locality->mutable_locality();
1131   locality_name->set_region("myregion");
1132   locality_name->set_zone("myzone");
1133   locality_name->set_sub_zone("mysubzone");
1134   auto* socket_address = locality->add_lb_endpoints()
1135                              ->mutable_endpoint()
1136                              ->mutable_address()
1137                              ->mutable_socket_address();
1138   socket_address->set_address("127.0.0.1");
1139   socket_address->set_port_value(443);
1140   auto* drop_overload = cla.mutable_policy()->add_drop_overloads();
1141   drop_overload->set_category("lb_drop");
1142   drop_overload->mutable_drop_percentage()->set_numerator(750000);
1143   drop_overload->mutable_drop_percentage()->set_denominator(
1144       static_cast<envoy::type::v3::FractionalPercent_DenominatorType>(100));
1145   std::string serialized_resource;
1146   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
1147   auto* resource_type = XdsEndpointResourceType::Get();
1148   auto decode_result =
1149       resource_type->Decode(decode_context_, serialized_resource);
1150   ASSERT_TRUE(decode_result.name.has_value());
1151   EXPECT_EQ(*decode_result.name, "foo");
1152   EXPECT_EQ(decode_result.resource.status().code(),
1153             absl::StatusCode::kInvalidArgument);
1154   EXPECT_EQ(decode_result.resource.status().message(),
1155             "errors parsing EDS resource: ["
1156             "field:policy.drop_overloads[0].drop_percentage.denominator "
1157             "error:unknown denominator type]")
1158       << decode_result.resource.status();
1159 }
1160 
TEST_F(XdsEndpointTest,EndpointHealthStatus)1161 TEST_F(XdsEndpointTest, EndpointHealthStatus) {
1162   ClusterLoadAssignment cla;
1163   cla.set_cluster_name("foo");
1164   auto* locality = cla.add_endpoints();
1165   locality->mutable_load_balancing_weight()->set_value(1);
1166   auto* locality_name = locality->mutable_locality();
1167   locality_name->set_region("myregion");
1168   locality_name->set_zone("myzone");
1169   locality_name->set_sub_zone("mysubzone");
1170   auto* endpoint = locality->add_lb_endpoints();
1171   auto* socket_address =
1172       endpoint->mutable_endpoint()->mutable_address()->mutable_socket_address();
1173   socket_address->set_address("127.0.0.1");
1174   socket_address->set_port_value(443);
1175   endpoint = locality->add_lb_endpoints();
1176   endpoint->set_health_status(envoy::config::core::v3::HealthStatus::DRAINING);
1177   socket_address =
1178       endpoint->mutable_endpoint()->mutable_address()->mutable_socket_address();
1179   socket_address->set_address("127.0.0.2");
1180   socket_address->set_port_value(443);
1181   endpoint = locality->add_lb_endpoints();
1182   endpoint->set_health_status(envoy::config::core::v3::HealthStatus::UNHEALTHY);
1183   socket_address =
1184       endpoint->mutable_endpoint()->mutable_address()->mutable_socket_address();
1185   socket_address->set_address("127.0.0.3");
1186   socket_address->set_port_value(443);
1187   std::string serialized_resource;
1188   ASSERT_TRUE(cla.SerializeToString(&serialized_resource));
1189   auto* resource_type = XdsEndpointResourceType::Get();
1190   auto decode_result =
1191       resource_type->Decode(decode_context_, serialized_resource);
1192   ASSERT_TRUE(decode_result.resource.ok()) << decode_result.resource.status();
1193   ASSERT_TRUE(decode_result.name.has_value());
1194   EXPECT_EQ(*decode_result.name, "foo");
1195   auto& resource =
1196       static_cast<const XdsEndpointResource&>(**decode_result.resource);
1197   ASSERT_EQ(resource.priorities.size(), 1);
1198   const auto& priority = resource.priorities[0];
1199   ASSERT_EQ(priority.localities.size(), 1);
1200   const auto& p = *priority.localities.begin();
1201   ASSERT_EQ(p.first, p.second.name.get());
1202   EXPECT_EQ(p.first->region(), "myregion");
1203   EXPECT_EQ(p.first->zone(), "myzone");
1204   EXPECT_EQ(p.first->sub_zone(), "mysubzone");
1205   EXPECT_EQ(p.second.lb_weight, 1);
1206   ASSERT_EQ(p.second.endpoints.size(), 2);
1207   const auto* address = &p.second.endpoints[0];
1208   auto addr = grpc_sockaddr_to_string(&address->address(), /*normalize=*/false);
1209   ASSERT_TRUE(addr.ok()) << addr.status();
1210   EXPECT_EQ(*addr, "127.0.0.1:443");
1211   EXPECT_EQ(address->args().GetInt(GRPC_ARG_XDS_HEALTH_STATUS),
1212             XdsHealthStatus::kUnknown);
1213   address = &p.second.endpoints[1];
1214   addr = grpc_sockaddr_to_string(&address->address(), /*normalize=*/false);
1215   ASSERT_TRUE(addr.ok()) << addr.status();
1216   EXPECT_EQ(*addr, "127.0.0.2:443");
1217   EXPECT_EQ(address->args().GetInt(GRPC_ARG_XDS_HEALTH_STATUS),
1218             XdsHealthStatus::kDraining);
1219 }
1220 
1221 }  // namespace
1222 }  // namespace testing
1223 }  // namespace grpc_core
1224 
main(int argc,char ** argv)1225 int main(int argc, char** argv) {
1226   ::testing::InitGoogleTest(&argc, argv);
1227   grpc::testing::TestEnvironment env(&argc, argv);
1228   grpc_init();
1229   int ret = RUN_ALL_TESTS();
1230   grpc_shutdown();
1231   return ret;
1232 }
1233