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