summaryrefslogtreecommitdiffstats
path: root/components/update_client/test
diff options
context:
space:
mode:
Diffstat (limited to 'components/update_client/test')
-rw-r--r--components/update_client/test/DEPS2
-rw-r--r--components/update_client/test/crx_downloader_unittest.cc8
-rw-r--r--components/update_client/test/ping_manager_unittest.cc19
-rw-r--r--components/update_client/test/request_sender_unittest.cc9
-rw-r--r--components/update_client/test/test_configurator.cc4
-rw-r--r--components/update_client/test/test_configurator.h6
-rw-r--r--components/update_client/test/test_installer.h3
-rw-r--r--components/update_client/test/update_checker_unittest.cc10
-rw-r--r--components/update_client/test/update_client_unittest.cc1417
9 files changed, 1454 insertions, 24 deletions
diff --git a/components/update_client/test/DEPS b/components/update_client/test/DEPS
index 60dbcf4..d0c36c4 100644
--- a/components/update_client/test/DEPS
+++ b/components/update_client/test/DEPS
@@ -1,3 +1,5 @@
include_rules = [
"+content",
+ "+courgette",
+ "+net",
]
diff --git a/components/update_client/test/crx_downloader_unittest.cc b/components/update_client/test/crx_downloader_unittest.cc
index 5b01b42..4b80f13 100644
--- a/components/update_client/test/crx_downloader_unittest.cc
+++ b/components/update_client/test/crx_downloader_unittest.cc
@@ -113,10 +113,10 @@ void CrxDownloaderTest::SetUp() {
num_progress_calls_ = 0;
download_progress_result_ = CrxDownloader::Result();
- crx_downloader_.reset(CrxDownloader::Create(
- false, // Do not use the background downloader in these tests.
- context_.get(), base::MessageLoopProxy::current(),
- NULL)); // No |background_task_runner| because no background downloader.
+ // Do not use the background downloader in these tests.
+ crx_downloader_.reset(CrxDownloader::Create(false, context_.get(),
+ base::MessageLoopProxy::current(),
+ NULL).release());
crx_downloader_->set_progress_callback(progress_callback_);
get_interceptor_.reset(new GetInterceptor(base::MessageLoopProxy::current(),
diff --git a/components/update_client/test/ping_manager_unittest.cc b/components/update_client/test/ping_manager_unittest.cc
index 95539f03..23308ac 100644
--- a/components/update_client/test/ping_manager_unittest.cc
+++ b/components/update_client/test/ping_manager_unittest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
@@ -29,25 +30,25 @@ class ComponentUpdaterPingManagerTest : public testing::Test {
void TearDown() override;
protected:
- scoped_ptr<TestConfigurator> config_;
+ scoped_refptr<TestConfigurator> config_;
scoped_ptr<PingManager> ping_manager_;
private:
base::MessageLoopForIO loop_;
};
-ComponentUpdaterPingManagerTest::ComponentUpdaterPingManagerTest()
- : config_(new TestConfigurator(base::MessageLoopProxy::current(),
- base::MessageLoopProxy::current())) {
+ComponentUpdaterPingManagerTest::ComponentUpdaterPingManagerTest() {
}
void ComponentUpdaterPingManagerTest::SetUp() {
+ config_ = new TestConfigurator(base::MessageLoopProxy::current(),
+ base::MessageLoopProxy::current());
ping_manager_.reset(new PingManager(*config_));
}
void ComponentUpdaterPingManagerTest::TearDown() {
ping_manager_.reset();
- config_.reset();
+ config_ = nullptr;
}
void ComponentUpdaterPingManagerTest::RunThreadsUntilIdle() {
@@ -65,7 +66,7 @@ TEST_F(ComponentUpdaterPingManagerTest, DISABLED_PingManagerTest) {
// Test eventresult="1" is sent for successful updates.
CrxUpdateItem item;
item.id = "abc";
- item.status = CrxUpdateItem::kUpdated;
+ item.state = CrxUpdateItem::State::kUpdated;
item.previous_version = base::Version("1.0");
item.next_version = base::Version("2.0");
@@ -83,7 +84,7 @@ TEST_F(ComponentUpdaterPingManagerTest, DISABLED_PingManagerTest) {
// Test eventresult="0" is sent for failed updates.
item = CrxUpdateItem();
item.id = "abc";
- item.status = CrxUpdateItem::kNoUpdate;
+ item.state = CrxUpdateItem::State::kNoUpdate;
item.previous_version = base::Version("1.0");
item.next_version = base::Version("2.0");
@@ -101,7 +102,7 @@ TEST_F(ComponentUpdaterPingManagerTest, DISABLED_PingManagerTest) {
// Test the error values and the fingerprints.
item = CrxUpdateItem();
item.id = "abc";
- item.status = CrxUpdateItem::kNoUpdate;
+ item.state = CrxUpdateItem::State::kNoUpdate;
item.previous_version = base::Version("1.0");
item.next_version = base::Version("2.0");
item.previous_fp = "prev fp";
@@ -133,7 +134,7 @@ TEST_F(ComponentUpdaterPingManagerTest, DISABLED_PingManagerTest) {
// Test the download metrics.
item = CrxUpdateItem();
item.id = "abc";
- item.status = CrxUpdateItem::kUpdated;
+ item.state = CrxUpdateItem::State::kUpdated;
item.previous_version = base::Version("1.0");
item.next_version = base::Version("2.0");
diff --git a/components/update_client/test/request_sender_unittest.cc b/components/update_client/test/request_sender_unittest.cc
index f8ad042..35d4487 100644
--- a/components/update_client/test/request_sender_unittest.cc
+++ b/components/update_client/test/request_sender_unittest.cc
@@ -4,6 +4,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
@@ -40,7 +41,7 @@ class RequestSenderTest : public testing::Test {
void RunThreads();
void RunThreadsUntilIdle();
- scoped_ptr<TestConfigurator> config_;
+ scoped_refptr<TestConfigurator> config_;
scoped_ptr<RequestSender> request_sender_;
scoped_ptr<InterceptorFactory> interceptor_factory_;
@@ -66,8 +67,8 @@ RequestSenderTest::~RequestSenderTest() {
}
void RequestSenderTest::SetUp() {
- config_.reset(new TestConfigurator(base::MessageLoopProxy::current(),
- base::MessageLoopProxy::current()));
+ config_ = new TestConfigurator(base::MessageLoopProxy::current(),
+ base::MessageLoopProxy::current());
interceptor_factory_.reset(
new InterceptorFactory(base::MessageLoopProxy::current()));
post_interceptor_1 =
@@ -88,7 +89,7 @@ void RequestSenderTest::TearDown() {
interceptor_factory_.reset();
- config_.reset();
+ config_ = nullptr;
RunThreadsUntilIdle();
}
diff --git a/components/update_client/test/test_configurator.cc b/components/update_client/test/test_configurator.cc
index 27aaf5f..23eaeff 100644
--- a/components/update_client/test/test_configurator.cc
+++ b/components/update_client/test/test_configurator.cc
@@ -68,6 +68,10 @@ int TestConfigurator::OnDemandDelay() const {
return ondemand_time_;
}
+int TestConfigurator::UpdateDelay() const {
+ return 1;
+}
+
std::vector<GURL> TestConfigurator::UpdateUrl() const {
return MakeDefaultUrls();
}
diff --git a/components/update_client/test/test_configurator.h b/components/update_client/test/test_configurator.h
index 4943cca..6c2ed0e 100644
--- a/components/update_client/test/test_configurator.h
+++ b/components/update_client/test/test_configurator.h
@@ -55,7 +55,6 @@ class TestConfigurator : public Configurator {
TestConfigurator(
const scoped_refptr<base::SequencedTaskRunner>& worker_task_runner,
const scoped_refptr<base::SingleThreadTaskRunner>& network_task_runner);
- ~TestConfigurator() override;
// Overrrides for Configurator.
int InitialDelay() const override;
@@ -64,6 +63,7 @@ class TestConfigurator : public Configurator {
int StepDelayMedium() override;
int MinimumReCheckWait() const override;
int OnDemandDelay() const override;
+ int UpdateDelay() const override;
std::vector<GURL> UpdateUrl() const override;
std::vector<GURL> PingUrl() const override;
base::Version GetBrowserVersion() const override;
@@ -88,6 +88,10 @@ class TestConfigurator : public Configurator {
void SetInitialDelay(int seconds);
private:
+ friend class base::RefCountedThreadSafe<TestConfigurator>;
+
+ ~TestConfigurator() override;
+
scoped_refptr<base::SequencedTaskRunner> worker_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_;
diff --git a/components/update_client/test/test_installer.h b/components/update_client/test/test_installer.h
index a31c499..e15ae0a 100644
--- a/components/update_client/test/test_installer.h
+++ b/components/update_client/test/test_installer.h
@@ -17,9 +17,10 @@ class DictionaryValue;
namespace update_client {
+// TODO(sorin): consider reducing the number of the installer mocks.
// A TestInstaller is an installer that does nothing for installation except
// increment a counter.
-class TestInstaller : public ComponentInstaller {
+class TestInstaller : public CrxInstaller {
public:
TestInstaller();
diff --git a/components/update_client/test/update_checker_unittest.cc b/components/update_client/test/update_checker_unittest.cc
index 20d3e79..ce6922a 100644
--- a/components/update_client/test/update_checker_unittest.cc
+++ b/components/update_client/test/update_checker_unittest.cc
@@ -60,7 +60,7 @@ class UpdateCheckerTest : public testing::Test {
CrxUpdateItem BuildCrxUpdateItem();
- scoped_ptr<TestConfigurator> config_;
+ scoped_refptr<TestConfigurator> config_;
scoped_ptr<UpdateChecker> update_checker_;
@@ -86,8 +86,8 @@ UpdateCheckerTest::~UpdateCheckerTest() {
}
void UpdateCheckerTest::SetUp() {
- config_.reset(new TestConfigurator(base::MessageLoopProxy::current(),
- base::MessageLoopProxy::current()));
+ config_ = new TestConfigurator(base::MessageLoopProxy::current(),
+ base::MessageLoopProxy::current());
interceptor_factory_.reset(
new InterceptorFactory(base::MessageLoopProxy::current()));
post_interceptor_ = interceptor_factory_->CreateInterceptor();
@@ -106,7 +106,7 @@ void UpdateCheckerTest::TearDown() {
post_interceptor_ = NULL;
interceptor_factory_.reset();
- config_.reset();
+ config_ = nullptr;
// The PostInterceptor requires the message loop to run to destruct correctly.
// TODO(sorin): This is fragile and should be fixed.
@@ -155,7 +155,7 @@ CrxUpdateItem UpdateCheckerTest::BuildCrxUpdateItem() {
crx_component.fingerprint = "fp1";
CrxUpdateItem crx_update_item;
- crx_update_item.status = CrxUpdateItem::kNew;
+ crx_update_item.state = CrxUpdateItem::State::kNew;
crx_update_item.id = "jebgalgnebhfojomionfpkfelancnnkf";
crx_update_item.component = crx_component;
diff --git a/components/update_client/test/update_client_unittest.cc b/components/update_client/test/update_client_unittest.cc
new file mode 100644
index 0000000..dbff673
--- /dev/null
+++ b/components/update_client/test/update_client_unittest.cc
@@ -0,0 +1,1417 @@
+// Copyright 2015 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 "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/values.h"
+#include "base/version.h"
+#include "components/update_client/crx_update_item.h"
+#include "components/update_client/ping_manager.h"
+#include "components/update_client/test/test_configurator.h"
+#include "components/update_client/test/test_installer.h"
+#include "components/update_client/update_checker.h"
+#include "components/update_client/update_client_internal.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace update_client {
+
+namespace {
+
+using base::FilePath;
+
+// Makes a copy of the file specified by |from_path| in a temporary directory
+// and returns the path of the copy. Returns true if successful. Cleans up if
+// there was an error creating the copy.
+bool MakeTestFile(const FilePath& from_path, FilePath* to_path) {
+ FilePath path;
+ bool result = CreateTemporaryFile(&path);
+ if (!result)
+ return false;
+
+ result = CopyFile(from_path, path);
+ if (!result) {
+ DeleteFile(path, false);
+ return result;
+ }
+
+ *to_path = path;
+ return true;
+}
+
+using Events = UpdateClient::Observer::Events;
+
+class MockObserver : public UpdateClient::Observer {
+ public:
+ MOCK_METHOD2(OnEvent, void(Events event, const std::string&));
+};
+
+class FakePingManagerImpl : public PingManager {
+ public:
+ explicit FakePingManagerImpl(const Configurator& config);
+ ~FakePingManagerImpl() override;
+
+ void OnUpdateComplete(const CrxUpdateItem* item) override;
+
+ const std::vector<CrxUpdateItem>& items() const;
+
+ private:
+ std::vector<CrxUpdateItem> items_;
+ DISALLOW_COPY_AND_ASSIGN(FakePingManagerImpl);
+};
+
+FakePingManagerImpl::FakePingManagerImpl(const Configurator& config)
+ : PingManager(config) {
+}
+
+FakePingManagerImpl::~FakePingManagerImpl() {
+}
+
+void FakePingManagerImpl::OnUpdateComplete(const CrxUpdateItem* item) {
+ items_.push_back(*item);
+}
+
+const std::vector<CrxUpdateItem>& FakePingManagerImpl::items() const {
+ return items_;
+}
+
+} // namespace
+
+using ::testing::_;
+using ::testing::AnyNumber;
+using ::testing::DoAll;
+using ::testing::InSequence;
+using ::testing::Invoke;
+using ::testing::Mock;
+using ::testing::Return;
+
+using content::BrowserThread;
+
+using std::string;
+
+class UpdateClientTest : public testing::Test {
+ public:
+ UpdateClientTest();
+ ~UpdateClientTest() override;
+
+ void SetUp() override;
+ void TearDown() override;
+
+ protected:
+ void RunThreads();
+
+ // Returns the full path to a test file.
+ static base::FilePath TestFilePath(const char* file);
+
+ content::TestBrowserThreadBundle thread_bundle_;
+
+ base::RunLoop runloop_;
+ base::Closure quit_closure_;
+
+ scoped_refptr<update_client::TestConfigurator> config_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(UpdateClientTest);
+};
+
+UpdateClientTest::UpdateClientTest()
+ : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
+ config_(new TestConfigurator(
+ BrowserThread::GetBlockingPool()
+ ->GetSequencedTaskRunnerWithShutdownBehavior(
+ BrowserThread::GetBlockingPool()->GetSequenceToken(),
+ base::SequencedWorkerPool::SKIP_ON_SHUTDOWN),
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO))) {
+}
+
+UpdateClientTest::~UpdateClientTest() {
+}
+
+void UpdateClientTest::SetUp() {
+ quit_closure_ = runloop_.QuitClosure();
+}
+
+void UpdateClientTest::TearDown() {
+}
+
+void UpdateClientTest::RunThreads() {
+ runloop_.Run();
+}
+
+base::FilePath UpdateClientTest::TestFilePath(const char* file) {
+ base::FilePath path;
+ PathService::Get(base::DIR_SOURCE_ROOT, &path);
+ return path.AppendASCII("components")
+ .AppendASCII("test")
+ .AppendASCII("data")
+ .AppendASCII("update_client")
+ .AppendASCII(file);
+}
+
+// Tests the scenario where one update check is done for one CRX. The CRX
+// has no update.
+TEST_F(UpdateClientTest, OneCrxNoUpdate) {
+ class DataCallbackFake {
+ public:
+ static void Callback(const std::vector<std::string>& ids,
+ std::vector<CrxComponent>* components) {
+ CrxComponent crx;
+ crx.name = "test_jebg";
+ crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
+ crx.version = Version("0.9");
+ crx.installer = new TestInstaller;
+ components->push_back(crx);
+ }
+ };
+
+ class CompletionCallbackFake {
+ public:
+ static void Callback(const base::Closure& quit_closure, int error) {
+ EXPECT_EQ(0, error);
+ quit_closure.Run();
+ }
+ };
+
+ class FakeUpdateChecker : public UpdateChecker {
+ public:
+ static scoped_ptr<UpdateChecker> Create(const Configurator& config) {
+ return scoped_ptr<UpdateChecker>(new FakeUpdateChecker());
+ }
+
+ bool CheckForUpdates(
+ const std::vector<CrxUpdateItem*>& items_to_check,
+ const std::string& additional_attributes,
+ const UpdateCheckCallback& update_check_callback) override {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(update_check_callback, GURL(), 0, "",
+ UpdateResponse::Results()));
+ return true;
+ }
+ };
+
+ class FakeCrxDownloader : public CrxDownloader {
+ public:
+ static scoped_ptr<CrxDownloader> Create(
+ bool is_background_download,
+ net::URLRequestContextGetter* context_getter,
+ const scoped_refptr<base::SequencedTaskRunner>& url_fetcher_task_runner,
+ const scoped_refptr<base::SingleThreadTaskRunner>&
+ background_task_runner) {
+ return scoped_ptr<CrxDownloader>(new FakeCrxDownloader());
+ }
+
+ private:
+ FakeCrxDownloader() : CrxDownloader(scoped_ptr<CrxDownloader>().Pass()) {}
+ ~FakeCrxDownloader() override {}
+
+ void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
+ };
+
+ class FakePingManager : public FakePingManagerImpl {
+ public:
+ explicit FakePingManager(const Configurator& config)
+ : FakePingManagerImpl(config) {}
+ ~FakePingManager() override { EXPECT_TRUE(items().empty()); }
+ };
+
+ scoped_ptr<PingManager> ping_manager(new FakePingManager(*config_));
+ scoped_ptr<UpdateClient> update_client(new UpdateClientImpl(
+ config_, ping_manager.Pass(), &FakeUpdateChecker::Create,
+ &FakeCrxDownloader::Create));
+
+ MockObserver observer;
+ InSequence seq;
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
+ "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
+ "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
+
+ update_client->AddObserver(&observer);
+
+ std::vector<std::string> ids;
+ ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf"));
+
+ update_client->Update(
+ ids, base::Bind(&DataCallbackFake::Callback),
+ base::Bind(&CompletionCallbackFake::Callback, quit_closure_));
+
+ RunThreads();
+
+ update_client->RemoveObserver(&observer);
+}
+
+// Tests the scenario where two CRXs are checked for updates. On CRX has
+// an update, the other CRX does not.
+TEST_F(UpdateClientTest, TwoCrxUpdateNoUpdate) {
+ class DataCallbackFake {
+ public:
+ static void Callback(const std::vector<std::string>& ids,
+ std::vector<CrxComponent>* components) {
+ CrxComponent crx1;
+ crx1.name = "test_jebg";
+ crx1.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
+ crx1.version = Version("0.9");
+ crx1.installer = new TestInstaller;
+
+ CrxComponent crx2;
+ crx2.name = "test_abag";
+ crx2.pk_hash.assign(abag_hash, abag_hash + arraysize(abag_hash));
+ crx2.version = Version("2.2");
+ crx2.installer = new TestInstaller;
+
+ components->push_back(crx1);
+ components->push_back(crx2);
+ }
+ };
+
+ class CompletionCallbackFake {
+ public:
+ static void Callback(const base::Closure& quit_closure, int error) {
+ EXPECT_EQ(0, error);
+ quit_closure.Run();
+ }
+ };
+
+ class FakeUpdateChecker : public UpdateChecker {
+ public:
+ static scoped_ptr<UpdateChecker> Create(const Configurator& config) {
+ return scoped_ptr<UpdateChecker>(new FakeUpdateChecker());
+ }
+
+ bool CheckForUpdates(
+ const std::vector<CrxUpdateItem*>& items_to_check,
+ const std::string& additional_attributes,
+ const UpdateCheckCallback& update_check_callback) override {
+ /*
+ Fake the following response:
+
+ <?xml version='1.0' encoding='UTF-8'?>
+ <response protocol='3.0'>
+ <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
+ <updatecheck status='ok'>
+ <urls>
+ <url codebase='http://localhost/download/'/>
+ </urls>
+ <manifest version='1.0' prodversionmin='11.0.1.0'>
+ <packages>
+ <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'/>
+ </packages>
+ </manifest>
+ </updatecheck>
+ </app>
+ </response>
+ */
+ UpdateResponse::Result::Manifest::Package package;
+ package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
+
+ UpdateResponse::Result result;
+ result.extension_id = "jebgalgnebhfojomionfpkfelancnnkf";
+ result.crx_urls.push_back(GURL("http://localhost/download/"));
+ result.manifest.version = "1.0";
+ result.manifest.browser_min_version = "11.0.1.0";
+ result.manifest.packages.push_back(package);
+
+ UpdateResponse::Results results;
+ results.list.push_back(result);
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(update_check_callback, GURL(), 0, "", results));
+ return true;
+ }
+ };
+
+ class FakeCrxDownloader : public CrxDownloader {
+ public:
+ static scoped_ptr<CrxDownloader> Create(
+ bool is_background_download,
+ net::URLRequestContextGetter* context_getter,
+ const scoped_refptr<base::SequencedTaskRunner>& url_fetcher_task_runner,
+ const scoped_refptr<base::SingleThreadTaskRunner>&
+ background_task_runner) {
+ return scoped_ptr<CrxDownloader>(new FakeCrxDownloader());
+ }
+
+ private:
+ FakeCrxDownloader() : CrxDownloader(scoped_ptr<CrxDownloader>().Pass()) {}
+ ~FakeCrxDownloader() override {}
+
+ void DoStartDownload(const GURL& url) override {
+ DownloadMetrics download_metrics;
+ download_metrics.url = url;
+ download_metrics.downloader = DownloadMetrics::kNone;
+ download_metrics.error = 0;
+ download_metrics.downloaded_bytes = 1843;
+ download_metrics.total_bytes = 1843;
+ download_metrics.download_time_ms = 1000;
+
+ FilePath path;
+ EXPECT_TRUE(MakeTestFile(
+ TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
+
+ Result result;
+ result.error = 0;
+ result.response = path;
+ result.downloaded_bytes = 1843;
+ result.total_bytes = 1843;
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
+ base::Unretained(this), result));
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&FakeCrxDownloader::OnDownloadComplete,
+ base::Unretained(this), true, result, download_metrics));
+ }
+ };
+
+ class FakePingManager : public FakePingManagerImpl {
+ public:
+ explicit FakePingManager(const Configurator& config)
+ : FakePingManagerImpl(config) {}
+ ~FakePingManager() override {
+ const auto& ping_items = items();
+ EXPECT_EQ(1U, ping_items.size());
+ EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id);
+ EXPECT_TRUE(base::Version("0.9").Equals(ping_items[0].previous_version));
+ EXPECT_TRUE(base::Version("1.0").Equals(ping_items[0].next_version));
+ EXPECT_EQ(0, ping_items[0].error_category);
+ EXPECT_EQ(0, ping_items[0].error_code);
+ }
+ };
+
+ scoped_ptr<PingManager> ping_manager(new FakePingManager(*config_));
+ scoped_ptr<UpdateClient> update_client(new UpdateClientImpl(
+ config_, ping_manager.Pass(), &FakeUpdateChecker::Create,
+ &FakeCrxDownloader::Create));
+
+ MockObserver observer;
+ {
+ InSequence seq;
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
+ "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
+ "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
+ "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
+ "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
+ "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
+ }
+ {
+ InSequence seq;
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
+ "abagagagagagagagagagagagagagagag")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
+ "abagagagagagagagagagagagagagagag")).Times(1);
+ }
+
+ update_client->AddObserver(&observer);
+
+ std::vector<std::string> ids;
+ ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf"));
+ ids.push_back(std::string("abagagagagagagagagagagagagagagag"));
+
+ update_client->Update(
+ ids, base::Bind(&DataCallbackFake::Callback),
+ base::Bind(&CompletionCallbackFake::Callback, quit_closure_));
+
+ RunThreads();
+
+ update_client->RemoveObserver(&observer);
+}
+
+// Tests the update check for two CRXs scenario. Both CRXs have updates.
+TEST_F(UpdateClientTest, TwoCrxUpdate) {
+ class DataCallbackFake {
+ public:
+ static void Callback(const std::vector<std::string>& ids,
+ std::vector<CrxComponent>* components) {
+ CrxComponent crx1;
+ crx1.name = "test_jebg";
+ crx1.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
+ crx1.version = Version("0.9");
+ crx1.installer = new TestInstaller;
+
+ CrxComponent crx2;
+ crx2.name = "test_ihfo";
+ crx2.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
+ crx2.version = Version("0.8");
+ crx2.installer = new TestInstaller;
+
+ components->push_back(crx1);
+ components->push_back(crx2);
+ }
+ };
+
+ class CompletionCallbackFake {
+ public:
+ static void Callback(const base::Closure& quit_closure, int error) {
+ EXPECT_EQ(0, error);
+ quit_closure.Run();
+ }
+ };
+
+ class FakeUpdateChecker : public UpdateChecker {
+ public:
+ static scoped_ptr<UpdateChecker> Create(const Configurator& config) {
+ return scoped_ptr<UpdateChecker>(new FakeUpdateChecker());
+ }
+
+ bool CheckForUpdates(
+ const std::vector<CrxUpdateItem*>& items_to_check,
+ const std::string& additional_attributes,
+ const UpdateCheckCallback& update_check_callback) override {
+ /*
+ Fake the following response:
+
+ <?xml version='1.0' encoding='UTF-8'?>
+ <response protocol='3.0'>
+ <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
+ <updatecheck status='ok'>
+ <urls>
+ <url codebase='http://localhost/download/'/>
+ </urls>
+ <manifest version='1.0' prodversionmin='11.0.1.0'>
+ <packages>
+ <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'/>
+ </packages>
+ </manifest>
+ </updatecheck>
+ </app>
+ <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
+ <updatecheck status='ok'>
+ <urls>
+ <url codebase='http://localhost/download/'/>
+ </urls>
+ <manifest version='1.0' prodversionmin='11.0.1.0'>
+ <packages>
+ <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'/>
+ </packages>
+ </manifest>
+ </updatecheck>
+ </app>
+ </response>
+ */
+ UpdateResponse::Result::Manifest::Package package1;
+ package1.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
+
+ UpdateResponse::Result result1;
+ result1.extension_id = "jebgalgnebhfojomionfpkfelancnnkf";
+ result1.crx_urls.push_back(GURL("http://localhost/download/"));
+ result1.manifest.version = "1.0";
+ result1.manifest.browser_min_version = "11.0.1.0";
+ result1.manifest.packages.push_back(package1);
+
+ UpdateResponse::Result::Manifest::Package package2;
+ package2.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
+
+ UpdateResponse::Result result2;
+ result2.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc";
+ result2.crx_urls.push_back(GURL("http://localhost/download/"));
+ result2.manifest.version = "1.0";
+ result2.manifest.browser_min_version = "11.0.1.0";
+ result2.manifest.packages.push_back(package2);
+
+ UpdateResponse::Results results;
+ results.list.push_back(result1);
+ results.list.push_back(result2);
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(update_check_callback, GURL(), 0, "", results));
+ return true;
+ }
+ };
+
+ class FakeCrxDownloader : public CrxDownloader {
+ public:
+ static scoped_ptr<CrxDownloader> Create(
+ bool is_background_download,
+ net::URLRequestContextGetter* context_getter,
+ const scoped_refptr<base::SequencedTaskRunner>& url_fetcher_task_runner,
+ const scoped_refptr<base::SingleThreadTaskRunner>&
+ background_task_runner) {
+ return scoped_ptr<CrxDownloader>(new FakeCrxDownloader());
+ }
+
+ private:
+ FakeCrxDownloader() : CrxDownloader(scoped_ptr<CrxDownloader>().Pass()) {}
+ ~FakeCrxDownloader() override {}
+
+ void DoStartDownload(const GURL& url) override {
+ DownloadMetrics download_metrics;
+ FilePath path;
+ Result result;
+ if (url.path() == "/download/jebgalgnebhfojomionfpkfelancnnkf.crx") {
+ download_metrics.url = url;
+ download_metrics.downloader = DownloadMetrics::kNone;
+ download_metrics.error = 0;
+ download_metrics.downloaded_bytes = 1843;
+ download_metrics.total_bytes = 1843;
+ download_metrics.download_time_ms = 1000;
+
+ EXPECT_TRUE(MakeTestFile(
+ TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
+
+ result.error = 0;
+ result.response = path;
+ result.downloaded_bytes = 1843;
+ result.total_bytes = 1843;
+ } else if (url.path() ==
+ "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
+ download_metrics.url = url;
+ download_metrics.downloader = DownloadMetrics::kNone;
+ download_metrics.error = 0;
+ download_metrics.downloaded_bytes = 53638;
+ download_metrics.total_bytes = 53638;
+ download_metrics.download_time_ms = 2000;
+
+ EXPECT_TRUE(MakeTestFile(
+ TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
+
+ result.error = 0;
+ result.response = path;
+ result.downloaded_bytes = 53638;
+ result.total_bytes = 53638;
+ } else {
+ NOTREACHED();
+ }
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
+ base::Unretained(this), result));
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&FakeCrxDownloader::OnDownloadComplete,
+ base::Unretained(this), true, result, download_metrics));
+ }
+ };
+
+ class FakePingManager : public FakePingManagerImpl {
+ public:
+ explicit FakePingManager(const Configurator& config)
+ : FakePingManagerImpl(config) {}
+ ~FakePingManager() override {
+ const auto& ping_items = items();
+ EXPECT_EQ(2U, ping_items.size());
+ EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id);
+ EXPECT_TRUE(base::Version("0.9").Equals(ping_items[0].previous_version));
+ EXPECT_TRUE(base::Version("1.0").Equals(ping_items[0].next_version));
+ EXPECT_EQ(0, ping_items[0].error_category);
+ EXPECT_EQ(0, ping_items[0].error_code);
+ EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[1].id);
+ EXPECT_TRUE(base::Version("0.8").Equals(ping_items[1].previous_version));
+ EXPECT_TRUE(base::Version("1.0").Equals(ping_items[1].next_version));
+ EXPECT_EQ(0, ping_items[1].error_category);
+ EXPECT_EQ(0, ping_items[1].error_code);
+ }
+ };
+
+ scoped_ptr<FakePingManager> ping_manager(new FakePingManager(*config_));
+ scoped_ptr<UpdateClient> update_client(new UpdateClientImpl(
+ config_, ping_manager.Pass(), &FakeUpdateChecker::Create,
+ &FakeCrxDownloader::Create));
+
+ MockObserver observer;
+ {
+ InSequence seq;
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
+ "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
+ "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
+ "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
+ "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
+ "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
+ }
+ {
+ InSequence seq;
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_WAIT,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ }
+
+ update_client->AddObserver(&observer);
+
+ std::vector<std::string> ids;
+ ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf"));
+ ids.push_back(std::string("ihfokbkgjpifnbbojhneepfflplebdkc"));
+
+ update_client->Update(
+ ids, base::Bind(&DataCallbackFake::Callback),
+ base::Bind(&CompletionCallbackFake::Callback, quit_closure_));
+
+ RunThreads();
+
+ update_client->RemoveObserver(&observer);
+}
+
+// Tests the differential update scenario for one CRX.
+TEST_F(UpdateClientTest, OneCrxDiffUpdate) {
+ class DataCallbackFake {
+ public:
+ static void Callback(const std::vector<std::string>& ids,
+ std::vector<CrxComponent>* components) {
+ static int num_calls = 0;
+
+ // Must use the same stateful installer object.
+ static scoped_refptr<CrxInstaller> installer(
+ new VersionedTestInstaller());
+
+ ++num_calls;
+
+ CrxComponent crx;
+ crx.name = "test_ihfo";
+ crx.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
+ crx.installer = installer;
+ if (num_calls == 1) {
+ crx.version = Version("0.8");
+ } else if (num_calls == 2) {
+ crx.version = Version("1.0");
+ } else {
+ NOTREACHED();
+ }
+
+ components->push_back(crx);
+ }
+ };
+
+ class CompletionCallbackFake {
+ public:
+ static void Callback(const base::Closure& quit_closure, int error) {
+ EXPECT_EQ(0, error);
+ quit_closure.Run();
+ }
+ };
+
+ class FakeUpdateChecker : public UpdateChecker {
+ public:
+ static scoped_ptr<UpdateChecker> Create(const Configurator& config) {
+ return scoped_ptr<UpdateChecker>(new FakeUpdateChecker());
+ }
+
+ bool CheckForUpdates(
+ const std::vector<CrxUpdateItem*>& items_to_check,
+ const std::string& additional_attributes,
+ const UpdateCheckCallback& update_check_callback) override {
+ static int num_call = 0;
+ ++num_call;
+
+ UpdateResponse::Results results;
+
+ if (num_call == 1) {
+ /*
+ Fake the following response:
+ <?xml version='1.0' encoding='UTF-8'?>
+ <response protocol='3.0'>
+ <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
+ <updatecheck status='ok'>
+ <urls>
+ <url codebase='http://localhost/download/'/>
+ </urls>
+ <manifest version='1.0' prodversionmin='11.0.1.0'>
+ <packages>
+ <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'/>
+ </packages>
+ </manifest>
+ </updatecheck>
+ </app>
+ </response>
+ */
+ UpdateResponse::Result::Manifest::Package package;
+ package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
+ package.fingerprint = "1";
+ UpdateResponse::Result result;
+ result.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc";
+ result.crx_urls.push_back(GURL("http://localhost/download/"));
+ result.manifest.version = "1.0";
+ result.manifest.browser_min_version = "11.0.1.0";
+ result.manifest.packages.push_back(package);
+ results.list.push_back(result);
+ } else if (num_call == 2) {
+ /*
+ Fake the following response:
+ <?xml version='1.0' encoding='UTF-8'?>
+ <response protocol='3.0'>
+ <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
+ <updatecheck status='ok'>
+ <urls>
+ <url codebase='http://localhost/download/'/>
+ <url codebasediff='http://localhost/download/'/>
+ </urls>
+ <manifest version='2.0' prodversionmin='11.0.1.0'>
+ <packages>
+ <package name='ihfokbkgjpifnbbojhneepfflplebdkc_2.crx'
+ namediff='ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx'
+ fp='22'/>
+ </packages>
+ </manifest>
+ </updatecheck>
+ </app>
+ </response>
+ */
+ UpdateResponse::Result::Manifest::Package package;
+ package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_2.crx";
+ package.namediff = "ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx";
+ package.fingerprint = "22";
+ UpdateResponse::Result result;
+ result.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc";
+ result.crx_urls.push_back(GURL("http://localhost/download/"));
+ result.crx_diffurls.push_back(GURL("http://localhost/download/"));
+ result.manifest.version = "2.0";
+ result.manifest.browser_min_version = "11.0.1.0";
+ result.manifest.packages.push_back(package);
+ results.list.push_back(result);
+ } else {
+ NOTREACHED();
+ }
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(update_check_callback, GURL(), 0, "", results));
+ return true;
+ }
+ };
+
+ class FakeCrxDownloader : public CrxDownloader {
+ public:
+ static scoped_ptr<CrxDownloader> Create(
+ bool is_background_download,
+ net::URLRequestContextGetter* context_getter,
+ const scoped_refptr<base::SequencedTaskRunner>& url_fetcher_task_runner,
+ const scoped_refptr<base::SingleThreadTaskRunner>&
+ background_task_runner) {
+ return scoped_ptr<CrxDownloader>(new FakeCrxDownloader());
+ }
+
+ private:
+ FakeCrxDownloader() : CrxDownloader(scoped_ptr<CrxDownloader>().Pass()) {}
+ ~FakeCrxDownloader() override {}
+
+ void DoStartDownload(const GURL& url) override {
+ DownloadMetrics download_metrics;
+ FilePath path;
+ Result result;
+ if (url.path() == "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
+ download_metrics.url = url;
+ download_metrics.downloader = DownloadMetrics::kNone;
+ download_metrics.error = 0;
+ download_metrics.downloaded_bytes = 53638;
+ download_metrics.total_bytes = 53638;
+ download_metrics.download_time_ms = 2000;
+
+ EXPECT_TRUE(MakeTestFile(
+ TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
+
+ result.error = 0;
+ result.response = path;
+ result.downloaded_bytes = 53638;
+ result.total_bytes = 53638;
+ } else if (url.path() ==
+ "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx") {
+ download_metrics.url = url;
+ download_metrics.downloader = DownloadMetrics::kNone;
+ download_metrics.error = 0;
+ download_metrics.downloaded_bytes = 2105;
+ download_metrics.total_bytes = 2105;
+ download_metrics.download_time_ms = 1000;
+
+ EXPECT_TRUE(MakeTestFile(
+ TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"), &path));
+
+ result.error = 0;
+ result.response = path;
+ result.downloaded_bytes = 2105;
+ result.total_bytes = 2105;
+ } else {
+ NOTREACHED();
+ }
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
+ base::Unretained(this), result));
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&FakeCrxDownloader::OnDownloadComplete,
+ base::Unretained(this), true, result, download_metrics));
+ }
+ };
+
+ class FakePingManager : public FakePingManagerImpl {
+ public:
+ explicit FakePingManager(const Configurator& config)
+ : FakePingManagerImpl(config) {}
+ ~FakePingManager() override {
+ const auto& ping_items = items();
+ EXPECT_EQ(2U, ping_items.size());
+ EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[0].id);
+ EXPECT_TRUE(base::Version("0.8").Equals(ping_items[0].previous_version));
+ EXPECT_TRUE(base::Version("1.0").Equals(ping_items[0].next_version));
+ EXPECT_EQ(0, ping_items[0].error_category);
+ EXPECT_EQ(0, ping_items[0].error_code);
+ EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[1].id);
+ EXPECT_TRUE(base::Version("1.0").Equals(ping_items[1].previous_version));
+ EXPECT_TRUE(base::Version("2.0").Equals(ping_items[1].next_version));
+ EXPECT_EQ(0, ping_items[1].diff_error_category);
+ EXPECT_EQ(0, ping_items[1].diff_error_code);
+ }
+ };
+
+ scoped_ptr<FakePingManager> ping_manager(new FakePingManager(*config_));
+ scoped_ptr<UpdateClient> update_client(new UpdateClientImpl(
+ config_, ping_manager.Pass(), &FakeUpdateChecker::Create,
+ &FakeCrxDownloader::Create));
+
+ MockObserver observer;
+ {
+ InSequence seq;
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ }
+
+ update_client->AddObserver(&observer);
+
+ std::vector<std::string> ids;
+ ids.push_back(std::string("ihfokbkgjpifnbbojhneepfflplebdkc"));
+
+ {
+ base::RunLoop runloop;
+ update_client->Update(
+ ids, base::Bind(&DataCallbackFake::Callback),
+ base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure()));
+ runloop.Run();
+ }
+
+ {
+ base::RunLoop runloop;
+ update_client->Update(
+ ids, base::Bind(&DataCallbackFake::Callback),
+ base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure()));
+ runloop.Run();
+ }
+
+ update_client->RemoveObserver(&observer);
+}
+
+// Tests the update scenario for one CRX where the CRX installer returns
+// an error.
+TEST_F(UpdateClientTest, OneCrxInstallError) {
+ class MockInstaller : public CrxInstaller {
+ public:
+ MOCK_METHOD1(OnUpdateError, void(int error));
+ MOCK_METHOD2(Install,
+ bool(const base::DictionaryValue& manifest,
+ const base::FilePath& unpack_path));
+ MOCK_METHOD2(GetInstalledFile,
+ bool(const std::string& file, base::FilePath* installed_file));
+ MOCK_METHOD0(Uninstall, bool());
+
+ static void OnInstall(const base::DictionaryValue& manifest,
+ const base::FilePath& unpack_path) {
+ base::DeleteFile(unpack_path, true);
+ }
+
+ protected:
+ ~MockInstaller() override {}
+ };
+
+ class DataCallbackFake {
+ public:
+ static void Callback(const std::vector<std::string>& ids,
+ std::vector<CrxComponent>* components) {
+ scoped_refptr<MockInstaller> installer(new MockInstaller());
+
+ EXPECT_CALL(*installer, OnUpdateError(_)).Times(0);
+ EXPECT_CALL(*installer, Install(_, _))
+ .WillOnce(DoAll(Invoke(MockInstaller::OnInstall), Return(false)));
+ EXPECT_CALL(*installer, GetInstalledFile(_, _)).Times(0);
+ EXPECT_CALL(*installer, Uninstall()).Times(0);
+
+ CrxComponent crx;
+ crx.name = "test_jebg";
+ crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
+ crx.version = Version("0.9");
+ crx.installer = installer;
+ components->push_back(crx);
+ }
+ };
+
+ class CompletionCallbackFake {
+ public:
+ static void Callback(const base::Closure& quit_closure, int error) {
+ EXPECT_EQ(0, error);
+ quit_closure.Run();
+ }
+ };
+
+ class FakeUpdateChecker : public UpdateChecker {
+ public:
+ static scoped_ptr<UpdateChecker> Create(const Configurator& config) {
+ return scoped_ptr<UpdateChecker>(new FakeUpdateChecker());
+ }
+
+ bool CheckForUpdates(
+ const std::vector<CrxUpdateItem*>& items_to_check,
+ const std::string& additional_attributes,
+ const UpdateCheckCallback& update_check_callback) override {
+ /*
+ Fake the following response:
+
+ <?xml version='1.0' encoding='UTF-8'?>
+ <response protocol='3.0'>
+ <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
+ <updatecheck status='ok'>
+ <urls>
+ <url codebase='http://localhost/download/'/>
+ </urls>
+ <manifest version='1.0' prodversionmin='11.0.1.0'>
+ <packages>
+ <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'/>
+ </packages>
+ </manifest>
+ </updatecheck>
+ </app>
+ </response>
+ */
+ UpdateResponse::Result::Manifest::Package package;
+ package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
+
+ UpdateResponse::Result result;
+ result.extension_id = "jebgalgnebhfojomionfpkfelancnnkf";
+ result.crx_urls.push_back(GURL("http://localhost/download/"));
+ result.manifest.version = "1.0";
+ result.manifest.browser_min_version = "11.0.1.0";
+ result.manifest.packages.push_back(package);
+
+ UpdateResponse::Results results;
+ results.list.push_back(result);
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(update_check_callback, GURL(), 0, "", results));
+ return true;
+ }
+ };
+
+ class FakeCrxDownloader : public CrxDownloader {
+ public:
+ static scoped_ptr<CrxDownloader> Create(
+ bool is_background_download,
+ net::URLRequestContextGetter* context_getter,
+ const scoped_refptr<base::SequencedTaskRunner>& url_fetcher_task_runner,
+ const scoped_refptr<base::SingleThreadTaskRunner>&
+ background_task_runner) {
+ return scoped_ptr<CrxDownloader>(new FakeCrxDownloader());
+ }
+
+ private:
+ FakeCrxDownloader() : CrxDownloader(scoped_ptr<CrxDownloader>().Pass()) {}
+ ~FakeCrxDownloader() override {}
+
+ void DoStartDownload(const GURL& url) override {
+ DownloadMetrics download_metrics;
+ download_metrics.url = url;
+ download_metrics.downloader = DownloadMetrics::kNone;
+ download_metrics.error = 0;
+ download_metrics.downloaded_bytes = 1843;
+ download_metrics.total_bytes = 1843;
+ download_metrics.download_time_ms = 1000;
+
+ FilePath path;
+ EXPECT_TRUE(MakeTestFile(
+ TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path));
+
+ Result result;
+ result.error = 0;
+ result.response = path;
+ result.downloaded_bytes = 1843;
+ result.total_bytes = 1843;
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
+ base::Unretained(this), result));
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&FakeCrxDownloader::OnDownloadComplete,
+ base::Unretained(this), true, result, download_metrics));
+ }
+ };
+
+ class FakePingManager : public FakePingManagerImpl {
+ public:
+ explicit FakePingManager(const Configurator& config)
+ : FakePingManagerImpl(config) {}
+ ~FakePingManager() override {
+ const auto& ping_items = items();
+ EXPECT_EQ(1U, ping_items.size());
+ EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id);
+ EXPECT_TRUE(base::Version("0.9").Equals(ping_items[0].previous_version));
+ EXPECT_TRUE(base::Version("1.0").Equals(ping_items[0].next_version));
+ EXPECT_EQ(3, ping_items[0].error_category); // kInstallError.
+ EXPECT_EQ(9, ping_items[0].error_code); // kInstallerError.
+ }
+ };
+
+ scoped_ptr<PingManager> ping_manager(new FakePingManager(*config_));
+ scoped_ptr<UpdateClient> update_client(new UpdateClientImpl(
+ config_, ping_manager.Pass(), &FakeUpdateChecker::Create,
+ &FakeCrxDownloader::Create));
+
+ MockObserver observer;
+ {
+ InSequence seq;
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
+ "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
+ "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
+ "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
+ "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
+ "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
+ }
+
+ update_client->AddObserver(&observer);
+
+ std::vector<std::string> ids;
+ ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf"));
+
+ update_client->Update(
+ ids, base::Bind(&DataCallbackFake::Callback),
+ base::Bind(&CompletionCallbackFake::Callback, quit_closure_));
+
+ RunThreads();
+
+ update_client->RemoveObserver(&observer);
+}
+
+// Tests the fallback from differential to full update scenario for one CRX.
+TEST_F(UpdateClientTest, OneCrxDiffUpdateFailsFullUpdateSucceeds) {
+ class DataCallbackFake {
+ public:
+ static void Callback(const std::vector<std::string>& ids,
+ std::vector<CrxComponent>* components) {
+ static int num_calls = 0;
+
+ // Must use the same stateful installer object.
+ static scoped_refptr<CrxInstaller> installer(
+ new VersionedTestInstaller());
+
+ ++num_calls;
+
+ CrxComponent crx;
+ crx.name = "test_ihfo";
+ crx.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
+ crx.installer = installer;
+ if (num_calls == 1) {
+ crx.version = Version("0.8");
+ } else if (num_calls == 2) {
+ crx.version = Version("1.0");
+ } else {
+ NOTREACHED();
+ }
+
+ components->push_back(crx);
+ }
+ };
+
+ class CompletionCallbackFake {
+ public:
+ static void Callback(const base::Closure& quit_closure, int error) {
+ EXPECT_EQ(0, error);
+ quit_closure.Run();
+ }
+ };
+
+ class FakeUpdateChecker : public UpdateChecker {
+ public:
+ static scoped_ptr<UpdateChecker> Create(const Configurator& config) {
+ return scoped_ptr<UpdateChecker>(new FakeUpdateChecker());
+ }
+
+ bool CheckForUpdates(
+ const std::vector<CrxUpdateItem*>& items_to_check,
+ const std::string& additional_attributes,
+ const UpdateCheckCallback& update_check_callback) override {
+ static int num_call = 0;
+ ++num_call;
+
+ UpdateResponse::Results results;
+
+ if (num_call == 1) {
+ /*
+ Fake the following response:
+ <?xml version='1.0' encoding='UTF-8'?>
+ <response protocol='3.0'>
+ <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
+ <updatecheck status='ok'>
+ <urls>
+ <url codebase='http://localhost/download/'/>
+ </urls>
+ <manifest version='1.0' prodversionmin='11.0.1.0'>
+ <packages>
+ <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'/>
+ </packages>
+ </manifest>
+ </updatecheck>
+ </app>
+ </response>
+ */
+ UpdateResponse::Result::Manifest::Package package;
+ package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
+ package.fingerprint = "1";
+ UpdateResponse::Result result;
+ result.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc";
+ result.crx_urls.push_back(GURL("http://localhost/download/"));
+ result.manifest.version = "1.0";
+ result.manifest.browser_min_version = "11.0.1.0";
+ result.manifest.packages.push_back(package);
+ results.list.push_back(result);
+ } else if (num_call == 2) {
+ /*
+ Fake the following response:
+ <?xml version='1.0' encoding='UTF-8'?>
+ <response protocol='3.0'>
+ <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
+ <updatecheck status='ok'>
+ <urls>
+ <url codebase='http://localhost/download/'/>
+ <url codebasediff='http://localhost/download/'/>
+ </urls>
+ <manifest version='2.0' prodversionmin='11.0.1.0'>
+ <packages>
+ <package name='ihfokbkgjpifnbbojhneepfflplebdkc_2.crx'
+ namediff='ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx'
+ fp='22'/>
+ </packages>
+ </manifest>
+ </updatecheck>
+ </app>
+ </response>
+ */
+ UpdateResponse::Result::Manifest::Package package;
+ package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_2.crx";
+ package.namediff = "ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx";
+ package.fingerprint = "22";
+ UpdateResponse::Result result;
+ result.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc";
+ result.crx_urls.push_back(GURL("http://localhost/download/"));
+ result.crx_diffurls.push_back(GURL("http://localhost/download/"));
+ result.manifest.version = "2.0";
+ result.manifest.browser_min_version = "11.0.1.0";
+ result.manifest.packages.push_back(package);
+ results.list.push_back(result);
+ } else {
+ NOTREACHED();
+ }
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(update_check_callback, GURL(), 0, "", results));
+ return true;
+ }
+ };
+
+ class FakeCrxDownloader : public CrxDownloader {
+ public:
+ static scoped_ptr<CrxDownloader> Create(
+ bool is_background_download,
+ net::URLRequestContextGetter* context_getter,
+ const scoped_refptr<base::SequencedTaskRunner>& url_fetcher_task_runner,
+ const scoped_refptr<base::SingleThreadTaskRunner>&
+ background_task_runner) {
+ return scoped_ptr<CrxDownloader>(new FakeCrxDownloader());
+ }
+
+ private:
+ FakeCrxDownloader() : CrxDownloader(scoped_ptr<CrxDownloader>().Pass()) {}
+ ~FakeCrxDownloader() override {}
+
+ void DoStartDownload(const GURL& url) override {
+ DownloadMetrics download_metrics;
+ FilePath path;
+ Result result;
+ if (url.path() == "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
+ download_metrics.url = url;
+ download_metrics.downloader = DownloadMetrics::kNone;
+ download_metrics.error = 0;
+ download_metrics.downloaded_bytes = 53638;
+ download_metrics.total_bytes = 53638;
+ download_metrics.download_time_ms = 2000;
+
+ EXPECT_TRUE(MakeTestFile(
+ TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
+
+ result.error = 0;
+ result.response = path;
+ result.downloaded_bytes = 53638;
+ result.total_bytes = 53638;
+ } else if (url.path() ==
+ "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx") {
+ // A download error is injected on this execution path.
+ download_metrics.url = url;
+ download_metrics.downloader = DownloadMetrics::kNone;
+ download_metrics.error = -1;
+ download_metrics.downloaded_bytes = 0;
+ download_metrics.total_bytes = 2105;
+ download_metrics.download_time_ms = 1000;
+
+ EXPECT_TRUE(MakeTestFile(
+ TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"), &path));
+
+ result.error = -1;
+ result.response = path;
+ result.downloaded_bytes = 0;
+ result.total_bytes = 2105;
+ } else if (url.path() ==
+ "/download/ihfokbkgjpifnbbojhneepfflplebdkc_2.crx") {
+ download_metrics.url = url;
+ download_metrics.downloader = DownloadMetrics::kNone;
+ download_metrics.error = 0;
+ download_metrics.downloaded_bytes = 53855;
+ download_metrics.total_bytes = 53855;
+ download_metrics.download_time_ms = 1000;
+
+ EXPECT_TRUE(MakeTestFile(
+ TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"), &path));
+
+ result.error = 0;
+ result.response = path;
+ result.downloaded_bytes = 53855;
+ result.total_bytes = 53855;
+ }
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
+ base::Unretained(this), result));
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&FakeCrxDownloader::OnDownloadComplete,
+ base::Unretained(this), true, result, download_metrics));
+ }
+ };
+
+ class FakePingManager : public FakePingManagerImpl {
+ public:
+ explicit FakePingManager(const Configurator& config)
+ : FakePingManagerImpl(config) {}
+ ~FakePingManager() override {
+ const auto& ping_items = items();
+ EXPECT_EQ(2U, ping_items.size());
+ EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[0].id);
+ EXPECT_TRUE(base::Version("0.8").Equals(ping_items[0].previous_version));
+ EXPECT_TRUE(base::Version("1.0").Equals(ping_items[0].next_version));
+ EXPECT_EQ(0, ping_items[0].error_category);
+ EXPECT_EQ(0, ping_items[0].error_code);
+ EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[1].id);
+ EXPECT_TRUE(base::Version("1.0").Equals(ping_items[1].previous_version));
+ EXPECT_TRUE(base::Version("2.0").Equals(ping_items[1].next_version));
+ EXPECT_TRUE(ping_items[1].diff_update_failed);
+ EXPECT_EQ(1, ping_items[1].diff_error_category); // kNetworkError.
+ EXPECT_EQ(-1, ping_items[1].diff_error_code);
+ }
+ };
+
+ scoped_ptr<FakePingManager> ping_manager(new FakePingManager(*config_));
+ scoped_ptr<UpdateClient> update_client(new UpdateClientImpl(
+ config_, ping_manager.Pass(), &FakeUpdateChecker::Create,
+ &FakeCrxDownloader::Create));
+
+ MockObserver observer;
+ {
+ InSequence seq;
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
+ "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ }
+
+ update_client->AddObserver(&observer);
+
+ std::vector<std::string> ids;
+ ids.push_back(std::string("ihfokbkgjpifnbbojhneepfflplebdkc"));
+
+ {
+ base::RunLoop runloop;
+ update_client->Update(
+ ids, base::Bind(&DataCallbackFake::Callback),
+ base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure()));
+ runloop.Run();
+ }
+
+ {
+ base::RunLoop runloop;
+ update_client->Update(
+ ids, base::Bind(&DataCallbackFake::Callback),
+ base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure()));
+ runloop.Run();
+ }
+
+ update_client->RemoveObserver(&observer);
+}
+
+} // namespace update_client