• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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/querier_impl.h"
6 
7 #include <memory>
8 #include <string>
9 #include <utility>
10 
11 #include "absl/strings/str_join.h"
12 #include "absl/strings/str_split.h"
13 #include "absl/types/optional.h"
14 #include "discovery/common/testing/mock_reporting_client.h"
15 #include "discovery/dnssd/impl/conversion_layer.h"
16 #include "discovery/dnssd/testing/fake_network_interface_config.h"
17 #include "discovery/mdns/mdns_records.h"
18 #include "discovery/mdns/testing/mdns_test_util.h"
19 #include "gmock/gmock.h"
20 #include "gtest/gtest.h"
21 #include "platform/test/fake_clock.h"
22 #include "platform/test/fake_task_runner.h"
23 #include "util/osp_logging.h"
24 
25 namespace openscreen {
26 namespace discovery {
27 namespace {
28 
29 NetworkInterfaceIndex kNetworkInterface = 0;
30 
31 class MockCallback : public DnsSdQuerier::Callback {
32  public:
33   MOCK_METHOD1(OnEndpointCreated, void(const DnsSdInstanceEndpoint&));
34   MOCK_METHOD1(OnEndpointUpdated, void(const DnsSdInstanceEndpoint&));
35   MOCK_METHOD1(OnEndpointDeleted, void(const DnsSdInstanceEndpoint&));
36 };
37 
38 class MockMdnsService : public MdnsService {
39  public:
40   MOCK_METHOD4(
41       StartQuery,
42       void(const DomainName&, DnsType, DnsClass, MdnsRecordChangedCallback*));
43 
44   MOCK_METHOD4(
45       StopQuery,
46       void(const DomainName&, DnsType, DnsClass, MdnsRecordChangedCallback*));
47 
48   MOCK_METHOD1(ReinitializeQueries, void(const DomainName& name));
49 
50   // Unused.
51   MOCK_METHOD3(StartProbe,
52                Error(MdnsDomainConfirmedProvider*, DomainName, IPAddress));
53   MOCK_METHOD1(RegisterRecord, Error(const MdnsRecord&));
54   MOCK_METHOD1(UnregisterRecord, Error(const MdnsRecord&));
55   MOCK_METHOD2(UpdateRegisteredRecord,
56                Error(const MdnsRecord&, const MdnsRecord&));
57 };
58 
59 class MockDnsDataGraph : public DnsDataGraph {
60  public:
61   MOCK_METHOD2(StartTracking,
62                void(const DomainName& domain,
63                     DomainChangeCallback on_start_tracking));
64   MOCK_METHOD2(StopTracking,
65                void(const DomainName& domain,
66                     DomainChangeCallback on_start_tracking));
67 
68   MOCK_CONST_METHOD2(
69       CreateEndpoints,
70       std::vector<ErrorOr<DnsSdInstanceEndpoint>>(DomainGroup,
71                                                   const DomainName&));
72 
73   MOCK_METHOD4(ApplyDataRecordChange,
74                Error(MdnsRecord,
75                      RecordChangedEvent,
76                      DomainChangeCallback,
77                      DomainChangeCallback));
78 
79   MOCK_CONST_METHOD0(GetTrackedDomainCount, size_t());
80 
81   MOCK_CONST_METHOD1(IsTracked, bool(const DomainName&));
82 };
83 
84 }  // namespace
85 
86 using testing::_;
87 using testing::ByMove;
88 using testing::Return;
89 using testing::StrictMock;
90 
91 class QuerierImplTesting : public QuerierImpl {
92  public:
QuerierImplTesting()93   QuerierImplTesting()
94       : QuerierImpl(&mock_service_,
95                     &task_runner_,
96                     &reporting_client_,
97                     &network_config_),
98         clock_(Clock::now()),
99         task_runner_(&clock_) {}
100 
service()101   StrictMock<MockMdnsService>& service() { return mock_service_; }
102 
reporting_client()103   StrictMock<MockReportingClient>& reporting_client() {
104     return reporting_client_;
105   }
106 
107   // NOTE: This should only be used for testing hard-to-achieve edge cases.
GetMockedGraph()108   StrictMock<MockDnsDataGraph>& GetMockedGraph() {
109     if (!is_graph_mocked_) {
110       graph_ = std::make_unique<StrictMock<MockDnsDataGraph>>();
111       is_graph_mocked_ = true;
112     }
113 
114     return static_cast<StrictMock<MockDnsDataGraph>&>(*graph_);
115   }
116 
GetTrackedDomainCount()117   size_t GetTrackedDomainCount() { return graph_->GetTrackedDomainCount(); }
118 
IsDomainTracked(const DomainName & domain)119   bool IsDomainTracked(const DomainName& domain) {
120     return graph_->IsTracked(domain);
121   }
122 
123   using QuerierImpl::OnRecordChanged;
124 
125  private:
126   FakeClock clock_;
127   FakeTaskRunner task_runner_;
128   FakeNetworkInterfaceConfig network_config_;
129   StrictMock<MockMdnsService> mock_service_;
130   StrictMock<MockReportingClient> reporting_client_;
131 
132   bool is_graph_mocked_ = false;
133 };
134 
135 class DnsSdQuerierImplTest : public testing::Test {
136  public:
DnsSdQuerierImplTest()137   DnsSdQuerierImplTest()
138       : querier(std::make_unique<QuerierImplTesting>()),
139         ptr_domain(DomainName{"_service", "_udp", domain}),
140         name(DomainName{instance, "_service", "_udp", domain}),
141         name2(DomainName{instance2, "_service", "_udp", domain}) {
142     EXPECT_FALSE(querier->IsQueryRunning(service));
143 
144     EXPECT_CALL(querier->service(),
145                 StartQuery(_, DnsType::kANY, DnsClass::kANY, _))
146         .Times(1);
147     querier->StartQuery(service, &callback);
148     EXPECT_TRUE(querier->IsQueryRunning(service));
149     testing::Mock::VerifyAndClearExpectations(&querier->service());
150 
151     EXPECT_TRUE(querier->IsQueryRunning(service));
152     testing::Mock::VerifyAndClearExpectations(&querier->service());
153   }
154 
155  protected:
ValidateRecordChangeStartsQuery(const std::vector<PendingQueryChange> & changes,const DomainName & name,size_t expected_size)156   void ValidateRecordChangeStartsQuery(
157       const std::vector<PendingQueryChange>& changes,
158       const DomainName& name,
159       size_t expected_size) {
160     ValidateRecordChangeResult(changes, name, expected_size,
161                                PendingQueryChange::kStartQuery);
162   }
163 
ValidateRecordChangeStopsQuery(const std::vector<PendingQueryChange> & changes,const DomainName & name,size_t expected_size)164   void ValidateRecordChangeStopsQuery(
165       const std::vector<PendingQueryChange>& changes,
166       const DomainName& name,
167       size_t expected_size) {
168     ValidateRecordChangeResult(changes, name, expected_size,
169                                PendingQueryChange::kStopQuery);
170   }
171 
CreateServiceInstance(const DomainName & service_domain,MockCallback * cb)172   void CreateServiceInstance(const DomainName& service_domain,
173                              MockCallback* cb) {
174     MdnsRecord ptr = GetFakePtrRecord(service_domain);
175     MdnsRecord srv = GetFakeSrvRecord(service_domain);
176     MdnsRecord txt = GetFakeTxtRecord(service_domain);
177     MdnsRecord a = GetFakeARecord(service_domain);
178     MdnsRecord aaaa = GetFakeAAAARecord(service_domain);
179 
180     auto result = querier->OnRecordChanged(ptr, RecordChangedEvent::kCreated);
181     ValidateRecordChangeStartsQuery(result, service_domain, 1);
182 
183     // NOTE: This verbose iterator handling is used to avoid gcc failures.
184     auto it = service_domain.labels().begin();
185     it++;
186     std::string service_name = *it;
187     it++;
188     std::string service_protocol = *it;
189     std::string service_id = "";
190     service_id.append(std::move(service_name))
191         .append(".")
192         .append(std::move(service_protocol));
193     ASSERT_TRUE(querier->IsQueryRunning(service_id));
194 
195     result = querier->OnRecordChanged(srv, RecordChangedEvent::kCreated);
196     EXPECT_EQ(result.size(), size_t{0});
197 
198     result = querier->OnRecordChanged(a, RecordChangedEvent::kCreated);
199     EXPECT_EQ(result.size(), size_t{0});
200 
201     result = querier->OnRecordChanged(aaaa, RecordChangedEvent::kCreated);
202     EXPECT_EQ(result.size(), size_t{0});
203 
204     EXPECT_CALL(*cb, OnEndpointCreated(_)).Times(1);
205     result = querier->OnRecordChanged(txt, RecordChangedEvent::kCreated);
206     EXPECT_EQ(result.size(), size_t{0});
207     testing::Mock::VerifyAndClearExpectations(cb);
208   }
209 
210   std::string instance = "instance";
211   std::string instance2 = "instance2";
212   std::string service = "_service._udp";
213   std::string service2 = "_service2._udp";
214   std::string domain = "local";
215   StrictMock<MockCallback> callback;
216   std::unique_ptr<QuerierImplTesting> querier;
217   DomainName ptr_domain;
218   DomainName name;
219   DomainName name2;
220 
221  private:
ValidateRecordChangeResult(const std::vector<PendingQueryChange> & changes,const DomainName & name,size_t expected_size,PendingQueryChange::ChangeType change_type)222   void ValidateRecordChangeResult(
223       const std::vector<PendingQueryChange>& changes,
224       const DomainName& name,
225       size_t expected_size,
226       PendingQueryChange::ChangeType change_type) {
227     EXPECT_EQ(changes.size(), expected_size);
228     auto it = std::find_if(
229         changes.begin(), changes.end(),
230         [&name, change_type](const PendingQueryChange& change) {
231           return change.dns_type == DnsType::kANY &&
232                  change.dns_class == DnsClass::kANY &&
233                  change.change_type == change_type && change.name == name;
234         });
235     EXPECT_TRUE(it != changes.end());
236   }
237 };
238 
239 // Common Use Cases
240 //
241 // The below tests validate the common use cases for QuerierImpl, which we
242 // expect will be hit for reasonable actors on the network. For these tests, the
243 // real DnsDataGraph object will be used.
244 
TEST_F(DnsSdQuerierImplTest,TestStartStopQueryCallsMdnsQueries)245 TEST_F(DnsSdQuerierImplTest, TestStartStopQueryCallsMdnsQueries) {
246   DomainName other_service_id(
247       DomainName{instance2, "_service2", "_udp", domain});
248 
249   StrictMock<MockCallback> callback2;
250   EXPECT_FALSE(querier->IsQueryRunning(service2));
251 
252   EXPECT_CALL(querier->service(),
253               StartQuery(_, DnsType::kANY, DnsClass::kANY, _))
254       .Times(1);
255   querier->StartQuery(service2, &callback2);
256   EXPECT_TRUE(querier->IsQueryRunning(service2));
257 
258   EXPECT_CALL(querier->service(),
259               StopQuery(_, DnsType::kANY, DnsClass::kANY, _))
260       .Times(1);
261   querier->StopQuery(service2, &callback2);
262   EXPECT_FALSE(querier->IsQueryRunning(service2));
263 }
264 
TEST_F(DnsSdQuerierImplTest,TestStartDuplicateQueryFiresCallbacksWhenAble)265 TEST_F(DnsSdQuerierImplTest, TestStartDuplicateQueryFiresCallbacksWhenAble) {
266   StrictMock<MockCallback> callback2;
267   CreateServiceInstance(name, &callback);
268 
269   EXPECT_CALL(callback2, OnEndpointCreated(_)).Times(1);
270   querier->StartQuery(service, &callback2);
271   testing::Mock::VerifyAndClearExpectations(&callback2);
272 }
273 
TEST_F(DnsSdQuerierImplTest,TestStopQueryStopsTrackingRecords)274 TEST_F(DnsSdQuerierImplTest, TestStopQueryStopsTrackingRecords) {
275   CreateServiceInstance(name, &callback);
276 
277   DomainName ptr_domain(++name.labels().begin(), name.labels().end());
278   EXPECT_CALL(querier->service(),
279               StopQuery(ptr_domain, DnsType::kANY, DnsClass::kANY, _))
280       .Times(1);
281   EXPECT_CALL(querier->service(),
282               StopQuery(name, DnsType::kANY, DnsClass::kANY, _))
283       .Times(1);
284   querier->StopQuery(service, &callback);
285   EXPECT_FALSE(querier->IsDomainTracked(ptr_domain));
286   EXPECT_FALSE(querier->IsDomainTracked(name));
287   EXPECT_EQ(querier->GetTrackedDomainCount(), size_t{0});
288   testing::Mock::VerifyAndClearExpectations(&callback);
289 
290   EXPECT_CALL(querier->service(),
291               StartQuery(_, DnsType::kANY, DnsClass::kANY, _))
292       .Times(1);
293   querier->StartQuery(service, &callback);
294   EXPECT_TRUE(querier->IsQueryRunning(service));
295 }
296 
TEST_F(DnsSdQuerierImplTest,TestStopNonexistantQueryHasNoEffect)297 TEST_F(DnsSdQuerierImplTest, TestStopNonexistantQueryHasNoEffect) {
298   StrictMock<MockCallback> callback2;
299   querier->StopQuery(service, &callback2);
300 }
301 
TEST_F(DnsSdQuerierImplTest,TestAFollowingAAAAFiresSecondCallback)302 TEST_F(DnsSdQuerierImplTest, TestAFollowingAAAAFiresSecondCallback) {
303   MdnsRecord ptr = GetFakePtrRecord(name);
304   MdnsRecord srv = GetFakeSrvRecord(name);
305   MdnsRecord txt = GetFakeTxtRecord(name);
306   MdnsRecord a = GetFakeARecord(name);
307   MdnsRecord aaaa = GetFakeAAAARecord(name);
308 
309   std::vector<DnsSdInstanceEndpoint> endpoints;
310   auto changes = querier->OnRecordChanged(ptr, RecordChangedEvent::kCreated);
311   ValidateRecordChangeStartsQuery(changes, name, 1);
312 
313   changes = querier->OnRecordChanged(srv, RecordChangedEvent::kCreated);
314   EXPECT_EQ(changes.size(), size_t{0});
315   changes = querier->OnRecordChanged(txt, RecordChangedEvent::kCreated);
316   EXPECT_EQ(changes.size(), size_t{0});
317 
318   EXPECT_CALL(callback, OnEndpointCreated(_))
319       .WillOnce([&endpoints](const DnsSdInstanceEndpoint& ep) mutable {
320         endpoints.push_back(ep);
321       });
322   changes = querier->OnRecordChanged(aaaa, RecordChangedEvent::kCreated);
323   EXPECT_EQ(changes.size(), size_t{0});
324   testing::Mock::VerifyAndClearExpectations(&callback);
325 
326   EXPECT_CALL(callback, OnEndpointUpdated(_))
327       .WillOnce([&endpoints](const DnsSdInstanceEndpoint& ep) mutable {
328         endpoints.push_back(ep);
329       });
330   changes = querier->OnRecordChanged(a, RecordChangedEvent::kCreated);
331   EXPECT_EQ(changes.size(), size_t{0});
332   testing::Mock::VerifyAndClearExpectations(&callback);
333 
334   ASSERT_EQ(endpoints.size(), size_t{2});
335   DnsSdInstanceEndpoint& created = endpoints[0];
336   DnsSdInstanceEndpoint& updated = endpoints[1];
337   EXPECT_EQ(static_cast<DnsSdInstance>(created),
338             static_cast<DnsSdInstance>(updated));
339 
340   ASSERT_EQ(created.addresses().size(), size_t{1});
341   EXPECT_TRUE(created.addresses()[0].IsV6());
342 
343   ASSERT_EQ(updated.addresses().size(), size_t{2});
344   EXPECT_TRUE(created.addresses()[0] == updated.addresses()[0] ||
345               created.addresses()[0] == updated.addresses()[1]);
346   EXPECT_TRUE(updated.addresses()[0].IsV4() || updated.addresses()[1].IsV4());
347 }
348 
TEST_F(DnsSdQuerierImplTest,TestGenerateTwoRecordsCallsCallbackTwice)349 TEST_F(DnsSdQuerierImplTest, TestGenerateTwoRecordsCallsCallbackTwice) {
350   DomainName third{"android", "local"};
351   MdnsRecord ptr1 = GetFakePtrRecord(name);
352   MdnsRecord srv1 = GetFakeSrvRecord(name, third);
353   MdnsRecord txt1 = GetFakeTxtRecord(name);
354   MdnsRecord ptr2 = GetFakePtrRecord(name2);
355   MdnsRecord srv2 = GetFakeSrvRecord(name2, third);
356   MdnsRecord txt2 = GetFakeTxtRecord(name2);
357   MdnsRecord a = GetFakeARecord(third);
358 
359   auto changes = querier->OnRecordChanged(ptr1, RecordChangedEvent::kCreated);
360   ValidateRecordChangeStartsQuery(changes, name, 1);
361 
362   changes = querier->OnRecordChanged(srv1, RecordChangedEvent::kCreated);
363   ValidateRecordChangeStartsQuery(changes, third, 1);
364 
365   changes = querier->OnRecordChanged(txt1, RecordChangedEvent::kCreated);
366   EXPECT_EQ(changes.size(), size_t{0});
367 
368   changes = querier->OnRecordChanged(ptr2, RecordChangedEvent::kCreated);
369   ValidateRecordChangeStartsQuery(changes, name2, 1);
370 
371   changes = querier->OnRecordChanged(srv2, RecordChangedEvent::kCreated);
372   EXPECT_EQ(changes.size(), size_t{0});
373 
374   changes = querier->OnRecordChanged(txt2, RecordChangedEvent::kCreated);
375   EXPECT_EQ(changes.size(), size_t{0});
376 
377   EXPECT_CALL(callback, OnEndpointCreated(_)).Times(2);
378   changes = querier->OnRecordChanged(a, RecordChangedEvent::kCreated);
379   EXPECT_EQ(changes.size(), size_t{0});
380   testing::Mock::VerifyAndClearExpectations(&callback);
381 
382   EXPECT_CALL(callback, OnEndpointDeleted(_)).Times(2);
383   changes = querier->OnRecordChanged(a, RecordChangedEvent::kExpired);
384   EXPECT_EQ(changes.size(), size_t{0});
385 }
386 
TEST_F(DnsSdQuerierImplTest,TestCreateDeletePtrRecordResults)387 TEST_F(DnsSdQuerierImplTest, TestCreateDeletePtrRecordResults) {
388   const auto ptr = GetFakePtrRecord(name);
389 
390   auto result = querier->OnRecordChanged(ptr, RecordChangedEvent::kCreated);
391   ValidateRecordChangeStartsQuery(result, name, 1);
392 
393   result = querier->OnRecordChanged(ptr, RecordChangedEvent::kExpired);
394   ValidateRecordChangeStopsQuery(result, name, 1);
395 }
396 
TEST_F(DnsSdQuerierImplTest,CallbackCalledWhenPtrDeleted)397 TEST_F(DnsSdQuerierImplTest, CallbackCalledWhenPtrDeleted) {
398   MdnsRecord ptr = GetFakePtrRecord(name);
399   MdnsRecord srv = GetFakeSrvRecord(name, name2);
400   MdnsRecord txt = GetFakeTxtRecord(name);
401   MdnsRecord a = GetFakeARecord(name2);
402 
403   auto changes = querier->OnRecordChanged(ptr, RecordChangedEvent::kCreated);
404   ValidateRecordChangeStartsQuery(changes, name, 1);
405 
406   changes = querier->OnRecordChanged(srv, RecordChangedEvent::kCreated);
407   ValidateRecordChangeStartsQuery(changes, name2, 1);
408 
409   changes = querier->OnRecordChanged(txt, RecordChangedEvent::kCreated);
410   EXPECT_EQ(changes.size(), size_t{0});
411 
412   EXPECT_CALL(callback, OnEndpointCreated(_));
413   changes = querier->OnRecordChanged(a, RecordChangedEvent::kCreated);
414   EXPECT_EQ(changes.size(), size_t{0});
415 
416   EXPECT_CALL(callback, OnEndpointDeleted(_));
417   changes = querier->OnRecordChanged(ptr, RecordChangedEvent::kExpired);
418   ValidateRecordChangeStopsQuery(changes, name, 2);
419   ValidateRecordChangeStopsQuery(changes, name2, 2);
420 }
421 
TEST_F(DnsSdQuerierImplTest,HardRefresh)422 TEST_F(DnsSdQuerierImplTest, HardRefresh) {
423   MdnsRecord ptr = GetFakePtrRecord(name);
424   MdnsRecord srv = GetFakeSrvRecord(name, name2);
425   MdnsRecord txt = GetFakeTxtRecord(name);
426   MdnsRecord a = GetFakeARecord(name2);
427 
428   querier->OnRecordChanged(ptr, RecordChangedEvent::kCreated);
429   querier->OnRecordChanged(srv, RecordChangedEvent::kCreated);
430   querier->OnRecordChanged(txt, RecordChangedEvent::kCreated);
431 
432   EXPECT_CALL(callback, OnEndpointCreated(_));
433   querier->OnRecordChanged(a, RecordChangedEvent::kCreated);
434   testing::Mock::VerifyAndClearExpectations(&callback);
435 
436   EXPECT_CALL(querier->service(),
437               StopQuery(ptr_domain, DnsType::kANY, DnsClass::kANY, _))
438       .Times(1);
439   EXPECT_CALL(querier->service(),
440               StopQuery(name, DnsType::kANY, DnsClass::kANY, _))
441       .Times(1);
442   EXPECT_CALL(querier->service(),
443               StopQuery(name2, DnsType::kANY, DnsClass::kANY, _))
444       .Times(1);
445   EXPECT_CALL(querier->service(), ReinitializeQueries(_)).Times(1);
446   EXPECT_CALL(querier->service(),
447               StartQuery(ptr_domain, DnsType::kANY, DnsClass::kANY, _))
448       .Times(1);
449   querier->ReinitializeQueries(service);
450   testing::Mock::VerifyAndClearExpectations(querier.get());
451 }
452 
453 // Edge Cases
454 //
455 // The below tests validate against edge cases that either either difficult to
456 // achieve, are not expected to be possible under normal circumstances but
457 // should be validated against for safety, or should only occur when either a
458 // bad actor or a misbehaving publisher is present on the network. To simplify
459 // these tests, the DnsDataGraph object will be mocked.
TEST_F(DnsSdQuerierImplTest,ErrorsOnlyAfterChangesAreLogged)460 TEST_F(DnsSdQuerierImplTest, ErrorsOnlyAfterChangesAreLogged) {
461   MockDnsDataGraph& mock_graph = querier->GetMockedGraph();
462   std::vector<ErrorOr<DnsSdInstanceEndpoint>> before_changes{};
463   std::vector<ErrorOr<DnsSdInstanceEndpoint>> after_changes{};
464   after_changes.emplace_back(Error::Code::kItemNotFound);
465   after_changes.emplace_back(Error::Code::kItemNotFound);
466   after_changes.emplace_back(Error::Code::kItemAlreadyExists);
467 
468   // Calls before and after applying record changes, then the error it logs.
469   EXPECT_CALL(mock_graph, CreateEndpoints(_, _))
470       .WillOnce(Return(ByMove(std::move(before_changes))))
471       .WillOnce(Return(ByMove(std::move(after_changes))));
472   EXPECT_CALL(querier->reporting_client(), OnRecoverableError(_)).Times(3);
473 
474   // Call to apply record changes. The specifics are unimportant.
475   EXPECT_CALL(mock_graph, ApplyDataRecordChange(_, _, _, _))
476       .WillOnce(Return(Error::None()));
477 
478   // Call with any record. The mocks make the specifics unimportant.
479   querier->OnRecordChanged(GetFakePtrRecord(name),
480                            RecordChangedEvent::kCreated);
481 }
482 
TEST_F(DnsSdQuerierImplTest,ErrorsOnlyBeforeChangesNotLogged)483 TEST_F(DnsSdQuerierImplTest, ErrorsOnlyBeforeChangesNotLogged) {
484   MockDnsDataGraph& mock_graph = querier->GetMockedGraph();
485   std::vector<ErrorOr<DnsSdInstanceEndpoint>> before_changes{};
486   before_changes.emplace_back(Error::Code::kItemNotFound);
487   before_changes.emplace_back(Error::Code::kItemNotFound);
488   before_changes.emplace_back(Error::Code::kItemAlreadyExists);
489   std::vector<ErrorOr<DnsSdInstanceEndpoint>> after_changes{};
490 
491   // Calls before and after applying record changes.
492   EXPECT_CALL(mock_graph, CreateEndpoints(_, _))
493       .WillOnce(Return(ByMove(std::move(before_changes))))
494       .WillOnce(Return(ByMove(std::move(after_changes))));
495 
496   // Call to apply record changes. The specifics are unimportant.
497   EXPECT_CALL(mock_graph, ApplyDataRecordChange(_, _, _, _))
498       .WillOnce(Return(Error::None()));
499 
500   // Call with any record. The mocks make the specifics unimportant.
501   querier->OnRecordChanged(GetFakePtrRecord(name),
502                            RecordChangedEvent::kCreated);
503 }
504 
TEST_F(DnsSdQuerierImplTest,ErrorsBeforeAndAfterChangesNotLogged)505 TEST_F(DnsSdQuerierImplTest, ErrorsBeforeAndAfterChangesNotLogged) {
506   MockDnsDataGraph& mock_graph = querier->GetMockedGraph();
507   std::vector<ErrorOr<DnsSdInstanceEndpoint>> before_changes{};
508   before_changes.emplace_back(Error::Code::kItemNotFound);
509   before_changes.emplace_back(Error::Code::kItemNotFound);
510   before_changes.emplace_back(Error::Code::kItemAlreadyExists);
511   std::vector<ErrorOr<DnsSdInstanceEndpoint>> after_changes{};
512   after_changes.emplace_back(Error::Code::kItemNotFound);
513   after_changes.emplace_back(Error::Code::kItemAlreadyExists);
514   after_changes.emplace_back(Error::Code::kItemNotFound);
515 
516   // Calls before and after applying record changes.
517   EXPECT_CALL(mock_graph, CreateEndpoints(_, _))
518       .WillOnce(Return(ByMove(std::move(before_changes))))
519       .WillOnce(Return(ByMove(std::move(after_changes))));
520 
521   // Call to apply record changes. The specifics are unimportant.
522   EXPECT_CALL(mock_graph, ApplyDataRecordChange(_, _, _, _))
523       .WillOnce(Return(Error::None()));
524 
525   // Call with any record. The mocks make the specifics unimportant.
526   querier->OnRecordChanged(GetFakePtrRecord(name),
527                            RecordChangedEvent::kCreated);
528 }
529 
TEST_F(DnsSdQuerierImplTest,OrderOfErrorsDoesNotAffectResults)530 TEST_F(DnsSdQuerierImplTest, OrderOfErrorsDoesNotAffectResults) {
531   MockDnsDataGraph& mock_graph = querier->GetMockedGraph();
532   std::vector<ErrorOr<DnsSdInstanceEndpoint>> before_changes{};
533   before_changes.emplace_back(Error::Code::kIndexOutOfBounds);
534   before_changes.emplace_back(Error::Code::kItemAlreadyExists);
535   before_changes.emplace_back(Error::Code::kOperationCancelled);
536   before_changes.emplace_back(Error::Code::kItemNotFound);
537   before_changes.emplace_back(Error::Code::kOperationInProgress);
538   std::vector<ErrorOr<DnsSdInstanceEndpoint>> after_changes{};
539   after_changes.emplace_back(Error::Code::kOperationInProgress);
540   after_changes.emplace_back(Error::Code::kUnknownError);
541   after_changes.emplace_back(Error::Code::kItemNotFound);
542   after_changes.emplace_back(Error::Code::kItemAlreadyExists);
543   after_changes.emplace_back(Error::Code::kOperationCancelled);
544 
545   // Calls before and after applying record changes, then the error it logs.
546   EXPECT_CALL(mock_graph, CreateEndpoints(_, _))
547       .WillOnce(Return(ByMove(std::move(before_changes))))
548       .WillOnce(Return(ByMove(std::move(after_changes))));
549   EXPECT_CALL(querier->reporting_client(), OnRecoverableError(_)).Times(1);
550 
551   // Call to apply record changes. The specifics are unimportant.
552   EXPECT_CALL(mock_graph, ApplyDataRecordChange(_, _, _, _))
553       .WillOnce(Return(Error::None()));
554 
555   // Call with any record. The mocks make the specifics unimportant.
556   querier->OnRecordChanged(GetFakePtrRecord(name),
557                            RecordChangedEvent::kCreated);
558 }
559 
TEST_F(DnsSdQuerierImplTest,ResultsWithMultipleAddressRecordsHandled)560 TEST_F(DnsSdQuerierImplTest, ResultsWithMultipleAddressRecordsHandled) {
561   IPEndpoint endpointa{{192, 168, 86, 23}, 80};
562   IPEndpoint endpointb{{1, 2, 3, 4, 5, 6, 7, 8}, 80};
563   IPEndpoint endpointc{{192, 168, 0, 1}, 80};
564   IPEndpoint endpointd{{192, 168, 0, 2}, 80};
565   IPEndpoint endpointe{{192, 168, 0, 3}, 80};
566 
567   DnsSdInstanceEndpoint instance1("instance1", "_service._udp", "local", {},
568                                   kNetworkInterface, {endpointa, endpointb});
569   DnsSdInstanceEndpoint instance2("instance2", "_service2._udp", "local", {},
570                                   kNetworkInterface, {endpointa, endpointb});
571   DnsSdInstanceEndpoint instance3("instance3", "_service._udp", "local", {},
572                                   kNetworkInterface, {endpointc});
573   DnsSdInstanceEndpoint instance4("instance1", "_service3._udp", "local", {},
574                                   kNetworkInterface, {endpointd, endpointe});
575   DnsSdInstanceEndpoint instance5("instance1", "_service3._udp", "local", {},
576                                   kNetworkInterface, {endpointe});
577 
578   MockDnsDataGraph& mock_graph = querier->GetMockedGraph();
579   std::vector<ErrorOr<DnsSdInstanceEndpoint>> before_changes{};
580   before_changes.emplace_back(instance4);
581   before_changes.emplace_back(instance2);
582   before_changes.emplace_back(instance3);
583   std::vector<ErrorOr<DnsSdInstanceEndpoint>> after_changes{};
584   after_changes.emplace_back(instance5);
585   after_changes.emplace_back(instance3);
586   after_changes.emplace_back(instance1);
587 
588   // Calls before and after applying record changes, then the error it logs.
589   EXPECT_CALL(mock_graph, CreateEndpoints(_, _))
590       .WillOnce(Return(ByMove(std::move(before_changes))))
591       .WillOnce(Return(ByMove(std::move(after_changes))));
592   EXPECT_CALL(callback, OnEndpointCreated(instance1));
593   EXPECT_CALL(callback, OnEndpointUpdated(instance5));
594   EXPECT_CALL(callback, OnEndpointDeleted(instance2));
595 
596   // Call to apply record changes. The specifics are unimportant.
597   EXPECT_CALL(mock_graph, ApplyDataRecordChange(_, _, _, _))
598       .WillOnce(Return(Error::None()));
599 
600   // Call with any record. The mocks make the specifics unimportant.
601   querier->OnRecordChanged(GetFakePtrRecord(name),
602                            RecordChangedEvent::kCreated);
603 }
604 
TEST_F(DnsSdQuerierImplTest,MixOfErrorsAndSuccessesHandledCorrectly)605 TEST_F(DnsSdQuerierImplTest, MixOfErrorsAndSuccessesHandledCorrectly) {
606   DnsSdInstanceEndpoint instance1("instance1", "_service._udp", "local", {},
607                                   kNetworkInterface, {{{192, 168, 2, 24}, 80}});
608   DnsSdInstanceEndpoint instance2("instance2", "_service2._udp", "local", {},
609                                   kNetworkInterface, {{{192, 168, 17, 2}, 80}});
610   DnsSdInstanceEndpoint instance3("instance3", "_service._udp", "local", {},
611                                   kNetworkInterface, {{{127, 0, 0, 1}, 80}});
612   DnsSdInstanceEndpoint instance4("instance1", "_service3._udp", "local", {},
613                                   kNetworkInterface, {{{127, 0, 0, 1}, 80}});
614   DnsSdInstanceEndpoint instance5("instance1", "_service3._udp", "local", {},
615                                   kNetworkInterface,
616                                   {{{127, 0, 0, 1}, 80}, {{127, 0, 0, 2}, 80}});
617 
618   MockDnsDataGraph& mock_graph = querier->GetMockedGraph();
619   std::vector<ErrorOr<DnsSdInstanceEndpoint>> before_changes{};
620   before_changes.emplace_back(Error::Code::kIndexOutOfBounds);
621   before_changes.emplace_back(instance2);
622   before_changes.emplace_back(Error::Code::kItemAlreadyExists);
623   before_changes.emplace_back(Error::Code::kOperationCancelled);
624   before_changes.emplace_back(instance1);
625   before_changes.emplace_back(Error::Code::kItemNotFound);
626   before_changes.emplace_back(Error::Code::kOperationInProgress);
627   before_changes.emplace_back(instance4);
628   std::vector<ErrorOr<DnsSdInstanceEndpoint>> after_changes{};
629   after_changes.emplace_back(instance1);
630   after_changes.emplace_back(Error::Code::kOperationInProgress);
631   after_changes.emplace_back(Error::Code::kUnknownError);
632   after_changes.emplace_back(Error::Code::kItemNotFound);
633   after_changes.emplace_back(Error::Code::kItemAlreadyExists);
634   after_changes.emplace_back(instance3);
635   after_changes.emplace_back(instance5);
636   after_changes.emplace_back(Error::Code::kOperationCancelled);
637 
638   // Calls before and after applying record changes, then the error it logs.
639   EXPECT_CALL(mock_graph, CreateEndpoints(_, _))
640       .WillOnce(Return(ByMove(std::move(before_changes))))
641       .WillOnce(Return(ByMove(std::move(after_changes))));
642   EXPECT_CALL(querier->reporting_client(), OnRecoverableError(_)).Times(1);
643   EXPECT_CALL(callback, OnEndpointCreated(instance3));
644   EXPECT_CALL(callback, OnEndpointUpdated(instance5));
645   EXPECT_CALL(callback, OnEndpointDeleted(instance2));
646 
647   // Call to apply record changes. The specifics are unimportant.
648   EXPECT_CALL(mock_graph, ApplyDataRecordChange(_, _, _, _))
649       .WillOnce(Return(Error::None()));
650 
651   // Call with any record. The mocks make the specifics unimportant.
652   querier->OnRecordChanged(GetFakePtrRecord(name),
653                            RecordChangedEvent::kCreated);
654 }
655 
656 }  // namespace discovery
657 }  // namespace openscreen
658