- add sources.
[platform/framework/web/crosswalk.git] / src / net / http / http_auth_cache_unittest.cc
1 // Copyright (c) 2011 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 <string>
6
7 #include "base/strings/string16.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "net/base/net_errors.h"
12 #include "net/http/http_auth_cache.h"
13 #include "net/http/http_auth_handler.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace net {
17
18 namespace {
19
20 class MockAuthHandler : public HttpAuthHandler {
21  public:
22   MockAuthHandler(HttpAuth::Scheme scheme,
23                   const std::string& realm,
24                   HttpAuth::Target target) {
25     // Can't use initializer list since these are members of the base class.
26     auth_scheme_ = scheme;
27     realm_ = realm;
28     score_ = 1;
29     target_ = target;
30     properties_ = 0;
31   }
32
33   virtual HttpAuth::AuthorizationResult HandleAnotherChallenge(
34       HttpAuth::ChallengeTokenizer* challenge) OVERRIDE {
35     return HttpAuth::AUTHORIZATION_RESULT_REJECT;
36   }
37
38  protected:
39   virtual bool Init(HttpAuth::ChallengeTokenizer* challenge) OVERRIDE {
40     return false;  // Unused.
41   }
42
43   virtual int GenerateAuthTokenImpl(const AuthCredentials*,
44                                     const HttpRequestInfo*,
45                                     const CompletionCallback& callback,
46                                     std::string* auth_token) OVERRIDE {
47     *auth_token = "mock-credentials";
48     return OK;
49   }
50
51
52  private:
53   virtual ~MockAuthHandler() {}
54 };
55
56 const char* kRealm1 = "Realm1";
57 const char* kRealm2 = "Realm2";
58 const char* kRealm3 = "Realm3";
59 const char* kRealm4 = "Realm4";
60 const char* kRealm5 = "Realm5";
61 const base::string16 k123(ASCIIToUTF16("123"));
62 const base::string16 k1234(ASCIIToUTF16("1234"));
63 const base::string16 kAdmin(ASCIIToUTF16("admin"));
64 const base::string16 kAlice(ASCIIToUTF16("alice"));
65 const base::string16 kAlice2(ASCIIToUTF16("alice2"));
66 const base::string16 kPassword(ASCIIToUTF16("password"));
67 const base::string16 kRoot(ASCIIToUTF16("root"));
68 const base::string16 kUsername(ASCIIToUTF16("username"));
69 const base::string16 kWileCoyote(ASCIIToUTF16("wilecoyote"));
70
71 AuthCredentials CreateASCIICredentials(const char* username,
72                                        const char* password) {
73   return AuthCredentials(ASCIIToUTF16(username), ASCIIToUTF16(password));
74 }
75
76 }  // namespace
77
78 // Test adding and looking-up cache entries (both by realm and by path).
79 TEST(HttpAuthCacheTest, Basic) {
80   GURL origin("http://www.google.com");
81   HttpAuthCache cache;
82   HttpAuthCache::Entry* entry;
83
84   // Add cache entries for 4 realms: "Realm1", "Realm2", "Realm3" and
85   // "Realm4"
86
87   scoped_ptr<HttpAuthHandler> realm1_handler(
88       new MockAuthHandler(HttpAuth::AUTH_SCHEME_BASIC,
89                           kRealm1,
90                           HttpAuth::AUTH_SERVER));
91   cache.Add(origin, realm1_handler->realm(), realm1_handler->auth_scheme(),
92             "Basic realm=Realm1",
93             CreateASCIICredentials("realm1-user", "realm1-password"),
94             "/foo/bar/index.html");
95
96   scoped_ptr<HttpAuthHandler> realm2_handler(
97       new MockAuthHandler(HttpAuth::AUTH_SCHEME_BASIC,
98                           kRealm2,
99                           HttpAuth::AUTH_SERVER));
100   cache.Add(origin, realm2_handler->realm(), realm2_handler->auth_scheme(),
101             "Basic realm=Realm2",
102             CreateASCIICredentials("realm2-user", "realm2-password"),
103             "/foo2/index.html");
104
105   scoped_ptr<HttpAuthHandler> realm3_basic_handler(
106       new MockAuthHandler(HttpAuth::AUTH_SCHEME_BASIC,
107                           kRealm3,
108                           HttpAuth::AUTH_PROXY));
109   cache.Add(
110       origin,
111       realm3_basic_handler->realm(),
112       realm3_basic_handler->auth_scheme(),
113       "Basic realm=Realm3",
114       CreateASCIICredentials("realm3-basic-user", "realm3-basic-password"),
115       std::string());
116
117   scoped_ptr<HttpAuthHandler> realm3_digest_handler(
118       new MockAuthHandler(HttpAuth::AUTH_SCHEME_DIGEST,
119                           kRealm3,
120                           HttpAuth::AUTH_PROXY));
121   cache.Add(origin, realm3_digest_handler->realm(),
122             realm3_digest_handler->auth_scheme(), "Digest realm=Realm3",
123             CreateASCIICredentials("realm3-digest-user",
124                                    "realm3-digest-password"),
125             "/baz/index.html");
126
127   scoped_ptr<HttpAuthHandler> realm4_basic_handler(
128       new MockAuthHandler(HttpAuth::AUTH_SCHEME_BASIC,
129                           kRealm4,
130                           HttpAuth::AUTH_SERVER));
131   cache.Add(origin, realm4_basic_handler->realm(),
132             realm4_basic_handler->auth_scheme(), "Basic realm=Realm4",
133             CreateASCIICredentials("realm4-basic-user",
134                                    "realm4-basic-password"),
135             "/");
136
137   // There is no Realm5
138   entry = cache.Lookup(origin, kRealm5, HttpAuth::AUTH_SCHEME_BASIC);
139   EXPECT_TRUE(NULL == entry);
140
141   // While Realm3 does exist, the origin scheme is wrong.
142   entry = cache.Lookup(GURL("https://www.google.com"), kRealm3,
143                        HttpAuth::AUTH_SCHEME_BASIC);
144   EXPECT_TRUE(NULL == entry);
145
146   // Realm, origin scheme ok, authentication scheme wrong
147   entry = cache.Lookup
148       (GURL("http://www.google.com"), kRealm1, HttpAuth::AUTH_SCHEME_DIGEST);
149   EXPECT_TRUE(NULL == entry);
150
151   // Valid lookup by origin, realm, scheme.
152   entry = cache.Lookup(
153       GURL("http://www.google.com:80"), kRealm3, HttpAuth::AUTH_SCHEME_BASIC);
154   ASSERT_FALSE(NULL == entry);
155   EXPECT_EQ(HttpAuth::AUTH_SCHEME_BASIC, entry->scheme());
156   EXPECT_EQ(kRealm3, entry->realm());
157   EXPECT_EQ("Basic realm=Realm3", entry->auth_challenge());
158   EXPECT_EQ(ASCIIToUTF16("realm3-basic-user"), entry->credentials().username());
159   EXPECT_EQ(ASCIIToUTF16("realm3-basic-password"),
160             entry->credentials().password());
161
162   // Valid lookup by origin, realm, scheme when there's a duplicate
163   // origin, realm in the cache
164   entry = cache.Lookup(
165       GURL("http://www.google.com:80"), kRealm3, HttpAuth::AUTH_SCHEME_DIGEST);
166   ASSERT_FALSE(NULL == entry);
167   EXPECT_EQ(HttpAuth::AUTH_SCHEME_DIGEST, entry->scheme());
168   EXPECT_EQ(kRealm3, entry->realm());
169   EXPECT_EQ("Digest realm=Realm3", entry->auth_challenge());
170   EXPECT_EQ(ASCIIToUTF16("realm3-digest-user"),
171             entry->credentials().username());
172   EXPECT_EQ(ASCIIToUTF16("realm3-digest-password"),
173             entry->credentials().password());
174
175   // Valid lookup by realm.
176   entry = cache.Lookup(origin, kRealm2, HttpAuth::AUTH_SCHEME_BASIC);
177   ASSERT_FALSE(NULL == entry);
178   EXPECT_EQ(HttpAuth::AUTH_SCHEME_BASIC, entry->scheme());
179   EXPECT_EQ(kRealm2, entry->realm());
180   EXPECT_EQ("Basic realm=Realm2", entry->auth_challenge());
181   EXPECT_EQ(ASCIIToUTF16("realm2-user"), entry->credentials().username());
182   EXPECT_EQ(ASCIIToUTF16("realm2-password"), entry->credentials().password());
183
184   // Check that subpaths are recognized.
185   HttpAuthCache::Entry* realm2_entry = cache.Lookup(
186       origin, kRealm2, HttpAuth::AUTH_SCHEME_BASIC);
187   HttpAuthCache::Entry* realm4_entry = cache.Lookup(
188       origin, kRealm4, HttpAuth::AUTH_SCHEME_BASIC);
189   EXPECT_FALSE(NULL == realm2_entry);
190   EXPECT_FALSE(NULL == realm4_entry);
191   // Realm4 applies to '/' and Realm2 applies to '/foo2/'.
192   // LookupByPath() should return the closest enclosing path.
193   // Positive tests:
194   entry = cache.LookupByPath(origin, "/foo2/index.html");
195   EXPECT_TRUE(realm2_entry == entry);
196   entry = cache.LookupByPath(origin, "/foo2/foobar.html");
197   EXPECT_TRUE(realm2_entry == entry);
198   entry = cache.LookupByPath(origin, "/foo2/bar/index.html");
199   EXPECT_TRUE(realm2_entry == entry);
200   entry = cache.LookupByPath(origin, "/foo2/");
201   EXPECT_TRUE(realm2_entry == entry);
202   entry = cache.LookupByPath(origin, "/foo2");
203   EXPECT_TRUE(realm4_entry == entry);
204   entry = cache.LookupByPath(origin, "/");
205   EXPECT_TRUE(realm4_entry == entry);
206
207   // Negative tests:
208   entry = cache.LookupByPath(origin, "/foo3/index.html");
209   EXPECT_FALSE(realm2_entry == entry);
210   entry = cache.LookupByPath(origin, std::string());
211   EXPECT_FALSE(realm2_entry == entry);
212
213   // Confirm we find the same realm, different auth scheme by path lookup
214   HttpAuthCache::Entry* realm3_digest_entry =
215       cache.Lookup(origin, kRealm3, HttpAuth::AUTH_SCHEME_DIGEST);
216   EXPECT_FALSE(NULL == realm3_digest_entry);
217   entry = cache.LookupByPath(origin, "/baz/index.html");
218   EXPECT_TRUE(realm3_digest_entry == entry);
219   entry = cache.LookupByPath(origin, "/baz/");
220   EXPECT_TRUE(realm3_digest_entry == entry);
221   entry = cache.LookupByPath(origin, "/baz");
222   EXPECT_FALSE(realm3_digest_entry == entry);
223
224   // Confirm we find the same realm, different auth scheme by path lookup
225   HttpAuthCache::Entry* realm3DigestEntry =
226       cache.Lookup(origin, kRealm3, HttpAuth::AUTH_SCHEME_DIGEST);
227   EXPECT_FALSE(NULL == realm3DigestEntry);
228   entry = cache.LookupByPath(origin, "/baz/index.html");
229   EXPECT_TRUE(realm3DigestEntry == entry);
230   entry = cache.LookupByPath(origin, "/baz/");
231   EXPECT_TRUE(realm3DigestEntry == entry);
232   entry = cache.LookupByPath(origin, "/baz");
233   EXPECT_FALSE(realm3DigestEntry == entry);
234
235   // Lookup using empty path (may be used for proxy).
236   entry = cache.LookupByPath(origin, std::string());
237   EXPECT_FALSE(NULL == entry);
238   EXPECT_EQ(HttpAuth::AUTH_SCHEME_BASIC, entry->scheme());
239   EXPECT_EQ(kRealm3, entry->realm());
240 }
241
242 TEST(HttpAuthCacheTest, AddPath) {
243   HttpAuthCache::Entry entry;
244
245   // All of these paths have a common root /1/2/2/4/5/
246   entry.AddPath("/1/2/3/4/5/x.txt");
247   entry.AddPath("/1/2/3/4/5/y.txt");
248   entry.AddPath("/1/2/3/4/5/z.txt");
249
250   EXPECT_EQ(1U, entry.paths_.size());
251   EXPECT_EQ("/1/2/3/4/5/", entry.paths_.front());
252
253   // Add a new entry (not a subpath).
254   entry.AddPath("/1/XXX/q");
255   EXPECT_EQ(2U, entry.paths_.size());
256   EXPECT_EQ("/1/XXX/", entry.paths_.front());
257   EXPECT_EQ("/1/2/3/4/5/", entry.paths_.back());
258
259   // Add containing paths of /1/2/3/4/5/ -- should swallow up the deeper paths.
260   entry.AddPath("/1/2/3/4/x.txt");
261   EXPECT_EQ(2U, entry.paths_.size());
262   EXPECT_EQ("/1/2/3/4/", entry.paths_.front());
263   EXPECT_EQ("/1/XXX/", entry.paths_.back());
264   entry.AddPath("/1/2/3/x");
265   EXPECT_EQ(2U, entry.paths_.size());
266   EXPECT_EQ("/1/2/3/", entry.paths_.front());
267   EXPECT_EQ("/1/XXX/", entry.paths_.back());
268
269   entry.AddPath("/index.html");
270   EXPECT_EQ(1U, entry.paths_.size());
271   EXPECT_EQ("/", entry.paths_.front());
272 }
273
274 // Calling Add when the realm entry already exists, should append that
275 // path.
276 TEST(HttpAuthCacheTest, AddToExistingEntry) {
277   HttpAuthCache cache;
278   GURL origin("http://www.foobar.com:70");
279   const std::string auth_challenge = "Basic realm=MyRealm";
280
281   scoped_ptr<HttpAuthHandler> handler(
282       new MockAuthHandler(
283           HttpAuth::AUTH_SCHEME_BASIC, "MyRealm", HttpAuth::AUTH_SERVER));
284   HttpAuthCache::Entry* orig_entry = cache.Add(
285       origin, handler->realm(), handler->auth_scheme(), auth_challenge,
286       CreateASCIICredentials("user1", "password1"), "/x/y/z/");
287   cache.Add(origin, handler->realm(), handler->auth_scheme(), auth_challenge,
288             CreateASCIICredentials("user2", "password2"), "/z/y/x/");
289   cache.Add(origin, handler->realm(), handler->auth_scheme(), auth_challenge,
290             CreateASCIICredentials("user3", "password3"), "/z/y");
291
292   HttpAuthCache::Entry* entry = cache.Lookup(
293       origin, "MyRealm", HttpAuth::AUTH_SCHEME_BASIC);
294
295   EXPECT_TRUE(entry == orig_entry);
296   EXPECT_EQ(ASCIIToUTF16("user3"), entry->credentials().username());
297   EXPECT_EQ(ASCIIToUTF16("password3"), entry->credentials().password());
298
299   EXPECT_EQ(2U, entry->paths_.size());
300   EXPECT_EQ("/z/", entry->paths_.front());
301   EXPECT_EQ("/x/y/z/", entry->paths_.back());
302 }
303
304 TEST(HttpAuthCacheTest, Remove) {
305   GURL origin("http://foobar2.com");
306
307   scoped_ptr<HttpAuthHandler> realm1_handler(
308       new MockAuthHandler(
309           HttpAuth::AUTH_SCHEME_BASIC, kRealm1, HttpAuth::AUTH_SERVER));
310
311   scoped_ptr<HttpAuthHandler> realm2_handler(
312       new MockAuthHandler(
313           HttpAuth::AUTH_SCHEME_BASIC, kRealm2, HttpAuth::AUTH_SERVER));
314
315   scoped_ptr<HttpAuthHandler> realm3_basic_handler(
316       new MockAuthHandler(
317           HttpAuth::AUTH_SCHEME_BASIC, kRealm3, HttpAuth::AUTH_SERVER));
318
319   scoped_ptr<HttpAuthHandler> realm3_digest_handler(
320       new MockAuthHandler(
321           HttpAuth::AUTH_SCHEME_DIGEST, kRealm3, HttpAuth::AUTH_SERVER));
322
323   HttpAuthCache cache;
324   cache.Add(origin, realm1_handler->realm(), realm1_handler->auth_scheme(),
325             "basic realm=Realm1", AuthCredentials(kAlice, k123), "/");
326   cache.Add(origin, realm2_handler->realm(), realm2_handler->auth_scheme(),
327             "basic realm=Realm2", CreateASCIICredentials("bob", "princess"),
328             "/");
329   cache.Add(origin, realm3_basic_handler->realm(),
330             realm3_basic_handler->auth_scheme(), "basic realm=Realm3",
331             AuthCredentials(kAdmin, kPassword), "/");
332   cache.Add(origin, realm3_digest_handler->realm(),
333             realm3_digest_handler->auth_scheme(), "digest realm=Realm3",
334             AuthCredentials(kRoot, kWileCoyote), "/");
335
336   // Fails, because there is no realm "Realm5".
337   EXPECT_FALSE(cache.Remove(
338       origin, kRealm5, HttpAuth::AUTH_SCHEME_BASIC,
339       AuthCredentials(kAlice, k123)));
340
341   // Fails because the origin is wrong.
342   EXPECT_FALSE(cache.Remove(GURL("http://foobar2.com:100"),
343                             kRealm1,
344                             HttpAuth::AUTH_SCHEME_BASIC,
345                             AuthCredentials(kAlice, k123)));
346
347   // Fails because the username is wrong.
348   EXPECT_FALSE(cache.Remove(
349       origin, kRealm1, HttpAuth::AUTH_SCHEME_BASIC,
350       AuthCredentials(kAlice2, k123)));
351
352   // Fails because the password is wrong.
353   EXPECT_FALSE(cache.Remove(
354       origin, kRealm1, HttpAuth::AUTH_SCHEME_BASIC,
355       AuthCredentials(kAlice, k1234)));
356
357   // Fails because the authentication type is wrong.
358   EXPECT_FALSE(cache.Remove(
359       origin, kRealm1, HttpAuth::AUTH_SCHEME_DIGEST,
360       AuthCredentials(kAlice, k123)));
361
362   // Succeeds.
363   EXPECT_TRUE(cache.Remove(
364       origin, kRealm1, HttpAuth::AUTH_SCHEME_BASIC,
365       AuthCredentials(kAlice, k123)));
366
367   // Fails because we just deleted the entry!
368   EXPECT_FALSE(cache.Remove(
369       origin, kRealm1, HttpAuth::AUTH_SCHEME_BASIC,
370       AuthCredentials(kAlice, k123)));
371
372   // Succeed when there are two authentication types for the same origin,realm.
373   EXPECT_TRUE(cache.Remove(
374       origin, kRealm3, HttpAuth::AUTH_SCHEME_DIGEST,
375       AuthCredentials(kRoot, kWileCoyote)));
376
377   // Succeed as above, but when entries were added in opposite order
378   cache.Add(origin, realm3_digest_handler->realm(),
379             realm3_digest_handler->auth_scheme(), "digest realm=Realm3",
380             AuthCredentials(kRoot, kWileCoyote), "/");
381   EXPECT_TRUE(cache.Remove(
382       origin, kRealm3, HttpAuth::AUTH_SCHEME_BASIC,
383       AuthCredentials(kAdmin, kPassword)));
384
385   // Make sure that removing one entry still leaves the other available for
386   // lookup.
387   HttpAuthCache::Entry* entry = cache.Lookup(
388       origin, kRealm3, HttpAuth::AUTH_SCHEME_DIGEST);
389   EXPECT_FALSE(NULL == entry);
390 }
391
392 TEST(HttpAuthCacheTest, UpdateStaleChallenge) {
393   HttpAuthCache cache;
394   GURL origin("http://foobar2.com");
395   scoped_ptr<HttpAuthHandler> digest_handler(
396       new MockAuthHandler(
397           HttpAuth::AUTH_SCHEME_DIGEST, kRealm1, HttpAuth::AUTH_PROXY));
398   HttpAuthCache::Entry* entry_pre = cache.Add(
399       origin,
400       digest_handler->realm(),
401       digest_handler->auth_scheme(),
402       "Digest realm=Realm1,"
403       "nonce=\"s3MzvFhaBAA=4c520af5acd9d8d7ae26947529d18c8eae1e98f4\"",
404       CreateASCIICredentials("realm-digest-user", "realm-digest-password"),
405       "/baz/index.html");
406   ASSERT_TRUE(entry_pre != NULL);
407
408   EXPECT_EQ(2, entry_pre->IncrementNonceCount());
409   EXPECT_EQ(3, entry_pre->IncrementNonceCount());
410   EXPECT_EQ(4, entry_pre->IncrementNonceCount());
411
412   bool update_success = cache.UpdateStaleChallenge(
413       origin,
414       digest_handler->realm(),
415       digest_handler->auth_scheme(),
416       "Digest realm=Realm1,"
417       "nonce=\"claGgoRXBAA=7583377687842fdb7b56ba0555d175baa0b800e3\","
418       "stale=\"true\"");
419   EXPECT_TRUE(update_success);
420
421   // After the stale update, the entry should still exist in the cache and
422   // the nonce count should be reset to 0.
423   HttpAuthCache::Entry* entry_post = cache.Lookup(
424       origin,
425       digest_handler->realm(),
426       digest_handler->auth_scheme());
427   ASSERT_TRUE(entry_post != NULL);
428   EXPECT_EQ(2, entry_post->IncrementNonceCount());
429
430   // UpdateStaleChallenge will fail if an entry doesn't exist in the cache.
431   bool update_failure = cache.UpdateStaleChallenge(
432       origin,
433       kRealm2,
434       digest_handler->auth_scheme(),
435       "Digest realm=Realm2,"
436       "nonce=\"claGgoRXBAA=7583377687842fdb7b56ba0555d175baa0b800e3\","
437       "stale=\"true\"");
438   EXPECT_FALSE(update_failure);
439 }
440
441 TEST(HttpAuthCacheTest, UpdateAllFrom) {
442   GURL origin("http://example.com");
443   std::string path("/some/path");
444   std::string another_path("/another/path");
445
446   scoped_ptr<HttpAuthHandler> realm1_handler(
447       new MockAuthHandler(
448           HttpAuth::AUTH_SCHEME_BASIC, kRealm1, HttpAuth::AUTH_SERVER));
449
450   scoped_ptr<HttpAuthHandler> realm2_handler(
451       new MockAuthHandler(
452           HttpAuth::AUTH_SCHEME_BASIC, kRealm2, HttpAuth::AUTH_PROXY));
453
454   scoped_ptr<HttpAuthHandler> realm3_digest_handler(
455       new MockAuthHandler(
456           HttpAuth::AUTH_SCHEME_DIGEST, kRealm3, HttpAuth::AUTH_SERVER));
457
458   scoped_ptr<HttpAuthHandler> realm4_handler(
459       new MockAuthHandler(
460           HttpAuth::AUTH_SCHEME_BASIC, kRealm4, HttpAuth::AUTH_SERVER));
461
462   HttpAuthCache first_cache;
463   HttpAuthCache::Entry* entry;
464
465   first_cache.Add(origin, realm1_handler->realm(),
466                   realm1_handler->auth_scheme(), "basic realm=Realm1",
467                   AuthCredentials(kAlice, k123), path);
468   first_cache.Add(origin, realm2_handler->realm(),
469                   realm2_handler->auth_scheme(), "basic realm=Realm2",
470                   AuthCredentials(kAlice2, k1234), path);
471   first_cache.Add(origin, realm3_digest_handler->realm(),
472                   realm3_digest_handler->auth_scheme(), "digest realm=Realm3",
473                   AuthCredentials(kRoot, kWileCoyote), path);
474   entry = first_cache.Add(
475       origin, realm3_digest_handler->realm(),
476       realm3_digest_handler->auth_scheme(), "digest realm=Realm3",
477       AuthCredentials(kRoot, kWileCoyote), another_path);
478
479   EXPECT_EQ(2, entry->IncrementNonceCount());
480
481   HttpAuthCache second_cache;
482   // Will be overwritten by kRoot:kWileCoyote.
483   second_cache.Add(origin, realm3_digest_handler->realm(),
484                    realm3_digest_handler->auth_scheme(), "digest realm=Realm3",
485                    AuthCredentials(kAlice2, k1234), path);
486   // Should be left intact.
487   second_cache.Add(origin, realm4_handler->realm(),
488                    realm4_handler->auth_scheme(), "basic realm=Realm4",
489                    AuthCredentials(kAdmin, kRoot), path);
490
491   second_cache.UpdateAllFrom(first_cache);
492
493   // Copied from first_cache.
494   entry = second_cache.Lookup(origin, kRealm1, HttpAuth::AUTH_SCHEME_BASIC);
495   EXPECT_TRUE(NULL != entry);
496   EXPECT_EQ(kAlice, entry->credentials().username());
497   EXPECT_EQ(k123, entry->credentials().password());
498
499   // Copied from first_cache.
500   entry = second_cache.Lookup(origin, kRealm2, HttpAuth::AUTH_SCHEME_BASIC);
501   EXPECT_TRUE(NULL != entry);
502   EXPECT_EQ(kAlice2, entry->credentials().username());
503   EXPECT_EQ(k1234, entry->credentials().password());
504
505   // Overwritten from first_cache.
506   entry = second_cache.Lookup(origin, kRealm3, HttpAuth::AUTH_SCHEME_DIGEST);
507   EXPECT_TRUE(NULL != entry);
508   EXPECT_EQ(kRoot, entry->credentials().username());
509   EXPECT_EQ(kWileCoyote, entry->credentials().password());
510   // Nonce count should get copied.
511   EXPECT_EQ(3, entry->IncrementNonceCount());
512
513   // All paths should get copied.
514   entry = second_cache.LookupByPath(origin, another_path);
515   EXPECT_TRUE(NULL != entry);
516   EXPECT_EQ(kRoot, entry->credentials().username());
517   EXPECT_EQ(kWileCoyote, entry->credentials().password());
518
519   // Left intact in second_cache.
520   entry = second_cache.Lookup(origin, kRealm4, HttpAuth::AUTH_SCHEME_BASIC);
521   EXPECT_TRUE(NULL != entry);
522   EXPECT_EQ(kAdmin, entry->credentials().username());
523   EXPECT_EQ(kRoot, entry->credentials().password());
524 }
525
526 // Test fixture class for eviction tests (contains helpers for bulk
527 // insertion and existence testing).
528 class HttpAuthCacheEvictionTest : public testing::Test {
529  protected:
530   HttpAuthCacheEvictionTest() : origin_("http://www.google.com") { }
531
532   std::string GenerateRealm(int realm_i) {
533     return base::StringPrintf("Realm %d", realm_i);
534   }
535
536   std::string GeneratePath(int realm_i, int path_i) {
537     return base::StringPrintf("/%d/%d/x/y", realm_i, path_i);
538   }
539
540   void AddRealm(int realm_i) {
541     AddPathToRealm(realm_i, 0);
542   }
543
544   void AddPathToRealm(int realm_i, int path_i) {
545     cache_.Add(origin_,
546                GenerateRealm(realm_i),
547                HttpAuth::AUTH_SCHEME_BASIC,
548                std::string(),
549                AuthCredentials(kUsername, kPassword),
550                GeneratePath(realm_i, path_i));
551   }
552
553   void CheckRealmExistence(int realm_i, bool exists) {
554     const HttpAuthCache::Entry* entry =
555         cache_.Lookup(
556             origin_, GenerateRealm(realm_i), HttpAuth::AUTH_SCHEME_BASIC);
557     if (exists) {
558       EXPECT_FALSE(entry == NULL);
559       EXPECT_EQ(GenerateRealm(realm_i), entry->realm());
560     } else {
561       EXPECT_TRUE(entry == NULL);
562     }
563   }
564
565   void CheckPathExistence(int realm_i, int path_i, bool exists) {
566     const HttpAuthCache::Entry* entry =
567         cache_.LookupByPath(origin_, GeneratePath(realm_i, path_i));
568     if (exists) {
569       EXPECT_FALSE(entry == NULL);
570       EXPECT_EQ(GenerateRealm(realm_i), entry->realm());
571     } else {
572       EXPECT_TRUE(entry == NULL);
573     }
574   }
575
576   GURL origin_;
577   HttpAuthCache cache_;
578
579   static const int kMaxPaths = HttpAuthCache::kMaxNumPathsPerRealmEntry;
580   static const int kMaxRealms = HttpAuthCache::kMaxNumRealmEntries;
581 };
582
583 // Add the maxinim number of realm entries to the cache. Each of these entries
584 // must still be retrievable. Next add three more entries -- since the cache is
585 // full this causes FIFO eviction of the first three entries.
586 TEST_F(HttpAuthCacheEvictionTest, RealmEntryEviction) {
587   for (int i = 0; i < kMaxRealms; ++i)
588     AddRealm(i);
589
590   for (int i = 0; i < kMaxRealms; ++i)
591     CheckRealmExistence(i, true);
592
593   for (int i = 0; i < 3; ++i)
594     AddRealm(i + kMaxRealms);
595
596   for (int i = 0; i < 3; ++i)
597     CheckRealmExistence(i, false);
598
599   for (int i = 0; i < kMaxRealms; ++i)
600     CheckRealmExistence(i + 3, true);
601 }
602
603 // Add the maximum number of paths to a single realm entry. Each of these
604 // paths should be retrievable. Next add 3 more paths -- since the cache is
605 // full this causes FIFO eviction of the first three paths.
606 TEST_F(HttpAuthCacheEvictionTest, RealmPathEviction) {
607   for (int i = 0; i < kMaxPaths; ++i)
608     AddPathToRealm(0, i);
609
610   for (int i = 1; i < kMaxRealms; ++i)
611     AddRealm(i);
612
613   for (int i = 0; i < 3; ++i)
614     AddPathToRealm(0, i + kMaxPaths);
615
616   for (int i = 0; i < 3; ++i)
617     CheckPathExistence(0, i, false);
618
619   for (int i = 0; i < kMaxPaths; ++i)
620     CheckPathExistence(0, i + 3, true);
621
622   for (int i = 0; i < kMaxRealms; ++i)
623     CheckRealmExistence(i, true);
624 }
625
626 }  // namespace net