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