Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / net / dns / mdns_cache_unittest.cc
blobc12ad6b6ec3c830fbb88489aea4d8c41df3ea5f4
1 // Copyright (c) 2013 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.
5 #include <algorithm>
7 #include "base/bind.h"
8 #include "net/dns/dns_response.h"
9 #include "net/dns/dns_test_util.h"
10 #include "net/dns/mdns_cache.h"
11 #include "net/dns/record_parsed.h"
12 #include "net/dns/record_rdata.h"
13 #include "testing/gmock/include/gmock/gmock.h"
14 #include "testing/gtest/include/gtest/gtest.h"
16 using ::testing::Return;
17 using ::testing::StrictMock;
19 namespace net {
21 static const uint8 kTestResponsesDifferentAnswers[] = {
22 // Answer 1
23 // ghs.l.google.com in DNS format.
24 3, 'g', 'h', 's',
25 1, 'l',
26 6, 'g', 'o', 'o', 'g', 'l', 'e',
27 3, 'c', 'o', 'm',
28 0x00,
29 0x00, 0x01, // TYPE is A.
30 0x00, 0x01, // CLASS is IN.
31 0, 0, 0, 53, // TTL (4 bytes) is 53 seconds.
32 0, 4, // RDLENGTH is 4 bytes.
33 74, 125, 95, 121, // RDATA is the IP: 74.125.95.121
35 // Answer 2
36 // Pointer to answer 1
37 0xc0, 0x00,
38 0x00, 0x01, // TYPE is A.
39 0x00, 0x01, // CLASS is IN.
40 0, 0, 0, 53, // TTL (4 bytes) is 53 seconds.
41 0, 4, // RDLENGTH is 4 bytes.
42 74, 125, 95, 122, // RDATA is the IP: 74.125.95.122
45 static const uint8 kTestResponsesSameAnswers[] = {
46 // Answer 1
47 // ghs.l.google.com in DNS format.
48 3, 'g', 'h', 's',
49 1, 'l',
50 6, 'g', 'o', 'o', 'g', 'l', 'e',
51 3, 'c', 'o', 'm',
52 0x00,
53 0x00, 0x01, // TYPE is A.
54 0x00, 0x01, // CLASS is IN.
55 0, 0, 0, 53, // TTL (4 bytes) is 53 seconds.
56 0, 4, // RDLENGTH is 4 bytes.
57 74, 125, 95, 121, // RDATA is the IP: 74.125.95.121
59 // Answer 2
60 // Pointer to answer 1
61 0xc0, 0x00,
62 0x00, 0x01, // TYPE is A.
63 0x00, 0x01, // CLASS is IN.
64 0, 0, 0, 112, // TTL (4 bytes) is 112 seconds.
65 0, 4, // RDLENGTH is 4 bytes.
66 74, 125, 95, 121, // RDATA is the IP: 74.125.95.121
69 static const uint8 kTestResponseTwoRecords[] = {
70 // Answer 1
71 // ghs.l.google.com in DNS format. (A)
72 3, 'g', 'h', 's',
73 1, 'l',
74 6, 'g', 'o', 'o', 'g', 'l', 'e',
75 3, 'c', 'o', 'm',
76 0x00,
77 0x00, 0x01, // TYPE is A.
78 0x00, 0x01, // CLASS is IN.
79 0, 0, 0, 53, // TTL (4 bytes) is 53 seconds.
80 0, 4, // RDLENGTH is 4 bytes.
81 74, 125, 95, 121, // RDATA is the IP: 74.125.95.121
83 // Answer 2
84 // ghs.l.google.com in DNS format. (AAAA)
85 3, 'g', 'h', 's',
86 1, 'l',
87 6, 'g', 'o', 'o', 'g', 'l', 'e',
88 3, 'c', 'o', 'm',
89 0x00,
90 0x00, 0x1c, // TYPE is AAA.
91 0x00, 0x01, // CLASS is IN.
92 0, 0, 0, 53, // TTL (4 bytes) is 53 seconds.
93 0, 16, // RDLENGTH is 16 bytes.
94 0x4a, 0x7d, 0x4a, 0x7d,
95 0x5f, 0x79, 0x5f, 0x79,
96 0x5f, 0x79, 0x5f, 0x79,
97 0x5f, 0x79, 0x5f, 0x79,
100 static const uint8 kTestResponsesGoodbyePacket[] = {
101 // Answer 1
102 // ghs.l.google.com in DNS format. (Goodbye packet)
103 3, 'g', 'h', 's',
104 1, 'l',
105 6, 'g', 'o', 'o', 'g', 'l', 'e',
106 3, 'c', 'o', 'm',
107 0x00,
108 0x00, 0x01, // TYPE is A.
109 0x00, 0x01, // CLASS is IN.
110 0, 0, 0, 0, // TTL (4 bytes) is zero.
111 0, 4, // RDLENGTH is 4 bytes.
112 74, 125, 95, 121, // RDATA is the IP: 74.125.95.121
114 // Answer 2
115 // ghs.l.google.com in DNS format.
116 3, 'g', 'h', 's',
117 1, 'l',
118 6, 'g', 'o', 'o', 'g', 'l', 'e',
119 3, 'c', 'o', 'm',
120 0x00,
121 0x00, 0x01, // TYPE is A.
122 0x00, 0x01, // CLASS is IN.
123 0, 0, 0, 53, // TTL (4 bytes) is 53 seconds.
124 0, 4, // RDLENGTH is 4 bytes.
125 74, 125, 95, 121, // RDATA is the IP: 74.125.95.121
128 class RecordRemovalMock {
129 public:
130 MOCK_METHOD1(OnRecordRemoved, void(const RecordParsed*));
133 class MDnsCacheTest : public ::testing::Test {
134 public:
135 MDnsCacheTest()
136 : default_time_(base::Time::FromDoubleT(1234.0)) {}
137 virtual ~MDnsCacheTest() {}
139 protected:
140 base::Time default_time_;
141 StrictMock<RecordRemovalMock> record_removal_;
142 MDnsCache cache_;
145 // Test a single insert, corresponding lookup, and unsuccessful lookup.
146 TEST_F(MDnsCacheTest, InsertLookupSingle) {
147 DnsRecordParser parser(kT1ResponseDatagram, sizeof(kT1ResponseDatagram),
148 sizeof(dns_protocol::Header));
149 parser.SkipQuestion();
151 scoped_ptr<const RecordParsed> record1;
152 scoped_ptr<const RecordParsed> record2;
153 std::vector<const RecordParsed*> results;
155 record1 = RecordParsed::CreateFrom(&parser, default_time_);
156 record2 = RecordParsed::CreateFrom(&parser, default_time_);
158 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(record1.Pass()));
160 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(record2.Pass()));
162 cache_.FindDnsRecords(ARecordRdata::kType, "ghs.l.google.com", &results,
163 default_time_);
165 EXPECT_EQ(1u, results.size());
166 EXPECT_EQ(default_time_, results.front()->time_created());
168 EXPECT_EQ("ghs.l.google.com", results.front()->name());
170 results.clear();
171 cache_.FindDnsRecords(PtrRecordRdata::kType, "ghs.l.google.com", &results,
172 default_time_);
174 EXPECT_EQ(0u, results.size());
177 // Test that records expire when their ttl has passed.
178 TEST_F(MDnsCacheTest, Expiration) {
179 DnsRecordParser parser(kT1ResponseDatagram, sizeof(kT1ResponseDatagram),
180 sizeof(dns_protocol::Header));
181 parser.SkipQuestion();
182 scoped_ptr<const RecordParsed> record1;
183 scoped_ptr<const RecordParsed> record2;
185 std::vector<const RecordParsed*> results;
186 const RecordParsed* record_to_be_deleted;
188 record1 = RecordParsed::CreateFrom(&parser, default_time_);
189 base::TimeDelta ttl1 = base::TimeDelta::FromSeconds(record1->ttl());
191 record2 = RecordParsed::CreateFrom(&parser, default_time_);
192 base::TimeDelta ttl2 = base::TimeDelta::FromSeconds(record2->ttl());
193 record_to_be_deleted = record2.get();
195 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(record1.Pass()));
196 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(record2.Pass()));
198 cache_.FindDnsRecords(ARecordRdata::kType, "ghs.l.google.com", &results,
199 default_time_);
201 EXPECT_EQ(1u, results.size());
203 EXPECT_EQ(default_time_ + ttl2, cache_.next_expiration());
206 cache_.FindDnsRecords(ARecordRdata::kType, "ghs.l.google.com", &results,
207 default_time_ + ttl2);
209 EXPECT_EQ(0u, results.size());
211 EXPECT_CALL(record_removal_, OnRecordRemoved(record_to_be_deleted));
213 cache_.CleanupRecords(default_time_ + ttl2, base::Bind(
214 &RecordRemovalMock::OnRecordRemoved, base::Unretained(&record_removal_)));
216 // To make sure that we've indeed removed them from the map, check no funny
217 // business happens once they're deleted for good.
219 EXPECT_EQ(default_time_ + ttl1, cache_.next_expiration());
220 cache_.FindDnsRecords(ARecordRdata::kType, "ghs.l.google.com", &results,
221 default_time_ + ttl2);
223 EXPECT_EQ(0u, results.size());
226 // Test that a new record replacing one with the same identity (name/rrtype for
227 // unique records) causes the cache to output a "record changed" event.
228 TEST_F(MDnsCacheTest, RecordChange) {
229 DnsRecordParser parser(kTestResponsesDifferentAnswers,
230 sizeof(kTestResponsesDifferentAnswers),
233 scoped_ptr<const RecordParsed> record1;
234 scoped_ptr<const RecordParsed> record2;
235 std::vector<const RecordParsed*> results;
237 record1 = RecordParsed::CreateFrom(&parser, default_time_);
238 record2 = RecordParsed::CreateFrom(&parser, default_time_);
240 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(record1.Pass()));
241 EXPECT_EQ(MDnsCache::RecordChanged,
242 cache_.UpdateDnsRecord(record2.Pass()));
245 // Test that a new record replacing an otherwise identical one already in the
246 // cache causes the cache to output a "no change" event.
247 TEST_F(MDnsCacheTest, RecordNoChange) {
248 DnsRecordParser parser(kTestResponsesSameAnswers,
249 sizeof(kTestResponsesSameAnswers),
252 scoped_ptr<const RecordParsed> record1;
253 scoped_ptr<const RecordParsed> record2;
254 std::vector<const RecordParsed*> results;
256 record1 = RecordParsed::CreateFrom(&parser, default_time_);
257 record2 = RecordParsed::CreateFrom(&parser, default_time_ +
258 base::TimeDelta::FromSeconds(1));
260 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(record1.Pass()));
261 EXPECT_EQ(MDnsCache::NoChange, cache_.UpdateDnsRecord(record2.Pass()));
264 // Test that the next expiration time of the cache is updated properly on record
265 // insertion.
266 TEST_F(MDnsCacheTest, RecordPreemptExpirationTime) {
267 DnsRecordParser parser(kTestResponsesSameAnswers,
268 sizeof(kTestResponsesSameAnswers),
271 scoped_ptr<const RecordParsed> record1;
272 scoped_ptr<const RecordParsed> record2;
273 std::vector<const RecordParsed*> results;
275 record1 = RecordParsed::CreateFrom(&parser, default_time_);
276 record2 = RecordParsed::CreateFrom(&parser, default_time_);
277 base::TimeDelta ttl1 = base::TimeDelta::FromSeconds(record1->ttl());
278 base::TimeDelta ttl2 = base::TimeDelta::FromSeconds(record2->ttl());
280 EXPECT_EQ(base::Time(), cache_.next_expiration());
281 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(record2.Pass()));
282 EXPECT_EQ(default_time_ + ttl2, cache_.next_expiration());
283 EXPECT_EQ(MDnsCache::NoChange, cache_.UpdateDnsRecord(record1.Pass()));
284 EXPECT_EQ(default_time_ + ttl1, cache_.next_expiration());
287 // Test that the cache handles mDNS "goodbye" packets correctly, not adding the
288 // records to the cache if they are not already there, and eventually removing
289 // records from the cache if they are.
290 TEST_F(MDnsCacheTest, GoodbyePacket) {
291 DnsRecordParser parser(kTestResponsesGoodbyePacket,
292 sizeof(kTestResponsesGoodbyePacket),
295 scoped_ptr<const RecordParsed> record_goodbye;
296 scoped_ptr<const RecordParsed> record_hello;
297 scoped_ptr<const RecordParsed> record_goodbye2;
298 std::vector<const RecordParsed*> results;
300 record_goodbye = RecordParsed::CreateFrom(&parser, default_time_);
301 record_hello = RecordParsed::CreateFrom(&parser, default_time_);
302 parser = DnsRecordParser(kTestResponsesGoodbyePacket,
303 sizeof(kTestResponsesGoodbyePacket),
305 record_goodbye2 = RecordParsed::CreateFrom(&parser, default_time_);
307 base::TimeDelta ttl = base::TimeDelta::FromSeconds(record_hello->ttl());
309 EXPECT_EQ(base::Time(), cache_.next_expiration());
310 EXPECT_EQ(MDnsCache::NoChange, cache_.UpdateDnsRecord(record_goodbye.Pass()));
311 EXPECT_EQ(base::Time(), cache_.next_expiration());
312 EXPECT_EQ(MDnsCache::RecordAdded,
313 cache_.UpdateDnsRecord(record_hello.Pass()));
314 EXPECT_EQ(default_time_ + ttl, cache_.next_expiration());
315 EXPECT_EQ(MDnsCache::NoChange,
316 cache_.UpdateDnsRecord(record_goodbye2.Pass()));
317 EXPECT_EQ(default_time_ + base::TimeDelta::FromSeconds(1),
318 cache_.next_expiration());
321 TEST_F(MDnsCacheTest, AnyRRType) {
322 DnsRecordParser parser(kTestResponseTwoRecords,
323 sizeof(kTestResponseTwoRecords),
326 scoped_ptr<const RecordParsed> record1;
327 scoped_ptr<const RecordParsed> record2;
328 std::vector<const RecordParsed*> results;
330 record1 = RecordParsed::CreateFrom(&parser, default_time_);
331 record2 = RecordParsed::CreateFrom(&parser, default_time_);
332 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(record1.Pass()));
333 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(record2.Pass()));
335 cache_.FindDnsRecords(0, "ghs.l.google.com", &results, default_time_);
337 EXPECT_EQ(2u, results.size());
338 EXPECT_EQ(default_time_, results.front()->time_created());
340 EXPECT_EQ("ghs.l.google.com", results[0]->name());
341 EXPECT_EQ("ghs.l.google.com", results[1]->name());
342 EXPECT_EQ(dns_protocol::kTypeA,
343 std::min(results[0]->type(), results[1]->type()));
344 EXPECT_EQ(dns_protocol::kTypeAAAA,
345 std::max(results[0]->type(), results[1]->type()));
348 TEST_F(MDnsCacheTest, RemoveRecord) {
349 DnsRecordParser parser(kT1ResponseDatagram, sizeof(kT1ResponseDatagram),
350 sizeof(dns_protocol::Header));
351 parser.SkipQuestion();
353 scoped_ptr<const RecordParsed> record1;
354 std::vector<const RecordParsed*> results;
356 record1 = RecordParsed::CreateFrom(&parser, default_time_);
357 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(record1.Pass()));
359 cache_.FindDnsRecords(dns_protocol::kTypeCNAME, "codereview.chromium.org",
360 &results, default_time_);
362 EXPECT_EQ(1u, results.size());
364 scoped_ptr<const RecordParsed> record_out =
365 cache_.RemoveRecord(results.front());
367 EXPECT_EQ(record_out.get(), results.front());
369 cache_.FindDnsRecords(dns_protocol::kTypeCNAME, "codereview.chromium.org",
370 &results, default_time_);
372 EXPECT_EQ(0u, results.size());
375 } // namespace net