root/webkit/browser/appcache/appcache_group_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. last_status_
  2. OnCacheSelected
  3. OnStatusChanged
  4. OnEventRaised
  5. OnErrorEventRaised
  6. OnProgressEventRaised
  7. OnLogMessage
  8. OnContentBlocked
  9. group_has_cache_
  10. OnUpdateComplete
  11. OnContentBlocked
  12. update_completed_
  13. OnUpdateComplete
  14. TEST_F
  15. TEST_F
  16. TEST_F
  17. TEST_F
  18. TEST_F

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <string>

#include "base/message_loop/message_loop.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/browser/appcache/appcache.h"
#include "webkit/browser/appcache/appcache_group.h"
#include "webkit/browser/appcache/appcache_host.h"
#include "webkit/browser/appcache/appcache_update_job.h"
#include "webkit/browser/appcache/mock_appcache_service.h"
#include "webkit/common/appcache/appcache_interfaces.h"

namespace {

class TestAppCacheFrontend : public appcache::AppCacheFrontend {
 public:
  TestAppCacheFrontend()
      : last_host_id_(-1), last_cache_id_(-1),
        last_status_(appcache::OBSOLETE) {
  }

  virtual void OnCacheSelected(
      int host_id, const appcache::AppCacheInfo& info) OVERRIDE {
    last_host_id_ = host_id;
    last_cache_id_ = info.cache_id;
    last_status_ = info.status;
  }

  virtual void OnStatusChanged(const std::vector<int>& host_ids,
                               appcache::Status status) OVERRIDE {
  }

  virtual void OnEventRaised(const std::vector<int>& host_ids,
                             appcache::EventID event_id) OVERRIDE {
  }

  virtual void OnErrorEventRaised(const std::vector<int>& host_ids,
                                  const appcache::ErrorDetails& details)
      OVERRIDE {}

  virtual void OnProgressEventRaised(const std::vector<int>& host_ids,
                                     const GURL& url,
                                     int num_total, int num_complete) OVERRIDE {
  }

  virtual void OnLogMessage(int host_id, appcache::LogLevel log_level,
                            const std::string& message) OVERRIDE {
  }

  virtual void OnContentBlocked(int host_id,
                                const GURL& manifest_url) OVERRIDE {
  }

  int last_host_id_;
  int64 last_cache_id_;
  appcache::Status last_status_;
};

}  // namespace anon

namespace appcache {

class TestUpdateObserver : public AppCacheGroup::UpdateObserver {
 public:
  TestUpdateObserver() : update_completed_(false), group_has_cache_(false) {
  }

  virtual void OnUpdateComplete(AppCacheGroup* group) OVERRIDE {
    update_completed_ = true;
    group_has_cache_ = group->HasCache();
  }

  virtual void OnContentBlocked(AppCacheGroup* group) {
  }

  bool update_completed_;
  bool group_has_cache_;
};

class TestAppCacheHost : public AppCacheHost {
 public:
  TestAppCacheHost(int host_id, AppCacheFrontend* frontend,
                   AppCacheService* service)
      : AppCacheHost(host_id, frontend, service),
        update_completed_(false) {
  }

  virtual void OnUpdateComplete(AppCacheGroup* group) OVERRIDE {
    update_completed_ = true;
  }

  bool update_completed_;
};

class AppCacheGroupTest : public testing::Test {
 private:
  base::MessageLoop message_loop_;
};

TEST_F(AppCacheGroupTest, AddRemoveCache) {
  MockAppCacheService service;
  scoped_refptr<AppCacheGroup> group(
      new AppCacheGroup(service.storage(), GURL("http://foo.com"), 111));

  base::Time now = base::Time::Now();

  scoped_refptr<AppCache> cache1(new AppCache(service.storage(), 111));
  cache1->set_complete(true);
  cache1->set_update_time(now);
  group->AddCache(cache1.get());
  EXPECT_EQ(cache1, group->newest_complete_cache());

  // Adding older cache does not change newest complete cache.
  scoped_refptr<AppCache> cache2(new AppCache(service.storage(), 222));
  cache2->set_complete(true);
  cache2->set_update_time(now - base::TimeDelta::FromDays(1));
  group->AddCache(cache2.get());
  EXPECT_EQ(cache1, group->newest_complete_cache());

  // Adding newer cache does change newest complete cache.
  scoped_refptr<AppCache> cache3(new AppCache(service.storage(), 333));
  cache3->set_complete(true);
  cache3->set_update_time(now + base::TimeDelta::FromDays(1));
  group->AddCache(cache3.get());
  EXPECT_EQ(cache3, group->newest_complete_cache());

  // Adding cache with same update time uses one with larger ID.
  scoped_refptr<AppCache> cache4(new AppCache(service.storage(), 444));
  cache4->set_complete(true);
  cache4->set_update_time(now + base::TimeDelta::FromDays(1));  // same as 3
  group->AddCache(cache4.get());
  EXPECT_EQ(cache4, group->newest_complete_cache());

  // smaller id
  scoped_refptr<AppCache> cache5(new AppCache(service.storage(), 55));
  cache5->set_complete(true);
  cache5->set_update_time(now + base::TimeDelta::FromDays(1));  // same as 4
  group->AddCache(cache5.get());
  EXPECT_EQ(cache4, group->newest_complete_cache());  // no change

  // Old caches can always be removed.
  group->RemoveCache(cache1.get());
  EXPECT_FALSE(cache1->owning_group());
  EXPECT_EQ(cache4, group->newest_complete_cache());  // newest unchanged

  // Remove rest of caches.
  group->RemoveCache(cache2.get());
  EXPECT_FALSE(cache2->owning_group());
  EXPECT_EQ(cache4, group->newest_complete_cache());  // newest unchanged
  group->RemoveCache(cache3.get());
  EXPECT_FALSE(cache3->owning_group());
  EXPECT_EQ(cache4, group->newest_complete_cache());  // newest unchanged
  group->RemoveCache(cache5.get());
  EXPECT_FALSE(cache5->owning_group());
  EXPECT_EQ(cache4, group->newest_complete_cache());  // newest unchanged
  group->RemoveCache(cache4.get());                   // newest removed
  EXPECT_FALSE(cache4->owning_group());
  EXPECT_FALSE(group->newest_complete_cache());       // no more newest cache

  // Can remove newest cache if there are older caches.
  group->AddCache(cache1.get());
  EXPECT_EQ(cache1, group->newest_complete_cache());
  group->AddCache(cache4.get());
  EXPECT_EQ(cache4, group->newest_complete_cache());
  group->RemoveCache(cache4.get());  // remove newest
  EXPECT_FALSE(cache4->owning_group());
  EXPECT_FALSE(group->newest_complete_cache());  // newest removed
}

TEST_F(AppCacheGroupTest, CleanupUnusedGroup) {
  MockAppCacheService service;
  TestAppCacheFrontend frontend;
  AppCacheGroup* group =
      new AppCacheGroup(service.storage(), GURL("http://foo.com"), 111);

  AppCacheHost host1(1, &frontend, &service);
  AppCacheHost host2(2, &frontend, &service);

  base::Time now = base::Time::Now();

  AppCache* cache1 = new AppCache(service.storage(), 111);
  cache1->set_complete(true);
  cache1->set_update_time(now);
  group->AddCache(cache1);
  EXPECT_EQ(cache1, group->newest_complete_cache());

  host1.AssociateCompleteCache(cache1);
  EXPECT_EQ(frontend.last_host_id_, host1.host_id());
  EXPECT_EQ(frontend.last_cache_id_, cache1->cache_id());
  EXPECT_EQ(frontend.last_status_, appcache::IDLE);

  host2.AssociateCompleteCache(cache1);
  EXPECT_EQ(frontend.last_host_id_, host2.host_id());
  EXPECT_EQ(frontend.last_cache_id_, cache1->cache_id());
  EXPECT_EQ(frontend.last_status_, appcache::IDLE);

  AppCache* cache2 = new AppCache(service.storage(), 222);
  cache2->set_complete(true);
  cache2->set_update_time(now + base::TimeDelta::FromDays(1));
  group->AddCache(cache2);
  EXPECT_EQ(cache2, group->newest_complete_cache());

  // Unassociate all hosts from older cache.
  host1.AssociateNoCache(GURL());
  host2.AssociateNoCache(GURL());
  EXPECT_EQ(frontend.last_host_id_, host2.host_id());
  EXPECT_EQ(frontend.last_cache_id_, appcache::kNoCacheId);
  EXPECT_EQ(frontend.last_status_, appcache::UNCACHED);
}

TEST_F(AppCacheGroupTest, StartUpdate) {
  MockAppCacheService service;
  scoped_refptr<AppCacheGroup> group(
      new AppCacheGroup(service.storage(), GURL("http://foo.com"), 111));

  // Set state to checking to prevent update job from executing fetches.
  group->update_status_ = AppCacheGroup::CHECKING;
  group->StartUpdate();
  AppCacheUpdateJob* update = group->update_job_;
  EXPECT_TRUE(update != NULL);

  // Start another update, check that same update job is in use.
  group->StartUpdateWithHost(NULL);
  EXPECT_EQ(update, group->update_job_);

  // Deleting the update should restore the group to IDLE.
  delete update;
  EXPECT_TRUE(group->update_job_ == NULL);
  EXPECT_EQ(AppCacheGroup::IDLE, group->update_status());
}

TEST_F(AppCacheGroupTest, CancelUpdate) {
  MockAppCacheService service;
  scoped_refptr<AppCacheGroup> group(
      new AppCacheGroup(service.storage(), GURL("http://foo.com"), 111));

  // Set state to checking to prevent update job from executing fetches.
  group->update_status_ = AppCacheGroup::CHECKING;
  group->StartUpdate();
  AppCacheUpdateJob* update = group->update_job_;
  EXPECT_TRUE(update != NULL);

  // Deleting the group should cancel the update.
  TestUpdateObserver observer;
  group->AddUpdateObserver(&observer);
  group = NULL;  // causes group to be deleted
  EXPECT_TRUE(observer.update_completed_);
  EXPECT_FALSE(observer.group_has_cache_);
}

TEST_F(AppCacheGroupTest, QueueUpdate) {
  MockAppCacheService service;
  scoped_refptr<AppCacheGroup> group(
      new AppCacheGroup(service.storage(), GURL("http://foo.com"), 111));

  // Set state to checking to prevent update job from executing fetches.
  group->update_status_ = AppCacheGroup::CHECKING;
  group->StartUpdate();
  EXPECT_TRUE(group->update_job_);

  // Pretend group's update job is terminating so that next update is queued.
  group->update_job_->internal_state_ = AppCacheUpdateJob::REFETCH_MANIFEST;
  EXPECT_TRUE(group->update_job_->IsTerminating());

  TestAppCacheFrontend frontend;
  TestAppCacheHost host(1, &frontend, &service);
  host.new_master_entry_url_ = GURL("http://foo.com/bar.txt");
  group->StartUpdateWithNewMasterEntry(&host, host.new_master_entry_url_);
  EXPECT_FALSE(group->queued_updates_.empty());

  group->AddUpdateObserver(&host);
  EXPECT_FALSE(group->FindObserver(&host, group->observers_));
  EXPECT_TRUE(group->FindObserver(&host, group->queued_observers_));

  // Delete update to cause it to complete. Verify no update complete notice
  // sent to host.
  delete group->update_job_;
  EXPECT_EQ(AppCacheGroup::IDLE, group->update_status_);
  EXPECT_FALSE(group->restart_update_task_.IsCancelled());
  EXPECT_FALSE(host.update_completed_);

  // Start another update. Cancels task and will run queued updates.
  group->update_status_ = AppCacheGroup::CHECKING;  // prevent actual fetches
  group->StartUpdate();
  EXPECT_TRUE(group->update_job_);
  EXPECT_TRUE(group->restart_update_task_.IsCancelled());
  EXPECT_TRUE(group->queued_updates_.empty());
  EXPECT_FALSE(group->update_job_->pending_master_entries_.empty());
  EXPECT_FALSE(group->FindObserver(&host, group->queued_observers_));
  EXPECT_TRUE(group->FindObserver(&host, group->observers_));

  // Delete update to cause it to complete. Verify host is notified.
  delete group->update_job_;
  EXPECT_EQ(AppCacheGroup::IDLE, group->update_status_);
  EXPECT_TRUE(group->restart_update_task_.IsCancelled());
  EXPECT_TRUE(host.update_completed_);
}

}  // namespace appcache

/* [<][>][^][v][top][bottom][index][help] */