Home | History | Annotate | Download | only in appcache
      1 // Copyright 2014 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/message_loop/message_loop.h"
      8 #include "content/browser/appcache/mock_appcache_service.h"
      9 #include "testing/gtest/include/gtest/gtest.h"
     10 #include "webkit/browser/appcache/appcache.h"
     11 #include "webkit/browser/appcache/appcache_group.h"
     12 #include "webkit/browser/appcache/appcache_host.h"
     13 #include "webkit/browser/appcache/appcache_update_job.h"
     14 #include "webkit/common/appcache/appcache_interfaces.h"
     15 
     16 using appcache::AppCache;
     17 using appcache::AppCacheFrontend;
     18 using appcache::AppCacheGroup;
     19 using appcache::AppCacheHost;
     20 using appcache::AppCacheServiceImpl;
     21 using appcache::AppCacheUpdateJob;
     22 
     23 namespace {
     24 
     25 class TestAppCacheFrontend : public appcache::AppCacheFrontend {
     26  public:
     27   TestAppCacheFrontend()
     28       : last_host_id_(-1), last_cache_id_(-1),
     29         last_status_(appcache::APPCACHE_STATUS_OBSOLETE) {
     30   }
     31 
     32   virtual void OnCacheSelected(
     33       int host_id, const appcache::AppCacheInfo& info) OVERRIDE {
     34     last_host_id_ = host_id;
     35     last_cache_id_ = info.cache_id;
     36     last_status_ = info.status;
     37   }
     38 
     39   virtual void OnStatusChanged(const std::vector<int>& host_ids,
     40                                appcache::AppCacheStatus status) OVERRIDE {
     41   }
     42 
     43   virtual void OnEventRaised(const std::vector<int>& host_ids,
     44                              appcache::AppCacheEventID event_id) OVERRIDE {
     45   }
     46 
     47   virtual void OnErrorEventRaised(const std::vector<int>& host_ids,
     48                                   const appcache::AppCacheErrorDetails& details)
     49       OVERRIDE {}
     50 
     51   virtual void OnProgressEventRaised(const std::vector<int>& host_ids,
     52                                      const GURL& url,
     53                                      int num_total, int num_complete) OVERRIDE {
     54   }
     55 
     56   virtual void OnLogMessage(int host_id, appcache::AppCacheLogLevel log_level,
     57                             const std::string& message) OVERRIDE {
     58   }
     59 
     60   virtual void OnContentBlocked(int host_id,
     61                                 const GURL& manifest_url) OVERRIDE {
     62   }
     63 
     64   int last_host_id_;
     65   int64 last_cache_id_;
     66   appcache::AppCacheStatus last_status_;
     67 };
     68 
     69 }  // namespace anon
     70 
     71 namespace content {
     72 
     73 class TestUpdateObserver : public AppCacheGroup::UpdateObserver {
     74  public:
     75   TestUpdateObserver() : update_completed_(false), group_has_cache_(false) {
     76   }
     77 
     78   virtual void OnUpdateComplete(AppCacheGroup* group) OVERRIDE {
     79     update_completed_ = true;
     80     group_has_cache_ = group->HasCache();
     81   }
     82 
     83   virtual void OnContentBlocked(AppCacheGroup* group) {
     84   }
     85 
     86   bool update_completed_;
     87   bool group_has_cache_;
     88 };
     89 
     90 class TestAppCacheHost : public AppCacheHost {
     91  public:
     92   TestAppCacheHost(int host_id, AppCacheFrontend* frontend,
     93                    AppCacheServiceImpl* service)
     94       : AppCacheHost(host_id, frontend, service),
     95         update_completed_(false) {
     96   }
     97 
     98   virtual void OnUpdateComplete(AppCacheGroup* group) OVERRIDE {
     99     update_completed_ = true;
    100   }
    101 
    102   bool update_completed_;
    103 };
    104 
    105 class AppCacheGroupTest : public testing::Test {
    106  private:
    107   base::MessageLoop message_loop_;
    108 };
    109 
    110 TEST_F(AppCacheGroupTest, AddRemoveCache) {
    111   MockAppCacheService service;
    112   scoped_refptr<AppCacheGroup> group(
    113       new AppCacheGroup(service.storage(), GURL("http://foo.com"), 111));
    114 
    115   base::Time now = base::Time::Now();
    116 
    117   scoped_refptr<AppCache> cache1(new AppCache(service.storage(), 111));
    118   cache1->set_complete(true);
    119   cache1->set_update_time(now);
    120   group->AddCache(cache1.get());
    121   EXPECT_EQ(cache1, group->newest_complete_cache());
    122 
    123   // Adding older cache does not change newest complete cache.
    124   scoped_refptr<AppCache> cache2(new AppCache(service.storage(), 222));
    125   cache2->set_complete(true);
    126   cache2->set_update_time(now - base::TimeDelta::FromDays(1));
    127   group->AddCache(cache2.get());
    128   EXPECT_EQ(cache1, group->newest_complete_cache());
    129 
    130   // Adding newer cache does change newest complete cache.
    131   scoped_refptr<AppCache> cache3(new AppCache(service.storage(), 333));
    132   cache3->set_complete(true);
    133   cache3->set_update_time(now + base::TimeDelta::FromDays(1));
    134   group->AddCache(cache3.get());
    135   EXPECT_EQ(cache3, group->newest_complete_cache());
    136 
    137   // Adding cache with same update time uses one with larger ID.
    138   scoped_refptr<AppCache> cache4(new AppCache(service.storage(), 444));
    139   cache4->set_complete(true);
    140   cache4->set_update_time(now + base::TimeDelta::FromDays(1));  // same as 3
    141   group->AddCache(cache4.get());
    142   EXPECT_EQ(cache4, group->newest_complete_cache());
    143 
    144   // smaller id
    145   scoped_refptr<AppCache> cache5(new AppCache(service.storage(), 55));
    146   cache5->set_complete(true);
    147   cache5->set_update_time(now + base::TimeDelta::FromDays(1));  // same as 4
    148   group->AddCache(cache5.get());
    149   EXPECT_EQ(cache4, group->newest_complete_cache());  // no change
    150 
    151   // Old caches can always be removed.
    152   group->RemoveCache(cache1.get());
    153   EXPECT_FALSE(cache1->owning_group());
    154   EXPECT_EQ(cache4, group->newest_complete_cache());  // newest unchanged
    155 
    156   // Remove rest of caches.
    157   group->RemoveCache(cache2.get());
    158   EXPECT_FALSE(cache2->owning_group());
    159   EXPECT_EQ(cache4, group->newest_complete_cache());  // newest unchanged
    160   group->RemoveCache(cache3.get());
    161   EXPECT_FALSE(cache3->owning_group());
    162   EXPECT_EQ(cache4, group->newest_complete_cache());  // newest unchanged
    163   group->RemoveCache(cache5.get());
    164   EXPECT_FALSE(cache5->owning_group());
    165   EXPECT_EQ(cache4, group->newest_complete_cache());  // newest unchanged
    166   group->RemoveCache(cache4.get());                   // newest removed
    167   EXPECT_FALSE(cache4->owning_group());
    168   EXPECT_FALSE(group->newest_complete_cache());       // no more newest cache
    169 
    170   // Can remove newest cache if there are older caches.
    171   group->AddCache(cache1.get());
    172   EXPECT_EQ(cache1, group->newest_complete_cache());
    173   group->AddCache(cache4.get());
    174   EXPECT_EQ(cache4, group->newest_complete_cache());
    175   group->RemoveCache(cache4.get());  // remove newest
    176   EXPECT_FALSE(cache4->owning_group());
    177   EXPECT_FALSE(group->newest_complete_cache());  // newest removed
    178 }
    179 
    180 TEST_F(AppCacheGroupTest, CleanupUnusedGroup) {
    181   MockAppCacheService service;
    182   TestAppCacheFrontend frontend;
    183   AppCacheGroup* group =
    184       new AppCacheGroup(service.storage(), GURL("http://foo.com"), 111);
    185 
    186   AppCacheHost host1(1, &frontend, &service);
    187   AppCacheHost host2(2, &frontend, &service);
    188 
    189   base::Time now = base::Time::Now();
    190 
    191   AppCache* cache1 = new AppCache(service.storage(), 111);
    192   cache1->set_complete(true);
    193   cache1->set_update_time(now);
    194   group->AddCache(cache1);
    195   EXPECT_EQ(cache1, group->newest_complete_cache());
    196 
    197   host1.AssociateCompleteCache(cache1);
    198   EXPECT_EQ(frontend.last_host_id_, host1.host_id());
    199   EXPECT_EQ(frontend.last_cache_id_, cache1->cache_id());
    200   EXPECT_EQ(frontend.last_status_, appcache::APPCACHE_STATUS_IDLE);
    201 
    202   host2.AssociateCompleteCache(cache1);
    203   EXPECT_EQ(frontend.last_host_id_, host2.host_id());
    204   EXPECT_EQ(frontend.last_cache_id_, cache1->cache_id());
    205   EXPECT_EQ(frontend.last_status_, appcache::APPCACHE_STATUS_IDLE);
    206 
    207   AppCache* cache2 = new AppCache(service.storage(), 222);
    208   cache2->set_complete(true);
    209   cache2->set_update_time(now + base::TimeDelta::FromDays(1));
    210   group->AddCache(cache2);
    211   EXPECT_EQ(cache2, group->newest_complete_cache());
    212 
    213   // Unassociate all hosts from older cache.
    214   host1.AssociateNoCache(GURL());
    215   host2.AssociateNoCache(GURL());
    216   EXPECT_EQ(frontend.last_host_id_, host2.host_id());
    217   EXPECT_EQ(frontend.last_cache_id_, appcache::kAppCacheNoCacheId);
    218   EXPECT_EQ(frontend.last_status_, appcache::APPCACHE_STATUS_UNCACHED);
    219 }
    220 
    221 TEST_F(AppCacheGroupTest, StartUpdate) {
    222   MockAppCacheService service;
    223   scoped_refptr<AppCacheGroup> group(
    224       new AppCacheGroup(service.storage(), GURL("http://foo.com"), 111));
    225 
    226   // Set state to checking to prevent update job from executing fetches.
    227   group->update_status_ = AppCacheGroup::CHECKING;
    228   group->StartUpdate();
    229   AppCacheUpdateJob* update = group->update_job_;
    230   EXPECT_TRUE(update != NULL);
    231 
    232   // Start another update, check that same update job is in use.
    233   group->StartUpdateWithHost(NULL);
    234   EXPECT_EQ(update, group->update_job_);
    235 
    236   // Deleting the update should restore the group to APPCACHE_STATUS_IDLE.
    237   delete update;
    238   EXPECT_TRUE(group->update_job_ == NULL);
    239   EXPECT_EQ(AppCacheGroup::IDLE, group->update_status());
    240 }
    241 
    242 TEST_F(AppCacheGroupTest, CancelUpdate) {
    243   MockAppCacheService service;
    244   scoped_refptr<AppCacheGroup> group(
    245       new AppCacheGroup(service.storage(), GURL("http://foo.com"), 111));
    246 
    247   // Set state to checking to prevent update job from executing fetches.
    248   group->update_status_ = AppCacheGroup::CHECKING;
    249   group->StartUpdate();
    250   AppCacheUpdateJob* update = group->update_job_;
    251   EXPECT_TRUE(update != NULL);
    252 
    253   // Deleting the group should cancel the update.
    254   TestUpdateObserver observer;
    255   group->AddUpdateObserver(&observer);
    256   group = NULL;  // causes group to be deleted
    257   EXPECT_TRUE(observer.update_completed_);
    258   EXPECT_FALSE(observer.group_has_cache_);
    259 }
    260 
    261 TEST_F(AppCacheGroupTest, QueueUpdate) {
    262   MockAppCacheService service;
    263   scoped_refptr<AppCacheGroup> group(
    264       new AppCacheGroup(service.storage(), GURL("http://foo.com"), 111));
    265 
    266   // Set state to checking to prevent update job from executing fetches.
    267   group->update_status_ = AppCacheGroup::CHECKING;
    268   group->StartUpdate();
    269   EXPECT_TRUE(group->update_job_);
    270 
    271   // Pretend group's update job is terminating so that next update is queued.
    272   group->update_job_->internal_state_ = AppCacheUpdateJob::REFETCH_MANIFEST;
    273   EXPECT_TRUE(group->update_job_->IsTerminating());
    274 
    275   TestAppCacheFrontend frontend;
    276   TestAppCacheHost host(1, &frontend, &service);
    277   host.new_master_entry_url_ = GURL("http://foo.com/bar.txt");
    278   group->StartUpdateWithNewMasterEntry(&host, host.new_master_entry_url_);
    279   EXPECT_FALSE(group->queued_updates_.empty());
    280 
    281   group->AddUpdateObserver(&host);
    282   EXPECT_FALSE(group->FindObserver(&host, group->observers_));
    283   EXPECT_TRUE(group->FindObserver(&host, group->queued_observers_));
    284 
    285   // Delete update to cause it to complete. Verify no update complete notice
    286   // sent to host.
    287   delete group->update_job_;
    288   EXPECT_EQ(AppCacheGroup::IDLE, group->update_status_);
    289   EXPECT_FALSE(group->restart_update_task_.IsCancelled());
    290   EXPECT_FALSE(host.update_completed_);
    291 
    292   // Start another update. Cancels task and will run queued updates.
    293   group->update_status_ = AppCacheGroup::CHECKING;  // prevent actual fetches
    294   group->StartUpdate();
    295   EXPECT_TRUE(group->update_job_);
    296   EXPECT_TRUE(group->restart_update_task_.IsCancelled());
    297   EXPECT_TRUE(group->queued_updates_.empty());
    298   EXPECT_FALSE(group->update_job_->pending_master_entries_.empty());
    299   EXPECT_FALSE(group->FindObserver(&host, group->queued_observers_));
    300   EXPECT_TRUE(group->FindObserver(&host, group->observers_));
    301 
    302   // Delete update to cause it to complete. Verify host is notified.
    303   delete group->update_job_;
    304   EXPECT_EQ(AppCacheGroup::IDLE, group->update_status_);
    305   EXPECT_TRUE(group->restart_update_task_.IsCancelled());
    306   EXPECT_TRUE(host.update_completed_);
    307 }
    308 
    309 }  // namespace content
    310