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/mdns/mdns_querier.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "discovery/common/config.h"
11 #include "discovery/common/testing/mock_reporting_client.h"
12 #include "discovery/mdns/mdns_random.h"
13 #include "discovery/mdns/mdns_receiver.h"
14 #include "discovery/mdns/mdns_record_changed_callback.h"
15 #include "discovery/mdns/mdns_sender.h"
16 #include "discovery/mdns/mdns_trackers.h"
17 #include "discovery/mdns/mdns_writer.h"
18 #include "gmock/gmock.h"
19 #include "gtest/gtest.h"
20 #include "platform/base/udp_packet.h"
21 #include "platform/test/fake_clock.h"
22 #include "platform/test/fake_task_runner.h"
23 #include "platform/test/mock_udp_socket.h"
24
25 namespace openscreen {
26 namespace discovery {
27
28 using testing::_;
29 using testing::Args;
30 using testing::Invoke;
31 using testing::Return;
32 using testing::StrictMock;
33 using testing::WithArgs;
34
35 // Only compare NAME, CLASS, TYPE and RDATA
ACTION_P(PartialCompareRecords,expected)36 ACTION_P(PartialCompareRecords, expected) {
37 const MdnsRecord& actual = arg0;
38 EXPECT_TRUE(actual.name() == expected.name());
39 EXPECT_TRUE(actual.dns_class() == expected.dns_class());
40 EXPECT_TRUE(actual.dns_type() == expected.dns_type());
41 EXPECT_TRUE(actual.rdata() == expected.rdata());
42 return std::vector<PendingQueryChange>{};
43 }
44
45 class MockRecordChangedCallback : public MdnsRecordChangedCallback {
46 public:
47 MOCK_METHOD(std::vector<PendingQueryChange>,
48 OnRecordChanged,
49 (const MdnsRecord&, RecordChangedEvent event),
50 (override));
51 };
52
53 class MdnsQuerierTest : public testing::Test {
54 public:
MdnsQuerierTest()55 MdnsQuerierTest()
56 : clock_(Clock::now()),
57 task_runner_(&clock_),
58 sender_(&socket_),
59 receiver_(config_),
60 record0_created_(DomainName{"testing", "local"},
61 DnsType::kA,
62 DnsClass::kIN,
63 RecordType::kUnique,
64 std::chrono::seconds(120),
65 ARecordRdata(IPAddress{172, 0, 0, 1})),
66 record0_updated_(DomainName{"testing", "local"},
67 DnsType::kA,
68 DnsClass::kIN,
69 RecordType::kUnique,
70 std::chrono::seconds(120),
71 ARecordRdata(IPAddress{172, 0, 0, 2})),
72 record0_deleted_(DomainName{"testing", "local"},
73 DnsType::kA,
74 DnsClass::kIN,
75 RecordType::kUnique,
76 std::chrono::seconds(0), // a goodbye record
77 ARecordRdata(IPAddress{172, 0, 0, 2})),
78 record1_created_(DomainName{"poking", "local"},
79 DnsType::kA,
80 DnsClass::kIN,
81 RecordType::kShared,
82 std::chrono::seconds(120),
83 ARecordRdata(IPAddress{192, 168, 0, 1})),
84 record1_deleted_(DomainName{"poking", "local"},
85 DnsType::kA,
86 DnsClass::kIN,
87 RecordType::kShared,
88 std::chrono::seconds(0), // a goodbye record
89 ARecordRdata(IPAddress{192, 168, 0, 1})),
90 record2_created_(DomainName{"testing", "local"},
91 DnsType::kAAAA,
92 DnsClass::kIN,
93 RecordType::kUnique,
94 std::chrono::seconds(120),
95 AAAARecordRdata(IPAddress{1, 2, 3, 4, 5, 6, 7, 8})),
96 nsec_record_created_(
97 DomainName{"testing", "local"},
98 DnsType::kNSEC,
99 DnsClass::kIN,
100 RecordType::kUnique,
101 std::chrono::seconds(120),
102 NsecRecordRdata(DomainName{"testing", "local"}, DnsType::kA)) {
103 receiver_.Start();
104 }
105
CreateQuerier()106 std::unique_ptr<MdnsQuerier> CreateQuerier() {
107 return std::make_unique<MdnsQuerier>(&sender_, &receiver_, &task_runner_,
108 &FakeClock::now, &random_,
109 &reporting_client_, config_);
110 }
111
112 protected:
113 template <typename... DnsTypes>
CreateNsec(DomainName name,DnsTypes...types)114 MdnsRecord CreateNsec(DomainName name, DnsTypes... types) {
115 NsecRecordRdata rdata(name, types...);
116 return MdnsRecord(std::move(name), nsec_record_created_.dns_type(),
117 nsec_record_created_.dns_class(),
118 nsec_record_created_.record_type(),
119 nsec_record_created_.ttl(), std::move(rdata));
120 }
121
CreatePacketWithRecords(const std::vector<MdnsRecord::ConstRef> & records,std::vector<MdnsRecord::ConstRef> additional_records)122 UdpPacket CreatePacketWithRecords(
123 const std::vector<MdnsRecord::ConstRef>& records,
124 std::vector<MdnsRecord::ConstRef> additional_records) {
125 MdnsMessage message(CreateMessageId(), MessageType::Response);
126 for (const MdnsRecord& record : records) {
127 message.AddAnswer(record);
128 }
129 for (const MdnsRecord& additional_record : additional_records) {
130 message.AddAdditionalRecord(additional_record);
131 }
132 UdpPacket packet(message.MaxWireSize());
133 MdnsWriter writer(packet.data(), packet.size());
134 EXPECT_TRUE(writer.Write(message));
135 packet.resize(writer.offset());
136 return packet;
137 }
138
CreatePacketWithRecords(const std::vector<MdnsRecord::ConstRef> & records)139 UdpPacket CreatePacketWithRecords(
140 const std::vector<MdnsRecord::ConstRef>& records) {
141 return CreatePacketWithRecords(records, {});
142 }
143
CreatePacketWithRecord(const MdnsRecord & record)144 UdpPacket CreatePacketWithRecord(const MdnsRecord& record) {
145 return CreatePacketWithRecords({MdnsRecord::ConstRef(record)});
146 }
147
148 // NSEC records are never exposed to outside callers, so the below methods are
149 // necessary to validate that they are functioning as expected.
ContainsRecord(MdnsQuerier * querier,const MdnsRecord & record,DnsType type=DnsType::kANY)150 bool ContainsRecord(MdnsQuerier* querier,
151 const MdnsRecord& record,
152 DnsType type = DnsType::kANY) {
153 auto record_trackers =
154 querier->records_.Find(record.name(), type, record.dns_class());
155
156 return std::find_if(record_trackers.begin(), record_trackers.end(),
157 [&record](const MdnsRecordTracker& tracker) {
158 return tracker.rdata() == record.rdata() &&
159 tracker.ttl() == record.ttl();
160 }) != record_trackers.end();
161 }
162
RecordCount(MdnsQuerier * querier)163 size_t RecordCount(MdnsQuerier* querier) { return querier->records_.size(); }
164
165 Config config_;
166 FakeClock clock_;
167 FakeTaskRunner task_runner_;
168 testing::NiceMock<MockUdpSocket> socket_;
169 MdnsSender sender_;
170 MdnsReceiver receiver_;
171 MdnsRandom random_;
172 StrictMock<MockReportingClient> reporting_client_;
173
174 MdnsRecord record0_created_;
175 MdnsRecord record0_updated_;
176 MdnsRecord record0_deleted_;
177 MdnsRecord record1_created_;
178 MdnsRecord record1_deleted_;
179 MdnsRecord record2_created_;
180 MdnsRecord nsec_record_created_;
181 };
182
TEST_F(MdnsQuerierTest,UniqueRecordCreatedUpdatedDeleted)183 TEST_F(MdnsQuerierTest, UniqueRecordCreatedUpdatedDeleted) {
184 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
185 MockRecordChangedCallback callback;
186
187 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
188 DnsClass::kIN, &callback);
189
190 EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
191 .WillOnce(WithArgs<0>(PartialCompareRecords(record0_created_)));
192 EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kUpdated))
193 .WillOnce(WithArgs<0>(PartialCompareRecords(record0_updated_)));
194 EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kExpired))
195 .WillOnce(WithArgs<0>(PartialCompareRecords(record0_deleted_)));
196
197 receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
198 // Receiving the same record should only reset TTL, no callback
199 receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
200 receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_updated_));
201 receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_deleted_));
202
203 // Advance clock for expiration to happen, since it's delayed by 1 second as
204 // per RFC 6762.
205 clock_.Advance(std::chrono::seconds(1));
206 }
207
TEST_F(MdnsQuerierTest,WildcardQuery)208 TEST_F(MdnsQuerierTest, WildcardQuery) {
209 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
210 MockRecordChangedCallback callback;
211
212 querier->StartQuery(DomainName{"poking", "local"}, DnsType::kANY,
213 DnsClass::kANY, &callback);
214
215 EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
216 .WillOnce(WithArgs<0>(PartialCompareRecords(record1_created_)));
217 EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kExpired))
218 .WillOnce(WithArgs<0>(PartialCompareRecords(record1_deleted_)));
219
220 receiver_.OnRead(&socket_, CreatePacketWithRecord(record1_created_));
221 receiver_.OnRead(&socket_, CreatePacketWithRecord(record1_deleted_));
222
223 // Advance clock for expiration to happen, since it's delayed by 1 second as
224 // per RFC 6762.
225 clock_.Advance(std::chrono::seconds(1));
226 }
227
TEST_F(MdnsQuerierTest,SharedRecordCreatedDeleted)228 TEST_F(MdnsQuerierTest, SharedRecordCreatedDeleted) {
229 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
230 MockRecordChangedCallback callback;
231
232 querier->StartQuery(DomainName{"poking", "local"}, DnsType::kA, DnsClass::kIN,
233 &callback);
234
235 EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
236 .WillOnce(WithArgs<0>(PartialCompareRecords(record1_created_)));
237 EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kExpired))
238 .WillOnce(WithArgs<0>(PartialCompareRecords(record1_deleted_)));
239
240 receiver_.OnRead(&socket_, CreatePacketWithRecord(record1_created_));
241 // Receiving the same record should only reset TTL, no callback
242 receiver_.OnRead(&socket_, CreatePacketWithRecord(record1_created_));
243 receiver_.OnRead(&socket_, CreatePacketWithRecord(record1_deleted_));
244
245 // Advance clock for expiration to happen, since it's delayed by 1 second as
246 // per RFC 6762.
247 clock_.Advance(std::chrono::seconds(1));
248 }
249
TEST_F(MdnsQuerierTest,StartQueryTwice)250 TEST_F(MdnsQuerierTest, StartQueryTwice) {
251 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
252 MockRecordChangedCallback callback;
253
254 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
255 DnsClass::kIN, &callback);
256 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
257 DnsClass::kIN, &callback);
258
259 EXPECT_CALL(callback, OnRecordChanged(_, _)).Times(1);
260
261 receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
262 }
263
TEST_F(MdnsQuerierTest,MultipleCallbacks)264 TEST_F(MdnsQuerierTest, MultipleCallbacks) {
265 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
266 MockRecordChangedCallback callback_1;
267 MockRecordChangedCallback callback_2;
268
269 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
270 DnsClass::kIN, &callback_1);
271 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
272 DnsClass::kIN, &callback_2);
273
274 EXPECT_CALL(callback_1, OnRecordChanged(_, _)).Times(1);
275 EXPECT_CALL(callback_2, OnRecordChanged(_, _)).Times(2);
276
277 // Both callbacks will be invoked.
278 receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
279
280 querier->StopQuery(DomainName{"testing", "local"}, DnsType::kA, DnsClass::kIN,
281 &callback_1);
282
283 // Only callback_2 will be invoked.
284 receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_updated_));
285
286 querier->StopQuery(DomainName{"testing", "local"}, DnsType::kA, DnsClass::kIN,
287 &callback_2);
288 // No callbacks will be invoked as all have been stopped.
289 receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_updated_));
290 }
291
TEST_F(MdnsQuerierTest,NoRecordChangesAfterStop)292 TEST_F(MdnsQuerierTest, NoRecordChangesAfterStop) {
293 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
294 MockRecordChangedCallback callback;
295 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
296 DnsClass::kIN, &callback);
297 EXPECT_CALL(callback, OnRecordChanged(_, _)).Times(1);
298 receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
299 querier->StopQuery(DomainName{"testing", "local"}, DnsType::kA, DnsClass::kIN,
300 &callback);
301 receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_updated_));
302 }
303
TEST_F(MdnsQuerierTest,OnRecordChangeCallbacksGetRun)304 TEST_F(MdnsQuerierTest, OnRecordChangeCallbacksGetRun) {
305 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
306 MockRecordChangedCallback callback;
307 DomainName name = DomainName{"testing", "local"};
308 querier->StartQuery(name, DnsType::kA, DnsClass::kIN, &callback);
309 PendingQueryChange result{name, DnsType::kA, DnsClass::kIN, &callback,
310 PendingQueryChange::kStopQuery};
311 EXPECT_CALL(callback, OnRecordChanged(_, _))
312 .WillOnce(Return(std::vector<PendingQueryChange>{result}));
313 receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
314 receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_updated_));
315 }
316
TEST_F(MdnsQuerierTest,StopQueryTwice)317 TEST_F(MdnsQuerierTest, StopQueryTwice) {
318 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
319 MockRecordChangedCallback callback;
320 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
321 DnsClass::kIN, &callback);
322 EXPECT_CALL(callback, OnRecordChanged(_, _)).Times(0);
323 querier->StopQuery(DomainName{"testing", "local"}, DnsType::kA, DnsClass::kIN,
324 &callback);
325 querier->StopQuery(DomainName{"testing", "local"}, DnsType::kA, DnsClass::kIN,
326 &callback);
327 receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
328 }
329
TEST_F(MdnsQuerierTest,StopNonExistingQuery)330 TEST_F(MdnsQuerierTest, StopNonExistingQuery) {
331 // Just making sure nothing crashes.
332 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
333 MockRecordChangedCallback callback;
334 querier->StopQuery(DomainName{"testing", "local"}, DnsType::kA, DnsClass::kIN,
335 &callback);
336 }
337
TEST_F(MdnsQuerierTest,IrrelevantRecordReceived)338 TEST_F(MdnsQuerierTest, IrrelevantRecordReceived) {
339 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
340 MockRecordChangedCallback callback;
341 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
342 DnsClass::kIN, &callback);
343 EXPECT_CALL(callback, OnRecordChanged(_, _)).Times(1);
344 receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
345 receiver_.OnRead(&socket_, CreatePacketWithRecord(record1_created_));
346 }
347
TEST_F(MdnsQuerierTest,DifferentCallersSameQuestion)348 TEST_F(MdnsQuerierTest, DifferentCallersSameQuestion) {
349 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
350 MockRecordChangedCallback callback1;
351 MockRecordChangedCallback callback2;
352 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
353 DnsClass::kIN, &callback1);
354 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
355 DnsClass::kIN, &callback2);
356 EXPECT_CALL(callback1, OnRecordChanged(_, _)).Times(1);
357 EXPECT_CALL(callback2, OnRecordChanged(_, _)).Times(1);
358 receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
359 }
360
TEST_F(MdnsQuerierTest,DifferentCallersDifferentQuestions)361 TEST_F(MdnsQuerierTest, DifferentCallersDifferentQuestions) {
362 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
363 MockRecordChangedCallback callback1;
364 MockRecordChangedCallback callback2;
365 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
366 DnsClass::kIN, &callback1);
367 querier->StartQuery(DomainName{"poking", "local"}, DnsType::kA, DnsClass::kIN,
368 &callback2);
369 EXPECT_CALL(callback1, OnRecordChanged(_, _)).Times(1);
370 EXPECT_CALL(callback2, OnRecordChanged(_, _)).Times(1);
371 receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
372 receiver_.OnRead(&socket_, CreatePacketWithRecord(record1_created_));
373 }
374
TEST_F(MdnsQuerierTest,SameCallerDifferentQuestions)375 TEST_F(MdnsQuerierTest, SameCallerDifferentQuestions) {
376 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
377 MockRecordChangedCallback callback;
378 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
379 DnsClass::kIN, &callback);
380 querier->StartQuery(DomainName{"poking", "local"}, DnsType::kA, DnsClass::kIN,
381 &callback);
382 EXPECT_CALL(callback, OnRecordChanged(_, _)).Times(2);
383 receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
384 receiver_.OnRead(&socket_, CreatePacketWithRecord(record1_created_));
385 }
386
TEST_F(MdnsQuerierTest,ReinitializeQueries)387 TEST_F(MdnsQuerierTest, ReinitializeQueries) {
388 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
389 MockRecordChangedCallback callback;
390
391 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
392 DnsClass::kIN, &callback);
393
394 EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
395 .WillOnce(WithArgs<0>(PartialCompareRecords(record0_created_)));
396
397 receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
398 // Receiving the same record should only reset TTL, no callback
399 receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
400 testing::Mock::VerifyAndClearExpectations(&receiver_);
401
402 // Queries should still be ongoing but all received records should have been
403 // deleted.
404 querier->ReinitializeQueries(DomainName{"testing", "local"});
405 EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
406 .WillOnce(WithArgs<0>(PartialCompareRecords(record0_created_)));
407 receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
408 testing::Mock::VerifyAndClearExpectations(&receiver_);
409
410 // Reinitializing a different domain should not affect other queries.
411 querier->ReinitializeQueries(DomainName{"testing2", "local"});
412 receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
413 }
414
TEST_F(MdnsQuerierTest,MessagesForUnknownQueriesDropped)415 TEST_F(MdnsQuerierTest, MessagesForUnknownQueriesDropped) {
416 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
417 MockRecordChangedCallback callback;
418
419 // Message for unknown query does not get processed.
420 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
421 DnsClass::kIN, &callback);
422 receiver_.OnRead(&socket_, CreatePacketWithRecord(record1_created_));
423 querier->StartQuery(DomainName{"poking", "local"}, DnsType::kA, DnsClass::kIN,
424 &callback);
425 testing::Mock::VerifyAndClearExpectations(&callback);
426
427 querier->StopQuery(DomainName{"poking", "local"}, DnsType::kA, DnsClass::kIN,
428 &callback);
429
430 // Only known records from the message are processed.
431 EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
432 .Times(1);
433 receiver_.OnRead(
434 &socket_, CreatePacketWithRecords({record0_created_, record1_created_}));
435 querier->StartQuery(DomainName{"poking", "local"}, DnsType::kA, DnsClass::kIN,
436 &callback);
437 }
438
TEST_F(MdnsQuerierTest,MessagesForKnownRecordsAllowed)439 TEST_F(MdnsQuerierTest, MessagesForKnownRecordsAllowed) {
440 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
441 MockRecordChangedCallback callback;
442
443 // Store a message for a known query.
444 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
445 DnsClass::kIN, &callback);
446 receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
447 testing::Mock::VerifyAndClearExpectations(&callback);
448
449 // Stop the query and validate that record updates are still received.
450 querier->StopQuery(DomainName{"testing", "local"}, DnsType::kA, DnsClass::kIN,
451 &callback);
452 receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_updated_));
453 testing::Mock::VerifyAndClearExpectations(&callback);
454
455 querier->StopQuery(DomainName{"poking", "local"}, DnsType::kA, DnsClass::kIN,
456 &callback);
457
458 // Only known records from the message are processed.
459 EXPECT_CALL(callback,
460 OnRecordChanged(record0_updated_, RecordChangedEvent::kCreated))
461 .Times(1);
462 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
463 DnsClass::kIN, &callback);
464 }
465
TEST_F(MdnsQuerierTest,MessagesForUnknownKnownRecordsAllowsAdditionalRecords)466 TEST_F(MdnsQuerierTest, MessagesForUnknownKnownRecordsAllowsAdditionalRecords) {
467 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
468 MockRecordChangedCallback callback;
469
470 // Store a message for a known query.
471 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
472 DnsClass::kIN, &callback);
473 EXPECT_CALL(callback,
474 OnRecordChanged(record0_created_, RecordChangedEvent::kCreated))
475 .Times(1);
476 receiver_.OnRead(&socket_, CreatePacketWithRecords({record1_created_},
477 {record0_created_}));
478 testing::Mock::VerifyAndClearExpectations(&callback);
479 }
480
TEST_F(MdnsQuerierTest,NsecDroppedWhenCorrespondsToNonNsec)481 TEST_F(MdnsQuerierTest, NsecDroppedWhenCorrespondsToNonNsec) {
482 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
483 StrictMock<MockRecordChangedCallback> callback;
484 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kANY,
485 DnsClass::kIN, &callback);
486 auto packet = CreatePacketWithRecords(
487 {record0_created_, nsec_record_created_, record2_created_});
488
489 EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
490 .WillOnce(WithArgs<0>(PartialCompareRecords(record0_created_)))
491 .WillOnce(WithArgs<0>(PartialCompareRecords(record2_created_)));
492 receiver_.OnRead(&socket_, std::move(packet));
493 ASSERT_EQ(RecordCount(querier.get()), size_t{2});
494 EXPECT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
495 EXPECT_TRUE(ContainsRecord(querier.get(), record2_created_, DnsType::kAAAA));
496
497 // Do it again in the another record order.
498 querier = CreateQuerier();
499 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kANY,
500 DnsClass::kIN, &callback);
501 packet = CreatePacketWithRecords(
502 {nsec_record_created_, record2_created_, record0_created_});
503
504 EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
505 .WillOnce(WithArgs<0>(PartialCompareRecords(record0_created_)))
506 .WillOnce(WithArgs<0>(PartialCompareRecords(record2_created_)));
507 receiver_.OnRead(&socket_, std::move(packet));
508 ASSERT_EQ(RecordCount(querier.get()), size_t{2});
509 EXPECT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
510 EXPECT_TRUE(ContainsRecord(querier.get(), record2_created_, DnsType::kAAAA));
511 }
512
TEST_F(MdnsQuerierTest,MultipleNsecCombinedWhenSameName)513 TEST_F(MdnsQuerierTest, MultipleNsecCombinedWhenSameName) {
514 DomainName alternate_name{"poking", "local"};
515 MdnsRecord multi_type_nsec =
516 CreateNsec(nsec_record_created_.name(), DnsType::kA, DnsType::kAAAA);
517 MdnsRecord aaaa_nsec =
518 CreateNsec(nsec_record_created_.name(), DnsType::kAAAA);
519 MdnsRecord srv_nsec = CreateNsec(alternate_name, DnsType::kSRV);
520
521 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
522 StrictMock<MockRecordChangedCallback> callback;
523 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kANY,
524 DnsClass::kIN, &callback);
525 querier->StartQuery(alternate_name, DnsType::kANY, DnsClass::kIN, &callback);
526 auto packet =
527 CreatePacketWithRecords({nsec_record_created_, srv_nsec, aaaa_nsec});
528
529 receiver_.OnRead(&socket_, std::move(packet));
530 ASSERT_EQ(RecordCount(querier.get()), size_t{3});
531 EXPECT_TRUE(ContainsRecord(querier.get(), multi_type_nsec, DnsType::kA));
532 EXPECT_TRUE(ContainsRecord(querier.get(), multi_type_nsec, DnsType::kAAAA));
533 EXPECT_TRUE(ContainsRecord(querier.get(), srv_nsec, DnsType::kSRV));
534 }
535
TEST_F(MdnsQuerierTest,NsecBitsUnSetWhenCorrespondsToExistingRecord)536 TEST_F(MdnsQuerierTest, NsecBitsUnSetWhenCorrespondsToExistingRecord) {
537 MdnsRecord multi_type_nsec =
538 CreateNsec(nsec_record_created_.name(), DnsType::kA, DnsType::kAAAA);
539 MdnsRecord aaaa_nsec =
540 CreateNsec(nsec_record_created_.name(), DnsType::kAAAA);
541
542 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
543 StrictMock<MockRecordChangedCallback> callback;
544 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kANY,
545 DnsClass::kIN, &callback);
546 auto packet = CreatePacketWithRecords({multi_type_nsec, record0_created_});
547
548 EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
549 .WillOnce(WithArgs<0>(PartialCompareRecords(record0_created_)));
550 receiver_.OnRead(&socket_, std::move(packet));
551 ASSERT_EQ(RecordCount(querier.get()), size_t{2});
552 EXPECT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
553 EXPECT_TRUE(ContainsRecord(querier.get(), aaaa_nsec, DnsType::kAAAA));
554
555 // Do it again in the another record order.
556 querier = CreateQuerier();
557 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kANY,
558 DnsClass::kIN, &callback);
559 packet = CreatePacketWithRecords({record0_created_, multi_type_nsec});
560
561 EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
562 .WillOnce(WithArgs<0>(PartialCompareRecords(record0_created_)));
563 receiver_.OnRead(&socket_, std::move(packet));
564 ASSERT_EQ(RecordCount(querier.get()), size_t{2});
565 EXPECT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
566 EXPECT_TRUE(ContainsRecord(querier.get(), aaaa_nsec, DnsType::kAAAA));
567 }
568
TEST_F(MdnsQuerierTest,NsecDroppedWhenAllBitsUnset)569 TEST_F(MdnsQuerierTest, NsecDroppedWhenAllBitsUnset) {
570 MdnsRecord multi_type_nsec =
571 CreateNsec(nsec_record_created_.name(), DnsType::kA, DnsType::kAAAA);
572 MdnsRecord aaaa(record0_created_.name(), DnsType::kAAAA,
573 record0_created_.dns_class(), record0_created_.record_type(),
574 record0_created_.ttl(),
575 AAAARecordRdata(IPAddress{172, 0, 0, 0, 0, 0, 0, 1}));
576
577 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
578 StrictMock<MockRecordChangedCallback> callback;
579 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kANY,
580 DnsClass::kIN, &callback);
581 auto packet =
582 CreatePacketWithRecords({multi_type_nsec, record0_created_, aaaa});
583
584 EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
585 .WillOnce(WithArgs<0>(PartialCompareRecords(record0_created_)))
586 .WillOnce(WithArgs<0>(PartialCompareRecords(aaaa)));
587 receiver_.OnRead(&socket_, std::move(packet));
588 ASSERT_EQ(RecordCount(querier.get()), size_t{2});
589 EXPECT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
590 EXPECT_TRUE(ContainsRecord(querier.get(), aaaa, DnsType::kAAAA));
591 }
592
TEST_F(MdnsQuerierTest,NsecUpdatesMultipleRecords)593 TEST_F(MdnsQuerierTest, NsecUpdatesMultipleRecords) {
594 const DomainName& first_name = record0_created_.name();
595 const DomainName alternate_name{"poking", "local"};
596 const DomainName third_name{"third", "local"};
597 MdnsRecord nsec_first_name =
598 CreateNsec(first_name, DnsType::kA, DnsType::kAAAA, DnsType::kSRV);
599 MdnsRecord aaaa(alternate_name, DnsType::kAAAA, record0_created_.dns_class(),
600 record0_created_.record_type(), record0_created_.ttl(),
601 AAAARecordRdata(IPAddress{172, 0, 0, 0, 0, 0, 0, 1}));
602 MdnsRecord nsec_second_name =
603 CreateNsec(alternate_name, DnsType::kA, DnsType::kAAAA, DnsType::kSRV);
604
605 MdnsRecord srv(third_name, DnsType::kSRV, record0_created_.dns_class(),
606 record0_created_.record_type(), record0_created_.ttl(),
607 SrvRecordRdata(1, 2, 3, third_name));
608 MdnsRecord nsec_third_name =
609 CreateNsec(third_name, DnsType::kA, DnsType::kAAAA, DnsType::kSRV);
610
611 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
612 StrictMock<MockRecordChangedCallback> callback;
613 querier->StartQuery(first_name, DnsType::kANY, DnsClass::kIN, &callback);
614 querier->StartQuery(alternate_name, DnsType::kANY, DnsClass::kIN, &callback);
615 querier->StartQuery(third_name, DnsType::kANY, DnsClass::kIN, &callback);
616 auto packet =
617 CreatePacketWithRecords({nsec_first_name, nsec_second_name,
618 nsec_third_name, record0_created_, aaaa, srv});
619
620 EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
621 .Times(3);
622 receiver_.OnRead(&socket_, std::move(packet));
623 ASSERT_EQ(RecordCount(querier.get()), size_t{9});
624
625 MdnsRecord new_first_nsec =
626 CreateNsec(first_name, DnsType::kAAAA, DnsType::kSRV);
627 MdnsRecord new_second_nsec =
628 CreateNsec(alternate_name, DnsType::kA, DnsType::kSRV);
629 MdnsRecord new_third_nsec =
630 CreateNsec(third_name, DnsType::kA, DnsType::kAAAA);
631
632 EXPECT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
633 EXPECT_TRUE(ContainsRecord(querier.get(), new_first_nsec, DnsType::kAAAA));
634 EXPECT_TRUE(ContainsRecord(querier.get(), new_first_nsec, DnsType::kSRV));
635
636 EXPECT_TRUE(ContainsRecord(querier.get(), new_second_nsec, DnsType::kA));
637 EXPECT_TRUE(ContainsRecord(querier.get(), aaaa, DnsType::kAAAA));
638 EXPECT_TRUE(ContainsRecord(querier.get(), new_second_nsec, DnsType::kSRV));
639
640 EXPECT_TRUE(ContainsRecord(querier.get(), new_third_nsec, DnsType::kA));
641 EXPECT_TRUE(ContainsRecord(querier.get(), new_third_nsec, DnsType::kAAAA));
642 EXPECT_TRUE(ContainsRecord(querier.get(), srv, DnsType::kSRV));
643 }
644
TEST_F(MdnsQuerierTest,NsecDeletesMultipleRecords)645 TEST_F(MdnsQuerierTest, NsecDeletesMultipleRecords) {
646 const DomainName& first_name = record0_created_.name();
647 const DomainName alternate_name{"poking", "local"};
648 MdnsRecord nsec_first = CreateNsec(first_name, DnsType::kA);
649
650 MdnsRecord aaaa(alternate_name, DnsType::kAAAA, record0_created_.dns_class(),
651 record0_created_.record_type(), record0_created_.ttl(),
652 AAAARecordRdata(IPAddress{172, 0, 0, 0, 0, 0, 0, 1}));
653 MdnsRecord srv(alternate_name, DnsType::kSRV, record0_created_.dns_class(),
654 record0_created_.record_type(), record0_created_.ttl(),
655 SrvRecordRdata(1, 2, 3, first_name));
656 MdnsRecord nsec_second =
657 CreateNsec(alternate_name, DnsType::kAAAA, DnsType::kSRV);
658 MdnsRecord nsec_third = CreateNsec(alternate_name, DnsType::kAAAA);
659
660 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
661 StrictMock<MockRecordChangedCallback> callback;
662 querier->StartQuery(first_name, DnsType::kANY, DnsClass::kIN, &callback);
663 querier->StartQuery(alternate_name, DnsType::kANY, DnsClass::kIN, &callback);
664 auto packet = CreatePacketWithRecords(
665 {record0_created_, aaaa, srv, nsec_first, nsec_second, nsec_third});
666
667 EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
668 .Times(3);
669 receiver_.OnRead(&socket_, std::move(packet));
670 ASSERT_EQ(RecordCount(querier.get()), size_t{3});
671
672 EXPECT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
673 EXPECT_TRUE(ContainsRecord(querier.get(), aaaa, DnsType::kAAAA));
674 EXPECT_TRUE(ContainsRecord(querier.get(), srv, DnsType::kSRV));
675 }
676
TEST_F(MdnsQuerierTest,NsecCreatesUpdatesAndDeletesMultipleRecords)677 TEST_F(MdnsQuerierTest, NsecCreatesUpdatesAndDeletesMultipleRecords) {
678 const DomainName& first_name = record0_created_.name();
679 const DomainName alternate_name{"poking", "local"};
680 const DomainName third_name{"third", "local"};
681 MdnsRecord nsec_first_name = CreateNsec(first_name, DnsType::kA);
682
683 MdnsRecord aaaa(alternate_name, DnsType::kAAAA, record0_created_.dns_class(),
684 record0_created_.record_type(), record0_created_.ttl(),
685 AAAARecordRdata(IPAddress{172, 0, 0, 0, 0, 0, 0, 1}));
686 MdnsRecord nsec_second_name =
687 CreateNsec(alternate_name, DnsType::kAAAA, DnsType::kSRV);
688 MdnsRecord srv(alternate_name, DnsType::kSRV, record0_created_.dns_class(),
689 record0_created_.record_type(), record0_created_.ttl(),
690 SrvRecordRdata(1, 2, 3, third_name));
691
692 MdnsRecord nsec_third_name = CreateNsec(third_name, DnsType::kA);
693
694 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
695 StrictMock<MockRecordChangedCallback> callback;
696 querier->StartQuery(first_name, DnsType::kANY, DnsClass::kIN, &callback);
697 querier->StartQuery(alternate_name, DnsType::kANY, DnsClass::kIN, &callback);
698 querier->StartQuery(third_name, DnsType::kANY, DnsClass::kIN, &callback);
699 auto packet =
700 CreatePacketWithRecords({nsec_first_name, nsec_second_name,
701 nsec_third_name, record0_created_, aaaa, srv});
702
703 EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
704 .Times(3);
705 receiver_.OnRead(&socket_, std::move(packet));
706 ASSERT_EQ(RecordCount(querier.get()), size_t{4});
707
708 MdnsRecord new_second_nsec = CreateNsec(alternate_name, DnsType::kSRV);
709
710 EXPECT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
711
712 EXPECT_TRUE(ContainsRecord(querier.get(), aaaa, DnsType::kAAAA));
713 EXPECT_TRUE(ContainsRecord(querier.get(), srv, DnsType::kSRV));
714
715 EXPECT_TRUE(ContainsRecord(querier.get(), nsec_third_name, DnsType::kA));
716 }
717
TEST_F(MdnsQuerierTest,CallbackNotCalledOnStartQueryForNsecRecords)718 TEST_F(MdnsQuerierTest, CallbackNotCalledOnStartQueryForNsecRecords) {
719 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
720
721 // Set up so an NSEC record has been received
722 StrictMock<MockRecordChangedCallback> callback;
723 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
724 DnsClass::kIN, &callback);
725 auto packet = CreatePacketWithRecord(nsec_record_created_);
726 receiver_.OnRead(&socket_, std::move(packet));
727 ASSERT_EQ(RecordCount(querier.get()), size_t{1});
728 EXPECT_TRUE(ContainsRecord(querier.get(), nsec_record_created_, DnsType::kA));
729
730 // Start new query
731 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
732 DnsClass::kIN, &callback);
733 }
734
TEST_F(MdnsQuerierTest,ReceiveNsecRecordFansOutToEachType)735 TEST_F(MdnsQuerierTest, ReceiveNsecRecordFansOutToEachType) {
736 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
737
738 StrictMock<MockRecordChangedCallback> callback;
739 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
740 DnsClass::kIN, &callback);
741 MdnsRecord multi_type_nsec =
742 MdnsRecord(nsec_record_created_.name(), nsec_record_created_.dns_type(),
743 nsec_record_created_.dns_class(),
744 nsec_record_created_.record_type(), nsec_record_created_.ttl(),
745 NsecRecordRdata(nsec_record_created_.name(), DnsType::kA,
746 DnsType::kSRV, DnsType::kAAAA));
747 auto packet = CreatePacketWithRecord(multi_type_nsec);
748 receiver_.OnRead(&socket_, std::move(packet));
749 ASSERT_EQ(RecordCount(querier.get()), size_t{3});
750 EXPECT_TRUE(ContainsRecord(querier.get(), multi_type_nsec, DnsType::kA));
751 EXPECT_TRUE(ContainsRecord(querier.get(), multi_type_nsec, DnsType::kAAAA));
752 EXPECT_TRUE(ContainsRecord(querier.get(), multi_type_nsec, DnsType::kSRV));
753 }
754
TEST_F(MdnsQuerierTest,ReceiveNsecKAnyRecordFansOutToAllTypes)755 TEST_F(MdnsQuerierTest, ReceiveNsecKAnyRecordFansOutToAllTypes) {
756 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
757
758 StrictMock<MockRecordChangedCallback> callback;
759 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
760 DnsClass::kIN, &callback);
761 MdnsRecord any_type_nsec =
762 MdnsRecord(nsec_record_created_.name(), nsec_record_created_.dns_type(),
763 nsec_record_created_.dns_class(),
764 nsec_record_created_.record_type(), nsec_record_created_.ttl(),
765 NsecRecordRdata(nsec_record_created_.name(), DnsType::kANY));
766 auto packet = CreatePacketWithRecord(any_type_nsec);
767 receiver_.OnRead(&socket_, std::move(packet));
768 ASSERT_EQ(RecordCount(querier.get()), size_t{5});
769 EXPECT_TRUE(ContainsRecord(querier.get(), any_type_nsec, DnsType::kA));
770 EXPECT_TRUE(ContainsRecord(querier.get(), any_type_nsec, DnsType::kAAAA));
771 EXPECT_TRUE(ContainsRecord(querier.get(), any_type_nsec, DnsType::kSRV));
772 EXPECT_TRUE(ContainsRecord(querier.get(), any_type_nsec, DnsType::kTXT));
773 EXPECT_TRUE(ContainsRecord(querier.get(), any_type_nsec, DnsType::kPTR));
774 }
775
TEST_F(MdnsQuerierTest,CorrectCallbackCalledWhenNsecRecordReplacesNonNsec)776 TEST_F(MdnsQuerierTest, CorrectCallbackCalledWhenNsecRecordReplacesNonNsec) {
777 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
778
779 // Set up so an A record has been received
780 StrictMock<MockRecordChangedCallback> callback;
781 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
782 DnsClass::kIN, &callback);
783 EXPECT_CALL(callback,
784 OnRecordChanged(record0_created_, RecordChangedEvent::kCreated));
785 auto packet = CreatePacketWithRecord(record0_created_);
786 receiver_.OnRead(&socket_, std::move(packet));
787 testing::Mock::VerifyAndClearExpectations(&callback);
788 ASSERT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
789 EXPECT_FALSE(
790 ContainsRecord(querier.get(), nsec_record_created_, DnsType::kA));
791
792 EXPECT_CALL(callback,
793 OnRecordChanged(record0_created_, RecordChangedEvent::kExpired));
794 packet = CreatePacketWithRecord(nsec_record_created_);
795 receiver_.OnRead(&socket_, std::move(packet));
796 EXPECT_FALSE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
797 EXPECT_TRUE(ContainsRecord(querier.get(), nsec_record_created_, DnsType::kA));
798 }
799
TEST_F(MdnsQuerierTest,NoCallbackCalledWhenNsecRecordWouldReplaceNonNsecButNsecDisabled)800 TEST_F(MdnsQuerierTest,
801 NoCallbackCalledWhenNsecRecordWouldReplaceNonNsecButNsecDisabled) {
802 config_.ignore_nsec_responses = true;
803 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
804
805 // Set up so an A record has been received
806 StrictMock<MockRecordChangedCallback> callback;
807 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
808 DnsClass::kIN, &callback);
809 EXPECT_CALL(callback,
810 OnRecordChanged(record0_created_, RecordChangedEvent::kCreated));
811 auto packet = CreatePacketWithRecord(record0_created_);
812 receiver_.OnRead(&socket_, std::move(packet));
813 testing::Mock::VerifyAndClearExpectations(&callback);
814 ASSERT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
815 EXPECT_FALSE(
816 ContainsRecord(querier.get(), nsec_record_created_, DnsType::kA));
817
818 packet = CreatePacketWithRecord(nsec_record_created_);
819 receiver_.OnRead(&socket_, std::move(packet));
820 EXPECT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
821 EXPECT_FALSE(
822 ContainsRecord(querier.get(), nsec_record_created_, DnsType::kA));
823 }
824
TEST_F(MdnsQuerierTest,CorrectCallbackCalledWhenNonNsecRecordReplacesNsec)825 TEST_F(MdnsQuerierTest, CorrectCallbackCalledWhenNonNsecRecordReplacesNsec) {
826 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
827
828 // Set up so an A record has been received
829 StrictMock<MockRecordChangedCallback> callback;
830 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
831 DnsClass::kIN, &callback);
832 auto packet = CreatePacketWithRecord(nsec_record_created_);
833 receiver_.OnRead(&socket_, std::move(packet));
834 ASSERT_TRUE(ContainsRecord(querier.get(), nsec_record_created_, DnsType::kA));
835 EXPECT_FALSE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
836
837 EXPECT_CALL(callback,
838 OnRecordChanged(record0_created_, RecordChangedEvent::kCreated));
839 packet = CreatePacketWithRecord(record0_created_);
840 receiver_.OnRead(&socket_, std::move(packet));
841 EXPECT_FALSE(
842 ContainsRecord(querier.get(), nsec_record_created_, DnsType::kA));
843 EXPECT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
844 }
845
TEST_F(MdnsQuerierTest,NoCallbackCalledWhenSecondNsecRecordReceived)846 TEST_F(MdnsQuerierTest, NoCallbackCalledWhenSecondNsecRecordReceived) {
847 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
848 MdnsRecord multi_type_nsec =
849 MdnsRecord(nsec_record_created_.name(), nsec_record_created_.dns_type(),
850 nsec_record_created_.dns_class(),
851 nsec_record_created_.record_type(), nsec_record_created_.ttl(),
852 NsecRecordRdata(nsec_record_created_.name(), DnsType::kA,
853 DnsType::kSRV, DnsType::kAAAA));
854
855 // Set up so an A record has been received
856 StrictMock<MockRecordChangedCallback> callback;
857 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
858 DnsClass::kIN, &callback);
859 auto packet = CreatePacketWithRecord(nsec_record_created_);
860 receiver_.OnRead(&socket_, std::move(packet));
861 ASSERT_TRUE(ContainsRecord(querier.get(), nsec_record_created_, DnsType::kA));
862 EXPECT_FALSE(ContainsRecord(querier.get(), multi_type_nsec, DnsType::kA));
863
864 packet = CreatePacketWithRecord(multi_type_nsec);
865 receiver_.OnRead(&socket_, std::move(packet));
866 EXPECT_FALSE(
867 ContainsRecord(querier.get(), nsec_record_created_, DnsType::kA));
868 EXPECT_TRUE(ContainsRecord(querier.get(), multi_type_nsec, DnsType::kA));
869 }
870
TEST_F(MdnsQuerierTest,TestMaxRecordsRespected)871 TEST_F(MdnsQuerierTest, TestMaxRecordsRespected) {
872 config_.querier_max_records_cached = 1;
873 std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
874
875 // Set up so an A record has been received
876 StrictMock<MockRecordChangedCallback> callback;
877 querier->StartQuery(DomainName{"testing", "local"}, DnsType::kANY,
878 DnsClass::kIN, &callback);
879 querier->StartQuery(DomainName{"poking", "local"}, DnsType::kANY,
880 DnsClass::kIN, &callback);
881 auto packet = CreatePacketWithRecord(record0_created_);
882 EXPECT_CALL(callback,
883 OnRecordChanged(record0_created_, RecordChangedEvent::kCreated));
884 receiver_.OnRead(&socket_, std::move(packet));
885 ASSERT_EQ(RecordCount(querier.get()), size_t{1});
886 EXPECT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
887 EXPECT_FALSE(ContainsRecord(querier.get(), record1_created_, DnsType::kA));
888 testing::Mock::VerifyAndClearExpectations(&callback);
889
890 EXPECT_CALL(callback,
891 OnRecordChanged(record0_created_, RecordChangedEvent::kExpired));
892 EXPECT_CALL(callback,
893 OnRecordChanged(record1_created_, RecordChangedEvent::kCreated));
894 packet = CreatePacketWithRecord(record1_created_);
895 receiver_.OnRead(&socket_, std::move(packet));
896 ASSERT_EQ(RecordCount(querier.get()), size_t{1});
897 EXPECT_FALSE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
898 EXPECT_TRUE(ContainsRecord(querier.get(), record1_created_, DnsType::kA));
899 }
900
901 } // namespace discovery
902 } // namespace openscreen
903