• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "discovery/dnssd/impl/dns_data_graph.h"
6 
7 #include <utility>
8 
9 #include "discovery/mdns/testing/mdns_test_util.h"
10 #include "gmock/gmock.h"
11 #include "gtest/gtest.h"
12 #include "platform/base/ip_address.h"
13 
14 namespace openscreen {
15 namespace discovery {
16 namespace {
17 
GetAddressV4(const DnsSdInstanceEndpoint endpoint)18 IPAddress GetAddressV4(const DnsSdInstanceEndpoint endpoint) {
19   for (const IPAddress& address : endpoint.addresses()) {
20     if (address.IsV4()) {
21       return address;
22     }
23   }
24   return IPAddress{};
25 }
26 
GetAddressV6(const DnsSdInstanceEndpoint endpoint)27 IPAddress GetAddressV6(const DnsSdInstanceEndpoint endpoint) {
28   for (const IPAddress& address : endpoint.addresses()) {
29     if (address.IsV6()) {
30       return address;
31     }
32   }
33   return IPAddress{};
34 }
35 
36 }  // namespace
37 
38 using testing::_;
39 using testing::Invoke;
40 using testing::Return;
41 using testing::StrictMock;
42 
43 class DomainChangeImpl {
44  public:
45   MOCK_METHOD1(OnStartTracking, void(const DomainName&));
46   MOCK_METHOD1(OnStopTracking, void(const DomainName&));
47 };
48 
49 class DnsDataGraphTests : public testing::Test {
50  public:
DnsDataGraphTests()51   DnsDataGraphTests() : graph_(DnsDataGraph::Create(network_interface_)) {
52     EXPECT_CALL(callbacks_, OnStartTracking(ptr_domain_));
53     StartTracking(ptr_domain_);
54     testing::Mock::VerifyAndClearExpectations(&callbacks_);
55     EXPECT_EQ(graph_->GetTrackedDomainCount(), size_t{1});
56   }
57 
58  protected:
TriggerRecordCreation(MdnsRecord record,Error::Code result_code=Error::Code::kNone)59   void TriggerRecordCreation(MdnsRecord record,
60                              Error::Code result_code = Error::Code::kNone) {
61     size_t size = graph_->GetTrackedDomainCount();
62     Error result =
63         ApplyDataRecordChange(std::move(record), RecordChangedEvent::kCreated);
64     EXPECT_EQ(result.code(), result_code)
65         << "Failed with error code " << result.code();
66     size_t new_size = graph_->GetTrackedDomainCount();
67     EXPECT_EQ(size, new_size);
68   }
69 
TriggerRecordCreationWithCallback(MdnsRecord record,const DomainName & target_domain)70   void TriggerRecordCreationWithCallback(MdnsRecord record,
71                                          const DomainName& target_domain) {
72     EXPECT_CALL(callbacks_, OnStartTracking(target_domain));
73     size_t size = graph_->GetTrackedDomainCount();
74     Error result =
75         ApplyDataRecordChange(std::move(record), RecordChangedEvent::kCreated);
76     EXPECT_TRUE(result.ok()) << "Failed with error code " << result.code();
77     size_t new_size = graph_->GetTrackedDomainCount();
78     EXPECT_EQ(size + 1, new_size);
79   }
80 
ExpectDomainEqual(const DnsSdInstance & instance,const DomainName & name)81   void ExpectDomainEqual(const DnsSdInstance& instance,
82                          const DomainName& name) {
83     EXPECT_EQ(name.labels().size(), size_t{4});
84     EXPECT_EQ(instance.instance_id(), name.labels()[0]);
85     EXPECT_EQ(instance.service_id(), name.labels()[1] + "." + name.labels()[2]);
86     EXPECT_EQ(instance.domain_id(), name.labels()[3]);
87   }
88 
ApplyDataRecordChange(MdnsRecord record,RecordChangedEvent event)89   Error ApplyDataRecordChange(MdnsRecord record, RecordChangedEvent event) {
90     return graph_->ApplyDataRecordChange(
91         std::move(record), event,
92         [this](const DomainName& domain) {
93           callbacks_.OnStartTracking(domain);
94         },
95         [this](const DomainName& domain) {
96           callbacks_.OnStopTracking(domain);
97         });
98   }
99 
StartTracking(const DomainName & domain)100   void StartTracking(const DomainName& domain) {
101     graph_->StartTracking(domain, [this](const DomainName& domain) {
102       callbacks_.OnStartTracking(domain);
103     });
104   }
105 
StopTracking(const DomainName & domain)106   void StopTracking(const DomainName& domain) {
107     graph_->StopTracking(domain, [this](const DomainName& domain) {
108       callbacks_.OnStopTracking(domain);
109     });
110   }
111 
112   StrictMock<DomainChangeImpl> callbacks_;
113   NetworkInterfaceIndex network_interface_ = 1234;
114   std::unique_ptr<DnsDataGraph> graph_;
115   DomainName ptr_domain_{"_cast", "_tcp", "local"};
116   DomainName primary_domain_{"test", "_cast", "_tcp", "local"};
117   DomainName secondary_domain_{"test2", "_cast", "_tcp", "local"};
118   DomainName tertiary_domain_{"test3", "_cast", "_tcp", "local"};
119 };
120 
TEST_F(DnsDataGraphTests,CallbacksCalledForStartStopTracking)121 TEST_F(DnsDataGraphTests, CallbacksCalledForStartStopTracking) {
122   EXPECT_CALL(callbacks_, OnStopTracking(ptr_domain_));
123   StopTracking(ptr_domain_);
124 
125   EXPECT_EQ(graph_->GetTrackedDomainCount(), size_t{0});
126 }
127 
TEST_F(DnsDataGraphTests,ApplyChangeForUntrackedDomainError)128 TEST_F(DnsDataGraphTests, ApplyChangeForUntrackedDomainError) {
129   Error result = ApplyDataRecordChange(GetFakeSrvRecord(primary_domain_),
130                                        RecordChangedEvent::kCreated);
131   EXPECT_EQ(result.code(), Error::Code::kOperationCancelled);
132   EXPECT_EQ(graph_->GetTrackedDomainCount(), size_t{1});
133 }
134 
TEST_F(DnsDataGraphTests,ChildrenStopTrackingWhenRootQueryStopped)135 TEST_F(DnsDataGraphTests, ChildrenStopTrackingWhenRootQueryStopped) {
136   auto ptr = GetFakePtrRecord(primary_domain_);
137   auto srv = GetFakeSrvRecord(primary_domain_, secondary_domain_);
138   auto a = GetFakeARecord(secondary_domain_);
139 
140   TriggerRecordCreationWithCallback(ptr, primary_domain_);
141   TriggerRecordCreationWithCallback(srv, secondary_domain_);
142   TriggerRecordCreation(a);
143 
144   EXPECT_CALL(callbacks_, OnStopTracking(ptr_domain_));
145   EXPECT_CALL(callbacks_, OnStopTracking(primary_domain_));
146   EXPECT_CALL(callbacks_, OnStopTracking(secondary_domain_));
147   StopTracking(ptr_domain_);
148   testing::Mock::VerifyAndClearExpectations(&callbacks_);
149 
150   EXPECT_EQ(graph_->GetTrackedDomainCount(), size_t{0});
151 }
152 
TEST_F(DnsDataGraphTests,CyclicSrvStopsTrackingWhenRootQueryStopped)153 TEST_F(DnsDataGraphTests, CyclicSrvStopsTrackingWhenRootQueryStopped) {
154   auto ptr = GetFakePtrRecord(primary_domain_);
155   auto srv = GetFakeSrvRecord(primary_domain_);
156   auto a = GetFakeARecord(primary_domain_);
157 
158   TriggerRecordCreationWithCallback(ptr, primary_domain_);
159   TriggerRecordCreation(srv);
160   TriggerRecordCreation(a);
161 
162   EXPECT_CALL(callbacks_, OnStopTracking(ptr_domain_));
163   EXPECT_CALL(callbacks_, OnStopTracking(primary_domain_));
164   StopTracking(ptr_domain_);
165   testing::Mock::VerifyAndClearExpectations(&callbacks_);
166 
167   EXPECT_EQ(graph_->GetTrackedDomainCount(), size_t{0});
168 }
169 
TEST_F(DnsDataGraphTests,ChildrenStopTrackingWhenParentDeleted)170 TEST_F(DnsDataGraphTests, ChildrenStopTrackingWhenParentDeleted) {
171   auto ptr = GetFakePtrRecord(primary_domain_);
172   auto srv = GetFakeSrvRecord(primary_domain_, secondary_domain_);
173   auto a = GetFakeARecord(secondary_domain_);
174 
175   TriggerRecordCreationWithCallback(ptr, primary_domain_);
176   TriggerRecordCreationWithCallback(srv, secondary_domain_);
177   TriggerRecordCreation(a);
178 
179   EXPECT_CALL(callbacks_, OnStopTracking(primary_domain_));
180   EXPECT_CALL(callbacks_, OnStopTracking(secondary_domain_));
181   auto result = ApplyDataRecordChange(ptr, RecordChangedEvent::kExpired);
182   EXPECT_TRUE(result.ok()) << "Failed with error code " << result.code();
183   testing::Mock::VerifyAndClearExpectations(&callbacks_);
184 
185   EXPECT_EQ(graph_->GetTrackedDomainCount(), size_t{1});
186 }
187 
TEST_F(DnsDataGraphTests,OnlyAffectedNodesChangedWhenParentDeleted)188 TEST_F(DnsDataGraphTests, OnlyAffectedNodesChangedWhenParentDeleted) {
189   auto ptr = GetFakePtrRecord(primary_domain_);
190   auto srv = GetFakeSrvRecord(primary_domain_, secondary_domain_);
191   auto a = GetFakeARecord(secondary_domain_);
192 
193   TriggerRecordCreationWithCallback(ptr, primary_domain_);
194   TriggerRecordCreationWithCallback(srv, secondary_domain_);
195   TriggerRecordCreation(a);
196 
197   EXPECT_CALL(callbacks_, OnStopTracking(secondary_domain_));
198   auto result = ApplyDataRecordChange(srv, RecordChangedEvent::kExpired);
199   EXPECT_TRUE(result.ok()) << "Failed with error code " << result.code();
200   testing::Mock::VerifyAndClearExpectations(&callbacks_);
201 
202   EXPECT_EQ(graph_->GetTrackedDomainCount(), size_t{2});
203 }
204 
TEST_F(DnsDataGraphTests,CreateFailsForExistingRecord)205 TEST_F(DnsDataGraphTests, CreateFailsForExistingRecord) {
206   auto ptr = GetFakePtrRecord(primary_domain_);
207   auto srv = GetFakeSrvRecord(primary_domain_);
208 
209   TriggerRecordCreationWithCallback(ptr, primary_domain_);
210   TriggerRecordCreation(srv);
211 
212   auto result = ApplyDataRecordChange(srv, RecordChangedEvent::kCreated);
213   EXPECT_FALSE(result.ok());
214   EXPECT_EQ(graph_->GetTrackedDomainCount(), size_t{2});
215 }
216 
TEST_F(DnsDataGraphTests,UpdateFailsForNonExistingRecord)217 TEST_F(DnsDataGraphTests, UpdateFailsForNonExistingRecord) {
218   auto ptr = GetFakePtrRecord(primary_domain_);
219   auto srv = GetFakeSrvRecord(primary_domain_);
220 
221   TriggerRecordCreationWithCallback(ptr, primary_domain_);
222 
223   auto result = ApplyDataRecordChange(srv, RecordChangedEvent::kUpdated);
224   EXPECT_FALSE(result.ok());
225   EXPECT_EQ(graph_->GetTrackedDomainCount(), size_t{2});
226 }
227 
TEST_F(DnsDataGraphTests,DeleteFailsForNonExistingRecord)228 TEST_F(DnsDataGraphTests, DeleteFailsForNonExistingRecord) {
229   auto ptr = GetFakePtrRecord(primary_domain_);
230   auto srv = GetFakeSrvRecord(primary_domain_);
231 
232   TriggerRecordCreationWithCallback(ptr, primary_domain_);
233 
234   auto result = ApplyDataRecordChange(srv, RecordChangedEvent::kExpired);
235   EXPECT_FALSE(result.ok());
236   EXPECT_EQ(graph_->GetTrackedDomainCount(), size_t{2});
237 }
238 
TEST_F(DnsDataGraphTests,DeleteSucceedsForRecordWithDifferentTtl)239 TEST_F(DnsDataGraphTests, DeleteSucceedsForRecordWithDifferentTtl) {
240   const MdnsRecord ptr = GetFakePtrRecord(primary_domain_);
241   TriggerRecordCreationWithCallback(ptr, primary_domain_);
242 
243   EXPECT_CALL(callbacks_, OnStopTracking(primary_domain_));
244   const MdnsRecord new_ptr(ptr.name(), ptr.dns_type(), ptr.dns_class(),
245                            ptr.record_type(),
246                            ptr.ttl() + std::chrono::seconds(10), ptr.rdata());
247   const auto result =
248       ApplyDataRecordChange(new_ptr, RecordChangedEvent::kExpired);
249 
250   EXPECT_TRUE(result.ok());
251   EXPECT_EQ(graph_->GetTrackedDomainCount(), size_t{1});
252 }
253 
TEST_F(DnsDataGraphTests,UpdateEndpointsWorksAsExpected)254 TEST_F(DnsDataGraphTests, UpdateEndpointsWorksAsExpected) {
255   auto ptr = GetFakePtrRecord(primary_domain_);
256   auto srv = GetFakeSrvRecord(primary_domain_, secondary_domain_);
257   auto txt = GetFakeTxtRecord(primary_domain_);
258   auto a = GetFakeARecord(secondary_domain_);
259 
260   TriggerRecordCreationWithCallback(ptr, primary_domain_);
261   TriggerRecordCreation(txt);
262   TriggerRecordCreationWithCallback(srv, secondary_domain_);
263   TriggerRecordCreation(a);
264 
265   std::vector<ErrorOr<DnsSdInstanceEndpoint>> endpoints =
266       graph_->CreateEndpoints(DnsDataGraph::GetDomainGroup(srv),
267                               primary_domain_);
268   ASSERT_EQ(endpoints.size(), size_t{1});
269   ErrorOr<DnsSdInstanceEndpoint> endpoint_or_error = std::move(endpoints[0]);
270   ASSERT_TRUE(endpoint_or_error.is_value());
271   DnsSdInstanceEndpoint endpoint = std::move(endpoint_or_error.value());
272 
273   ARecordRdata rdata(IPAddress(192, 168, 1, 2));
274   MdnsRecord new_a(secondary_domain_, DnsType::kA, DnsClass::kIN,
275                    RecordType::kUnique, std::chrono::seconds(0),
276                    std::move(rdata));
277   auto result = ApplyDataRecordChange(new_a, RecordChangedEvent::kUpdated);
278 
279   endpoints = graph_->CreateEndpoints(DnsDataGraph::GetDomainGroup(srv),
280                                       primary_domain_);
281   ASSERT_EQ(endpoints.size(), size_t{1});
282   endpoint_or_error = std::move(endpoints[0]);
283   ASSERT_TRUE(endpoint_or_error.is_value());
284   DnsSdInstanceEndpoint endpoint2 = std::move(endpoint_or_error.value());
285   ASSERT_EQ(endpoint.addresses().size(), size_t{1});
286   ASSERT_EQ(endpoint.addresses().size(), endpoint2.addresses().size());
287   EXPECT_NE(endpoint.addresses()[0], endpoint2.addresses()[0]);
288   EXPECT_EQ(endpoint.instance_id(), endpoint2.instance_id());
289   EXPECT_EQ(endpoint.service_id(), endpoint2.service_id());
290   EXPECT_EQ(endpoint.domain_id(), endpoint2.domain_id());
291   EXPECT_EQ(endpoint.txt(), endpoint2.txt());
292   EXPECT_EQ(endpoint.port(), endpoint2.port());
293 }
294 
TEST_F(DnsDataGraphTests,CreateEndpointsGeneratesCorrectRecords)295 TEST_F(DnsDataGraphTests, CreateEndpointsGeneratesCorrectRecords) {
296   auto ptr = GetFakePtrRecord(primary_domain_);
297   auto srv = GetFakeSrvRecord(primary_domain_, secondary_domain_);
298   auto txt = GetFakeTxtRecord(primary_domain_);
299   auto a = GetFakeARecord(secondary_domain_);
300   auto aaaa = GetFakeAAAARecord(secondary_domain_);
301 
302   TriggerRecordCreationWithCallback(ptr, primary_domain_);
303   TriggerRecordCreation(txt);
304   TriggerRecordCreationWithCallback(srv, secondary_domain_);
305 
306   std::vector<ErrorOr<DnsSdInstanceEndpoint>> endpoints =
307       graph_->CreateEndpoints(DnsDataGraph::GetDomainGroup(srv),
308                               primary_domain_);
309   EXPECT_EQ(endpoints.size(), size_t{0});
310 
311   TriggerRecordCreation(a);
312   endpoints = graph_->CreateEndpoints(DnsDataGraph::GetDomainGroup(srv),
313                                       primary_domain_);
314   ASSERT_EQ(endpoints.size(), size_t{1});
315   ErrorOr<DnsSdInstanceEndpoint> endpoint_or_error = std::move(endpoints[0]);
316   ASSERT_TRUE(endpoint_or_error.is_value());
317   DnsSdInstanceEndpoint endpoint_a = std::move(endpoint_or_error.value());
318   EXPECT_TRUE(GetAddressV4(endpoint_a));
319   EXPECT_FALSE(GetAddressV6(endpoint_a));
320   EXPECT_EQ(GetAddressV4(endpoint_a), kFakeARecordAddress);
321   ExpectDomainEqual(endpoint_a, primary_domain_);
322   EXPECT_EQ(endpoint_a.port(), kFakeSrvRecordPort);
323 
324   TriggerRecordCreation(aaaa);
325   endpoints = graph_->CreateEndpoints(DnsDataGraph::GetDomainGroup(srv),
326                                       primary_domain_);
327   ASSERT_EQ(endpoints.size(), size_t{1});
328   endpoint_or_error = std::move(endpoints[0]);
329   ASSERT_TRUE(endpoint_or_error.is_value());
330   DnsSdInstanceEndpoint endpoint_a_aaaa = std::move(endpoint_or_error.value());
331   ASSERT_TRUE(GetAddressV4(endpoint_a_aaaa));
332   ASSERT_TRUE(GetAddressV6(endpoint_a_aaaa));
333   EXPECT_EQ(GetAddressV4(endpoint_a_aaaa), kFakeARecordAddress);
334   EXPECT_EQ(GetAddressV6(endpoint_a_aaaa), kFakeAAAARecordAddress);
335   EXPECT_EQ(static_cast<DnsSdInstance>(endpoint_a),
336             static_cast<DnsSdInstance>(endpoint_a_aaaa));
337 
338   auto result = ApplyDataRecordChange(a, RecordChangedEvent::kExpired);
339   EXPECT_TRUE(result.ok()) << "Failed with error code " << result.code();
340   endpoints = graph_->CreateEndpoints(DnsDataGraph::GetDomainGroup(srv),
341                                       primary_domain_);
342   ASSERT_EQ(endpoints.size(), size_t{1});
343   endpoint_or_error = std::move(endpoints[0]);
344   ASSERT_TRUE(endpoint_or_error.is_value());
345   DnsSdInstanceEndpoint endpoint_aaaa = std::move(endpoint_or_error.value());
346   EXPECT_FALSE(GetAddressV4(endpoint_aaaa));
347   ASSERT_TRUE(GetAddressV6(endpoint_aaaa));
348   EXPECT_EQ(GetAddressV6(endpoint_aaaa), kFakeAAAARecordAddress);
349   EXPECT_EQ(static_cast<DnsSdInstance>(endpoint_a),
350             static_cast<DnsSdInstance>(endpoint_aaaa));
351 
352   result = ApplyDataRecordChange(aaaa, RecordChangedEvent::kExpired);
353   EXPECT_TRUE(result.ok()) << "Failed with error code " << result.code();
354   endpoints = graph_->CreateEndpoints(DnsDataGraph::GetDomainGroup(srv),
355                                       primary_domain_);
356   ASSERT_EQ(endpoints.size(), size_t{0});
357 }
358 
TEST_F(DnsDataGraphTests,CreateEndpointsHandlesSelfLoops)359 TEST_F(DnsDataGraphTests, CreateEndpointsHandlesSelfLoops) {
360   auto ptr = GetFakePtrRecord(primary_domain_);
361   auto srv = GetFakeSrvRecord(primary_domain_, primary_domain_);
362   auto txt = GetFakeTxtRecord(primary_domain_);
363   auto a = GetFakeARecord(primary_domain_);
364   auto aaaa = GetFakeAAAARecord(primary_domain_);
365 
366   TriggerRecordCreationWithCallback(ptr, primary_domain_);
367   TriggerRecordCreation(srv);
368   TriggerRecordCreation(txt);
369   TriggerRecordCreation(a);
370   TriggerRecordCreation(aaaa);
371 
372   auto endpoints = graph_->CreateEndpoints(DnsDataGraph::GetDomainGroup(srv),
373                                            primary_domain_);
374   ASSERT_EQ(endpoints.size(), size_t{1});
375   ASSERT_TRUE(endpoints[0].is_value());
376   DnsSdInstanceEndpoint endpoint = std::move(endpoints[0].value());
377 
378   EXPECT_EQ(GetAddressV4(endpoint), kFakeARecordAddress);
379   EXPECT_EQ(GetAddressV6(endpoint), kFakeAAAARecordAddress);
380   ExpectDomainEqual(endpoint, primary_domain_);
381   EXPECT_EQ(endpoint.port(), kFakeSrvRecordPort);
382 
383   auto endpoints2 =
384       graph_->CreateEndpoints(DnsDataGraph::GetDomainGroup(ptr), ptr_domain_);
385   ASSERT_EQ(endpoints2.size(), size_t{1});
386   ASSERT_TRUE(endpoints2[0].is_value());
387   DnsSdInstanceEndpoint endpoint2 = std::move(endpoints2[0].value());
388 
389   EXPECT_EQ(GetAddressV4(endpoint2), kFakeARecordAddress);
390   EXPECT_EQ(GetAddressV6(endpoint2), kFakeAAAARecordAddress);
391   ExpectDomainEqual(endpoint2, primary_domain_);
392   EXPECT_EQ(endpoint2.port(), kFakeSrvRecordPort);
393 
394   EXPECT_EQ(static_cast<DnsSdInstance>(endpoint),
395             static_cast<DnsSdInstance>(endpoint2));
396   EXPECT_EQ(endpoint, endpoint2);
397 }
398 
TEST_F(DnsDataGraphTests,CreateEndpointsWithMultipleParents)399 TEST_F(DnsDataGraphTests, CreateEndpointsWithMultipleParents) {
400   auto ptr = GetFakePtrRecord(primary_domain_);
401   auto srv = GetFakeSrvRecord(primary_domain_, tertiary_domain_);
402   auto txt = GetFakeTxtRecord(primary_domain_);
403   auto ptr2 = GetFakePtrRecord(secondary_domain_);
404   auto srv2 = GetFakeSrvRecord(secondary_domain_, tertiary_domain_);
405   auto txt2 = GetFakeTxtRecord(secondary_domain_);
406   auto a = GetFakeARecord(tertiary_domain_);
407   auto aaaa = GetFakeAAAARecord(tertiary_domain_);
408 
409   TriggerRecordCreationWithCallback(ptr, primary_domain_);
410   TriggerRecordCreationWithCallback(srv, tertiary_domain_);
411   TriggerRecordCreation(txt);
412   TriggerRecordCreationWithCallback(ptr2, secondary_domain_);
413   TriggerRecordCreation(srv2);
414   TriggerRecordCreation(txt2);
415   TriggerRecordCreation(a);
416   TriggerRecordCreation(aaaa);
417 
418   auto endpoints = graph_->CreateEndpoints(DnsDataGraph::GetDomainGroup(a),
419                                            tertiary_domain_);
420   ASSERT_EQ(endpoints.size(), size_t{2});
421   ASSERT_TRUE(endpoints[0].is_value());
422   ASSERT_TRUE(endpoints[1].is_value());
423 
424   DnsSdInstanceEndpoint endpoint_a = std::move(endpoints[0].value());
425   DnsSdInstanceEndpoint endpoint_b = std::move(endpoints[1].value());
426   DnsSdInstanceEndpoint* endpoint_1;
427   DnsSdInstanceEndpoint* endpoint_2;
428   if (endpoint_a.instance_id() == "test") {
429     endpoint_1 = &endpoint_a;
430     endpoint_2 = &endpoint_b;
431   } else {
432     endpoint_2 = &endpoint_a;
433     endpoint_1 = &endpoint_b;
434   }
435 
436   EXPECT_EQ(GetAddressV4(*endpoint_1), kFakeARecordAddress);
437   EXPECT_EQ(GetAddressV6(*endpoint_1), kFakeAAAARecordAddress);
438   EXPECT_EQ(endpoint_1->port(), kFakeSrvRecordPort);
439   ExpectDomainEqual(*endpoint_1, primary_domain_);
440 
441   EXPECT_EQ(GetAddressV4(*endpoint_2), kFakeARecordAddress);
442   EXPECT_EQ(GetAddressV6(*endpoint_2), kFakeAAAARecordAddress);
443   EXPECT_EQ(endpoint_2->port(), kFakeSrvRecordPort);
444   ExpectDomainEqual(*endpoint_2, secondary_domain_);
445 }
446 
TEST_F(DnsDataGraphTests,FailedConversionOnlyFailsSingleEndpointCreation)447 TEST_F(DnsDataGraphTests, FailedConversionOnlyFailsSingleEndpointCreation) {
448   auto ptr = GetFakePtrRecord(primary_domain_);
449   auto srv = GetFakeSrvRecord(primary_domain_, tertiary_domain_);
450   auto txt = GetFakeTxtRecord(primary_domain_);
451   auto ptr2 = GetFakePtrRecord(secondary_domain_);
452   auto srv2 = GetFakeSrvRecord(secondary_domain_, tertiary_domain_);
453   auto txt2 = MdnsRecord(secondary_domain_, DnsType::kTXT, DnsClass::kIN,
454                          RecordType::kUnique, std::chrono::seconds(0),
455                          MakeTxtRecord({"=bad_txt_record"}));
456   auto a = GetFakeARecord(tertiary_domain_);
457   auto aaaa = GetFakeAAAARecord(tertiary_domain_);
458 
459   TriggerRecordCreationWithCallback(ptr, primary_domain_);
460   TriggerRecordCreationWithCallback(ptr2, secondary_domain_);
461   TriggerRecordCreationWithCallback(srv, tertiary_domain_);
462   TriggerRecordCreation(srv2);
463   TriggerRecordCreation(txt);
464   TriggerRecordCreation(txt2);
465   TriggerRecordCreation(a);
466   TriggerRecordCreation(aaaa);
467 
468   auto endpoints = graph_->CreateEndpoints(DnsDataGraph::GetDomainGroup(a),
469                                            tertiary_domain_);
470   ASSERT_EQ(endpoints.size(), size_t{2});
471   ASSERT_TRUE(endpoints[0].is_error() || endpoints[1].is_error());
472   ASSERT_TRUE(endpoints[0].is_value() || endpoints[1].is_value());
473 
474   DnsSdInstanceEndpoint endpoint = endpoints[0].is_value()
475                                        ? std::move(endpoints[0].value())
476                                        : std::move(endpoints[1].value());
477   EXPECT_EQ(GetAddressV4(endpoint), kFakeARecordAddress);
478   EXPECT_EQ(GetAddressV6(endpoint), kFakeAAAARecordAddress);
479   EXPECT_EQ(endpoint.port(), kFakeSrvRecordPort);
480   ExpectDomainEqual(endpoint, primary_domain_);
481 }
482 
483 }  // namespace discovery
484 }  // namespace openscreen
485