1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <netdb.h>
18
19 #include <array>
20 #include <atomic>
21 #include <chrono>
22 #include <ctime>
23 #include <thread>
24
25 #include <android-base/logging.h>
26 #include <android-base/stringprintf.h>
27 #include <android/multinetwork.h>
28 #include <arpa/inet.h>
29 #include <cutils/properties.h>
30 #include <gmock/gmock-matchers.h>
31 #include <gtest/gtest.h>
32
33 #include "resolv_cache.h"
34 #include "resolv_private.h"
35 #include "stats.h"
36 #include "tests/dns_responder/dns_responder.h"
37 #include "tests/resolv_test_utils.h"
38
39 using namespace std::chrono_literals;
40
41 using android::netdutils::IPSockAddr;
42
43 constexpr int TEST_NETID_2 = 31;
44 constexpr int DNS_PORT = 53;
45
46 // Constant values sync'd from res_cache.cpp
47 constexpr int DNS_HEADER_SIZE = 12;
48 constexpr int MAX_ENTRIES = 64 * 2 * 5;
49
50 namespace {
51
52 struct CacheEntry {
53 std::vector<char> query;
54 std::vector<char> answer;
55 };
56
57 struct SetupParams {
58 std::vector<std::string> servers;
59 std::vector<std::string> domains;
60 res_params params;
61 aidl::android::net::ResolverOptionsParcel resolverOptions;
62 std::vector<int32_t> transportTypes;
63 };
64
65 struct CacheStats {
66 SetupParams setup;
67 std::vector<res_stats> stats;
68 int pendingReqTimeoutCount;
69 };
70
makeQuery(int op,const char * qname,int qclass,int qtype)71 std::vector<char> makeQuery(int op, const char* qname, int qclass, int qtype) {
72 uint8_t buf[MAXPACKET] = {};
73 const int len = res_nmkquery(op, qname, qclass, qtype, /*data=*/nullptr, /*datalen=*/0, buf,
74 sizeof(buf),
75 /*netcontext_flags=*/0);
76 return std::vector<char>(buf, buf + len);
77 }
78
makeAnswer(const std::vector<char> & query,const char * rdata_str,const unsigned ttl)79 std::vector<char> makeAnswer(const std::vector<char>& query, const char* rdata_str,
80 const unsigned ttl) {
81 test::DNSHeader header;
82 header.read(query.data(), query.data() + query.size());
83
84 for (const test::DNSQuestion& question : header.questions) {
85 std::string rname(question.qname.name);
86 test::DNSRecord record{
87 .name = {.name = question.qname.name},
88 .rtype = question.qtype,
89 .rclass = question.qclass,
90 .ttl = ttl,
91 };
92 test::DNSResponder::fillRdata(rdata_str, record);
93 header.answers.push_back(std::move(record));
94 }
95
96 char answer[MAXPACKET] = {};
97 char* answer_end = header.write(answer, answer + sizeof(answer));
98 return std::vector<char>(answer, answer_end);
99 }
100
101 // Get the current time in unix timestamp since the Epoch.
currentTime()102 time_t currentTime() {
103 return std::time(nullptr);
104 }
105
106 // Comparison for res_sample.
operator ==(const res_sample & a,const res_sample & b)107 bool operator==(const res_sample& a, const res_sample& b) {
108 return std::tie(a.at, a.rtt, a.rcode) == std::tie(b.at, b.rtt, b.rcode);
109 }
110
111 // Comparison for res_stats.
operator ==(const res_stats & a,const res_stats & b)112 bool operator==(const res_stats& a, const res_stats& b) {
113 if (std::tie(a.sample_count, a.sample_next) != std::tie(b.sample_count, b.sample_next)) {
114 return false;
115 }
116 for (int i = 0; i < a.sample_count; i++) {
117 if (a.samples[i] != b.samples[i]) return false;
118 }
119 return true;
120 }
121
122 // Comparison for res_params.
operator ==(const res_params & a,const res_params & b)123 bool operator==(const res_params& a, const res_params& b) {
124 return std::tie(a.sample_validity, a.success_threshold, a.min_samples, a.max_samples,
125 a.base_timeout_msec, a.retry_count) ==
126 std::tie(b.sample_validity, b.success_threshold, b.min_samples, b.max_samples,
127 b.base_timeout_msec, b.retry_count);
128 }
129
130 } // namespace
131
132 class ResolvCacheTest : public ::testing::Test {
133 protected:
134 static constexpr res_params kParams = {
135 .sample_validity = 300,
136 .success_threshold = 25,
137 .min_samples = 8,
138 .max_samples = 8,
139 .base_timeout_msec = 1000,
140 .retry_count = 2,
141 };
142
ResolvCacheTest()143 ResolvCacheTest() {
144 // Store the default one and conceal 10000+ lines of resolver cache logs.
145 defaultLogSeverity = android::base::SetMinimumLogSeverity(
146 static_cast<android::base::LogSeverity>(android::base::WARNING));
147 }
~ResolvCacheTest()148 ~ResolvCacheTest() {
149 cacheDelete(TEST_NETID);
150 cacheDelete(TEST_NETID_2);
151
152 // Restore the log severity.
153 android::base::SetMinimumLogSeverity(defaultLogSeverity);
154 }
155
cacheLookup(ResolvCacheStatus expectedCacheStatus,uint32_t netId,const CacheEntry & ce,uint32_t flags=0)156 [[nodiscard]] bool cacheLookup(ResolvCacheStatus expectedCacheStatus, uint32_t netId,
157 const CacheEntry& ce, uint32_t flags = 0) {
158 int anslen = 0;
159 std::vector<char> answer(MAXPACKET);
160 const auto cacheStatus = resolv_cache_lookup(netId, ce.query.data(), ce.query.size(),
161 answer.data(), answer.size(), &anslen, flags);
162 if (cacheStatus != expectedCacheStatus) {
163 ADD_FAILURE() << "cacheStatus: expected = " << expectedCacheStatus
164 << ", actual =" << cacheStatus;
165 return false;
166 }
167
168 if (cacheStatus == RESOLV_CACHE_FOUND) {
169 answer.resize(anslen);
170 if (answer != ce.answer) {
171 ADD_FAILURE() << "The answer from the cache is not as expected.";
172 return false;
173 }
174 }
175 return true;
176 }
177
cacheCreate(uint32_t netId)178 int cacheCreate(uint32_t netId) {
179 return resolv_create_cache_for_net(netId);
180 }
181
cacheDelete(uint32_t netId)182 void cacheDelete(uint32_t netId) {
183 resolv_delete_cache_for_net(netId);
184 }
185
cacheAdd(uint32_t netId,const CacheEntry & ce)186 int cacheAdd(uint32_t netId, const CacheEntry& ce) {
187 return resolv_cache_add(netId, ce.query.data(), ce.query.size(), ce.answer.data(),
188 ce.answer.size());
189 }
190
cacheAdd(uint32_t netId,const std::vector<char> & query,const std::vector<char> & answer)191 int cacheAdd(uint32_t netId, const std::vector<char>& query, const std::vector<char>& answer) {
192 return resolv_cache_add(netId, query.data(), query.size(), answer.data(), answer.size());
193 }
194
cacheGetExpiration(uint32_t netId,const std::vector<char> & query,time_t * expiration)195 int cacheGetExpiration(uint32_t netId, const std::vector<char>& query, time_t* expiration) {
196 return resolv_cache_get_expiration(netId, query, expiration);
197 }
198
cacheQueryFailed(uint32_t netId,const CacheEntry & ce,uint32_t flags)199 void cacheQueryFailed(uint32_t netId, const CacheEntry& ce, uint32_t flags) {
200 _resolv_cache_query_failed(netId, ce.query.data(), ce.query.size(), flags);
201 }
202
cacheSetupResolver(uint32_t netId,const SetupParams & setup)203 int cacheSetupResolver(uint32_t netId, const SetupParams& setup) {
204 return resolv_set_nameservers(netId, setup.servers, setup.domains, setup.params,
205 setup.resolverOptions, setup.transportTypes);
206 }
207
cacheAddStats(uint32_t netId,int revision_id,const IPSockAddr & ipsa,const res_sample & sample,int max_samples)208 void cacheAddStats(uint32_t netId, int revision_id, const IPSockAddr& ipsa,
209 const res_sample& sample, int max_samples) {
210 resolv_cache_add_resolver_stats_sample(netId, revision_id, ipsa, sample, max_samples);
211 }
212
cacheFlush(uint32_t netId)213 int cacheFlush(uint32_t netId) { return resolv_flush_cache_for_net(netId); }
214
expectCacheStats(const std::string & msg,uint32_t netId,const CacheStats & expected)215 void expectCacheStats(const std::string& msg, uint32_t netId, const CacheStats& expected) {
216 int nscount = -1;
217 sockaddr_storage servers[MAXNS];
218 int dcount = -1;
219 char domains[MAXDNSRCH][MAXDNSRCHPATH];
220 res_stats stats[MAXNS];
221 res_params params = {};
222 int res_wait_for_pending_req_timeout_count;
223 android_net_res_stats_get_info_for_net(netId, &nscount, servers, &dcount, domains, ¶ms,
224 stats, &res_wait_for_pending_req_timeout_count);
225
226 // Server checking.
227 EXPECT_EQ(nscount, static_cast<int>(expected.setup.servers.size())) << msg;
228 for (int i = 0; i < nscount; i++) {
229 EXPECT_EQ(ToString(&servers[i]), expected.setup.servers[i]) << msg;
230 }
231
232 // Domain checking
233 EXPECT_EQ(dcount, static_cast<int>(expected.setup.domains.size())) << msg;
234 for (int i = 0; i < dcount; i++) {
235 EXPECT_EQ(std::string(domains[i]), expected.setup.domains[i]) << msg;
236 }
237
238 // res_params checking.
239 EXPECT_TRUE(params == expected.setup.params) << msg;
240
241 // res_stats checking.
242 if (expected.stats.size() == 0) {
243 for (int ns = 0; ns < nscount; ns++) {
244 EXPECT_EQ(0U, stats[ns].sample_count) << msg;
245 }
246 }
247 for (size_t i = 0; i < expected.stats.size(); i++) {
248 EXPECT_TRUE(stats[i] == expected.stats[i]) << msg;
249 }
250
251 // wait_for_pending_req_timeout_count checking.
252 EXPECT_EQ(res_wait_for_pending_req_timeout_count, expected.pendingReqTimeoutCount) << msg;
253 }
254
makeCacheEntry(int op,const char * qname,int qclass,int qtype,const char * rdata,std::chrono::seconds ttl=10s)255 CacheEntry makeCacheEntry(int op, const char* qname, int qclass, int qtype, const char* rdata,
256 std::chrono::seconds ttl = 10s) {
257 CacheEntry ce;
258 ce.query = makeQuery(op, qname, qclass, qtype);
259 ce.answer = makeAnswer(ce.query, rdata, static_cast<unsigned>(ttl.count()));
260 return ce;
261 }
262
263 private:
264 android::base::LogSeverity defaultLogSeverity;
265 };
266
TEST_F(ResolvCacheTest,CreateAndDeleteCache)267 TEST_F(ResolvCacheTest, CreateAndDeleteCache) {
268 // Create the cache for network 1.
269 EXPECT_EQ(0, cacheCreate(TEST_NETID));
270 EXPECT_EQ(-EEXIST, cacheCreate(TEST_NETID));
271 EXPECT_TRUE(has_named_cache(TEST_NETID));
272
273 // Create the cache for network 2.
274 EXPECT_EQ(0, cacheCreate(TEST_NETID_2));
275 EXPECT_EQ(-EEXIST, cacheCreate(TEST_NETID_2));
276 EXPECT_TRUE(has_named_cache(TEST_NETID_2));
277
278 // Delete the cache in network 1.
279 cacheDelete(TEST_NETID);
280 EXPECT_FALSE(has_named_cache(TEST_NETID));
281 EXPECT_TRUE(has_named_cache(TEST_NETID_2));
282 }
283
284 // Missing checks for the argument 'answer'.
TEST_F(ResolvCacheTest,CacheAdd_InvalidArgs)285 TEST_F(ResolvCacheTest, CacheAdd_InvalidArgs) {
286 EXPECT_EQ(0, cacheCreate(TEST_NETID));
287
288 const std::vector<char> queryEmpty(MAXPACKET, 0);
289 const std::vector<char> queryTooSmall(DNS_HEADER_SIZE - 1, 0);
290 CacheEntry ce = makeCacheEntry(QUERY, "valid.cache", ns_c_in, ns_t_a, "1.2.3.4");
291
292 EXPECT_EQ(-EINVAL, cacheAdd(TEST_NETID, queryEmpty, ce.answer));
293 EXPECT_EQ(-EINVAL, cacheAdd(TEST_NETID, queryTooSmall, ce.answer));
294
295 // Cache not existent in TEST_NETID_2.
296 EXPECT_EQ(-ENONET, cacheAdd(TEST_NETID_2, ce));
297 }
298
TEST_F(ResolvCacheTest,CacheAdd_DuplicateEntry)299 TEST_F(ResolvCacheTest, CacheAdd_DuplicateEntry) {
300 EXPECT_EQ(0, cacheCreate(TEST_NETID));
301 CacheEntry ce = makeCacheEntry(QUERY, "existent.in.cache", ns_c_in, ns_t_a, "1.2.3.4");
302 time_t now = currentTime();
303
304 // Add the cache entry.
305 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_NOTFOUND, TEST_NETID, ce));
306 EXPECT_EQ(0, cacheAdd(TEST_NETID, ce));
307 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_FOUND, TEST_NETID, ce));
308
309 // Get the expiration time and verify its value is greater than now.
310 time_t expiration1;
311 EXPECT_EQ(0, cacheGetExpiration(TEST_NETID, ce.query, &expiration1));
312 EXPECT_GT(expiration1, now);
313
314 // Adding the duplicate entry will return an error, and the expiration time won't be modified.
315 EXPECT_EQ(-EEXIST, cacheAdd(TEST_NETID, ce));
316 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_FOUND, TEST_NETID, ce));
317 time_t expiration2;
318 EXPECT_EQ(0, cacheGetExpiration(TEST_NETID, ce.query, &expiration2));
319 EXPECT_EQ(expiration1, expiration2);
320 }
321
TEST_F(ResolvCacheTest,CacheLookup)322 TEST_F(ResolvCacheTest, CacheLookup) {
323 EXPECT_EQ(0, cacheCreate(TEST_NETID));
324 EXPECT_EQ(0, cacheCreate(TEST_NETID_2));
325 CacheEntry ce = makeCacheEntry(QUERY, "existent.in.cache", ns_c_in, ns_t_a, "1.2.3.4");
326
327 // Cache found in network 1.
328 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_NOTFOUND, TEST_NETID, ce));
329 EXPECT_EQ(0, cacheAdd(TEST_NETID, ce));
330 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_FOUND, TEST_NETID, ce));
331
332 // No cache found in network 2.
333 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_NOTFOUND, TEST_NETID_2, ce));
334
335 ce = makeCacheEntry(QUERY, "existent.in.cache", ns_c_in, ns_t_aaaa, "2001:db8::1.2.3.4");
336
337 // type A and AAAA are independent.
338 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_NOTFOUND, TEST_NETID, ce));
339 EXPECT_EQ(0, cacheAdd(TEST_NETID, ce));
340 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_FOUND, TEST_NETID, ce));
341 }
342
TEST_F(ResolvCacheTest,CacheLookup_CacheFlags)343 TEST_F(ResolvCacheTest, CacheLookup_CacheFlags) {
344 EXPECT_EQ(0, cacheCreate(TEST_NETID));
345 std::vector<char> answerFromCache;
346 CacheEntry ce = makeCacheEntry(QUERY, "existent.in.cache", ns_c_in, ns_t_a, "1.2.3.4");
347
348 // The entry can't be found when only no-cache-lookup bit is carried.
349 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_NOTFOUND, TEST_NETID, ce, ANDROID_RESOLV_NO_CACHE_LOOKUP));
350
351 // Ensure RESOLV_CACHE_SKIP is returned when there's no such the same entry in the cache.
352 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_SKIP, TEST_NETID, ce, ANDROID_RESOLV_NO_CACHE_STORE));
353
354 // Skip the cache lookup if no-cache-lookup and no-cache-store bits are carried
355 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_SKIP, TEST_NETID, ce,
356 ANDROID_RESOLV_NO_CACHE_LOOKUP | ANDROID_RESOLV_NO_CACHE_STORE));
357
358 // Add the cache entry.
359 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_NOTFOUND, TEST_NETID, ce));
360 EXPECT_EQ(0, cacheAdd(TEST_NETID, ce));
361 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_FOUND, TEST_NETID, ce));
362
363 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_NOTFOUND, TEST_NETID, ce, ANDROID_RESOLV_NO_CACHE_LOOKUP));
364
365 // Now no-cache-store has no effect if a same entry is existent in the cache.
366 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_SKIP, TEST_NETID, ce, ANDROID_RESOLV_NO_CACHE_STORE));
367
368 // Skip the cache lookup again regardless of a same entry being already in the cache.
369 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_SKIP, TEST_NETID, ce,
370 ANDROID_RESOLV_NO_CACHE_LOOKUP | ANDROID_RESOLV_NO_CACHE_STORE));
371 }
372
TEST_F(ResolvCacheTest,CacheLookup_Types)373 TEST_F(ResolvCacheTest, CacheLookup_Types) {
374 EXPECT_EQ(0, cacheCreate(TEST_NETID));
375 static const struct QueryTypes {
376 int type;
377 std::string rdata;
378 } Types[] = {
379 {ns_t_a, "1.2.3.4"},
380 {ns_t_aaaa, "2001:db8::1.2.3.4"},
381 {ns_t_ptr, "4.3.2.1.in-addr.arpa."},
382 {ns_t_ptr, "4.0.3.0.2.0.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa."},
383 };
384
385 for (const auto& t : Types) {
386 std::string name = android::base::StringPrintf("cache.lookup.type.%s", t.rdata.c_str());
387 SCOPED_TRACE(name);
388
389 CacheEntry ce = makeCacheEntry(QUERY, name.data(), ns_c_in, t.type, t.rdata.data());
390 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_NOTFOUND, TEST_NETID, ce));
391 EXPECT_EQ(0, cacheAdd(TEST_NETID, ce));
392 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_FOUND, TEST_NETID, ce));
393 }
394 }
395
TEST_F(ResolvCacheTest,CacheLookup_InvalidArgs)396 TEST_F(ResolvCacheTest, CacheLookup_InvalidArgs) {
397 EXPECT_EQ(0, cacheCreate(TEST_NETID));
398
399 const std::vector<char> queryEmpty(MAXPACKET, 0);
400 const std::vector<char> queryTooSmall(DNS_HEADER_SIZE - 1, 0);
401 std::vector<char> answerTooSmall(DNS_HEADER_SIZE - 1, 0);
402 const CacheEntry ce = makeCacheEntry(QUERY, "valid.cache", ns_c_in, ns_t_a, "1.2.3.4");
403 auto cacheLookupFn = [](const std::vector<char>& query,
404 std::vector<char> answer) -> ResolvCacheStatus {
405 int anslen = 0;
406 return resolv_cache_lookup(TEST_NETID, query.data(), query.size(), answer.data(),
407 answer.size(), &anslen, 0);
408 };
409
410 EXPECT_EQ(0, cacheAdd(TEST_NETID, ce));
411
412 EXPECT_EQ(RESOLV_CACHE_UNSUPPORTED, cacheLookupFn(queryEmpty, ce.answer));
413 EXPECT_EQ(RESOLV_CACHE_UNSUPPORTED, cacheLookupFn(queryTooSmall, ce.answer));
414 EXPECT_EQ(RESOLV_CACHE_UNSUPPORTED, cacheLookupFn(ce.query, answerTooSmall));
415
416 // It can actually be found with valid arguments.
417 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_FOUND, TEST_NETID, ce));
418
419 // Cache not existent in TEST_NETID_2.
420 EXPECT_EQ(-ENONET, cacheAdd(TEST_NETID_2, ce));
421 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_UNSUPPORTED, TEST_NETID_2, ce));
422 }
423
TEST_F(ResolvCacheTest,CacheLookup_Expired)424 TEST_F(ResolvCacheTest, CacheLookup_Expired) {
425 EXPECT_EQ(0, cacheCreate(TEST_NETID));
426
427 // An entry with zero ttl won't be stored in the cache.
428 CacheEntry ce = makeCacheEntry(QUERY, "expired.in.0s", ns_c_in, ns_t_a, "1.2.3.4", 0s);
429 EXPECT_EQ(0, cacheAdd(TEST_NETID, ce));
430 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_NOTFOUND, TEST_NETID, ce));
431
432 // Create an entry expired in 1s.
433 ce = makeCacheEntry(QUERY, "expired.in.1s", ns_c_in, ns_t_a, "1.2.3.4", 1s);
434 EXPECT_EQ(0, cacheAdd(TEST_NETID, ce));
435
436 // Cache found.
437 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_FOUND, TEST_NETID, ce));
438 time_t expiration;
439 EXPECT_EQ(0, cacheGetExpiration(TEST_NETID, ce.query, &expiration));
440
441 // Wait for the cache expired.
442 std::this_thread::sleep_for(1500ms);
443 EXPECT_GE(currentTime(), expiration);
444 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_NOTFOUND, TEST_NETID, ce));
445 }
446
TEST_F(ResolvCacheTest,PendingRequest_QueryDeferred)447 TEST_F(ResolvCacheTest, PendingRequest_QueryDeferred) {
448 EXPECT_EQ(0, cacheCreate(TEST_NETID));
449 EXPECT_EQ(0, cacheCreate(TEST_NETID_2));
450
451 CacheEntry ce = makeCacheEntry(QUERY, "query.deferred", ns_c_in, ns_t_a, "1.2.3.4");
452 std::atomic_bool done(false);
453
454 // This is the first lookup. The following lookups from other threads will be in the
455 // pending request list.
456 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_NOTFOUND, TEST_NETID, ce));
457
458 std::vector<std::thread> threads(5);
459 for (std::thread& thread : threads) {
460 thread = std::thread([&]() {
461 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_FOUND, TEST_NETID, ce));
462
463 // Ensure this thread gets stuck in lookups before we wake it.
464 EXPECT_TRUE(done);
465 });
466 }
467
468 // Wait for a while for the threads performing lookups.
469 // TODO: Perhaps implement a test-only function to get the number of pending requests
470 // instead of sleep.
471 std::this_thread::sleep_for(100ms);
472
473 // The threads keep waiting regardless of any other networks or even if cache flag is set.
474 EXPECT_EQ(0, cacheAdd(TEST_NETID_2, ce));
475 cacheQueryFailed(TEST_NETID, ce, ANDROID_RESOLV_NO_CACHE_STORE);
476 cacheQueryFailed(TEST_NETID, ce, ANDROID_RESOLV_NO_CACHE_LOOKUP);
477 cacheQueryFailed(TEST_NETID_2, ce, ANDROID_RESOLV_NO_CACHE_STORE);
478 cacheQueryFailed(TEST_NETID_2, ce, ANDROID_RESOLV_NO_CACHE_LOOKUP);
479 cacheDelete(TEST_NETID_2);
480
481 // Ensure none of the threads has finished the lookups.
482 std::this_thread::sleep_for(100ms);
483
484 // Wake up the threads
485 done = true;
486 EXPECT_EQ(0, cacheAdd(TEST_NETID, ce));
487
488 for (std::thread& thread : threads) {
489 thread.join();
490 }
491 }
492
TEST_F(ResolvCacheTest,PendingRequest_QueryFailed)493 TEST_F(ResolvCacheTest, PendingRequest_QueryFailed) {
494 EXPECT_EQ(0, cacheCreate(TEST_NETID));
495
496 CacheEntry ce = makeCacheEntry(QUERY, "query.failed", ns_c_in, ns_t_a, "1.2.3.4");
497 std::atomic_bool done(false);
498
499 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_NOTFOUND, TEST_NETID, ce));
500
501 std::vector<std::thread> threads(5);
502 for (std::thread& thread : threads) {
503 thread = std::thread([&]() {
504 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_NOTFOUND, TEST_NETID, ce));
505
506 // Ensure this thread gets stuck in lookups before we wake it.
507 EXPECT_TRUE(done);
508 });
509 }
510
511 // Wait for a while for the threads performing lookups.
512 std::this_thread::sleep_for(100ms);
513
514 // Wake up the threads
515 done = true;
516 cacheQueryFailed(TEST_NETID, ce, 0);
517
518 for (std::thread& thread : threads) {
519 thread.join();
520 }
521 }
522
TEST_F(ResolvCacheTest,PendingRequest_CacheDestroyed)523 TEST_F(ResolvCacheTest, PendingRequest_CacheDestroyed) {
524 EXPECT_EQ(0, cacheCreate(TEST_NETID));
525 EXPECT_EQ(0, cacheCreate(TEST_NETID_2));
526
527 CacheEntry ce = makeCacheEntry(QUERY, "query.failed", ns_c_in, ns_t_a, "1.2.3.4");
528 std::atomic_bool done(false);
529
530 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_NOTFOUND, TEST_NETID, ce));
531
532 std::vector<std::thread> threads(5);
533 for (std::thread& thread : threads) {
534 thread = std::thread([&]() {
535 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_NOTFOUND, TEST_NETID, ce));
536
537 // Ensure this thread gets stuck in lookups before we wake it.
538 EXPECT_TRUE(done);
539 });
540 }
541
542 // Wait for a while for the threads performing lookups.
543 std::this_thread::sleep_for(100ms);
544
545 // Deleting another network must not cause the threads to wake up.
546 cacheDelete(TEST_NETID_2);
547
548 // Ensure none of the threads has finished the lookups.
549 std::this_thread::sleep_for(100ms);
550
551 // Wake up the threads
552 done = true;
553 cacheDelete(TEST_NETID);
554
555 for (std::thread& thread : threads) {
556 thread.join();
557 }
558 }
559
TEST_F(ResolvCacheTest,MaxEntries)560 TEST_F(ResolvCacheTest, MaxEntries) {
561 EXPECT_EQ(0, cacheCreate(TEST_NETID));
562 std::vector<CacheEntry> ces;
563
564 for (int i = 0; i < 2 * MAX_ENTRIES; i++) {
565 std::string qname = android::base::StringPrintf("cache.%04d", i);
566 SCOPED_TRACE(qname);
567 CacheEntry ce = makeCacheEntry(QUERY, qname.data(), ns_c_in, ns_t_a, "1.2.3.4");
568 EXPECT_EQ(0, cacheAdd(TEST_NETID, ce));
569 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_FOUND, TEST_NETID, ce));
570 ces.emplace_back(ce);
571 }
572
573 for (int i = 0; i < 2 * MAX_ENTRIES; i++) {
574 std::string qname = android::base::StringPrintf("cache.%04d", i);
575 SCOPED_TRACE(qname);
576 if (i < MAX_ENTRIES) {
577 // Because the cache is LRU, the oldest queries should have been purged,
578 // and the most recent MAX_ENTRIES ones should still be present.
579 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_NOTFOUND, TEST_NETID, ces[i]));
580 } else {
581 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_FOUND, TEST_NETID, ces[i]));
582 }
583 }
584 }
585
TEST_F(ResolvCacheTest,CacheFull)586 TEST_F(ResolvCacheTest, CacheFull) {
587 EXPECT_EQ(0, cacheCreate(TEST_NETID));
588
589 CacheEntry ce1 = makeCacheEntry(QUERY, "cache.0000", ns_c_in, ns_t_a, "1.2.3.4", 100s);
590 EXPECT_EQ(0, cacheAdd(TEST_NETID, ce1));
591 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_FOUND, TEST_NETID, ce1));
592
593 CacheEntry ce2 = makeCacheEntry(QUERY, "cache.0001", ns_c_in, ns_t_a, "1.2.3.4", 1s);
594 EXPECT_EQ(0, cacheAdd(TEST_NETID, ce2));
595 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_FOUND, TEST_NETID, ce2));
596
597 // Stuff the resolver cache.
598 for (int i = 2; i < MAX_ENTRIES; i++) {
599 std::string qname = android::base::StringPrintf("cache.%04d", i);
600 SCOPED_TRACE(qname);
601 CacheEntry ce = makeCacheEntry(QUERY, qname.data(), ns_c_in, ns_t_a, "1.2.3.4", 50s);
602 EXPECT_EQ(0, cacheAdd(TEST_NETID, ce));
603 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_FOUND, TEST_NETID, ce));
604 }
605
606 // Wait for ce2 expired.
607 std::this_thread::sleep_for(1500ms);
608
609 // The cache is full now, and the expired ce2 will be removed first.
610 CacheEntry ce3 = makeCacheEntry(QUERY, "cache.overfilled.1", ns_c_in, ns_t_a, "1.2.3.4", 50s);
611 EXPECT_EQ(0, cacheAdd(TEST_NETID, ce3));
612 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_FOUND, TEST_NETID, ce3));
613 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_NOTFOUND, TEST_NETID, ce2));
614
615 // The cache is full again but there's no one expired, so the oldest ce1 will be removed.
616 CacheEntry ce4 = makeCacheEntry(QUERY, "cache.overfilled.2", ns_c_in, ns_t_a, "1.2.3.4", 50s);
617 EXPECT_EQ(0, cacheAdd(TEST_NETID, ce4));
618 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_FOUND, TEST_NETID, ce4));
619 EXPECT_TRUE(cacheLookup(RESOLV_CACHE_NOTFOUND, TEST_NETID, ce1));
620 }
621
TEST_F(ResolvCacheTest,ResolverSetup)622 TEST_F(ResolvCacheTest, ResolverSetup) {
623 const SetupParams setup = {
624 .servers = {"127.0.0.1", "::127.0.0.2", "fe80::3"},
625 .domains = {"domain1.com", "domain2.com"},
626 .params = kParams,
627 };
628
629 // Failed to setup resolver because of the cache not created.
630 EXPECT_EQ(-ENONET, cacheSetupResolver(TEST_NETID, setup));
631 EXPECT_FALSE(resolv_has_nameservers(TEST_NETID));
632
633 // The cache is created now.
634 EXPECT_EQ(0, cacheCreate(TEST_NETID));
635 EXPECT_EQ(0, cacheSetupResolver(TEST_NETID, setup));
636 EXPECT_TRUE(resolv_has_nameservers(TEST_NETID));
637 }
638
TEST_F(ResolvCacheTest,ResolverSetup_InvalidNameServers)639 TEST_F(ResolvCacheTest, ResolverSetup_InvalidNameServers) {
640 EXPECT_EQ(0, cacheCreate(TEST_NETID));
641 const std::string invalidServers[]{
642 "127.A.b.1",
643 "127.^.0",
644 "::^:1",
645 "",
646 };
647 SetupParams setup = {
648 .servers = {},
649 .domains = {"domain1.com"},
650 .params = kParams,
651 };
652
653 // Failed to setup resolver because of invalid name servers.
654 for (const auto& server : invalidServers) {
655 SCOPED_TRACE(server);
656 setup.servers = {"127.0.0.1", server, "127.0.0.2"};
657 EXPECT_EQ(-EINVAL, cacheSetupResolver(TEST_NETID, setup));
658 EXPECT_FALSE(resolv_has_nameservers(TEST_NETID));
659 }
660 }
661
TEST_F(ResolvCacheTest,ResolverSetup_DropDomain)662 TEST_F(ResolvCacheTest, ResolverSetup_DropDomain) {
663 EXPECT_EQ(0, cacheCreate(TEST_NETID));
664
665 // Setup with one domain which is too long.
666 const std::vector<std::string> servers = {"127.0.0.1", "fe80::1"};
667 const std::string domainTooLong(MAXDNSRCHPATH, '1');
668 const std::string validDomain1(MAXDNSRCHPATH - 1, '2');
669 const std::string validDomain2(MAXDNSRCHPATH - 1, '3');
670 SetupParams setup = {
671 .servers = servers,
672 .domains = {},
673 .params = kParams,
674 };
675 CacheStats expect = {
676 .setup = setup,
677 .stats = {},
678 .pendingReqTimeoutCount = 0,
679 };
680
681 // Overlength domains are dropped.
682 setup.domains = {validDomain1, domainTooLong, validDomain2};
683 expect.setup.domains = {validDomain1, validDomain2};
684 EXPECT_EQ(0, cacheSetupResolver(TEST_NETID, setup));
685 EXPECT_TRUE(resolv_has_nameservers(TEST_NETID));
686 expectCacheStats("ResolverSetup_Domains drop overlength", TEST_NETID, expect);
687
688 // Duplicate domains are dropped.
689 setup.domains = {validDomain1, validDomain2, validDomain1, validDomain2};
690 expect.setup.domains = {validDomain1, validDomain2};
691 EXPECT_EQ(0, cacheSetupResolver(TEST_NETID, setup));
692 EXPECT_TRUE(resolv_has_nameservers(TEST_NETID));
693 expectCacheStats("ResolverSetup_Domains drop duplicates", TEST_NETID, expect);
694 }
695
TEST_F(ResolvCacheTest,ResolverSetup_Prune)696 TEST_F(ResolvCacheTest, ResolverSetup_Prune) {
697 EXPECT_EQ(0, cacheCreate(TEST_NETID));
698 const std::vector<std::string> servers = {"127.0.0.1", "::127.0.0.2", "fe80::1", "fe80::2",
699 "fe80::3"};
700 const std::vector<std::string> domains = {"d1.com", "d2.com", "d3.com", "d4.com",
701 "d5.com", "d6.com", "d7.com"};
702 const SetupParams setup = {
703 .servers = servers,
704 .domains = domains,
705 .params = kParams,
706 };
707
708 EXPECT_EQ(0, cacheSetupResolver(TEST_NETID, setup));
709 EXPECT_TRUE(resolv_has_nameservers(TEST_NETID));
710
711 const CacheStats cacheStats = {
712 .setup = {.servers = std::vector(servers.begin(), servers.begin() + MAXNS),
713 .domains = std::vector(domains.begin(), domains.begin() + MAXDNSRCH),
714 .params = setup.params},
715 .stats = {},
716 .pendingReqTimeoutCount = 0,
717 };
718 expectCacheStats("ResolverSetup_Prune", TEST_NETID, cacheStats);
719 }
720
TEST_F(ResolvCacheTest,GetStats)721 TEST_F(ResolvCacheTest, GetStats) {
722 EXPECT_EQ(0, cacheCreate(TEST_NETID));
723 const SetupParams setup = {
724 .servers = {"127.0.0.1", "::127.0.0.2", "fe80::3"},
725 .domains = {"domain1.com", "domain2.com"},
726 .params = kParams,
727 };
728
729 EXPECT_EQ(0, cacheSetupResolver(TEST_NETID, setup));
730 EXPECT_TRUE(resolv_has_nameservers(TEST_NETID));
731
732 const CacheStats cacheStats = {
733 .setup = setup,
734 .stats = {},
735 .pendingReqTimeoutCount = 0,
736 };
737 expectCacheStats("GetStats", TEST_NETID, cacheStats);
738 }
739
TEST_F(ResolvCacheTest,FlushCache)740 TEST_F(ResolvCacheTest, FlushCache) {
741 EXPECT_EQ(0, cacheCreate(TEST_NETID));
742 const SetupParams setup = {
743 .servers = {"127.0.0.1", "::127.0.0.2", "fe80::3"},
744 .domains = {"domain1.com", "domain2.com"},
745 .params = kParams,
746 };
747 EXPECT_EQ(0, cacheSetupResolver(TEST_NETID, setup));
748 EXPECT_TRUE(resolv_has_nameservers(TEST_NETID));
749
750 res_sample sample = {.at = time(NULL), .rtt = 100, .rcode = ns_r_noerror};
751 sockaddr_in sin = {.sin_family = AF_INET, .sin_port = htons(DNS_PORT)};
752 ASSERT_TRUE(inet_pton(AF_INET, setup.servers[0].c_str(), &sin.sin_addr));
753 cacheAddStats(TEST_NETID, 1 /*revision_id*/, IPSockAddr(sin), sample, setup.params.max_samples);
754
755 const CacheStats cacheStats = {
756 .setup = setup,
757 .stats = {{{sample}, 1 /*sample_count*/, 1 /*sample_next*/}},
758 .pendingReqTimeoutCount = 0,
759 };
760 expectCacheStats("FlushCache: a record in cache stats", TEST_NETID, cacheStats);
761
762 EXPECT_EQ(0, cacheFlush(TEST_NETID));
763 const CacheStats cacheStats_empty = {
764 .setup = setup,
765 .stats = {},
766 .pendingReqTimeoutCount = 0,
767 };
768 expectCacheStats("FlushCache: no record in cache stats", TEST_NETID, cacheStats_empty);
769 }
770
TEST_F(ResolvCacheTest,GetHostByAddrFromCache_InvalidArgs)771 TEST_F(ResolvCacheTest, GetHostByAddrFromCache_InvalidArgs) {
772 char domain_name[NS_MAXDNAME] = {};
773 const char query_v4[] = "1.2.3.5";
774
775 // invalid buffer size
776 EXPECT_FALSE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME + 1, nullptr,
777 AF_INET));
778 EXPECT_STREQ("", domain_name);
779
780 // invalid query
781 EXPECT_FALSE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, nullptr,
782 AF_INET));
783 EXPECT_STREQ("", domain_name);
784
785 // unsupported AF
786 EXPECT_FALSE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v4,
787 AF_UNSPEC));
788 EXPECT_STREQ("", domain_name);
789 }
790
TEST_F(ResolvCacheTest,GetHostByAddrFromCache)791 TEST_F(ResolvCacheTest, GetHostByAddrFromCache) {
792 char domain_name[NS_MAXDNAME] = {};
793 const char query_v4[] = "1.2.3.5";
794 const char query_v6[] = "2001:db8::102:304";
795 const char query_v6_unabbreviated[] = "2001:0db8:0000:0000:0000:0000:0102:0304";
796 const char query_v6_mixed[] = "2001:db8::1.2.3.4";
797 const char answer[] = "existent.in.cache";
798
799 // cache does not exist
800 EXPECT_FALSE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v4,
801 AF_INET));
802 EXPECT_STREQ("", domain_name);
803
804 // cache is empty
805 EXPECT_EQ(0, cacheCreate(TEST_NETID));
806 EXPECT_FALSE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v4,
807 AF_INET));
808 EXPECT_STREQ("", domain_name);
809
810 // no v4 match in cache
811 CacheEntry ce = makeCacheEntry(QUERY, "any.data", ns_c_in, ns_t_a, "1.2.3.4");
812 EXPECT_EQ(0, cacheAdd(TEST_NETID, ce));
813 EXPECT_FALSE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v4,
814 AF_INET));
815 EXPECT_STREQ("", domain_name);
816
817 // v4 match
818 ce = makeCacheEntry(QUERY, answer, ns_c_in, ns_t_a, query_v4);
819 EXPECT_EQ(0, cacheAdd(TEST_NETID, ce));
820 EXPECT_TRUE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v4,
821 AF_INET));
822 EXPECT_STREQ(answer, domain_name);
823
824 // no v6 match in cache
825 memset(domain_name, 0, NS_MAXDNAME);
826 EXPECT_FALSE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v6,
827 AF_INET6));
828 EXPECT_STREQ("", domain_name);
829
830 // v6 match
831 ce = makeCacheEntry(QUERY, answer, ns_c_in, ns_t_aaaa, query_v6);
832 EXPECT_EQ(0, cacheAdd(TEST_NETID, ce));
833 EXPECT_TRUE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME, query_v6,
834 AF_INET6));
835 EXPECT_STREQ(answer, domain_name);
836
837 // v6 match with unabbreviated address format
838 memset(domain_name, 0, NS_MAXDNAME);
839 EXPECT_TRUE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME,
840 query_v6_unabbreviated, AF_INET6));
841 EXPECT_STREQ(answer, domain_name);
842
843 // v6 with mixed address format
844 memset(domain_name, 0, NS_MAXDNAME);
845 EXPECT_TRUE(resolv_gethostbyaddr_from_cache(TEST_NETID, domain_name, NS_MAXDNAME,
846 query_v6_mixed, AF_INET6));
847 EXPECT_STREQ(answer, domain_name);
848 }
849
TEST_F(ResolvCacheTest,GetResolverStats)850 TEST_F(ResolvCacheTest, GetResolverStats) {
851 const res_sample sample1 = {.at = time(nullptr), .rtt = 100, .rcode = ns_r_noerror};
852 const res_sample sample2 = {.at = time(nullptr), .rtt = 200, .rcode = ns_r_noerror};
853 const res_sample sample3 = {.at = time(nullptr), .rtt = 300, .rcode = ns_r_noerror};
854 const res_stats expectedStats[MAXNS] = {
855 {{sample1}, 1 /*sample_count*/, 1 /*sample_next*/},
856 {{sample2}, 1, 1},
857 {{sample3}, 1, 1},
858 };
859 std::vector<IPSockAddr> nameserverSockAddrs = {
860 IPSockAddr::toIPSockAddr("127.0.0.1", DNS_PORT),
861 IPSockAddr::toIPSockAddr("::127.0.0.2", DNS_PORT),
862 IPSockAddr::toIPSockAddr("fe80::3", DNS_PORT),
863 };
864 const SetupParams setup = {
865 .servers = {"127.0.0.1", "::127.0.0.2", "fe80::3"},
866 .domains = {"domain1.com", "domain2.com"},
867 .params = kParams,
868 };
869 EXPECT_EQ(0, cacheCreate(TEST_NETID));
870 EXPECT_EQ(0, cacheSetupResolver(TEST_NETID, setup));
871 int revision_id = 1;
872 cacheAddStats(TEST_NETID, revision_id, nameserverSockAddrs[0], sample1,
873 setup.params.max_samples);
874 cacheAddStats(TEST_NETID, revision_id, nameserverSockAddrs[1], sample2,
875 setup.params.max_samples);
876 cacheAddStats(TEST_NETID, revision_id, nameserverSockAddrs[2], sample3,
877 setup.params.max_samples);
878
879 res_stats cacheStats[MAXNS]{};
880 res_params params;
881 EXPECT_EQ(resolv_cache_get_resolver_stats(TEST_NETID, ¶ms, cacheStats, nameserverSockAddrs),
882 revision_id);
883 EXPECT_TRUE(params == kParams);
884 for (size_t i = 0; i < MAXNS; i++) {
885 EXPECT_TRUE(cacheStats[i] == expectedStats[i]);
886 }
887
888 // pass another list of IPSockAddr
889 const res_stats expectedStats2[MAXNS] = {
890 {{sample3, sample2}, 2, 2},
891 {{sample2}, 1, 1},
892 {{sample1}, 1, 1},
893 };
894 nameserverSockAddrs = {
895 IPSockAddr::toIPSockAddr("fe80::3", DNS_PORT),
896 IPSockAddr::toIPSockAddr("::127.0.0.2", DNS_PORT),
897 IPSockAddr::toIPSockAddr("127.0.0.1", DNS_PORT),
898 };
899 cacheAddStats(TEST_NETID, revision_id, nameserverSockAddrs[0], sample2,
900 setup.params.max_samples);
901 EXPECT_EQ(resolv_cache_get_resolver_stats(TEST_NETID, ¶ms, cacheStats, nameserverSockAddrs),
902 revision_id);
903 EXPECT_TRUE(params == kParams);
904 for (size_t i = 0; i < MAXNS; i++) {
905 EXPECT_TRUE(cacheStats[i] == expectedStats2[i]);
906 }
907 }
908
909 namespace {
910
911 constexpr int EAI_OK = 0;
912 constexpr char DNS_EVENT_SUBSAMPLING_MAP_FLAG[] =
913 "persist.device_config.netd_native.dns_event_subsample_map";
914
915 class ScopedCacheCreate {
916 public:
ScopedCacheCreate(unsigned netid,const char * subsampling_map,const char * property=DNS_EVENT_SUBSAMPLING_MAP_FLAG)917 explicit ScopedCacheCreate(unsigned netid, const char* subsampling_map,
918 const char* property = DNS_EVENT_SUBSAMPLING_MAP_FLAG)
919 : mStoredNetId(netid), mStoredProperty(property) {
920 property_get(property, mStoredMap, "");
921 property_set(property, subsampling_map);
922 EXPECT_EQ(0, resolv_create_cache_for_net(netid));
923 }
~ScopedCacheCreate()924 ~ScopedCacheCreate() {
925 resolv_delete_cache_for_net(mStoredNetId);
926 property_set(mStoredProperty, mStoredMap);
927 }
928
929 private:
930 unsigned mStoredNetId;
931 const char* mStoredProperty;
932 char mStoredMap[PROPERTY_VALUE_MAX]{};
933 };
934
935 } // namespace
936
TEST_F(ResolvCacheTest,DnsEventSubsampling)937 TEST_F(ResolvCacheTest, DnsEventSubsampling) {
938 // Test defaults, default flag is "default:8 0:400 2:110 7:110" if no experiment flag is set
939 {
940 ScopedCacheCreate scopedCacheCreate(TEST_NETID, "");
941 EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_AGAIN), 110U);
942 EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_NODATA), 110U);
943 EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_OK), 400U);
944 EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_BADFLAGS),
945 8U); // default
946 EXPECT_THAT(resolv_cache_dump_subsampling_map(TEST_NETID),
947 testing::UnorderedElementsAreArray({"default:8", "0:400", "2:110", "7:110"}));
948 }
949 // Now change the experiment flag to "0:42 default:666"
950 {
951 ScopedCacheCreate scopedCacheCreate(TEST_NETID, "0:42 default:666");
952 EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_OK), 42U);
953 EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_NODATA),
954 666U); // default
955 EXPECT_THAT(resolv_cache_dump_subsampling_map(TEST_NETID),
956 testing::UnorderedElementsAreArray({"default:666", "0:42"}));
957 }
958 // Now change the experiment flag to something illegal
959 {
960 ScopedCacheCreate scopedCacheCreate(TEST_NETID, "asvaxx");
961 // 0(disable log) is the default value if experiment flag is invalid.
962 EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_OK), 0U);
963 EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_NODATA), 0U);
964 EXPECT_TRUE(resolv_cache_dump_subsampling_map(TEST_NETID).empty());
965 }
966 // Test negative and zero denom
967 {
968 ScopedCacheCreate scopedCacheCreate(TEST_NETID, "0:-42 default:-666 7:10 10:0");
969 // 0(disable log) is the default value if no valid denom is set
970 EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_OK), 0U);
971 EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_BADFLAGS), 0U);
972 EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_NODATA), 10U);
973 EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_SOCKTYPE), 0U);
974 EXPECT_THAT(resolv_cache_dump_subsampling_map(TEST_NETID),
975 testing::UnorderedElementsAreArray({"7:10", "10:0"}));
976 }
977 }
978
979 // TODO: Tests for NetConfig, including:
980 // - res_stats
981 // -- _resolv_cache_add_resolver_stats_sample()
982 // -- android_net_res_stats_get_info_for_net()
983 // TODO: inject a mock timer into the cache to make TTL tests pass instantly
984 // TODO: test TTL of RFC 2308 negative caching
985