1// Copyright (c) 2012 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 "base/run_loop.h"
6#include "testing/gtest/include/gtest/gtest.h"
7#include "webkit/browser/appcache/appcache.h"
8#include "webkit/browser/appcache/appcache_group.h"
9#include "webkit/browser/appcache/appcache_response.h"
10#include "webkit/browser/appcache/appcache_storage.h"
11#include "webkit/browser/appcache/mock_appcache_service.h"
12
13namespace appcache {
14
15class MockAppCacheStorageTest : public testing::Test {
16 public:
17  class MockStorageDelegate : public AppCacheStorage::Delegate {
18   public:
19    explicit MockStorageDelegate()
20        : loaded_cache_id_(0), stored_group_success_(false),
21          obsoleted_success_(false), found_cache_id_(kNoCacheId) {
22    }
23
24    virtual void OnCacheLoaded(AppCache* cache, int64 cache_id) OVERRIDE {
25      loaded_cache_ = cache;
26      loaded_cache_id_ = cache_id;
27    }
28
29    virtual void OnGroupLoaded(AppCacheGroup* group,
30                               const GURL& manifest_url) OVERRIDE {
31      loaded_group_ = group;
32      loaded_manifest_url_ = manifest_url;
33    }
34
35    virtual void OnGroupAndNewestCacheStored(
36        AppCacheGroup* group, AppCache* newest_cache, bool success,
37        bool would_exceed_quota) OVERRIDE {
38      stored_group_ = group;
39      stored_group_success_ = success;
40    }
41
42    virtual void OnGroupMadeObsolete(AppCacheGroup* group,
43                                     bool success) OVERRIDE {
44      obsoleted_group_ = group;
45      obsoleted_success_ = success;
46    }
47
48    virtual void OnMainResponseFound(const GURL& url,
49                                     const AppCacheEntry& entry,
50                                     const GURL& fallback_url,
51                                     const AppCacheEntry& fallback_entry,
52                                     int64 cache_id,
53                                     int64 group_id,
54                                     const GURL& manifest_url) OVERRIDE {
55      found_url_ = url;
56      found_entry_ = entry;
57      found_fallback_url_ = fallback_url;
58      found_fallback_entry_ = fallback_entry;
59      found_cache_id_ = cache_id;
60      found_manifest_url_ = manifest_url;
61    }
62
63    scoped_refptr<AppCache> loaded_cache_;
64    int64 loaded_cache_id_;
65    scoped_refptr<AppCacheGroup> loaded_group_;
66    GURL loaded_manifest_url_;
67    scoped_refptr<AppCacheGroup> stored_group_;
68    bool stored_group_success_;
69    scoped_refptr<AppCacheGroup> obsoleted_group_;
70    bool obsoleted_success_;
71    GURL found_url_;
72    AppCacheEntry found_entry_;
73    GURL found_fallback_url_;
74    AppCacheEntry found_fallback_entry_;
75    int64 found_cache_id_;
76    GURL found_manifest_url_;
77  };
78
79 private:
80  base::MessageLoop message_loop_;
81};
82
83TEST_F(MockAppCacheStorageTest, LoadCache_Miss) {
84  // Attempt to load a cache that doesn't exist. Should
85  // complete asyncly.
86  MockAppCacheService service;
87  MockStorageDelegate delegate;
88  service.storage()->LoadCache(111, &delegate);
89  EXPECT_NE(111, delegate.loaded_cache_id_);
90  base::RunLoop().RunUntilIdle();  // Do async task execution.
91  EXPECT_EQ(111, delegate.loaded_cache_id_);
92  EXPECT_FALSE(delegate.loaded_cache_.get());
93}
94
95TEST_F(MockAppCacheStorageTest, LoadCache_NearHit) {
96  // Attempt to load a cache that is currently in use
97  // and does not require loading from disk. This
98  // load should complete syncly.
99  MockAppCacheService service;
100
101  // Setup some preconditions. Make an 'unstored' cache for
102  // us to load. The ctor should put it in the working set.
103  int64 cache_id = service.storage()->NewCacheId();
104  scoped_refptr<AppCache> cache(new AppCache(service.storage(), cache_id));
105
106  // Conduct the test.
107  MockStorageDelegate delegate;
108  service.storage()->LoadCache(cache_id, &delegate);
109  EXPECT_EQ(cache_id, delegate.loaded_cache_id_);
110  EXPECT_EQ(cache.get(), delegate.loaded_cache_.get());
111}
112
113TEST_F(MockAppCacheStorageTest, CreateGroup) {
114  // Attempt to load/create a group that doesn't exist.
115  // Should complete asyncly.
116  MockAppCacheService service;
117  MockAppCacheStorage* storage =
118      reinterpret_cast<MockAppCacheStorage*>(service.storage());
119  MockStorageDelegate delegate;
120  GURL manifest_url("http://blah/");
121  service.storage()->LoadOrCreateGroup(manifest_url, &delegate);
122  EXPECT_NE(manifest_url, delegate.loaded_manifest_url_);
123  EXPECT_FALSE(delegate.loaded_group_.get());
124  base::RunLoop().RunUntilIdle();  // Do async task execution.
125  EXPECT_EQ(manifest_url, delegate.loaded_manifest_url_);
126  EXPECT_TRUE(delegate.loaded_group_.get());
127  EXPECT_TRUE(delegate.loaded_group_->HasOneRef());
128  EXPECT_FALSE(delegate.loaded_group_->newest_complete_cache());
129  EXPECT_TRUE(storage->stored_groups_.empty());
130}
131
132TEST_F(MockAppCacheStorageTest, LoadGroup_NearHit) {
133  // Attempt to load a group that is currently in use
134  // and does not require loading from disk. This
135  // load should complete syncly.
136  MockAppCacheService service;
137  MockStorageDelegate delegate;
138
139  // Setup some preconditions. Create a group that appears
140  // to be "unstored" and "currently in use".
141  GURL manifest_url("http://blah/");
142  service.storage()->LoadOrCreateGroup(manifest_url, &delegate);
143  base::RunLoop().RunUntilIdle();  // Do async task execution.
144  EXPECT_EQ(manifest_url, delegate.loaded_manifest_url_);
145  EXPECT_TRUE(delegate.loaded_group_.get());
146
147  // Reset our delegate, and take a reference to the new group.
148  scoped_refptr<AppCacheGroup> group;
149  group.swap(delegate.loaded_group_);
150  delegate.loaded_manifest_url_ = GURL();
151
152  // Conduct the test.
153  service.storage()->LoadOrCreateGroup(manifest_url, &delegate);
154  EXPECT_EQ(manifest_url, delegate.loaded_manifest_url_);
155  EXPECT_EQ(group.get(), delegate.loaded_group_.get());
156}
157
158TEST_F(MockAppCacheStorageTest, LoadGroupAndCache_FarHit) {
159  // Attempt to load a cache that is not currently in use
160  // and does require loading from disk. This
161  // load should complete asyncly.
162  MockAppCacheService service;
163  MockAppCacheStorage* storage =
164      reinterpret_cast<MockAppCacheStorage*>(service.storage());
165
166  // Setup some preconditions. Create a group and newest cache that
167  // appears to be "stored" and "not currently in use".
168  GURL manifest_url("http://blah/");
169  scoped_refptr<AppCacheGroup> group(
170      new AppCacheGroup(service.storage(), manifest_url, 111));
171  int64 cache_id = storage->NewCacheId();
172  scoped_refptr<AppCache> cache(new AppCache(service.storage(), cache_id));
173  cache->set_complete(true);
174  group->AddCache(cache.get());
175  storage->AddStoredGroup(group.get());
176  storage->AddStoredCache(cache.get());
177
178  // Drop the references from above so the only refs to these
179  // objects are from within the storage class. This is to make
180  // these objects appear as "not currently in use".
181  AppCache* cache_ptr = cache.get();
182  AppCacheGroup* group_ptr = group.get();
183  cache = NULL;
184  group = NULL;
185
186  // Setup a delegate to receive completion callbacks.
187  MockStorageDelegate delegate;
188
189  // Conduct the cache load test.
190  EXPECT_NE(cache_id, delegate.loaded_cache_id_);
191  EXPECT_NE(cache_ptr, delegate.loaded_cache_.get());
192  storage->LoadCache(cache_id, &delegate);
193  EXPECT_NE(cache_id, delegate.loaded_cache_id_);
194  EXPECT_NE(cache_ptr, delegate.loaded_cache_.get());
195  base::RunLoop().RunUntilIdle();  // Do async task execution.
196  EXPECT_EQ(cache_id, delegate.loaded_cache_id_);
197  EXPECT_EQ(cache_ptr, delegate.loaded_cache_.get());
198  delegate.loaded_cache_ = NULL;
199
200  // Conduct the group load test.
201  EXPECT_NE(manifest_url, delegate.loaded_manifest_url_);
202  EXPECT_FALSE(delegate.loaded_group_.get());
203  storage->LoadOrCreateGroup(manifest_url, &delegate);
204  EXPECT_NE(manifest_url, delegate.loaded_manifest_url_);
205  EXPECT_FALSE(delegate.loaded_group_.get());
206  base::RunLoop().RunUntilIdle();  // Do async task execution.
207  EXPECT_EQ(manifest_url, delegate.loaded_manifest_url_);
208  EXPECT_EQ(group_ptr, delegate.loaded_group_.get());
209}
210
211TEST_F(MockAppCacheStorageTest, StoreNewGroup) {
212  // Store a group and its newest cache. Should complete asyncly.
213  MockAppCacheService service;
214  MockAppCacheStorage* storage =
215      reinterpret_cast<MockAppCacheStorage*>(service.storage());
216
217  // Setup some preconditions. Create a group and newest cache that
218  // appears to be "unstored".
219  GURL manifest_url("http://blah/");
220  scoped_refptr<AppCacheGroup> group(
221      new AppCacheGroup(service.storage(), manifest_url, 111));
222  int64 cache_id = storage->NewCacheId();
223  scoped_refptr<AppCache> cache(new AppCache(service.storage(), cache_id));
224  // Hold a ref to the cache simulate the UpdateJob holding that ref,
225  // and hold a ref to the group to simulate the CacheHost holding that ref.
226
227  // Conduct the store test.
228  MockStorageDelegate delegate;
229  EXPECT_TRUE(storage->stored_caches_.empty());
230  EXPECT_TRUE(storage->stored_groups_.empty());
231  storage->StoreGroupAndNewestCache(group.get(), cache.get(), &delegate);
232  EXPECT_FALSE(delegate.stored_group_success_);
233  EXPECT_TRUE(storage->stored_caches_.empty());
234  EXPECT_TRUE(storage->stored_groups_.empty());
235  base::RunLoop().RunUntilIdle();  // Do async task execution.
236  EXPECT_TRUE(delegate.stored_group_success_);
237  EXPECT_FALSE(storage->stored_caches_.empty());
238  EXPECT_FALSE(storage->stored_groups_.empty());
239  EXPECT_EQ(cache, group->newest_complete_cache());
240  EXPECT_TRUE(cache->is_complete());
241}
242
243TEST_F(MockAppCacheStorageTest, StoreExistingGroup) {
244  // Store a group and its newest cache. Should complete asyncly.
245  MockAppCacheService service;
246  MockAppCacheStorage* storage =
247      reinterpret_cast<MockAppCacheStorage*>(service.storage());
248
249  // Setup some preconditions. Create a group and old complete cache
250  // that appear to be "stored", and a newest unstored complete cache.
251  GURL manifest_url("http://blah/");
252  scoped_refptr<AppCacheGroup> group(
253      new AppCacheGroup(service.storage(), manifest_url, 111));
254  int64 old_cache_id = storage->NewCacheId();
255  scoped_refptr<AppCache> old_cache(
256      new AppCache(service.storage(), old_cache_id));
257  old_cache->set_complete(true);
258  group->AddCache(old_cache.get());
259  storage->AddStoredGroup(group.get());
260  storage->AddStoredCache(old_cache.get());
261  int64 new_cache_id = storage->NewCacheId();
262  scoped_refptr<AppCache> new_cache(
263      new AppCache(service.storage(), new_cache_id));
264  // Hold our refs to simulate the UpdateJob holding these refs.
265
266  // Conduct the test.
267  MockStorageDelegate delegate;
268  EXPECT_EQ(size_t(1), storage->stored_caches_.size());
269  EXPECT_EQ(size_t(1), storage->stored_groups_.size());
270  EXPECT_TRUE(storage->IsCacheStored(old_cache.get()));
271  EXPECT_FALSE(storage->IsCacheStored(new_cache.get()));
272  storage->StoreGroupAndNewestCache(group.get(), new_cache.get(), &delegate);
273  EXPECT_FALSE(delegate.stored_group_success_);
274  EXPECT_EQ(size_t(1), storage->stored_caches_.size());
275  EXPECT_EQ(size_t(1), storage->stored_groups_.size());
276  EXPECT_TRUE(storage->IsCacheStored(old_cache.get()));
277  EXPECT_FALSE(storage->IsCacheStored(new_cache.get()));
278  base::RunLoop().RunUntilIdle();  // Do async task execution.
279  EXPECT_TRUE(delegate.stored_group_success_);
280  EXPECT_EQ(size_t(1), storage->stored_caches_.size());
281  EXPECT_EQ(size_t(1), storage->stored_groups_.size());
282  EXPECT_FALSE(storage->IsCacheStored(old_cache.get()));
283  EXPECT_TRUE(storage->IsCacheStored(new_cache.get()));
284  EXPECT_EQ(new_cache.get(), group->newest_complete_cache());
285  EXPECT_TRUE(new_cache->is_complete());
286}
287
288TEST_F(MockAppCacheStorageTest, StoreExistingGroupExistingCache) {
289  // Store a group with updates to its existing newest complete cache.
290  MockAppCacheService service;
291  MockAppCacheStorage* storage =
292      reinterpret_cast<MockAppCacheStorage*>(service.storage());
293
294  // Setup some preconditions. Create a group and a complete cache that
295  // appear to be "stored".
296  GURL manifest_url("http://blah");
297  scoped_refptr<AppCacheGroup> group(
298      new AppCacheGroup(service.storage(), manifest_url, 111));
299  int64 cache_id = storage->NewCacheId();
300  scoped_refptr<AppCache> cache(new AppCache(service.storage(), cache_id));
301  cache->set_complete(true);
302  group->AddCache(cache.get());
303  storage->AddStoredGroup(group.get());
304  storage->AddStoredCache(cache.get());
305  // Hold our refs to simulate the UpdateJob holding these refs.
306
307  // Change the group's newest cache.
308  EXPECT_EQ(cache, group->newest_complete_cache());
309  GURL entry_url("http://blah/blah");
310  cache->AddEntry(entry_url, AppCacheEntry(AppCacheEntry::MASTER));
311
312  // Conduct the test.
313  MockStorageDelegate delegate;
314  EXPECT_EQ(size_t(1), storage->stored_caches_.size());
315  EXPECT_EQ(size_t(1), storage->stored_groups_.size());
316  EXPECT_TRUE(storage->IsCacheStored(cache.get()));
317  storage->StoreGroupAndNewestCache(group.get(), cache.get(), &delegate);
318  EXPECT_FALSE(delegate.stored_group_success_);
319  EXPECT_EQ(size_t(1), storage->stored_caches_.size());
320  EXPECT_EQ(size_t(1), storage->stored_groups_.size());
321  base::RunLoop().RunUntilIdle();  // Do async task execution.
322  EXPECT_TRUE(delegate.stored_group_success_);
323  EXPECT_EQ(size_t(1), storage->stored_caches_.size());
324  EXPECT_EQ(size_t(1), storage->stored_groups_.size());
325  EXPECT_TRUE(storage->IsCacheStored(cache.get()));
326  EXPECT_EQ(cache, group->newest_complete_cache());
327  EXPECT_TRUE(cache->GetEntry(entry_url));
328}
329
330TEST_F(MockAppCacheStorageTest, MakeGroupObsolete) {
331  // Make a group obsolete, should complete asyncly.
332  MockAppCacheService service;
333  MockAppCacheStorage* storage =
334      reinterpret_cast<MockAppCacheStorage*>(service.storage());
335
336  // Setup some preconditions. Create a group and newest cache that
337  // appears to be "stored" and "currently in use".
338  GURL manifest_url("http://blah/");
339  scoped_refptr<AppCacheGroup> group(
340      new AppCacheGroup(service.storage(), manifest_url, 111));
341  int64 cache_id = storage->NewCacheId();
342  scoped_refptr<AppCache> cache(new AppCache(service.storage(), cache_id));
343  cache->set_complete(true);
344  group->AddCache(cache.get());
345  storage->AddStoredGroup(group.get());
346  storage->AddStoredCache(cache.get());
347  // Hold our refs to simulate the UpdateJob holding these refs.
348
349  // Conduct the test.
350  MockStorageDelegate delegate;
351  EXPECT_FALSE(group->is_obsolete());
352  EXPECT_EQ(size_t(1), storage->stored_caches_.size());
353  EXPECT_EQ(size_t(1), storage->stored_groups_.size());
354  EXPECT_FALSE(cache->HasOneRef());
355  EXPECT_FALSE(group->HasOneRef());
356  storage->MakeGroupObsolete(group.get(), &delegate);
357  EXPECT_FALSE(group->is_obsolete());
358  EXPECT_EQ(size_t(1), storage->stored_caches_.size());
359  EXPECT_EQ(size_t(1), storage->stored_groups_.size());
360  EXPECT_FALSE(cache->HasOneRef());
361  EXPECT_FALSE(group->HasOneRef());
362  base::RunLoop().RunUntilIdle();  // Do async task execution.
363  EXPECT_TRUE(delegate.obsoleted_success_);
364  EXPECT_EQ(group.get(), delegate.obsoleted_group_.get());
365  EXPECT_TRUE(group->is_obsolete());
366  EXPECT_TRUE(storage->stored_caches_.empty());
367  EXPECT_TRUE(storage->stored_groups_.empty());
368  EXPECT_TRUE(cache->HasOneRef());
369  EXPECT_FALSE(group->HasOneRef());
370  delegate.obsoleted_group_ = NULL;
371  cache = NULL;
372  EXPECT_TRUE(group->HasOneRef());
373}
374
375TEST_F(MockAppCacheStorageTest, MarkEntryAsForeign) {
376  // Should complete syncly.
377  MockAppCacheService service;
378  MockAppCacheStorage* storage =
379      reinterpret_cast<MockAppCacheStorage*>(service.storage());
380
381  // Setup some preconditions. Create a cache with an entry.
382  GURL entry_url("http://blah/entry");
383  int64 cache_id = storage->NewCacheId();
384  scoped_refptr<AppCache> cache(new AppCache(service.storage(), cache_id));
385  cache->AddEntry(entry_url, AppCacheEntry(AppCacheEntry::EXPLICIT));
386
387  // Conduct the test.
388  MockStorageDelegate delegate;
389  EXPECT_FALSE(cache->GetEntry(entry_url)->IsForeign());
390  storage->MarkEntryAsForeign(entry_url, cache_id);
391  EXPECT_TRUE(cache->GetEntry(entry_url)->IsForeign());
392  EXPECT_TRUE(cache->GetEntry(entry_url)->IsExplicit());
393}
394
395TEST_F(MockAppCacheStorageTest, FindNoMainResponse) {
396  // Should complete asyncly.
397  MockAppCacheService service;
398  MockAppCacheStorage* storage =
399      reinterpret_cast<MockAppCacheStorage*>(service.storage());
400
401  // Conduct the test.
402  MockStorageDelegate delegate;
403  GURL url("http://blah/some_url");
404  EXPECT_NE(url, delegate.found_url_);
405  storage->FindResponseForMainRequest(url, GURL(), &delegate);
406  EXPECT_NE(url, delegate.found_url_);
407  base::RunLoop().RunUntilIdle();  // Do async task execution.
408  EXPECT_EQ(url, delegate.found_url_);
409  EXPECT_TRUE(delegate.found_manifest_url_.is_empty());
410  EXPECT_EQ(kNoCacheId, delegate.found_cache_id_);
411  EXPECT_EQ(kNoResponseId, delegate.found_entry_.response_id());
412  EXPECT_EQ(kNoResponseId, delegate.found_fallback_entry_.response_id());
413  EXPECT_TRUE(delegate.found_fallback_url_.is_empty());
414  EXPECT_EQ(0, delegate.found_entry_.types());
415  EXPECT_EQ(0, delegate.found_fallback_entry_.types());
416}
417
418TEST_F(MockAppCacheStorageTest, BasicFindMainResponse) {
419  // Should complete asyncly.
420  MockAppCacheService service;
421  MockAppCacheStorage* storage =
422      reinterpret_cast<MockAppCacheStorage*>(service.storage());
423
424  // Setup some preconditions. Create a complete cache with an entry.
425  const int64 kCacheId = storage->NewCacheId();
426  const GURL kEntryUrl("http://blah/entry");
427  const GURL kManifestUrl("http://blah/manifest");
428  const int64 kResponseId = 1;
429  scoped_refptr<AppCache> cache(new AppCache(service.storage(), kCacheId));
430  cache->AddEntry(
431      kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, kResponseId));
432  cache->set_complete(true);
433  scoped_refptr<AppCacheGroup> group(
434      new AppCacheGroup(service.storage(), kManifestUrl, 111));
435  group->AddCache(cache.get());
436  storage->AddStoredGroup(group.get());
437  storage->AddStoredCache(cache.get());
438
439  // Conduct the test.
440  MockStorageDelegate delegate;
441  EXPECT_NE(kEntryUrl, delegate.found_url_);
442  storage->FindResponseForMainRequest(kEntryUrl, GURL(), &delegate);
443  EXPECT_NE(kEntryUrl, delegate.found_url_);
444  base::RunLoop().RunUntilIdle();  // Do async task execution.
445  EXPECT_EQ(kEntryUrl, delegate.found_url_);
446  EXPECT_EQ(kManifestUrl, delegate.found_manifest_url_);
447  EXPECT_EQ(kCacheId, delegate.found_cache_id_);
448  EXPECT_EQ(kResponseId, delegate.found_entry_.response_id());
449  EXPECT_TRUE(delegate.found_entry_.IsExplicit());
450  EXPECT_FALSE(delegate.found_fallback_entry_.has_response_id());
451}
452
453TEST_F(MockAppCacheStorageTest, BasicFindMainFallbackResponse) {
454  // Should complete asyncly.
455  MockAppCacheService service;
456  MockAppCacheStorage* storage =
457      reinterpret_cast<MockAppCacheStorage*>(service.storage());
458
459  // Setup some preconditions. Create a complete cache with a
460  // fallback namespace and entry.
461  const int64 kCacheId = storage->NewCacheId();
462  const GURL kFallbackEntryUrl1("http://blah/fallback_entry1");
463  const GURL kFallbackNamespaceUrl1("http://blah/fallback_namespace/");
464  const GURL kFallbackEntryUrl2("http://blah/fallback_entry2");
465  const GURL kFallbackNamespaceUrl2("http://blah/fallback_namespace/longer");
466  const GURL kManifestUrl("http://blah/manifest");
467  const int64 kResponseId1 = 1;
468  const int64 kResponseId2 = 2;
469
470  Manifest manifest;
471  manifest.fallback_namespaces.push_back(
472      Namespace(FALLBACK_NAMESPACE, kFallbackNamespaceUrl1,
473                kFallbackEntryUrl1, false));
474  manifest.fallback_namespaces.push_back(
475      Namespace(FALLBACK_NAMESPACE, kFallbackNamespaceUrl2,
476                kFallbackEntryUrl2, false));
477
478  scoped_refptr<AppCache> cache(new AppCache(service.storage(), kCacheId));
479  cache->InitializeWithManifest(&manifest);
480  cache->AddEntry(kFallbackEntryUrl1,
481                  AppCacheEntry(AppCacheEntry::FALLBACK, kResponseId1));
482  cache->AddEntry(kFallbackEntryUrl2,
483                  AppCacheEntry(AppCacheEntry::FALLBACK, kResponseId2));
484  cache->set_complete(true);
485
486  scoped_refptr<AppCacheGroup> group(
487      new AppCacheGroup(service.storage(), kManifestUrl, 111));
488  group->AddCache(cache.get());
489  storage->AddStoredGroup(group.get());
490  storage->AddStoredCache(cache.get());
491
492  // The test url is in both fallback namespace urls, but should match
493  // the longer of the two.
494  const GURL kTestUrl("http://blah/fallback_namespace/longer/test");
495
496  // Conduct the test.
497  MockStorageDelegate delegate;
498  EXPECT_NE(kTestUrl, delegate.found_url_);
499  storage->FindResponseForMainRequest(kTestUrl, GURL(), &delegate);
500  EXPECT_NE(kTestUrl, delegate.found_url_);
501  base::RunLoop().RunUntilIdle();  // Do async task execution.
502  EXPECT_EQ(kTestUrl, delegate.found_url_);
503  EXPECT_EQ(kManifestUrl, delegate.found_manifest_url_);
504  EXPECT_EQ(kCacheId, delegate.found_cache_id_);
505  EXPECT_FALSE(delegate.found_entry_.has_response_id());
506  EXPECT_EQ(kResponseId2, delegate.found_fallback_entry_.response_id());
507  EXPECT_EQ(kFallbackEntryUrl2, delegate.found_fallback_url_);
508  EXPECT_TRUE(delegate.found_fallback_entry_.IsFallback());
509}
510
511TEST_F(MockAppCacheStorageTest, FindMainResponseWithMultipleCandidates) {
512  // Should complete asyncly.
513  MockAppCacheService service;
514  MockAppCacheStorage* storage =
515      reinterpret_cast<MockAppCacheStorage*>(service.storage());
516
517  // Setup some preconditions. Create 2 complete caches with an entry
518  // for the same url.
519
520  const GURL kEntryUrl("http://blah/entry");
521  const int64 kCacheId1 = storage->NewCacheId();
522  const int64 kCacheId2 = storage->NewCacheId();
523  const GURL kManifestUrl1("http://blah/manifest1");
524  const GURL kManifestUrl2("http://blah/manifest2");
525  const int64 kResponseId1 = 1;
526  const int64 kResponseId2 = 2;
527
528  // The first cache.
529  scoped_refptr<AppCache> cache(new AppCache(service.storage(), kCacheId1));
530  cache->AddEntry(
531      kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, kResponseId1));
532  cache->set_complete(true);
533  scoped_refptr<AppCacheGroup> group(
534      new AppCacheGroup(service.storage(), kManifestUrl1, 111));
535  group->AddCache(cache.get());
536  storage->AddStoredGroup(group.get());
537  storage->AddStoredCache(cache.get());
538  // Drop our references to cache1 so it appears as "not in use".
539  cache = NULL;
540  group = NULL;
541
542  // The second cache.
543  cache = new AppCache(service.storage(), kCacheId2);
544  cache->AddEntry(
545      kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, kResponseId2));
546  cache->set_complete(true);
547  group = new AppCacheGroup(service.storage(), kManifestUrl2, 222);
548  group->AddCache(cache.get());
549  storage->AddStoredGroup(group.get());
550  storage->AddStoredCache(cache.get());
551
552  // Conduct the test, we should find the response from the second cache
553  // since it's "in use".
554  MockStorageDelegate delegate;
555  EXPECT_NE(kEntryUrl, delegate.found_url_);
556  storage->FindResponseForMainRequest(kEntryUrl, GURL(), &delegate);
557  EXPECT_NE(kEntryUrl, delegate.found_url_);
558  base::RunLoop().RunUntilIdle();  // Do async task execution.
559  EXPECT_EQ(kEntryUrl, delegate.found_url_);
560  EXPECT_EQ(kManifestUrl2, delegate.found_manifest_url_);
561  EXPECT_EQ(kCacheId2, delegate.found_cache_id_);
562  EXPECT_EQ(kResponseId2, delegate.found_entry_.response_id());
563  EXPECT_TRUE(delegate.found_entry_.IsExplicit());
564  EXPECT_FALSE(delegate.found_fallback_entry_.has_response_id());
565}
566
567TEST_F(MockAppCacheStorageTest, FindMainResponseExclusions) {
568  // Should complete asyncly.
569  MockAppCacheService service;
570  MockAppCacheStorage* storage =
571      reinterpret_cast<MockAppCacheStorage*>(service.storage());
572
573  // Setup some preconditions. Create a complete cache with a
574  // foreign entry and an online namespace.
575
576  const int64 kCacheId = storage->NewCacheId();
577  const GURL kEntryUrl("http://blah/entry");
578  const GURL kManifestUrl("http://blah/manifest");
579  const GURL kOnlineNamespaceUrl("http://blah/online_namespace");
580  const int64 kResponseId = 1;
581
582  Manifest manifest;
583  manifest.online_whitelist_namespaces.push_back(
584      Namespace(NETWORK_NAMESPACE, kOnlineNamespaceUrl,
585                GURL(), false));
586  scoped_refptr<AppCache> cache(new AppCache(service.storage(), kCacheId));
587  cache->InitializeWithManifest(&manifest);
588  cache->AddEntry(
589      kEntryUrl,
590      AppCacheEntry(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN,
591                    kResponseId));
592  cache->set_complete(true);
593  scoped_refptr<AppCacheGroup> group(
594      new AppCacheGroup(service.storage(), kManifestUrl, 111));
595  group->AddCache(cache.get());
596  storage->AddStoredGroup(group.get());
597  storage->AddStoredCache(cache.get());
598
599  MockStorageDelegate delegate;
600
601  // We should not find anything for the foreign entry.
602  EXPECT_NE(kEntryUrl, delegate.found_url_);
603  storage->FindResponseForMainRequest(kEntryUrl, GURL(), &delegate);
604  EXPECT_NE(kEntryUrl, delegate.found_url_);
605  base::RunLoop().RunUntilIdle();  // Do async task execution.
606  EXPECT_EQ(kEntryUrl, delegate.found_url_);
607  EXPECT_TRUE(delegate.found_manifest_url_.is_empty());
608  EXPECT_EQ(kNoCacheId, delegate.found_cache_id_);
609  EXPECT_EQ(kNoResponseId, delegate.found_entry_.response_id());
610  EXPECT_EQ(kNoResponseId, delegate.found_fallback_entry_.response_id());
611  EXPECT_TRUE(delegate.found_fallback_url_.is_empty());
612  EXPECT_EQ(0, delegate.found_entry_.types());
613  EXPECT_EQ(0, delegate.found_fallback_entry_.types());
614
615  // We should not find anything for the online namespace.
616  EXPECT_NE(kOnlineNamespaceUrl, delegate.found_url_);
617  storage->FindResponseForMainRequest(kOnlineNamespaceUrl, GURL(), &delegate);
618  EXPECT_NE(kOnlineNamespaceUrl, delegate.found_url_);
619  base::RunLoop().RunUntilIdle();  // Do async task execution.
620  EXPECT_EQ(kOnlineNamespaceUrl, delegate.found_url_);
621  EXPECT_TRUE(delegate.found_manifest_url_.is_empty());
622  EXPECT_EQ(kNoCacheId, delegate.found_cache_id_);
623  EXPECT_EQ(kNoResponseId, delegate.found_entry_.response_id());
624  EXPECT_EQ(kNoResponseId, delegate.found_fallback_entry_.response_id());
625  EXPECT_TRUE(delegate.found_fallback_url_.is_empty());
626  EXPECT_EQ(0, delegate.found_entry_.types());
627  EXPECT_EQ(0, delegate.found_fallback_entry_.types());
628}
629
630}  // namespace appcache
631