1 // Copyright 2021 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "services/proxy_resolver/proxy_host_resolver_cache.h"
7 #include "base/test/task_environment.h"
8 #include "net/base/ip_address.h"
9 #include "net/base/network_anonymization_key.h"
10 #include "testing/gmock/include/gmock/gmock.h"
11 #include "testing/gtest/include/gtest/gtest.h"
13 namespace proxy_resolver {
16 class ProxyHostResolverCacheTest : public testing::Test {
18 base::test::TaskEnvironment task_environment_{
19 base::test::TaskEnvironment::TimeSource::MOCK_TIME};
20 ProxyHostResolverCache cache_;
23 TEST_F(ProxyHostResolverCacheTest, SimpleNegativeLookup) {
24 ASSERT_EQ(cache_.GetSizeForTesting(), 0u);
25 EXPECT_FALSE(cache_.LookupEntry("host.test", net::NetworkAnonymizationKey(),
26 /*is_ex_operation=*/false));
29 TEST_F(ProxyHostResolverCacheTest, SimpleCachedLookup) {
30 const net::IPAddress kResult(1, 2, 3, 4);
32 cache_.StoreEntry("host.test", net::NetworkAnonymizationKey(),
33 /*is_ex_operation=*/false, {kResult});
35 EXPECT_EQ(cache_.GetSizeForTesting(), 1u);
36 EXPECT_THAT(cache_.LookupEntry("host.test", net::NetworkAnonymizationKey(),
37 /*is_ex_operation=*/false),
38 testing::Pointee(testing::ElementsAre(kResult)));
41 TEST_F(ProxyHostResolverCacheTest, NoResultWithNonMatchingKeyFields) {
42 cache_.StoreEntry("host.test", net::NetworkAnonymizationKey(),
43 /*is_ex_operation=*/false, {net::IPAddress(1, 2, 3, 5)});
44 ASSERT_EQ(cache_.GetSizeForTesting(), 1u);
46 // Non-matching hostname
47 EXPECT_FALSE(cache_.LookupEntry("host1.test", net::NetworkAnonymizationKey(),
48 /*is_ex_operation=*/false));
50 // Non-matching anonymization key
51 EXPECT_FALSE(cache_.LookupEntry(
52 "host.test", net::NetworkAnonymizationKey::CreateTransient(),
53 /*is_ex_operation=*/false));
55 // Non-matching `is_ex_operation`
56 EXPECT_FALSE(cache_.LookupEntry("host.test", net::NetworkAnonymizationKey(),
57 /*is_ex_operation=*/true));
60 TEST_F(ProxyHostResolverCacheTest, NoResultForExpiredLookup) {
61 const net::IPAddress kResult(1, 2, 3, 6);
63 cache_.StoreEntry("host.test", net::NetworkAnonymizationKey(),
64 /*is_ex_operation=*/false, {kResult});
66 task_environment_.FastForwardBy(ProxyHostResolverCache::kTtl -
67 base::Milliseconds(5));
68 EXPECT_EQ(cache_.GetSizeForTesting(), 1u);
69 ASSERT_THAT(cache_.LookupEntry("host.test", net::NetworkAnonymizationKey(),
70 /*is_ex_operation=*/false),
71 testing::Pointee(testing::ElementsAre(kResult)));
73 task_environment_.FastForwardBy(base::Milliseconds(10));
74 EXPECT_FALSE(cache_.LookupEntry("host.test", net::NetworkAnonymizationKey(),
75 /*is_ex_operation=*/false));
77 // Expect expired entry to be deleted by lookup attempt.
78 EXPECT_EQ(cache_.GetSizeForTesting(), 0u);
81 TEST_F(ProxyHostResolverCacheTest, EvictsOldestEntriesWhenFull) {
82 ProxyHostResolverCache cache(/*max_entries=*/3u);
84 // Initial entry to be deleted.
85 cache.StoreEntry("to-be-deleted.test", net::NetworkAnonymizationKey(),
86 /*is_ex_operation=*/false, /*results=*/{});
88 // Fill to max capacity
89 task_environment_.FastForwardBy(base::Milliseconds(5));
90 cache.StoreEntry("other1.test", net::NetworkAnonymizationKey(),
91 /*is_ex_operation=*/false, /*results=*/{});
92 cache.StoreEntry("other2.test", net::NetworkAnonymizationKey(),
93 /*is_ex_operation=*/false, /*results=*/{});
95 // Nothing should be evicted yet.
96 EXPECT_EQ(cache.GetSizeForTesting(), 3u);
97 EXPECT_TRUE(cache.LookupEntry("to-be-deleted.test",
98 net::NetworkAnonymizationKey(),
99 /*is_ex_operation=*/false));
100 EXPECT_TRUE(cache.LookupEntry("other1.test", net::NetworkAnonymizationKey(),
101 /*is_ex_operation=*/false));
102 EXPECT_TRUE(cache.LookupEntry("other2.test", net::NetworkAnonymizationKey(),
103 /*is_ex_operation=*/false));
105 // Add another entry and expect eviction of oldest.
106 cache.StoreEntry("evictor.test", net::NetworkAnonymizationKey(),
107 /*is_ex_operation=*/false, /*results=*/{});
109 EXPECT_EQ(cache.GetSizeForTesting(), 3u);
110 EXPECT_FALSE(cache.LookupEntry("to-be-deleted.test",
111 net::NetworkAnonymizationKey(),
112 /*is_ex_operation=*/false));
113 EXPECT_TRUE(cache.LookupEntry("other1.test", net::NetworkAnonymizationKey(),
114 /*is_ex_operation=*/false));
115 EXPECT_TRUE(cache.LookupEntry("other2.test", net::NetworkAnonymizationKey(),
116 /*is_ex_operation=*/false));
117 EXPECT_TRUE(cache.LookupEntry("evictor.test", net::NetworkAnonymizationKey(),
118 /*is_ex_operation=*/false));
121 TEST_F(ProxyHostResolverCacheTest, UpdatesAlreadyExistingEntryWithSameKey) {
122 cache_.StoreEntry("host.test", net::NetworkAnonymizationKey(),
123 /*is_ex_operation=*/false, /*results=*/{});
124 ASSERT_EQ(cache_.GetSizeForTesting(), 1u);
126 const net::IPAddress kResult(1, 2, 3, 7);
127 cache_.StoreEntry("host.test", net::NetworkAnonymizationKey(),
128 /*is_ex_operation=*/false, {kResult});
130 EXPECT_EQ(cache_.GetSizeForTesting(), 1u);
131 EXPECT_THAT(cache_.LookupEntry("host.test", net::NetworkAnonymizationKey(),
132 /*is_ex_operation=*/false),
133 testing::Pointee(testing::ElementsAre(kResult)));
136 TEST_F(ProxyHostResolverCacheTest, EntryUpdateRefreshesExpiration) {
137 ProxyHostResolverCache cache(/*max_entries=*/2u);
139 // Insert two entries, with "to-be-refreshed.test" as the older one.
140 cache.StoreEntry("to-be-refreshed.test", net::NetworkAnonymizationKey(),
141 /*is_ex_operation=*/false, /*results=*/{});
142 task_environment_.FastForwardBy(base::Milliseconds(5));
143 cache.StoreEntry("to-be-evicted.test", net::NetworkAnonymizationKey(),
144 /*is_ex_operation=*/false, /*results=*/{});
145 ASSERT_EQ(cache.GetSizeForTesting(), 2u);
147 // Update "to-be-refreshed.test" to refresh its expiration.
148 task_environment_.FastForwardBy(base::Milliseconds(5));
149 cache.StoreEntry("to-be-refreshed.test", net::NetworkAnonymizationKey(),
150 /*is_ex_operation=*/false, /*results=*/{});
151 ASSERT_EQ(cache.GetSizeForTesting(), 2u);
153 // Add another entry to force an eviction.
154 cache.StoreEntry("evictor.test", net::NetworkAnonymizationKey(),
155 /*is_ex_operation=*/false, /*results=*/{});
157 EXPECT_EQ(cache.GetSizeForTesting(), 2u);
158 EXPECT_FALSE(cache.LookupEntry("to-be-evicted.test",
159 net::NetworkAnonymizationKey(),
160 /*is_ex_operation=*/false));
161 EXPECT_TRUE(cache.LookupEntry("to-be-refreshed.test",
162 net::NetworkAnonymizationKey(),
163 /*is_ex_operation=*/false));
164 EXPECT_TRUE(cache.LookupEntry("evictor.test", net::NetworkAnonymizationKey(),
165 /*is_ex_operation=*/false));
168 TEST_F(ProxyHostResolverCacheTest, EntryCanBeEvictedAfterUpdate) {
169 ProxyHostResolverCache cache(/*max_entries=*/1u);
171 // Add entry and then update it.
172 cache.StoreEntry("host.test", net::NetworkAnonymizationKey(),
173 /*is_ex_operation=*/false, /*results=*/{});
174 ASSERT_EQ(cache.GetSizeForTesting(), 1u);
175 task_environment_.FastForwardBy(base::Milliseconds(5));
176 cache.StoreEntry("host.test", net::NetworkAnonymizationKey(),
177 /*is_ex_operation=*/false, /*results=*/{});
178 ASSERT_EQ(cache.GetSizeForTesting(), 1u);
180 // Add another entry to force an eviction.
181 task_environment_.FastForwardBy(base::Milliseconds(5));
182 cache.StoreEntry("evictor.test", net::NetworkAnonymizationKey(),
183 /*is_ex_operation=*/false, /*results=*/{});
185 EXPECT_EQ(cache.GetSizeForTesting(), 1u);
186 EXPECT_FALSE(cache.LookupEntry("host.test", net::NetworkAnonymizationKey(),
187 /*is_ex_operation=*/false));
188 EXPECT_TRUE(cache.LookupEntry("evictor.test", net::NetworkAnonymizationKey(),
189 /*is_ex_operation=*/false));
193 } // namespace proxy_resolver