summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsorin <sorin@chromium.org>2015-05-26 12:59:09 -0700
committerCommit bot <commit-bot@chromium.org>2015-05-26 20:00:01 +0000
commit7c7176234e553c35a2d8ec014f2caa29f7278065 (patch)
tree70eb3c58c82369cc13c939c17ae63344644c4b31
parent92780e77b6e0755e1d4bacbd493032969d04293b (diff)
downloadchromium_src-7c7176234e553c35a2d8ec014f2caa29f7278065.zip
chromium_src-7c7176234e553c35a2d8ec014f2caa29f7278065.tar.gz
chromium_src-7c7176234e553c35a2d8ec014f2caa29f7278065.tar.bz2
Rewrite component update service in terms of components/update_client.
The goal of this change is to re-implement the component updater by reusing the common code in components/update_client while keeping the its public interface the same as before, in order to minimize changes in its existing clients. BUG=450337 Review URL: https://codereview.chromium.org/1133443002 Cr-Commit-Position: refs/heads/master@{#331412}
-rw-r--r--chrome/browser/chrome_browser_main.cc2
-rw-r--r--chrome/browser/component_updater/chrome_component_updater_configurator.cc20
-rw-r--r--chrome/browser/component_updater/chrome_component_updater_configurator_unittest.cc2
-rw-r--r--chrome/browser/component_updater/component_updater_service_unittest.cc1398
-rw-r--r--chrome/browser/component_updater/component_updater_service_unittest.h102
-rw-r--r--chrome/browser/component_updater/pepper_flash_component_installer.cc3
-rw-r--r--chrome/browser/component_updater/pnacl_component_installer.cc6
-rw-r--r--chrome/browser/component_updater/recovery_component_installer.cc2
-rw-r--r--chrome/browser/component_updater/supervised_user_whitelist_installer.cc13
-rw-r--r--chrome/browser/component_updater/supervised_user_whitelist_installer_unittest.cc28
-rw-r--r--chrome/browser/component_updater/swiftshader_component_installer.cc3
-rw-r--r--chrome/browser/net/crl_set_fetcher.cc4
-rw-r--r--chrome/browser/ui/webui/components_ui.cc4
-rw-r--r--chrome/chrome_tests_unit.gypi1
-rw-r--r--components/BUILD.gn1
-rw-r--r--components/component_updater.gypi3
-rw-r--r--components/component_updater/BUILD.gn18
-rw-r--r--components/component_updater/component_updater_service.cc1109
-rw-r--r--components/component_updater/component_updater_service.h87
-rw-r--r--components/component_updater/component_updater_service_internal.h111
-rw-r--r--components/component_updater/component_updater_service_unittest.cc355
-rw-r--r--components/component_updater/default_component_installer.cc7
-rw-r--r--components/component_updater/timer.cc47
-rw-r--r--components/component_updater/timer.h42
-rw-r--r--components/component_updater/timer_unittest.cc61
-rw-r--r--components/components_tests.gyp6
-rw-r--r--components/update_client/action.cc2
-rw-r--r--components/update_client/action_update.cc26
-rw-r--r--components/update_client/action_update.h8
-rw-r--r--components/update_client/action_update_check.cc6
-rw-r--r--components/update_client/configurator.h11
-rw-r--r--components/update_client/crx_update_item.h6
-rw-r--r--components/update_client/task.h3
-rw-r--r--components/update_client/task_update.cc14
-rw-r--r--components/update_client/task_update.h21
-rw-r--r--components/update_client/test_configurator.cc34
-rw-r--r--components/update_client/test_configurator.h12
-rw-r--r--components/update_client/update_client.cc43
-rw-r--r--components/update_client/update_client.h13
-rw-r--r--components/update_client/update_client_internal.h5
-rw-r--r--components/update_client/update_client_unittest.cc361
-rw-r--r--components/update_client/update_engine.cc8
-rw-r--r--components/update_client/update_engine.h7
43 files changed, 1342 insertions, 2673 deletions
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 58235fa..a9a1e5f 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -471,8 +471,6 @@ void RegisterComponentsForUpdate() {
RegisterSwReporterComponent(cus, g_browser_process->local_state());
RegisterCAPSComponent(cus);
#endif // defined(OS_WIN)
-
- cus->Start();
}
#if !defined(OS_ANDROID)
diff --git a/chrome/browser/component_updater/chrome_component_updater_configurator.cc b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
index 687f0e7..cc0fb61 100644
--- a/chrome/browser/component_updater/chrome_component_updater_configurator.cc
+++ b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
@@ -106,10 +106,8 @@ class ChromeConfigurator : public Configurator {
net::URLRequestContextGetter* url_request_getter);
int InitialDelay() const override;
- int NextCheckDelay() override;
+ int NextCheckDelay() const override;
int StepDelay() const override;
- int StepDelayMedium() override;
- int MinimumReCheckWait() const override;
int OnDemandDelay() const override;
int UpdateDelay() const override;
std::vector<GURL> UpdateUrl() const override;
@@ -183,31 +181,23 @@ ChromeConfigurator::ChromeConfigurator(
}
int ChromeConfigurator::InitialDelay() const {
- return fast_update_ ? 1 : (6 * kDelayOneMinute);
+ return fast_update_ ? 10 : (6 * kDelayOneMinute);
}
-int ChromeConfigurator::NextCheckDelay() {
- return fast_update_ ? 3 : (6 * kDelayOneHour);
-}
-
-int ChromeConfigurator::StepDelayMedium() {
- return fast_update_ ? 3 : (15 * kDelayOneMinute);
+int ChromeConfigurator::NextCheckDelay() const {
+ return fast_update_ ? 60 : (6 * kDelayOneHour);
}
int ChromeConfigurator::StepDelay() const {
return fast_update_ ? 1 : 1;
}
-int ChromeConfigurator::MinimumReCheckWait() const {
- return fast_update_ ? 30 : (6 * kDelayOneHour);
-}
-
int ChromeConfigurator::OnDemandDelay() const {
return fast_update_ ? 2 : (30 * kDelayOneMinute);
}
int ChromeConfigurator::UpdateDelay() const {
- return fast_update_ ? 1 : (15 * kDelayOneMinute);
+ return fast_update_ ? 10 : (15 * kDelayOneMinute);
}
std::vector<GURL> ChromeConfigurator::UpdateUrl() const {
diff --git a/chrome/browser/component_updater/chrome_component_updater_configurator_unittest.cc b/chrome/browser/component_updater/chrome_component_updater_configurator_unittest.cc
index 5a7589e..ebc99d8 100644
--- a/chrome/browser/component_updater/chrome_component_updater_configurator_unittest.cc
+++ b/chrome/browser/component_updater/chrome_component_updater_configurator_unittest.cc
@@ -31,7 +31,7 @@ TEST(ChromeComponentUpdaterConfiguratorTest, TestFastUpdate) {
const auto config(MakeChromeComponentUpdaterConfigurator(cmdline, NULL));
- ASSERT_EQ(1, config->InitialDelay());
+ ASSERT_EQ(10, config->InitialDelay());
}
TEST(ChromeComponentUpdaterConfiguratorTest, TestOverrideUrl) {
diff --git a/chrome/browser/component_updater/component_updater_service_unittest.cc b/chrome/browser/component_updater/component_updater_service_unittest.cc
deleted file mode 100644
index 49d86bd..0000000
--- a/chrome/browser/component_updater/component_updater_service_unittest.cc
+++ /dev/null
@@ -1,1398 +0,0 @@
-// Copyright 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 "chrome/browser/component_updater/component_updater_service_unittest.h"
-
-#include <vector>
-
-#include "base/files/file_util.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/path_service.h"
-#include "base/run_loop.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/values.h"
-#include "chrome/browser/component_updater/component_updater_resource_throttle.h"
-#include "chrome/common/chrome_paths.h"
-#include "components/update_client/test_configurator.h"
-#include "components/update_client/test_installer.h"
-#include "components/update_client/url_request_post_interceptor.h"
-#include "components/update_client/utils.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/resource_controller.h"
-#include "content/public/browser/resource_request_info.h"
-#include "content/public/browser/resource_throttle.h"
-#include "libxml/globals.h"
-#include "net/base/upload_bytes_element_reader.h"
-#include "net/url_request/test_url_request_interceptor.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_test_util.h"
-#include "url/gurl.h"
-
-using ::testing::_;
-using ::testing::AnyNumber;
-using ::testing::InSequence;
-using ::testing::Mock;
-
-using content::BrowserThread;
-
-using std::string;
-
-using update_client::CrxComponent;
-using update_client::PartialMatch;
-using update_client::InterceptorFactory;
-using update_client::TestConfigurator;
-using update_client::TestInstaller;
-using update_client::URLRequestPostInterceptor;
-using update_client::VersionedTestInstaller;
-
-using update_client::abag_hash;
-using update_client::ihfo_hash;
-using update_client::jebg_hash;
-
-using Events = component_updater::ServiceObserver::Events;
-using Status = component_updater::ComponentUpdateService::Status;
-
-namespace component_updater {
-
-MockServiceObserver::MockServiceObserver() {
-}
-
-MockServiceObserver::~MockServiceObserver() {
-}
-
-ComponentUpdaterTest::ComponentUpdaterTest()
- : post_interceptor_(NULL),
- thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
- test_config_(NULL) {
- // The component updater instance under test.
- test_config_ = new TestConfigurator(
- BrowserThread::GetBlockingPool()
- ->GetSequencedTaskRunnerWithShutdownBehavior(
- BrowserThread::GetBlockingPool()->GetSequenceToken(),
- base::SequencedWorkerPool::SKIP_ON_SHUTDOWN),
- BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
- component_updater_.reset(
- ComponentUpdateServiceFactory(test_config_).release());
-}
-
-ComponentUpdaterTest::~ComponentUpdaterTest() {
-}
-
-void ComponentUpdaterTest::SetUp() {
- get_interceptor_.reset(new GetInterceptor(
- BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO),
- BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
- base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)));
- interceptor_factory_.reset(new InterceptorFactory(
- BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)));
- post_interceptor_ = interceptor_factory_->CreateInterceptor();
- EXPECT_TRUE(post_interceptor_);
-}
-
-void ComponentUpdaterTest::TearDown() {
- interceptor_factory_.reset();
- get_interceptor_.reset();
- xmlCleanupGlobals();
-}
-
-ComponentUpdateService* ComponentUpdaterTest::component_updater() {
- return component_updater_.get();
-}
-
-// Makes the full path to a component updater test file.
-const base::FilePath ComponentUpdaterTest::test_file(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);
-}
-
-scoped_refptr<update_client::TestConfigurator>
-ComponentUpdaterTest::test_configurator() {
- return test_config_;
-}
-
-ComponentUpdateService::Status ComponentUpdaterTest::RegisterComponent(
- CrxComponent* com,
- TestComponents component,
- const Version& version,
- const scoped_refptr<TestInstaller>& installer) {
- switch (component) {
- case kTestComponent_abag: {
- com->name = "test_abag";
- com->pk_hash.assign(abag_hash, abag_hash + arraysize(abag_hash));
- break;
- }
- case kTestComponent_jebg: {
- com->name = "test_jebg";
- com->pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- break;
- }
- case kTestComponent_ihfo: {
- com->name = "test_ihfo";
- com->pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
- break;
- }
- }
- com->version = version;
- com->installer = installer;
- return component_updater_->RegisterComponent(*com);
-}
-
-void ComponentUpdaterTest::RunThreads() {
- base::RunLoop runloop;
- test_configurator()->SetQuitClosure(runloop.QuitClosure());
- runloop.Run();
-
- // Since some tests need to drain currently enqueued tasks such as network
- // intercepts on the IO thread, run the threads until they are
- // idle. The component updater service won't loop again until the loop count
- // is set and the service is started.
- RunThreadsUntilIdle();
-}
-
-void ComponentUpdaterTest::RunThreadsUntilIdle() {
- base::RunLoop().RunUntilIdle();
-}
-
-ComponentUpdateService::Status OnDemandTester::OnDemand(
- ComponentUpdateService* cus,
- const std::string& component_id) {
- return cus->GetOnDemandUpdater().OnDemandUpdate(component_id);
-}
-
-// Verify that our test fixture work and the component updater can
-// be created and destroyed with no side effects.
-TEST_F(ComponentUpdaterTest, VerifyFixture) {
- EXPECT_TRUE(component_updater() != NULL);
-}
-
-// Verify that the component updater can be caught in a quick
-// start-shutdown situation. Failure of this test will be a crash.
-TEST_F(ComponentUpdaterTest, StartStop) {
- component_updater()->Start();
- RunThreadsUntilIdle();
- component_updater()->Stop();
-}
-
-// Verify that when the server has no updates, we go back to sleep and
-// the COMPONENT_UPDATER_STARTED and COMPONENT_UPDATER_SLEEPING notifications
-// are generated. No pings are sent.
-TEST_F(ComponentUpdaterTest, CheckCrxSleep) {
- MockServiceObserver observer;
-
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_STARTED, ""))
- .Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_SLEEPING, ""))
- .Times(2);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
- "abagagagagagagagagagagagagagagag")).Times(2);
-
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
-
- scoped_refptr<TestInstaller> installer(new TestInstaller);
- CrxComponent com;
- component_updater()->AddObserver(&observer);
- EXPECT_EQ(Status::kOk, RegisterComponent(&com, kTestComponent_abag,
- Version("1.1"), installer));
-
- // We loop twice, but there are no updates so we expect two sleep messages.
- test_configurator()->SetLoopCount(2);
- component_updater()->Start();
- RunThreads();
-
- EXPECT_EQ(0, installer->error());
- EXPECT_EQ(0, installer->install_count());
-
- // Expect to see the two update check requests and no other requests,
- // including pings.
- EXPECT_EQ(2, post_interceptor_->GetHitCount())
- << post_interceptor_->GetRequestsAsString();
- EXPECT_EQ(2, post_interceptor_->GetCount())
- << post_interceptor_->GetRequestsAsString();
- EXPECT_NE(
- string::npos,
- post_interceptor_->GetRequests()[0].find(
- "<app appid=\"abagagagagagagagagagagagagagagag\" version=\"1.1\">"
- "<updatecheck /></app>"))
- << post_interceptor_->GetRequestsAsString();
- EXPECT_NE(
- string::npos,
- post_interceptor_->GetRequests()[1].find(
- "<app appid=\"abagagagagagagagagagagagagagagag\" version=\"1.1\">"
- "<updatecheck /></app>"))
- << post_interceptor_->GetRequestsAsString();
-
- component_updater()->Stop();
-
- // Loop twice again but this case we simulate a server error by returning
- // an empty file. Expect the behavior of the service to be the same as before.
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_STARTED, ""))
- .Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_SLEEPING, ""))
- .Times(2);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
- "abagagagagagagagagagagagagagagag")).Times(2);
-
- post_interceptor_->Reset();
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"), test_file("updatecheck_reply_empty")));
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"), test_file("updatecheck_reply_empty")));
-
- test_configurator()->SetLoopCount(2);
- component_updater()->Start();
- RunThreads();
-
- EXPECT_EQ(0, installer->error());
- EXPECT_EQ(0, installer->install_count());
-
- EXPECT_EQ(2, post_interceptor_->GetHitCount())
- << post_interceptor_->GetRequestsAsString();
- EXPECT_EQ(2, post_interceptor_->GetCount())
- << post_interceptor_->GetRequestsAsString();
- EXPECT_NE(
- string::npos,
- post_interceptor_->GetRequests()[0].find(
- "<app appid=\"abagagagagagagagagagagagagagagag\" version=\"1.1\">"
- "<updatecheck /></app>"))
- << post_interceptor_->GetRequestsAsString();
- EXPECT_NE(
- string::npos,
- post_interceptor_->GetRequests()[1].find(
- "<app appid=\"abagagagagagagagagagagagagagagag\" version=\"1.1\">"
- "<updatecheck /></app>"))
- << post_interceptor_->GetRequestsAsString();
-
- component_updater()->Stop();
-}
-
-// Verify that we can check for updates and install one component. Besides
-// the notifications above COMPONENT_UPDATE_FOUND and COMPONENT_UPDATE_READY
-// should have been fired. We do two loops so the second time around there
-// should be nothing left to do.
-// We also check that the following network requests are issued:
-// 1- update check
-// 2- download crx
-// 3- ping
-// 4- second update check.
-TEST_F(ComponentUpdaterTest, InstallCrx) {
- MockServiceObserver observer;
- {
- InSequence seq;
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_STARTED, ""))
- .Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
- "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
- "abagagagagagagagagagagagagagagag")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
- "jebgalgnebhfojomionfpkfelancnnkf"))
- .Times(AnyNumber());
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
- "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
- "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_SLEEPING, ""))
- .Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
- "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
- "abagagagagagagagagagagagagagagag")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_SLEEPING, ""))
- .Times(1);
- }
-
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
- EXPECT_TRUE(post_interceptor_->ExpectRequest(new PartialMatch("event")));
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
-
- get_interceptor_->SetResponse(
- GURL(expected_crx_url),
- test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"));
-
- component_updater()->AddObserver(&observer);
-
- scoped_refptr<TestInstaller> installer1(new TestInstaller);
- CrxComponent com1;
- RegisterComponent(&com1, kTestComponent_jebg, Version("0.9"), installer1);
- scoped_refptr<TestInstaller> installer2(new TestInstaller);
- CrxComponent com2;
- RegisterComponent(&com2, kTestComponent_abag, Version("2.2"), installer2);
-
- test_configurator()->SetLoopCount(2);
- component_updater()->Start();
- RunThreads();
-
- EXPECT_EQ(0, installer1->error());
- EXPECT_EQ(1, installer1->install_count());
- EXPECT_EQ(0, installer2->error());
- EXPECT_EQ(0, installer2->install_count());
-
- // Expect three request in total: two update checks and one ping.
- EXPECT_EQ(3, post_interceptor_->GetHitCount())
- << post_interceptor_->GetRequestsAsString();
- EXPECT_EQ(3, post_interceptor_->GetCount())
- << post_interceptor_->GetRequestsAsString();
-
- // Expect one component download.
- EXPECT_EQ(1, get_interceptor_->GetHitCount());
-
- EXPECT_NE(
- string::npos,
- post_interceptor_->GetRequests()[0].find(
- "<app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" version=\"0.9\">"
- "<updatecheck /></app>"))
- << post_interceptor_->GetRequestsAsString();
- EXPECT_NE(
- string::npos,
- post_interceptor_->GetRequests()[0].find(
- "<app appid=\"abagagagagagagagagagagagagagagag\" version=\"2.2\">"
- "<updatecheck /></app>"))
- << post_interceptor_->GetRequestsAsString();
-
- EXPECT_NE(string::npos, post_interceptor_->GetRequests()[1].find(
- "<app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" "
- "version=\"0.9\" nextversion=\"1.0\">"
- "<event eventtype=\"3\" eventresult=\"1\"/>"))
- << post_interceptor_->GetRequestsAsString();
-
- EXPECT_NE(
- string::npos,
- post_interceptor_->GetRequests()[2].find(
- "<app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" version=\"1.0\">"
- "<updatecheck /></app>"));
- EXPECT_NE(
- string::npos,
- post_interceptor_->GetRequests()[2].find(
- "<app appid=\"abagagagagagagagagagagagagagagag\" version=\"2.2\">"
- "<updatecheck /></app>"))
- << post_interceptor_->GetRequestsAsString();
-
- // Test the protocol version is correct and the extra request attributes
- // are included in the request.
- EXPECT_NE(string::npos, post_interceptor_->GetRequests()[0].find(
- "request protocol=\"3.0\" extra=\"foo\""))
- << post_interceptor_->GetRequestsAsString();
-
- // Tokenize the request string to look for specific attributes, which
- // are important for backward compatibility with the version v2 of the update
- // protocol. In this case, inspect the <request>, which is the first element
- // after the xml declaration of the update request body.
- // Expect to find the |os|, |arch|, |prodchannel|, and |prodversion|
- // attributes:
- // <?xml version="1.0" encoding="UTF-8"?>
- // <request... os=... arch=... prodchannel=... prodversion=...>
- // ...
- // </request>
- const std::string update_request(post_interceptor_->GetRequests()[0]);
- std::vector<base::StringPiece> elements;
- Tokenize(update_request, "<>", &elements);
- EXPECT_NE(string::npos, elements[1].find(" os="));
- EXPECT_NE(string::npos, elements[1].find(" arch="));
- EXPECT_NE(string::npos, elements[1].find(" prodchannel="));
- EXPECT_NE(string::npos, elements[1].find(" prodversion="));
-
- // Look for additional attributes of the request, such as |version|,
- // |requestid|, |lang|, and |nacl_arch|.
- EXPECT_NE(string::npos, elements[1].find(" version="));
- EXPECT_NE(string::npos, elements[1].find(" requestid="));
- EXPECT_NE(string::npos, elements[1].find(" lang="));
- EXPECT_NE(string::npos, elements[1].find(" nacl_arch="));
-
- component_updater()->Stop();
-}
-
-// This test checks that the "prodversionmin" value is handled correctly. In
-// particular there should not be an install because the minimum product
-// version is much higher than of chrome.
-TEST_F(ComponentUpdaterTest, ProdVersionCheck) {
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"), test_file("updatecheck_reply_2.xml")));
-
- get_interceptor_->SetResponse(
- GURL(expected_crx_url),
- test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"));
-
- scoped_refptr<TestInstaller> installer(new TestInstaller);
- CrxComponent com;
- RegisterComponent(&com, kTestComponent_jebg, Version("0.9"), installer);
-
- test_configurator()->SetLoopCount(1);
- component_updater()->Start();
- RunThreads();
-
- // Expect one update check and no ping.
- EXPECT_EQ(1, post_interceptor_->GetHitCount())
- << post_interceptor_->GetRequestsAsString();
- EXPECT_EQ(1, post_interceptor_->GetCount())
- << post_interceptor_->GetRequestsAsString();
-
- // Expect no download to occur.
- EXPECT_EQ(0, get_interceptor_->GetHitCount());
-
- EXPECT_EQ(0, installer->error());
- EXPECT_EQ(0, installer->install_count());
-
- component_updater()->Stop();
-}
-
-// Test that a update check due to an on demand call can cause installs.
-// Here is the timeline:
-// - First loop: we return a reply that indicates no update, so
-// nothing happens.
-// - We make an on demand call.
-// - This triggers a second loop, which has a reply that triggers an install.
-#if defined(OS_LINUX)
-// http://crbug.com/396488
-#define MAYBE_OnDemandUpdate DISABLED_OnDemandUpdate
-#else
-#define MAYBE_OnDemandUpdate OnDemandUpdate
-#endif
-TEST_F(ComponentUpdaterTest, MAYBE_OnDemandUpdate) {
- MockServiceObserver observer;
- {
- InSequence seq;
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_STARTED, ""))
- .Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
- "abagagagagagagagagagagagagagagag")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
- "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_SLEEPING, ""))
- .Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_STARTED, ""))
- .Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
- "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
- "abagagagagagagagagagagagagagagag")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
- "jebgalgnebhfojomionfpkfelancnnkf"))
- .Times(AnyNumber());
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
- "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
- "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_SLEEPING, ""))
- .Times(1);
- }
-
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"), test_file("updatecheck_reply_empty")));
-
- get_interceptor_->SetResponse(
- GURL(expected_crx_url),
- test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"));
-
- component_updater()->AddObserver(&observer);
-
- scoped_refptr<TestInstaller> installer1(new TestInstaller);
- CrxComponent com1;
- RegisterComponent(&com1, kTestComponent_abag, Version("2.2"), installer1);
- scoped_refptr<TestInstaller> installer2(new TestInstaller);
- CrxComponent com2;
- RegisterComponent(&com2, kTestComponent_jebg, Version("0.9"), installer2);
-
- // No update normally.
- test_configurator()->SetLoopCount(1);
- component_updater()->Start();
- RunThreads();
- component_updater()->Stop();
-
- EXPECT_EQ(1, post_interceptor_->GetHitCount())
- << post_interceptor_->GetRequestsAsString();
- EXPECT_EQ(1, post_interceptor_->GetCount())
- << post_interceptor_->GetRequestsAsString();
-
- EXPECT_EQ(0, get_interceptor_->GetHitCount());
-
- // Update after an on-demand check is issued.
- post_interceptor_->Reset();
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
- EXPECT_TRUE(post_interceptor_->ExpectRequest(new PartialMatch("event")));
-
- EXPECT_EQ(Status::kOk, OnDemandTester::OnDemand(component_updater(),
- GetCrxComponentID(com2)));
- test_configurator()->SetLoopCount(1);
- component_updater()->Start();
- RunThreads();
-
- EXPECT_EQ(0, installer1->error());
- EXPECT_EQ(0, installer1->install_count());
- EXPECT_EQ(0, installer2->error());
- EXPECT_EQ(1, installer2->install_count());
-
- EXPECT_EQ(2, post_interceptor_->GetHitCount())
- << post_interceptor_->GetRequestsAsString();
- EXPECT_EQ(2, post_interceptor_->GetCount())
- << post_interceptor_->GetRequestsAsString();
-
- EXPECT_EQ(1, get_interceptor_->GetHitCount());
-
- // Expect the update check to contain an "ondemand" request for the
- // second component (com2) and a normal request for the other component.
- EXPECT_NE(string::npos, post_interceptor_->GetRequests()[0].find(
- "<app appid=\"abagagagagagagagagagagagagagagag\" "
- "version=\"2.2\"><updatecheck /></app>"))
- << post_interceptor_->GetRequestsAsString();
- EXPECT_NE(
- string::npos,
- post_interceptor_->GetRequests()[0].find(
- "<app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" "
- "version=\"0.9\" installsource=\"ondemand\"><updatecheck /></app>"))
- << post_interceptor_->GetRequestsAsString();
- EXPECT_NE(string::npos, post_interceptor_->GetRequests()[1].find(
- "<app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" "
- "version=\"0.9\" nextversion=\"1.0\">"
- "<event eventtype=\"3\" eventresult=\"1\"/>"))
- << post_interceptor_->GetRequestsAsString();
-
- // Also check what happens if previous check too soon. It works, since this
- // direct OnDemand call does not implement a cooldown.
- test_configurator()->SetOnDemandTime(60 * 60);
- EXPECT_EQ(Status::kOk, OnDemandTester::OnDemand(component_updater(),
- GetCrxComponentID(com2)));
- // Okay, now reset to 0 for the other tests.
- test_configurator()->SetOnDemandTime(0);
- component_updater()->Stop();
-
- // Test a few error cases. NOTE: We don't have callbacks for
- // when the updates failed yet.
- EXPECT_TRUE(Mock::VerifyAndClearExpectations(&observer));
- {
- InSequence seq;
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_STARTED, ""))
- .Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
- "abagagagagagagagagagagagagagagag")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
- "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_SLEEPING, ""))
- .Times(1);
- }
-
- // No update: error from no server response
- post_interceptor_->Reset();
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"), test_file("updatecheck_reply_empty")));
-
- test_configurator()->SetLoopCount(1);
- component_updater()->Start();
- EXPECT_EQ(Status::kOk, OnDemandTester::OnDemand(component_updater(),
- GetCrxComponentID(com2)));
- RunThreads();
- component_updater()->Stop();
-
- EXPECT_EQ(1, post_interceptor_->GetHitCount())
- << post_interceptor_->GetRequestsAsString();
- EXPECT_EQ(1, post_interceptor_->GetCount())
- << post_interceptor_->GetRequestsAsString();
-
- // No update: already updated to 1.0 so nothing new
- EXPECT_TRUE(Mock::VerifyAndClearExpectations(&observer));
- {
- InSequence seq;
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_STARTED, ""))
- .Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
- "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
- "abagagagagagagagagagagagagagagag")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_SLEEPING, ""))
- .Times(1);
- }
-
- post_interceptor_->Reset();
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
-
- test_configurator()->SetLoopCount(1);
- component_updater()->Start();
- EXPECT_EQ(Status::kOk, OnDemandTester::OnDemand(component_updater(),
- GetCrxComponentID(com2)));
- RunThreads();
-
- EXPECT_EQ(1, post_interceptor_->GetHitCount())
- << post_interceptor_->GetRequestsAsString();
- EXPECT_EQ(1, post_interceptor_->GetCount())
- << post_interceptor_->GetRequestsAsString();
-
- component_updater()->Stop();
-}
-
-// Verify that a previously registered component can get re-registered
-// with a different version.
-TEST_F(ComponentUpdaterTest, CheckReRegistration) {
- MockServiceObserver observer;
- {
- InSequence seq;
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_STARTED, ""))
- .Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
- "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
- "abagagagagagagagagagagagagagagag")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
- "jebgalgnebhfojomionfpkfelancnnkf"))
- .Times(AnyNumber());
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
- "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
- "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_SLEEPING, ""))
- .Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
- "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
- "abagagagagagagagagagagagagagagag")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_SLEEPING, ""))
- .Times(1);
- }
-
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
- EXPECT_TRUE(post_interceptor_->ExpectRequest(new PartialMatch("event")));
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
-
- get_interceptor_->SetResponse(
- GURL(expected_crx_url),
- test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"));
-
- component_updater()->AddObserver(&observer);
-
- scoped_refptr<TestInstaller> installer1(new TestInstaller);
- CrxComponent com1;
- RegisterComponent(&com1, kTestComponent_jebg, Version("0.9"), installer1);
- scoped_refptr<TestInstaller> installer2(new TestInstaller);
- CrxComponent com2;
- RegisterComponent(&com2, kTestComponent_abag, Version("2.2"), installer2);
-
- // Loop twice to issue two checks: (1) with original 0.9 version, update to
- // 1.0, and do the second check (2) with the updated 1.0 version.
- test_configurator()->SetLoopCount(2);
- component_updater()->Start();
- RunThreads();
-
- EXPECT_EQ(0, installer1->error());
- EXPECT_EQ(1, installer1->install_count());
- EXPECT_EQ(0, installer2->error());
- EXPECT_EQ(0, installer2->install_count());
-
- EXPECT_EQ(3, post_interceptor_->GetHitCount())
- << post_interceptor_->GetRequestsAsString();
- EXPECT_EQ(1, get_interceptor_->GetHitCount());
-
- EXPECT_NE(
- string::npos,
- post_interceptor_->GetRequests()[0].find(
- "<app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" version=\"0.9\">"
- "<updatecheck /></app>"))
- << post_interceptor_->GetRequestsAsString();
- EXPECT_NE(string::npos, post_interceptor_->GetRequests()[1].find(
- "<app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" "
- "version=\"0.9\" nextversion=\"1.0\">"
- "<event eventtype=\"3\" eventresult=\"1\"/>"))
- << post_interceptor_->GetRequestsAsString();
- EXPECT_NE(
- string::npos,
- post_interceptor_->GetRequests()[2].find(
- "<app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" version=\"1.0\">"
- "<updatecheck /></app>"))
- << post_interceptor_->GetRequestsAsString();
-
- component_updater()->Stop();
-
- // Now re-register, pretending to be an even newer version (2.2)
- EXPECT_TRUE(Mock::VerifyAndClearExpectations(&observer));
- {
- InSequence seq;
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_STARTED, ""))
- .Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
- "jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
- "abagagagagagagagagagagagagagagag")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_SLEEPING, ""))
- .Times(1);
- }
-
- post_interceptor_->Reset();
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
-
- scoped_refptr<TestInstaller> installer3(new TestInstaller);
- EXPECT_EQ(Status::kReplaced, RegisterComponent(&com1, kTestComponent_jebg,
- Version("2.2"), installer3));
-
- // Loop once just to notice the check happening with the re-register version.
- test_configurator()->SetLoopCount(1);
- component_updater()->Start();
- RunThreads();
-
- // We created a new installer, so the counts go back to 0.
- EXPECT_EQ(0, installer3->error());
- EXPECT_EQ(0, installer3->install_count());
- EXPECT_EQ(0, installer2->error());
- EXPECT_EQ(0, installer2->install_count());
-
- // One update check and no additional pings are expected.
- EXPECT_EQ(1, post_interceptor_->GetHitCount())
- << post_interceptor_->GetRequestsAsString();
- EXPECT_EQ(1, post_interceptor_->GetCount())
- << post_interceptor_->GetRequestsAsString();
-
- EXPECT_NE(
- string::npos,
- post_interceptor_->GetRequests()[0].find(
- "<app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" version=\"2.2\">"
- "<updatecheck /></app>"));
-
- component_updater()->Stop();
-}
-
-// Verify that we can download and install a component and a differential
-// update to that component. We do three loops; the final loop should do
-// nothing.
-// We also check that exactly 5 non-ping network requests are issued:
-// 1- update check (response: v1 available)
-// 2- download crx (v1)
-// 3- update check (response: v2 available)
-// 4- download differential crx (v1 to v2)
-// 5- update check (response: no further update available)
-// There should be two pings, one for each update. The second will bear a
-// diffresult=1, while the first will not.
-TEST_F(ComponentUpdaterTest, DifferentialUpdate) {
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"),
- test_file("updatecheck_diff_reply_1.xml")));
- EXPECT_TRUE(post_interceptor_->ExpectRequest(new PartialMatch("event")));
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"),
- test_file("updatecheck_diff_reply_2.xml")));
- EXPECT_TRUE(post_interceptor_->ExpectRequest(new PartialMatch("event")));
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"),
- test_file("updatecheck_diff_reply_3.xml")));
-
- get_interceptor_->SetResponse(
- GURL("http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"),
- test_file("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"));
- get_interceptor_->SetResponse(
- GURL(
- "http://localhost/download/"
- "ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"),
- test_file("ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"));
-
- scoped_refptr<TestInstaller> installer(new VersionedTestInstaller);
- CrxComponent com;
- RegisterComponent(&com, kTestComponent_ihfo, Version("0.0"), installer);
-
- test_configurator()->SetLoopCount(3);
- component_updater()->Start();
- RunThreads();
-
- EXPECT_EQ(0, installer->error());
- EXPECT_EQ(2, installer->install_count());
-
- EXPECT_EQ(5, post_interceptor_->GetHitCount())
- << post_interceptor_->GetRequestsAsString();
- EXPECT_EQ(5, post_interceptor_->GetCount())
- << post_interceptor_->GetRequestsAsString();
- EXPECT_EQ(2, get_interceptor_->GetHitCount());
-
- EXPECT_NE(
- string::npos,
- post_interceptor_->GetRequests()[0].find(
- "<app appid=\"ihfokbkgjpifnbbojhneepfflplebdkc\" version=\"0.0\">"
- "<updatecheck /></app>"))
- << post_interceptor_->GetRequestsAsString();
- EXPECT_NE(string::npos,
- post_interceptor_->GetRequests()[1].find(
- "<app appid=\"ihfokbkgjpifnbbojhneepfflplebdkc\" "
- "version=\"0.0\" nextversion=\"1.0\">"
- "<event eventtype=\"3\" eventresult=\"1\" nextfp=\"1\"/>"))
- << post_interceptor_->GetRequestsAsString();
- EXPECT_NE(
- string::npos,
- post_interceptor_->GetRequests()[2].find(
- "<app appid=\"ihfokbkgjpifnbbojhneepfflplebdkc\" version=\"1.0\">"
- "<updatecheck /><packages><package fp=\"1\"/></packages></app>"))
- << post_interceptor_->GetRequestsAsString();
- EXPECT_NE(string::npos,
- post_interceptor_->GetRequests()[3].find(
- "<app appid=\"ihfokbkgjpifnbbojhneepfflplebdkc\" "
- "version=\"1.0\" nextversion=\"2.0\">"
- "<event eventtype=\"3\" eventresult=\"1\" diffresult=\"1\" "
- "previousfp=\"1\" nextfp=\"22\"/>"))
- << post_interceptor_->GetRequestsAsString();
- EXPECT_NE(
- string::npos,
- post_interceptor_->GetRequests()[4].find(
- "<app appid=\"ihfokbkgjpifnbbojhneepfflplebdkc\" version=\"2.0\">"
- "<updatecheck /><packages><package fp=\"22\"/></packages></app>"))
- << post_interceptor_->GetRequestsAsString();
- component_updater()->Stop();
-}
-
-// Verify that component installation falls back to downloading and installing
-// a full update if the differential update fails (in this case, because the
-// installer does not know about the existing files). We do two loops; the final
-// loop should do nothing.
-// We also check that exactly 4 non-ping network requests are issued:
-// 1- update check (loop 1)
-// 2- download differential crx
-// 3- download full crx
-// 4- update check (loop 2 - no update available)
-// There should be one ping for the first attempted update.
-// This test is flaky on Android. crbug.com/329883
-#if defined(OS_ANDROID)
-#define MAYBE_DifferentialUpdateFails DISABLED_DifferentialUpdateFails
-#else
-#define MAYBE_DifferentialUpdateFails DifferentialUpdateFails
-#endif
-TEST_F(ComponentUpdaterTest, MAYBE_DifferentialUpdateFails) {
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"),
- test_file("updatecheck_diff_reply_2.xml")));
- EXPECT_TRUE(post_interceptor_->ExpectRequest(new PartialMatch("event")));
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"),
- test_file("updatecheck_diff_reply_3.xml")));
-
- get_interceptor_->SetResponse(
- GURL("http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"),
- test_file("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"));
- get_interceptor_->SetResponse(
- GURL(
- "http://localhost/download/"
- "ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"),
- test_file("ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"));
- get_interceptor_->SetResponse(
- GURL("http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"),
- test_file("ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"));
-
- scoped_refptr<TestInstaller> installer(new TestInstaller);
- CrxComponent com;
- RegisterComponent(&com, kTestComponent_ihfo, Version("1.0"), installer);
-
- test_configurator()->SetLoopCount(2);
- component_updater()->Start();
- RunThreads();
-
- // A failed differential update does not count as a failed install.
- EXPECT_EQ(0, installer->error());
- EXPECT_EQ(1, installer->install_count());
-
- EXPECT_EQ(3, post_interceptor_->GetHitCount())
- << post_interceptor_->GetRequestsAsString();
- EXPECT_EQ(3, post_interceptor_->GetCount())
- << post_interceptor_->GetRequestsAsString();
- EXPECT_EQ(2, get_interceptor_->GetHitCount());
-
- EXPECT_NE(
- string::npos,
- post_interceptor_->GetRequests()[0].find(
- "<app appid=\"ihfokbkgjpifnbbojhneepfflplebdkc\" version=\"1.0\">"
- "<updatecheck /></app>"))
- << post_interceptor_->GetRequestsAsString();
- EXPECT_NE(string::npos,
- post_interceptor_->GetRequests()[1].find(
- "<app appid=\"ihfokbkgjpifnbbojhneepfflplebdkc\" "
- "version=\"1.0\" nextversion=\"2.0\">"
- "<event eventtype=\"3\" eventresult=\"1\" diffresult=\"0\" "
- "differrorcat=\"2\" differrorcode=\"16\" nextfp=\"22\"/>"))
- << post_interceptor_->GetRequestsAsString();
- EXPECT_NE(
- string::npos,
- post_interceptor_->GetRequests()[2].find(
- "<app appid=\"ihfokbkgjpifnbbojhneepfflplebdkc\" version=\"2.0\">"
- "<updatecheck /><packages><package fp=\"22\"/></packages></app>"))
- << post_interceptor_->GetRequestsAsString();
-
- component_updater()->Stop();
-}
-
-// Test is flakey on Android bots. See crbug.com/331420.
-#if defined(OS_ANDROID)
-#define MAYBE_CheckFailedInstallPing DISABLED_CheckFailedInstallPing
-#else
-#define MAYBE_CheckFailedInstallPing CheckFailedInstallPing
-#endif
-// Verify that a failed installation causes an install failure ping.
-TEST_F(ComponentUpdaterTest, MAYBE_CheckFailedInstallPing) {
- // This test installer reports installation failure.
- class FailingTestInstaller : public TestInstaller {
- bool Install(const base::DictionaryValue& manifest,
- const base::FilePath& unpack_path) override {
- ++install_count_;
- base::DeleteFile(unpack_path, true);
- return false;
- }
-
- private:
- ~FailingTestInstaller() override {}
- };
- scoped_refptr<FailingTestInstaller> installer(new FailingTestInstaller);
-
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
- EXPECT_TRUE(post_interceptor_->ExpectRequest(new PartialMatch("event")));
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
- EXPECT_TRUE(post_interceptor_->ExpectRequest(new PartialMatch("event")));
- get_interceptor_->SetResponse(
- GURL(expected_crx_url),
- test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"));
-
- // Start with 0.9, and attempt update to 1.0.
- // Loop twice to issue two checks: (1) with original 0.9 version
- // and (2), which should retry with 0.9.
- CrxComponent com;
- RegisterComponent(&com, kTestComponent_jebg, Version("0.9"), installer);
-
- test_configurator()->SetLoopCount(2);
- component_updater()->Start();
- RunThreads();
-
- EXPECT_EQ(4, post_interceptor_->GetHitCount())
- << post_interceptor_->GetRequestsAsString();
- EXPECT_EQ(2, get_interceptor_->GetHitCount());
-
- EXPECT_NE(
- string::npos,
- post_interceptor_->GetRequests()[0].find(
- "<app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" version=\"0.9\">"
- "<updatecheck /></app>"))
- << post_interceptor_->GetRequestsAsString();
- EXPECT_NE(string::npos, post_interceptor_->GetRequests()[1].find(
- "<app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" "
- "version=\"0.9\" nextversion=\"1.0\">"
- "<event eventtype=\"3\" eventresult=\"0\" "
- "errorcat=\"3\" errorcode=\"9\"/>"))
- << post_interceptor_->GetRequestsAsString();
- EXPECT_NE(
- string::npos,
- post_interceptor_->GetRequests()[2].find(
- "<app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" version=\"0.9\">"
- "<updatecheck /></app>"))
- << post_interceptor_->GetRequestsAsString();
- EXPECT_NE(string::npos, post_interceptor_->GetRequests()[3].find(
- "<app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" "
- "version=\"0.9\" nextversion=\"1.0\">"
- "<event eventtype=\"3\" eventresult=\"0\" "
- "errorcat=\"3\" errorcode=\"9\"/>"))
- << post_interceptor_->GetRequestsAsString();
-
- // Loop once more, but expect no ping because a noupdate response is issued.
- // This is necessary to clear out the fire-and-forget ping from the previous
- // iteration.
- post_interceptor_->Reset();
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"),
- test_file("updatecheck_reply_noupdate.xml")));
-
- test_configurator()->SetLoopCount(1);
- component_updater()->Start();
- RunThreads();
-
- EXPECT_EQ(0, installer->error());
- EXPECT_EQ(2, installer->install_count());
-
- EXPECT_EQ(1, post_interceptor_->GetHitCount())
- << post_interceptor_->GetRequestsAsString();
- EXPECT_EQ(1, post_interceptor_->GetCount())
- << post_interceptor_->GetRequestsAsString();
-
- EXPECT_NE(
- string::npos,
- post_interceptor_->GetRequests()[0].find(
- "<app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" version=\"0.9\">"
- "<updatecheck /></app>"))
- << post_interceptor_->GetRequestsAsString();
-
- component_updater()->Stop();
-}
-
-// Verify that we successfully propagate a patcher error.
-// ihfokbkgjpifnbbojhneepfflplebdkc_1to2_bad.crx contains an incorrect
-// patching instruction that should fail.
-TEST_F(ComponentUpdaterTest, DifferentialUpdateFailErrorcode) {
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"),
- test_file("updatecheck_diff_reply_1.xml")));
- EXPECT_TRUE(post_interceptor_->ExpectRequest(new PartialMatch("event")));
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"),
- test_file("updatecheck_diff_reply_2.xml")));
- EXPECT_TRUE(post_interceptor_->ExpectRequest(new PartialMatch("event")));
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"),
- test_file("updatecheck_diff_reply_3.xml")));
-
- get_interceptor_->SetResponse(
- GURL("http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"),
- test_file("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"));
- // This intercept returns a different file than what is specified in the
- // update check response and requested in the download. The file that is
- // actually dowloaded contains a patching error, an therefore, an error
- // is injected at the time of patching.
- get_interceptor_->SetResponse(
- GURL(
- "http://localhost/download/"
- "ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"),
- test_file("ihfokbkgjpifnbbojhneepfflplebdkc_1to2_bad.crx"));
- get_interceptor_->SetResponse(
- GURL("http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"),
- test_file("ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"));
-
- scoped_refptr<TestInstaller> installer(new VersionedTestInstaller);
- CrxComponent com;
- RegisterComponent(&com, kTestComponent_ihfo, Version("0.0"), installer);
-
- test_configurator()->SetLoopCount(3);
- component_updater()->Start();
- RunThreads();
- component_updater()->Stop();
-
- EXPECT_EQ(0, installer->error());
- EXPECT_EQ(2, installer->install_count());
-
- EXPECT_EQ(5, post_interceptor_->GetHitCount())
- << post_interceptor_->GetRequestsAsString();
- EXPECT_EQ(5, post_interceptor_->GetCount())
- << post_interceptor_->GetRequestsAsString();
- EXPECT_EQ(3, get_interceptor_->GetHitCount());
-
- EXPECT_NE(
- string::npos,
- post_interceptor_->GetRequests()[0].find(
- "<app appid=\"ihfokbkgjpifnbbojhneepfflplebdkc\" version=\"0.0\">"
- "<updatecheck /></app>"))
- << post_interceptor_->GetRequestsAsString();
- EXPECT_NE(string::npos,
- post_interceptor_->GetRequests()[1].find(
- "<app appid=\"ihfokbkgjpifnbbojhneepfflplebdkc\" "
- "version=\"0.0\" nextversion=\"1.0\">"
- "<event eventtype=\"3\" eventresult=\"1\" nextfp=\"1\"/>"))
- << post_interceptor_->GetRequestsAsString();
- EXPECT_NE(
- string::npos,
- post_interceptor_->GetRequests()[2].find(
- "<app appid=\"ihfokbkgjpifnbbojhneepfflplebdkc\" version=\"1.0\">"
- "<updatecheck /><packages><package fp=\"1\"/></packages></app>"))
- << post_interceptor_->GetRequestsAsString();
- EXPECT_NE(string::npos, post_interceptor_->GetRequests()[3].find(
- "<app appid=\"ihfokbkgjpifnbbojhneepfflplebdkc\" "
- "version=\"1.0\" nextversion=\"2.0\">"
- "<event eventtype=\"3\" eventresult=\"1\" "
- "diffresult=\"0\" differrorcat=\"2\" "
- "differrorcode=\"14\" diffextracode1=\"305\" "
- "previousfp=\"1\" nextfp=\"22\"/>"))
- << post_interceptor_->GetRequestsAsString();
- EXPECT_NE(
- string::npos,
- post_interceptor_->GetRequests()[4].find(
- "<app appid=\"ihfokbkgjpifnbbojhneepfflplebdkc\" version=\"2.0\">"
- "<updatecheck /><packages><package fp=\"22\"/></packages></app>"))
- << post_interceptor_->GetRequestsAsString();
-}
-
-class TestResourceController : public content::ResourceController {
- public:
- virtual void SetThrottle(content::ResourceThrottle* throttle) {}
-};
-
-content::ResourceThrottle* RequestTestResourceThrottle(
- ComponentUpdateService* cus,
- TestResourceController* controller,
- const char* crx_id) {
- net::TestURLRequestContext context;
- scoped_ptr<net::URLRequest> url_request(context.CreateRequest(
- GURL("http://foo.example.com/thing.bin"), net::DEFAULT_PRIORITY, NULL));
-
- content::ResourceThrottle* rt = GetOnDemandResourceThrottle(cus, crx_id);
- rt->set_controller_for_testing(controller);
- controller->SetThrottle(rt);
- return rt;
-}
-
-void RequestAndDeleteResourceThrottle(ComponentUpdateService* cus,
- const char* crx_id) {
- // By requesting a throttle and deleting it immediately we ensure that we
- // hit the case where the component updater tries to use the weak
- // pointer to a dead Resource throttle.
- class NoCallResourceController : public TestResourceController {
- public:
- ~NoCallResourceController() override {}
- void Cancel() override { CHECK(false); }
- void CancelAndIgnore() override { CHECK(false); }
- void CancelWithError(int error_code) override { CHECK(false); }
- void Resume() override { CHECK(false); }
- } controller;
-
- delete RequestTestResourceThrottle(cus, &controller, crx_id);
-}
-
-TEST_F(ComponentUpdaterTest, ResourceThrottleDeletedNoUpdate) {
- MockServiceObserver observer;
- {
- InSequence seq;
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_STARTED, ""))
- .Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
- "abagagagagagagagagagagagagagagag")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_SLEEPING, ""))
- .Times(1);
- }
-
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
-
- scoped_refptr<TestInstaller> installer(new TestInstaller);
- CrxComponent com;
- component_updater()->AddObserver(&observer);
- EXPECT_EQ(Status::kOk, RegisterComponent(&com, kTestComponent_abag,
- Version("1.1"), installer));
- // The following two calls ensure that we don't do an update check via the
- // timer, so the only update check should be the on-demand one.
- test_configurator()->SetInitialDelay(1000000);
- test_configurator()->SetRecheckTime(1000000);
- test_configurator()->SetLoopCount(1);
- component_updater()->Start();
-
- RunThreadsUntilIdle();
-
- EXPECT_EQ(0, post_interceptor_->GetHitCount());
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&RequestAndDeleteResourceThrottle, component_updater(),
- "abagagagagagagagagagagagagagagag"));
-
- RunThreads();
-
- EXPECT_EQ(1, post_interceptor_->GetHitCount());
- EXPECT_EQ(0, installer->error());
- EXPECT_EQ(0, installer->install_count());
-
- component_updater()->Stop();
-}
-
-class CancelResourceController : public TestResourceController {
- public:
- CancelResourceController() : throttle_(NULL), resume_called_(0) {}
- ~CancelResourceController() override {
- // Check that the throttle has been resumed by the time we
- // exit the test.
- CHECK_EQ(1, resume_called_);
- delete throttle_;
- }
- void Cancel() override { CHECK(false); }
- void CancelAndIgnore() override { CHECK(false); }
- void CancelWithError(int error_code) override { CHECK(false); }
- void Resume() override {
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
- base::Bind(&CancelResourceController::ResumeCalled,
- base::Unretained(this)));
- }
- void SetThrottle(content::ResourceThrottle* throttle) override {
- throttle_ = throttle;
- bool defer = false;
- // Initially the throttle is blocked. The CUS needs to run a
- // task on the UI thread to decide if it should unblock.
- throttle_->WillStartRequest(&defer);
- CHECK(defer);
- }
-
- private:
- void ResumeCalled() { ++resume_called_; }
-
- content::ResourceThrottle* throttle_;
- int resume_called_;
-};
-
-// Tests the on-demand update with resource throttle, including the
-// cooldown interval between calls.
-TEST_F(ComponentUpdaterTest, ResourceThrottleLiveNoUpdate) {
- MockServiceObserver observer;
- {
- InSequence seq;
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_STARTED, ""))
- .Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
- "abagagagagagagagagagagagagagagag")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_SLEEPING, ""))
- .Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_STARTED, ""))
- .Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
- "abagagagagagagagagagagagagagagag")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_SLEEPING, ""))
- .Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATER_STARTED, ""))
- .Times(1);
- }
-
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
-
- scoped_refptr<TestInstaller> installer(new TestInstaller);
- CrxComponent com;
- component_updater()->AddObserver(&observer);
- EXPECT_EQ(Status::kOk, RegisterComponent(&com, kTestComponent_abag,
- Version("1.1"), installer));
- // The following two calls ensure that we don't do an update check via the
- // timer, so the only update check should be the on-demand one.
- test_configurator()->SetInitialDelay(1000000);
- test_configurator()->SetRecheckTime(1000000);
- test_configurator()->SetLoopCount(1);
- component_updater()->Start();
-
- RunThreadsUntilIdle();
-
- EXPECT_EQ(0, post_interceptor_->GetHitCount());
-
- {
- // First on-demand update check is expected to succeeded.
- CancelResourceController controller;
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(base::IgnoreResult(&RequestTestResourceThrottle),
- component_updater(), &controller,
- "abagagagagagagagagagagagagagagag"));
-
- RunThreads();
-
- EXPECT_EQ(1, post_interceptor_->GetHitCount());
- EXPECT_EQ(0, installer->error());
- EXPECT_EQ(0, installer->install_count());
-
- component_updater()->Stop();
- }
-
- {
- // Second on-demand update check is expected to succeed as well, since there
- // is no cooldown interval between calls, due to calling SetOnDemandTime.
- test_configurator()->SetOnDemandTime(0);
- test_configurator()->SetLoopCount(1);
- component_updater()->Start();
-
- CancelResourceController controller;
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(base::IgnoreResult(&RequestTestResourceThrottle),
- component_updater(), &controller,
- "abagagagagagagagagagagagagagagag"));
-
- RunThreads();
-
- EXPECT_EQ(1, post_interceptor_->GetHitCount());
- EXPECT_EQ(0, installer->error());
- EXPECT_EQ(0, installer->install_count());
-
- component_updater()->Stop();
- }
-
- {
- // This on-demand call is expected not to trigger a component update check.
- test_configurator()->SetOnDemandTime(1000000);
- component_updater()->Start();
-
- CancelResourceController controller;
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(base::IgnoreResult(&RequestTestResourceThrottle),
- component_updater(), &controller,
- "abagagagagagagagagagagagagagagag"));
- RunThreadsUntilIdle();
- }
-}
-
-// Tests adding and removing observers.
-TEST_F(ComponentUpdaterTest, Observer) {
- MockServiceObserver observer1, observer2;
-
- // Expect that two observers see the events.
- {
- InSequence seq;
- EXPECT_CALL(observer1, OnEvent(Events::COMPONENT_UPDATER_STARTED, ""))
- .Times(1);
- EXPECT_CALL(observer2, OnEvent(Events::COMPONENT_UPDATER_STARTED, ""))
- .Times(1);
- EXPECT_CALL(observer1, OnEvent(Events::COMPONENT_NOT_UPDATED,
- "abagagagagagagagagagagagagagagag"))
- .Times(1);
- EXPECT_CALL(observer2, OnEvent(Events::COMPONENT_NOT_UPDATED,
- "abagagagagagagagagagagagagagagag"))
- .Times(1);
- EXPECT_CALL(observer1, OnEvent(Events::COMPONENT_UPDATER_SLEEPING, ""))
- .Times(1);
- EXPECT_CALL(observer2, OnEvent(Events::COMPONENT_UPDATER_SLEEPING, ""))
- .Times(1);
- }
-
- EXPECT_TRUE(post_interceptor_->ExpectRequest(
- new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
-
- component_updater()->AddObserver(&observer1);
- component_updater()->AddObserver(&observer2);
-
- scoped_refptr<TestInstaller> installer(new TestInstaller);
- CrxComponent com;
- EXPECT_EQ(Status::kOk, RegisterComponent(&com, kTestComponent_abag,
- Version("1.1"), installer));
- test_configurator()->SetLoopCount(1);
- component_updater()->Start();
- RunThreads();
-
- // After removing the first observer, it's only the second observer that
- // gets the events.
- EXPECT_TRUE(Mock::VerifyAndClearExpectations(&observer1));
- EXPECT_TRUE(Mock::VerifyAndClearExpectations(&observer2));
- {
- InSequence seq;
- EXPECT_CALL(observer2, OnEvent(Events::COMPONENT_UPDATER_STARTED, ""))
- .Times(1);
- EXPECT_CALL(observer2, OnEvent(Events::COMPONENT_NOT_UPDATED,
- "abagagagagagagagagagagagagagagag"))
- .Times(1);
- EXPECT_CALL(observer2, OnEvent(Events::COMPONENT_UPDATER_SLEEPING, ""))
- .Times(1);
- }
-
- component_updater()->RemoveObserver(&observer1);
-
- test_configurator()->SetLoopCount(1);
- component_updater()->Start();
- RunThreads();
-
- // Both observers are removed and no one gets the events.
- EXPECT_TRUE(Mock::VerifyAndClearExpectations(&observer1));
- EXPECT_TRUE(Mock::VerifyAndClearExpectations(&observer2));
- component_updater()->RemoveObserver(&observer2);
-
- test_configurator()->SetLoopCount(1);
- component_updater()->Start();
- RunThreads();
-
- component_updater()->Stop();
-}
-
-} // namespace component_updater
diff --git a/chrome/browser/component_updater/component_updater_service_unittest.h b/chrome/browser/component_updater/component_updater_service_unittest.h
deleted file mode 100644
index e0d1c41..0000000
--- a/chrome/browser/component_updater/component_updater_service_unittest.h
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2013 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.
-
-#ifndef CHROME_BROWSER_COMPONENT_UPDATER_COMPONENT_UPDATER_SERVICE_UNITTEST_H_
-#define CHROME_BROWSER_COMPONENT_UPDATER_COMPONENT_UPDATER_SERVICE_UNITTEST_H_
-
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "base/files/file_path.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "components/component_updater/component_updater_service.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-class LocalHostTestURLRequestInterceptor;
-}
-
-namespace update_client {
-struct CrxComponent;
-class InterceptorFactory;
-class TestConfigurator;
-class TestInstaller;
-class URLRequestPostInterceptor;
-}
-
-namespace component_updater {
-
-// Intercepts HTTP GET requests sent to "localhost".
-typedef net::LocalHostTestURLRequestInterceptor GetInterceptor;
-
-class ComponentUpdaterTest : public testing::Test {
- public:
- enum TestComponents {
- kTestComponent_abag,
- kTestComponent_jebg,
- kTestComponent_ihfo,
- };
-
- ComponentUpdaterTest();
-
- ~ComponentUpdaterTest() override;
-
- void SetUp() override;
-
- void TearDown() override;
-
- ComponentUpdateService* component_updater();
-
- // Makes the full path to a component updater test file.
- const base::FilePath test_file(const char* file);
-
- scoped_refptr<update_client::TestConfigurator> test_configurator();
-
- ComponentUpdateService::Status RegisterComponent(
- update_client::CrxComponent* com,
- TestComponents component,
- const Version& version,
- const scoped_refptr<update_client::TestInstaller>& installer);
-
- protected:
- void RunThreads();
- void RunThreadsUntilIdle();
-
- scoped_ptr<update_client::InterceptorFactory> interceptor_factory_;
-
- // Owned by the factory.
- update_client::URLRequestPostInterceptor* post_interceptor_;
-
- scoped_ptr<GetInterceptor> get_interceptor_;
-
- private:
- content::TestBrowserThreadBundle thread_bundle_;
- scoped_refptr<update_client::TestConfigurator> test_config_;
- scoped_ptr<ComponentUpdateService> component_updater_;
-};
-
-const char expected_crx_url[] =
- "http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx";
-
-class MockServiceObserver : public ServiceObserver {
- public:
- MockServiceObserver();
- ~MockServiceObserver();
- MOCK_METHOD2(OnEvent, void(Events event, const std::string&));
-};
-
-class OnDemandTester {
- public:
- static ComponentUpdateService::Status OnDemand(
- ComponentUpdateService* cus,
- const std::string& component_id);
-};
-
-} // namespace component_updater
-
-#endif // CHROME_BROWSER_COMPONENT_UPDATER_COMPONENT_UPDATER_SERVICE_UNITTEST_H_
diff --git a/chrome/browser/component_updater/pepper_flash_component_installer.cc b/chrome/browser/component_updater/pepper_flash_component_installer.cc
index 80d5715..80138da 100644
--- a/chrome/browser/component_updater/pepper_flash_component_installer.cc
+++ b/chrome/browser/component_updater/pepper_flash_component_installer.cc
@@ -263,9 +263,8 @@ void FinishPepperFlashUpdateRegistration(ComponentUpdateService* cus,
pepflash.installer = new PepperFlashComponentInstaller(version);
pepflash.version = version;
pepflash.pk_hash.assign(kSha2Hash, &kSha2Hash[sizeof(kSha2Hash)]);
- if (cus->RegisterComponent(pepflash) != ComponentUpdateService::Status::kOk) {
+ if (!cus->RegisterComponent(pepflash))
NOTREACHED() << "Pepper Flash component registration failed.";
- }
}
void StartPepperFlashUpdateRegistration(ComponentUpdateService* cus) {
diff --git a/chrome/browser/component_updater/pnacl_component_installer.cc b/chrome/browser/component_updater/pnacl_component_installer.cc
index d9da419..4f2c822 100644
--- a/chrome/browser/component_updater/pnacl_component_installer.cc
+++ b/chrome/browser/component_updater/pnacl_component_installer.cc
@@ -307,12 +307,8 @@ void FinishPnaclUpdateRegistration(
pci->set_current_fingerprint(current_fingerprint);
CrxComponent pnacl_component = pci->GetCrxComponent();
- ComponentUpdateService::Status status =
- pci->cus()->RegisterComponent(pnacl_component);
- if (status != ComponentUpdateService::Status::kOk &&
- status != ComponentUpdateService::Status::kReplaced) {
+ if (!pci->cus()->RegisterComponent(pnacl_component))
NOTREACHED() << "Pnacl component registration failed.";
- }
}
// Check if there is an existing version on disk first to know when
diff --git a/chrome/browser/component_updater/recovery_component_installer.cc b/chrome/browser/component_updater/recovery_component_installer.cc
index 0b901e6..3657d64 100644
--- a/chrome/browser/component_updater/recovery_component_installer.cc
+++ b/chrome/browser/component_updater/recovery_component_installer.cc
@@ -235,7 +235,7 @@ void RecoveryRegisterHelper(ComponentUpdateService* cus, PrefService* prefs) {
recovery.installer = new RecoveryComponentInstaller(version, prefs);
recovery.version = version;
recovery.pk_hash.assign(kSha2Hash, &kSha2Hash[sizeof(kSha2Hash)]);
- if (cus->RegisterComponent(recovery) != ComponentUpdateService::Status::kOk) {
+ if (!cus->RegisterComponent(recovery)) {
NOTREACHED() << "Recovery component registration failed.";
}
}
diff --git a/chrome/browser/component_updater/supervised_user_whitelist_installer.cc b/chrome/browser/component_updater/supervised_user_whitelist_installer.cc
index aa2a2c9..c41c144d 100644
--- a/chrome/browser/component_updater/supervised_user_whitelist_installer.cc
+++ b/chrome/browser/component_updater/supervised_user_whitelist_installer.cc
@@ -252,16 +252,14 @@ bool SupervisedUserWhitelistInstallerImpl::UnregisterWhitelistInternal(
base::ListValue* clients = nullptr;
success = whitelist_dict->GetList(kClients, &clients);
- bool removed = clients->Remove(base::StringValue(client_id), nullptr);
+ const bool removed = clients->Remove(base::StringValue(client_id), nullptr);
if (!clients->empty())
return removed;
pref_dict->RemoveWithoutPathExpansion(crx_id, nullptr);
- const ComponentUpdateService::Status status =
- cus_->UnregisterComponent(crx_id);
- DCHECK_EQ(static_cast<int>(ComponentUpdateService::Status::kOk),
- static_cast<int>(status));
+ const bool result = cus_->UnregisterComponent(crx_id);
+ DCHECK(result);
return removed;
}
@@ -433,9 +431,8 @@ std::vector<uint8_t> SupervisedUserWhitelistInstaller::GetHashFromCrxId(
void SupervisedUserWhitelistInstaller::TriggerComponentUpdate(
OnDemandUpdater* updater,
const std::string& crx_id) {
- ComponentUpdateService::Status status = updater->OnDemandUpdate(crx_id);
- DCHECK_EQ(static_cast<int>(ComponentUpdateService::Status::kOk),
- static_cast<int>(status));
+ const bool result = updater->OnDemandUpdate(crx_id);
+ DCHECK(result);
}
} // namespace component_updater
diff --git a/chrome/browser/component_updater/supervised_user_whitelist_installer_unittest.cc b/chrome/browser/component_updater/supervised_user_whitelist_installer_unittest.cc
index c5e897f..a80e3a0 100644
--- a/chrome/browser/component_updater/supervised_user_whitelist_installer_unittest.cc
+++ b/chrome/browser/component_updater/supervised_user_whitelist_installer_unittest.cc
@@ -78,44 +78,34 @@ class MockComponentUpdateService : public ComponentUpdateService,
void AddObserver(Observer* observer) override { ADD_FAILURE(); }
void RemoveObserver(Observer* observer) override { ADD_FAILURE(); }
- Status Start() override {
- ADD_FAILURE();
- return Status::kError;
- }
-
- Status Stop() override {
- ADD_FAILURE();
- return Status::kError;
- }
-
std::vector<std::string> GetComponentIDs() const override {
ADD_FAILURE();
return std::vector<std::string>();
}
- Status RegisterComponent(const CrxComponent& component) override {
+ bool RegisterComponent(const CrxComponent& component) override {
EXPECT_EQ(nullptr, component_.get());
component_.reset(new CrxComponent(component));
if (!registration_callback_.is_null())
registration_callback_.Run();
- return Status::kOk;
+ return true;
}
- Status UnregisterComponent(const std::string& crx_id) override {
+ bool UnregisterComponent(const std::string& crx_id) override {
if (!component_) {
ADD_FAILURE();
- return Status::kError;
+ return false;
}
EXPECT_EQ(GetCrxComponentID(*component_), crx_id);
if (!component_->installer->Uninstall()) {
ADD_FAILURE();
- return Status::kError;
+ return false;
}
component_.reset();
- return Status::kOk;
+ return true;
}
OnDemandUpdater& GetOnDemandUpdater() override { return *this; }
@@ -136,16 +126,16 @@ class MockComponentUpdateService : public ComponentUpdateService,
}
// OnDemandUpdater implementation:
- Status OnDemandUpdate(const std::string& crx_id) override {
+ bool OnDemandUpdate(const std::string& crx_id) override {
on_demand_update_called_ = true;
if (!component_) {
ADD_FAILURE() << "Trying to update unregistered component " << crx_id;
- return Status::kError;
+ return false;
}
EXPECT_EQ(GetCrxComponentID(*component_), crx_id);
- return Status::kOk;
+ return true;
}
private:
diff --git a/chrome/browser/component_updater/swiftshader_component_installer.cc b/chrome/browser/component_updater/swiftshader_component_installer.cc
index 34355ca..1e82d3e 100644
--- a/chrome/browser/component_updater/swiftshader_component_installer.cc
+++ b/chrome/browser/component_updater/swiftshader_component_installer.cc
@@ -178,8 +178,7 @@ void FinishSwiftShaderUpdateRegistration(ComponentUpdateService* cus,
swiftshader.installer = new SwiftShaderComponentInstaller(version);
swiftshader.version = version;
swiftshader.pk_hash.assign(kSha2Hash, &kSha2Hash[sizeof(kSha2Hash)]);
- if (cus->RegisterComponent(swiftshader) !=
- ComponentUpdateService::Status::kOk) {
+ if (!cus->RegisterComponent(swiftshader)) {
NOTREACHED() << "SwiftShader component registration fail";
}
}
diff --git a/chrome/browser/net/crl_set_fetcher.cc b/chrome/browser/net/crl_set_fetcher.cc
index 4118952..5c402cd 100644
--- a/chrome/browser/net/crl_set_fetcher.cc
+++ b/chrome/browser/net/crl_set_fetcher.cc
@@ -151,10 +151,8 @@ void CRLSetFetcher::RegisterComponent(uint32 sequence_of_loaded_crl) {
component.version = Version("0");
}
- if (cus_->RegisterComponent(component) !=
- ComponentUpdateService::Status::kOk) {
+ if (!cus_->RegisterComponent(component))
NOTREACHED() << "RegisterComponent returned error";
- }
}
void CRLSetFetcher::DoDeleteFromDisk() {
diff --git a/chrome/browser/ui/webui/components_ui.cc b/chrome/browser/ui/webui/components_ui.cc
index da8d1fb..a929a16 100644
--- a/chrome/browser/ui/webui/components_ui.cc
+++ b/chrome/browser/ui/webui/components_ui.cc
@@ -189,9 +189,9 @@ base::RefCountedMemory* ComponentsUI::GetFaviconResourceBytes(
base::string16 ComponentsUI::ComponentEventToString(Events event) {
switch (event) {
- case Events::COMPONENT_UPDATER_STARTED:
+ case Events::COMPONENT_CHECKING_FOR_UPDATES:
return l10n_util::GetStringUTF16(IDS_COMPONENTS_EVT_STATUS_STARTED);
- case Events::COMPONENT_UPDATER_SLEEPING:
+ case Events::COMPONENT_WAIT:
return l10n_util::GetStringUTF16(IDS_COMPONENTS_EVT_STATUS_SLEEPING);
case Events::COMPONENT_UPDATE_FOUND:
return l10n_util::GetStringUTF16(IDS_COMPONENTS_EVT_STATUS_FOUND);
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 0648d0c..9c28425 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -62,7 +62,6 @@
'browser/command_updater_unittest.cc',
'browser/component_updater/chrome_component_updater_configurator_unittest.cc',
'browser/component_updater/cld_component_installer_unittest.cc',
- 'browser/component_updater/component_updater_service_unittest.cc',
'browser/component_updater/supervised_user_whitelist_installer_unittest.cc',
'browser/content_settings/content_settings_default_provider_unittest.cc',
'browser/content_settings/content_settings_mock_observer.cc',
diff --git a/components/BUILD.gn b/components/BUILD.gn
index e57a779..cef6b23 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -267,6 +267,7 @@ test("components_unittests") {
"//components/bookmarks/managed:unit_tests",
"//components/captive_portal:unit_tests",
"//components/cloud_devices/common:unit_tests",
+ "//components/component_updater:unit_tests",
"//components/content_settings/core/browser:unit_tests",
"//components/content_settings/core/common:unit_tests",
"//components/crx_file:unit_tests",
diff --git a/components/component_updater.gypi b/components/component_updater.gypi
index cfc5a9f..124eb21 100644
--- a/components/component_updater.gypi
+++ b/components/component_updater.gypi
@@ -22,12 +22,15 @@
'component_updater/component_updater_paths.h',
'component_updater/component_updater_service.cc',
'component_updater/component_updater_service.h',
+ 'component_updater/component_updater_service_internal.h',
'component_updater/component_updater_switches.cc',
'component_updater/component_updater_switches.h',
'component_updater/default_component_installer.cc',
'component_updater/default_component_installer.h',
'component_updater/pref_names.cc',
'component_updater/pref_names.h',
+ 'component_updater/timer.cc',
+ 'component_updater/timer.h',
],
},
],
diff --git a/components/component_updater/BUILD.gn b/components/component_updater/BUILD.gn
index fb756a7..46fea6a 100644
--- a/components/component_updater/BUILD.gn
+++ b/components/component_updater/BUILD.gn
@@ -8,12 +8,15 @@ source_set("component_updater") {
"component_updater_paths.h",
"component_updater_service.cc",
"component_updater_service.h",
+ "component_updater_service_internal.h",
"component_updater_switches.cc",
"component_updater_switches.h",
"default_component_installer.cc",
"default_component_installer.h",
"pref_names.cc",
"pref_names.h",
+ "timer.cc",
+ "timer.h",
]
deps = [
@@ -23,3 +26,18 @@ source_set("component_updater") {
"//url",
]
}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "component_updater_service_unittest.cc",
+ "timer_unittest.cc",
+ ]
+
+ deps = [
+ ":component_updater",
+ "//base",
+ "//testing/gtest",
+ "//testing/gmock",
+ ]
+}
diff --git a/components/component_updater/component_updater_service.cc b/components/component_updater/component_updater_service.cc
index ed49787..29b120e 100644
--- a/components/component_updater/component_updater_service.cc
+++ b/components/component_updater/component_updater_service.cc
@@ -5,10 +5,11 @@
#include "components/component_updater/component_updater_service.h"
#include <algorithm>
-#include <set>
+#include <map>
+#include <string>
+#include <utility>
#include <vector>
-#include "base/at_exit.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
@@ -18,1035 +19,339 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "base/observer_list.h"
#include "base/sequenced_task_runner.h"
-#include "base/stl_util.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/thread_checker.h"
#include "base/timer/timer.h"
-#include "components/update_client/component_patcher_operation.h"
-#include "components/update_client/component_unpacker.h"
+#include "components/component_updater/component_updater_service_internal.h"
+#include "components/component_updater/timer.h"
#include "components/update_client/configurator.h"
-#include "components/update_client/crx_downloader.h"
#include "components/update_client/crx_update_item.h"
-#include "components/update_client/ping_manager.h"
-#include "components/update_client/update_checker.h"
#include "components/update_client/update_client.h"
-#include "components/update_client/update_response.h"
#include "components/update_client/utils.h"
#include "url/gurl.h"
-using update_client::CrxInstaller;
-using update_client::ComponentUnpacker;
-using update_client::Configurator;
-using update_client::CrxComponent;
-using update_client::CrxDownloader;
-using update_client::CrxUpdateItem;
-using update_client::PingManager;
-using update_client::UpdateChecker;
-using update_client::UpdateResponse;
+using CrxInstaller = update_client::CrxInstaller;
+using UpdateClient = update_client::UpdateClient;
namespace component_updater {
-// The component updater is designed to live until process shutdown, so
-// base::Bind() calls are not refcounted.
-
-namespace {
-
-// Returns true if the |proposed| version is newer than |current| version.
-bool IsVersionNewer(const Version& current, const std::string& proposed) {
- Version proposed_ver(proposed);
- return proposed_ver.IsValid() && current.CompareTo(proposed_ver) < 0;
-}
-
-// Returns true if a differential update is available, it has not failed yet,
-// and the configuration allows it.
-bool CanTryDiffUpdate(const CrxUpdateItem* update_item,
- const Configurator& config) {
- return HasDiffUpdate(update_item) && !update_item->diff_update_failed &&
- config.DeltasEnabled();
-}
-
-void AppendDownloadMetrics(
- const std::vector<CrxDownloader::DownloadMetrics>& source,
- std::vector<CrxDownloader::DownloadMetrics>* destination) {
- destination->insert(destination->end(), source.begin(), source.end());
+CrxUpdateService::CrxUpdateService(
+ const scoped_refptr<Configurator>& config,
+ const scoped_refptr<UpdateClient>& update_client)
+ : config_(config),
+ update_client_(update_client),
+ blocking_task_runner_(config->GetSequencedTaskRunner()) {
+ AddObserver(this);
}
-} // namespace
-
-//////////////////////////////////////////////////////////////////////////////
-// The one and only implementation of the ComponentUpdateService interface. In
-// charge of running the show. The main method is ProcessPendingItems() which
-// is called periodically to do the upgrades/installs or the update checks.
-// An important consideration here is to be as "low impact" as we can to the
-// rest of the browser, so even if we have many components registered and
-// eligible for update, we only do one thing at a time with pauses in between
-// the tasks. Also when we do network requests there is only one |url_fetcher_|
-// in flight at a time.
-// There are no locks in this code, the main structure |work_items_| is mutated
-// only from the main thread. The unpack and installation is done in a blocking
-// pool thread. The network requests are done in the IO thread or in the file
-// thread.
-class CrxUpdateService : public ComponentUpdateService, public OnDemandUpdater {
- public:
- explicit CrxUpdateService(const scoped_refptr<Configurator>& config);
- ~CrxUpdateService() override;
-
- // Overrides for ComponentUpdateService.
- void AddObserver(Observer* observer) override;
- void RemoveObserver(Observer* observer) override;
- Status Start() override;
- Status Stop() override;
- Status RegisterComponent(const CrxComponent& component) override;
- Status UnregisterComponent(const std::string& crx_id) override;
- std::vector<std::string> GetComponentIDs() const override;
- OnDemandUpdater& GetOnDemandUpdater() override;
- void MaybeThrottle(const std::string& crx_id,
- const base::Closure& callback) override;
- scoped_refptr<base::SequencedTaskRunner> GetSequencedTaskRunner() override;
-
- // Context for a crx download url request.
- struct CRXContext {
- scoped_refptr<CrxInstaller> installer;
- std::vector<uint8_t> pk_hash;
- std::string id;
- std::string fingerprint;
- CRXContext() : installer(NULL) {}
- };
-
- private:
- enum ErrorCategory {
- kErrorNone = 0,
- kNetworkError,
- kUnpackError,
- kInstallError,
- };
-
- enum StepDelayInterval {
- kStepDelayShort = 0,
- kStepDelayMedium,
- kStepDelayLong,
- };
-
- // Overrides for ComponentUpdateService.
- bool GetComponentDetails(const std::string& component_id,
- CrxUpdateItem* item) const override;
-
- // Overrides for OnDemandUpdater.
- Status OnDemandUpdate(const std::string& component_id) override;
-
- void UpdateCheckComplete(const GURL& original_url,
- int error,
- const std::string& error_message,
- const UpdateResponse::Results& results);
- void OnUpdateCheckSucceeded(const UpdateResponse::Results& results);
- void OnUpdateCheckFailed(int error, const std::string& error_message);
-
- void DownloadProgress(const std::string& component_id,
- const CrxDownloader::Result& download_result);
-
- void DownloadComplete(scoped_ptr<CRXContext> crx_context,
- const CrxDownloader::Result& download_result);
-
- Status OnDemandUpdateInternal(CrxUpdateItem* item);
- Status OnDemandUpdateWithCooldown(CrxUpdateItem* item);
-
- void ProcessPendingItems();
-
- // Uninstall and remove all unregistered work items.
- void UninstallUnregisteredItems();
-
- // Find a component that is ready to update.
- CrxUpdateItem* FindReadyComponent() const;
-
- // Prepares the components for an update check and initiates the request.
- // Returns true if an update check request has been made. Returns false if
- // no update check was needed or an error occured.
- bool CheckForUpdates();
-
- void UpdateComponent(CrxUpdateItem* workitem);
-
- void ScheduleNextRun(StepDelayInterval step_delay);
-
- void ParseResponse(const std::string& xml);
-
- void Install(scoped_ptr<CRXContext> context, const base::FilePath& crx_path);
-
- void EndUnpacking(const std::string& component_id,
- const base::FilePath& crx_path,
- ComponentUnpacker::Error error,
- int extended_error);
-
- void DoneInstalling(const std::string& component_id,
- ComponentUnpacker::Error error,
- int extended_error);
-
- void ChangeItemState(CrxUpdateItem* item, CrxUpdateItem::State to);
-
- size_t ChangeItemStatus(CrxUpdateItem::State from, CrxUpdateItem::State to);
-
- CrxUpdateItem* FindUpdateItemById(const std::string& id) const;
-
- void NotifyObservers(Observer::Events event, const std::string& id);
-
- bool HasOnDemandItems() const;
-
- Status GetServiceStatus(const CrxUpdateItem::State state);
-
- scoped_refptr<Configurator> config_;
-
- scoped_ptr<UpdateChecker> update_checker_;
-
- scoped_ptr<PingManager> ping_manager_;
-
- scoped_refptr<ComponentUnpacker> unpacker_;
-
- scoped_ptr<CrxDownloader> crx_downloader_;
-
- // A collection of every work item.
- typedef std::vector<CrxUpdateItem*> UpdateItems;
- UpdateItems work_items_;
-
- base::OneShotTimer<CrxUpdateService> timer_;
-
- base::ThreadChecker thread_checker_;
-
- // Used to post responses back to the main thread.
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
-
- scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-
- bool running_;
-
- ObserverList<Observer> observer_list_;
-
- DISALLOW_COPY_AND_ASSIGN(CrxUpdateService);
-};
+CrxUpdateService::~CrxUpdateService() {
+ DCHECK(thread_checker_.CalledOnValidThread());
-//////////////////////////////////////////////////////////////////////////////
+ for (const auto item : ready_callbacks_) {
+ item.second.Run();
+ }
-CrxUpdateService::CrxUpdateService(const scoped_refptr<Configurator>& config)
- : config_(config),
- ping_manager_(new PingManager(*config)),
- main_task_runner_(base::MessageLoopProxy::current()),
- blocking_task_runner_(config->GetSequencedTaskRunner()),
- running_(false) {
-}
+ RemoveObserver(this);
-CrxUpdateService::~CrxUpdateService() {
- // Because we are a singleton, at this point only the main thread should be
- // alive, this simplifies the management of the work that could be in
- // flight in other threads.
Stop();
- STLDeleteElements(&work_items_);
}
void CrxUpdateService::AddObserver(Observer* observer) {
DCHECK(thread_checker_.CalledOnValidThread());
- observer_list_.AddObserver(observer);
+ update_client_->AddObserver(observer);
}
void CrxUpdateService::RemoveObserver(Observer* observer) {
DCHECK(thread_checker_.CalledOnValidThread());
- observer_list_.RemoveObserver(observer);
+ update_client_->RemoveObserver(observer);
}
-ComponentUpdateService::Status CrxUpdateService::Start() {
- // Note that RegisterComponent will call Start() when the first
- // component is registered, so it can be called twice. This way
- // we avoid scheduling the timer if there is no work to do.
- VLOG(1) << "CrxUpdateService starting up";
- running_ = true;
- if (work_items_.empty())
- return Status::kOk;
-
- NotifyObservers(Observer::Events::COMPONENT_UPDATER_STARTED, "");
-
- VLOG(1) << "First update attempt will take place in "
- << config_->InitialDelay() << " seconds";
- timer_.Start(FROM_HERE,
- base::TimeDelta::FromSeconds(config_->InitialDelay()),
- this,
- &CrxUpdateService::ProcessPendingItems);
- return Status::kOk;
+void CrxUpdateService::Start() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ VLOG(1) << "CrxUpdateService starting up. "
+ << "First update attempt will take place in "
+ << config_->InitialDelay() << " seconds. "
+ << "Next update attempt will take place in "
+ << config_->NextCheckDelay() << " seconds. ";
+
+ timer_.Start(
+ base::TimeDelta::FromSeconds(config_->InitialDelay()),
+ base::TimeDelta::FromSeconds(config_->NextCheckDelay()),
+ base::Bind(base::IgnoreResult(&CrxUpdateService::CheckForUpdates),
+ base::Unretained(this)));
}
-// Stop the main check + update loop. In flight operations will be
-// completed.
-ComponentUpdateService::Status CrxUpdateService::Stop() {
+// Stops the update loop. In flight operations will be completed.
+void CrxUpdateService::Stop() {
+ DCHECK(thread_checker_.CalledOnValidThread());
VLOG(1) << "CrxUpdateService stopping";
- running_ = false;
timer_.Stop();
- return Status::kOk;
-}
-
-bool CrxUpdateService::HasOnDemandItems() const {
- class Helper {
- public:
- static bool IsOnDemand(CrxUpdateItem* item) { return item->on_demand; }
- };
- return std::find_if(work_items_.begin(),
- work_items_.end(),
- Helper::IsOnDemand) != work_items_.end();
}
-// This function sets the timer which will call ProcessPendingItems() or
-// ProcessRequestedItem() if there is an on_demand item. There
-// are three kinds of waits:
-// - a short delay, when there is immediate work to be done.
-// - a medium delay, when there are updates to be applied within the current
-// update cycle, or there are components that are still unchecked.
-// - a long delay when a full check/update cycle has completed for all
-// components.
-void CrxUpdateService::ScheduleNextRun(StepDelayInterval step_delay) {
+// Adds a component to be checked for upgrades. If the component exists it
+// it will be replaced.
+bool CrxUpdateService::RegisterComponent(const CrxComponent& component) {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(!update_checker_);
- CHECK(!timer_.IsRunning());
- // It could be the case that Stop() had been called while a url request
- // or unpacking was in flight, if so we arrive here but |running_| is
- // false. In that case do not loop again.
- if (!running_)
- return;
+ if (component.pk_hash.empty() || !component.version.IsValid() ||
+ !component.installer) {
+ return false;
+ }
- // Keep the delay short if in the middle of an update (step_delay),
- // or there are new requested_work_items_ that have not been processed yet.
- int64_t delay_seconds = 0;
- if (!HasOnDemandItems()) {
- switch (step_delay) {
- case kStepDelayShort:
- delay_seconds = config_->StepDelay();
- break;
- case kStepDelayMedium:
- delay_seconds = config_->StepDelayMedium();
- break;
- case kStepDelayLong:
- delay_seconds = config_->NextCheckDelay();
- break;
- }
- } else {
- delay_seconds = config_->StepDelay();
+ // Update the registration data if the component has been registered before.
+ const std::string id(GetCrxComponentID(component));
+ auto it = components_.find(id);
+ if (it != components_.end()) {
+ it->second = component;
+ return true;
}
- if (step_delay != kStepDelayShort) {
- NotifyObservers(Observer::Events::COMPONENT_UPDATER_SLEEPING, "");
+ components_.insert(std::make_pair(id, component));
+ components_order_.push_back(id);
- // Zero is only used for unit tests.
- if (0 == delay_seconds)
- return;
- }
+ // Create an initial state for this component. The state is mutated in
+ // response to events from the UpdateClient instance.
+ CrxUpdateItem item;
+ item.id = id;
+ item.component = component;
+ const auto inserted = component_states_.insert(std::make_pair(id, item));
+ DCHECK(inserted.second);
- VLOG(1) << "Scheduling next run to occur in " << delay_seconds << " seconds";
- timer_.Start(FROM_HERE,
- base::TimeDelta::FromSeconds(delay_seconds),
- this,
- &CrxUpdateService::ProcessPendingItems);
-}
+ // Start the timer if this is the first component registered. The first timer
+ // event occurs after an interval defined by the component update
+ // configurator. The subsequent timer events are repeated with a period
+ // defined by the same configurator.
+ if (components_.size() == 1)
+ Start();
-// Given a extension-like component id, find the associated component.
-CrxUpdateItem* CrxUpdateService::FindUpdateItemById(
- const std::string& id) const {
- DCHECK(thread_checker_.CalledOnValidThread());
- CrxUpdateItem::FindById finder(id);
- UpdateItems::const_iterator it =
- std::find_if(work_items_.begin(), work_items_.end(), finder);
- return it != work_items_.end() ? *it : NULL;
+ return true;
}
-// Changes a component's state, clearing on_demand and firing notifications as
-// necessary. By convention, this is the only function that can change a
-// CrxUpdateItem's |state|.
-// TODO(waffles): Do we want to add DCHECKS for valid state transitions here?
-void CrxUpdateService::ChangeItemState(CrxUpdateItem* item,
- CrxUpdateItem::State to) {
+bool CrxUpdateService::UnregisterComponent(const std::string& id) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (to == CrxUpdateItem::State::kNoUpdate ||
- to == CrxUpdateItem::State::kUpdated ||
- to == CrxUpdateItem::State::kUpToDate) {
- item->on_demand = false;
- }
+ auto it = components_.find(id);
+ if (it == components_.end())
+ return false;
- item->state = to;
-
- switch (to) {
- case CrxUpdateItem::State::kCanUpdate:
- NotifyObservers(Observer::Events::COMPONENT_UPDATE_FOUND, item->id);
- break;
- case CrxUpdateItem::State::kUpdatingDiff:
- case CrxUpdateItem::State::kUpdating:
- NotifyObservers(Observer::Events::COMPONENT_UPDATE_READY, item->id);
- break;
- case CrxUpdateItem::State::kUpdated:
- NotifyObservers(Observer::Events::COMPONENT_UPDATED, item->id);
- break;
- case CrxUpdateItem::State::kUpToDate:
- case CrxUpdateItem::State::kNoUpdate:
- NotifyObservers(Observer::Events::COMPONENT_NOT_UPDATED, item->id);
- break;
- case CrxUpdateItem::State::kNew:
- case CrxUpdateItem::State::kChecking:
- case CrxUpdateItem::State::kDownloading:
- case CrxUpdateItem::State::kDownloadingDiff:
- case CrxUpdateItem::State::kDownloaded:
- case CrxUpdateItem::State::kLastStatus:
- // No notification for these states.
- break;
- }
+ DCHECK_EQ(id, it->first);
- // Free possible pending network requests.
- if ((to == CrxUpdateItem::State::kUpdated) ||
- (to == CrxUpdateItem::State::kUpToDate) ||
- (to == CrxUpdateItem::State::kNoUpdate)) {
- for (std::vector<base::Closure>::iterator it =
- item->ready_callbacks.begin();
- it != item->ready_callbacks.end();
- ++it) {
- it->Run();
- }
- item->ready_callbacks.clear();
+ // Delay the uninstall of the component if the component is being updated.
+ if (update_client_->IsUpdating(id)) {
+ components_pending_unregistration_.push_back(id);
+ return true;
}
-}
-// Changes all the components in |work_items_| that have |from| state to
-// |to| state and returns how many have been changed.
-size_t CrxUpdateService::ChangeItemStatus(CrxUpdateItem::State from,
- CrxUpdateItem::State to) {
- DCHECK(thread_checker_.CalledOnValidThread());
- size_t count = 0;
- for (UpdateItems::iterator it = work_items_.begin();
- it != work_items_.end();
- ++it) {
- CrxUpdateItem* item = *it;
- if (item->state == from) {
- ChangeItemState(item, to);
- ++count;
- }
- }
- return count;
+ return DoUnregisterComponent(it->second);
}
-// Adds a component to be checked for upgrades. If the component exists it
-// it will be replaced and the return code is Status::kReplaced.
-ComponentUpdateService::Status CrxUpdateService::RegisterComponent(
- const CrxComponent& component) {
+bool CrxUpdateService::DoUnregisterComponent(const CrxComponent& component) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (component.pk_hash.empty() || !component.version.IsValid() ||
- !component.installer)
- return Status::kError;
-
- std::string id(GetCrxComponentID(component));
- CrxUpdateItem* uit = FindUpdateItemById(id);
- if (uit) {
- uit->component = component;
- uit->unregistered = false;
- return Status::kReplaced;
- }
- uit = new CrxUpdateItem;
- uit->id.swap(id);
- uit->component = component;
-
- work_items_.push_back(uit);
-
- // If this is the first component registered we call Start to
- // schedule the first timer. Otherwise, reset the timer to trigger another
- // pass over the work items, if the component updater is sleeping, fact
- // indicated by a running timer. If the timer is not running, it means that
- // the service is busy updating something, and in that case, this component
- // will be picked up at the next pass.
- if (running_) {
- if (work_items_.size() == 1) {
- Start();
- } else if (timer_.IsRunning()) {
- timer_.Start(FROM_HERE,
- base::TimeDelta::FromSeconds(config_->InitialDelay()),
- this,
- &CrxUpdateService::ProcessPendingItems);
- }
- }
+ const auto id = GetCrxComponentID(component);
+ DCHECK(ready_callbacks_.find(id) == ready_callbacks_.end());
- return Status::kOk;
-}
+ const bool result = component.installer->Uninstall();
-ComponentUpdateService::Status CrxUpdateService::UnregisterComponent(
- const std::string& crx_id) {
- auto it = std::find_if(work_items_.begin(), work_items_.end(),
- CrxUpdateItem::FindById(crx_id));
- if (it == work_items_.end())
- return Status::kError;
+ const auto pos =
+ std::find(components_order_.begin(), components_order_.end(), id);
+ if (pos != components_order_.end())
+ components_order_.erase(pos);
- (*it)->unregistered = true;
+ components_.erase(id);
+ component_states_.erase(id);
- ScheduleNextRun(kStepDelayShort);
- return Status::kOk;
+ return result;
}
std::vector<std::string> CrxUpdateService::GetComponentIDs() const {
DCHECK(thread_checker_.CalledOnValidThread());
- std::vector<std::string> component_ids;
- for (UpdateItems::const_iterator it = work_items_.begin();
- it != work_items_.end();
- ++it) {
- const CrxUpdateItem* item = *it;
- component_ids.push_back(item->id);
- }
- return component_ids;
+ std::vector<std::string> ids;
+ for (const auto& it : components_)
+ ids.push_back(it.first);
+ return ids;
}
OnDemandUpdater& CrxUpdateService::GetOnDemandUpdater() {
+ DCHECK(thread_checker_.CalledOnValidThread());
return *this;
}
-void CrxUpdateService::MaybeThrottle(const std::string& crx_id,
- const base::Closure& callback) {
+const CrxComponent* CrxUpdateService::GetComponent(
+ const std::string& id) const {
DCHECK(thread_checker_.CalledOnValidThread());
- // Check if we can on-demand update, else unblock the request anyway.
- CrxUpdateItem* item = FindUpdateItemById(crx_id);
- Status status = OnDemandUpdateWithCooldown(item);
- if (status == Status::kOk || status == Status::kInProgress) {
- item->ready_callbacks.push_back(callback);
- return;
- }
- callback.Run();
+ const auto it(components_.find(id));
+ return it != components_.end() ? &(it->second) : NULL;
}
-scoped_refptr<base::SequencedTaskRunner>
-CrxUpdateService::GetSequencedTaskRunner() {
- return blocking_task_runner_;
-}
-
-bool CrxUpdateService::GetComponentDetails(const std::string& component_id,
- CrxUpdateItem* item) const {
+const CrxUpdateItem* CrxUpdateService::GetComponentState(
+ const std::string& id) const {
DCHECK(thread_checker_.CalledOnValidThread());
- const CrxUpdateItem* crx_update_item(FindUpdateItemById(component_id));
- if (crx_update_item)
- *item = *crx_update_item;
- return crx_update_item != NULL;
+ const auto it(component_states_.find(id));
+ return it != component_states_.end() ? &it->second : NULL;
}
-// Start the process of checking for an update, for a particular component
-// that was previously registered.
-// |component_id| is a value returned from GetCrxComponentID().
-ComponentUpdateService::Status CrxUpdateService::OnDemandUpdate(
- const std::string& component_id) {
- return OnDemandUpdateInternal(FindUpdateItemById(component_id));
-}
-
-// This is the main loop of the component updater. It updates one component
-// at a time if updates are available. Otherwise, it does an update check or
-// takes a long sleep until the loop runs again.
-void CrxUpdateService::ProcessPendingItems() {
+void CrxUpdateService::MaybeThrottle(const std::string& id,
+ const base::Closure& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
-
- CrxUpdateItem* ready_upgrade = FindReadyComponent();
- if (ready_upgrade) {
- UpdateComponent(ready_upgrade);
- return;
- }
-
- UninstallUnregisteredItems();
-
- if (!CheckForUpdates())
- ScheduleNextRun(kStepDelayLong);
-}
-
-void CrxUpdateService::UninstallUnregisteredItems() {
- std::vector<CrxUpdateItem*> new_work_items;
- for (CrxUpdateItem* item : work_items_) {
- scoped_ptr<CrxUpdateItem> owned_item(item);
- if (owned_item->unregistered) {
- const bool success = owned_item->component.installer->Uninstall();
- DCHECK(success);
- } else {
- new_work_items.push_back(owned_item.release());
+ auto it = components_.find(id);
+ if (it != components_.end()) {
+ DCHECK_EQ(it->first, id);
+ if (OnDemandUpdateWithCooldown(id)) {
+ ready_callbacks_.insert(std::make_pair(id, callback));
+ return;
}
}
- new_work_items.swap(work_items_);
-}
-CrxUpdateItem* CrxUpdateService::FindReadyComponent() const {
- class Helper {
- public:
- static bool IsReadyOnDemand(CrxUpdateItem* item) {
- return item->on_demand && IsReady(item);
- }
- static bool IsReady(CrxUpdateItem* item) {
- return item->state == CrxUpdateItem::State::kCanUpdate;
- }
- };
-
- std::vector<CrxUpdateItem*>::const_iterator it = std::find_if(
- work_items_.begin(), work_items_.end(), Helper::IsReadyOnDemand);
- if (it != work_items_.end())
- return *it;
- it = std::find_if(work_items_.begin(), work_items_.end(), Helper::IsReady);
- if (it != work_items_.end())
- return *it;
- return NULL;
+ callback.Run(); // Unblock the request if the request can't be throttled.
}
-// Prepares the components for an update check and initiates the request.
-// On demand components are always included in the update check request.
-// Otherwise, only include components that have not been checked recently.
-bool CrxUpdateService::CheckForUpdates() {
- const base::TimeDelta minimum_recheck_wait_time =
- base::TimeDelta::FromSeconds(config_->MinimumReCheckWait());
- const base::Time now(base::Time::Now());
-
- std::vector<CrxUpdateItem*> items_to_check;
- for (size_t i = 0; i != work_items_.size(); ++i) {
- CrxUpdateItem* item = work_items_[i];
- DCHECK(item->state == CrxUpdateItem::State::kNew ||
- item->state == CrxUpdateItem::State::kNoUpdate ||
- item->state == CrxUpdateItem::State::kUpToDate ||
- item->state == CrxUpdateItem::State::kUpdated);
-
- const base::TimeDelta time_since_last_checked(now - item->last_check);
-
- if (!item->on_demand &&
- time_since_last_checked < minimum_recheck_wait_time) {
- VLOG(1) << "Skipping check for component update: id=" << item->id
- << ", time_since_last_checked="
- << time_since_last_checked.InSeconds()
- << " seconds: too soon to check for an update";
- continue;
- }
-
- VLOG(1) << "Scheduling update check for component id=" << item->id
- << ", time_since_last_checked="
- << time_since_last_checked.InSeconds() << " seconds";
-
- item->last_check = now;
- item->crx_urls.clear();
- item->crx_diffurls.clear();
- item->previous_version = item->component.version;
- item->next_version = Version();
- item->previous_fp = item->component.fingerprint;
- item->next_fp.clear();
- item->diff_update_failed = false;
- item->error_category = 0;
- item->error_code = 0;
- item->extra_code1 = 0;
- item->diff_error_category = 0;
- item->diff_error_code = 0;
- item->diff_extra_code1 = 0;
- item->download_metrics.clear();
-
- items_to_check.push_back(item);
-
- ChangeItemState(item, CrxUpdateItem::State::kChecking);
- }
+bool CrxUpdateService::OnDemandUpdate(const std::string& id) {
+ DCHECK(thread_checker_.CalledOnValidThread());
- if (items_to_check.empty())
+ if (!GetComponent(id))
return false;
- update_checker_ = UpdateChecker::Create(*config_).Pass();
- return update_checker_->CheckForUpdates(
- items_to_check,
- config_->ExtraRequestParams(),
- base::Bind(&CrxUpdateService::UpdateCheckComplete,
- base::Unretained(this)));
+ return OnDemandUpdateInternal(id);
}
-void CrxUpdateService::UpdateComponent(CrxUpdateItem* workitem) {
- scoped_ptr<CRXContext> crx_context(new CRXContext);
- crx_context->pk_hash = workitem->component.pk_hash;
- crx_context->id = workitem->id;
- crx_context->installer = workitem->component.installer;
- crx_context->fingerprint = workitem->next_fp;
- const std::vector<GURL>* urls = NULL;
- bool allow_background_download = false;
- if (CanTryDiffUpdate(workitem, *config_)) {
- urls = &workitem->crx_diffurls;
- ChangeItemState(workitem, CrxUpdateItem::State::kDownloadingDiff);
- } else {
- // Background downloads are enabled only for selected components and
- // only for full downloads (see issue 340448).
- allow_background_download = workitem->component.allow_background_download;
- urls = &workitem->crx_urls;
- ChangeItemState(workitem, CrxUpdateItem::State::kDownloading);
- }
-
- // On demand component updates are always downloaded in foreground.
- const bool is_background_download = !workitem->on_demand &&
- allow_background_download &&
- config_->UseBackgroundDownloader();
-
- crx_downloader_.reset(
- CrxDownloader::Create(is_background_download, config_->RequestContext(),
- blocking_task_runner_,
- config_->GetSingleThreadTaskRunner()).release());
- crx_downloader_->set_progress_callback(
- base::Bind(&CrxUpdateService::DownloadProgress,
- base::Unretained(this),
- crx_context->id));
- crx_downloader_->StartDownload(*urls,
- base::Bind(&CrxUpdateService::DownloadComplete,
- base::Unretained(this),
- base::Passed(&crx_context)));
-}
-
-void CrxUpdateService::UpdateCheckComplete(
- const GURL& original_url,
- int error,
- const std::string& error_message,
- const UpdateResponse::Results& results) {
+bool CrxUpdateService::OnDemandUpdateWithCooldown(const std::string& id) {
DCHECK(thread_checker_.CalledOnValidThread());
- VLOG(1) << "Update check completed from: " << original_url.spec();
- update_checker_.reset();
- if (!error)
- OnUpdateCheckSucceeded(results);
- else
- OnUpdateCheckFailed(error, error_message);
-}
-
-// Handles a valid Omaha update check response by matching the results with
-// the registered components which were checked for updates.
-// If updates are found, prepare the components for the actual version upgrade.
-// One of these components will be drafted for the upgrade next time
-// ProcessPendingItems is called.
-void CrxUpdateService::OnUpdateCheckSucceeded(
- const UpdateResponse::Results& results) {
- size_t num_updates_pending = 0;
- DCHECK(thread_checker_.CalledOnValidThread());
- VLOG(1) << "Update check succeeded.";
- std::vector<UpdateResponse::Result>::const_iterator it;
- for (it = results.list.begin(); it != results.list.end(); ++it) {
- CrxUpdateItem* crx = FindUpdateItemById(it->extension_id);
- if (!crx)
- continue;
-
- if (crx->state != CrxUpdateItem::State::kChecking) {
- NOTREACHED();
- continue; // Not updating this component now.
- }
-
- if (it->manifest.version.empty()) {
- // No version means no update available.
- ChangeItemState(crx, CrxUpdateItem::State::kNoUpdate);
- VLOG(1) << "No update available for component: " << crx->id;
- continue;
- }
-
- if (!IsVersionNewer(crx->component.version, it->manifest.version)) {
- // The component is up to date.
- ChangeItemState(crx, CrxUpdateItem::State::kUpToDate);
- VLOG(1) << "Component already up-to-date: " << crx->id;
- continue;
- }
-
- if (!it->manifest.browser_min_version.empty()) {
- if (IsVersionNewer(config_->GetBrowserVersion(),
- it->manifest.browser_min_version)) {
- // The component is not compatible with this Chrome version.
- VLOG(1) << "Ignoring incompatible component: " << crx->id;
- ChangeItemState(crx, CrxUpdateItem::State::kNoUpdate);
- continue;
- }
- }
-
- if (it->manifest.packages.size() != 1) {
- // Assume one and only one package per component.
- VLOG(1) << "Ignoring multiple packages for component: " << crx->id;
- ChangeItemState(crx, CrxUpdateItem::State::kNoUpdate);
- continue;
- }
-
- // Parse the members of the result and queue an upgrade for this component.
- crx->next_version = Version(it->manifest.version);
-
- VLOG(1) << "Update found for component: " << crx->id;
-
- typedef UpdateResponse::Result::Manifest::Package Package;
- const Package& package(it->manifest.packages[0]);
- crx->next_fp = package.fingerprint;
- // Resolve the urls by combining the base urls with the package names.
- for (size_t i = 0; i != it->crx_urls.size(); ++i) {
- const GURL url(it->crx_urls[i].Resolve(package.name));
- if (url.is_valid())
- crx->crx_urls.push_back(url);
- }
- for (size_t i = 0; i != it->crx_diffurls.size(); ++i) {
- const GURL url(it->crx_diffurls[i].Resolve(package.namediff));
- if (url.is_valid())
- crx->crx_diffurls.push_back(url);
- }
+ DCHECK(GetComponent(id));
- ChangeItemState(crx, CrxUpdateItem::State::kCanUpdate);
- ++num_updates_pending;
+ // Check if the request is too soon.
+ const auto component_state(GetComponentState(id));
+ if (component_state) {
+ base::TimeDelta delta = base::Time::Now() - component_state->last_check;
+ if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay()))
+ return false;
}
- // All components that are not included in the update response are
- // considered up to date.
- ChangeItemStatus(CrxUpdateItem::State::kChecking,
- CrxUpdateItem::State::kUpToDate);
-
- // If there are updates pending we do a short wait, otherwise we take
- // a longer delay until we check the components again.
- ScheduleNextRun(num_updates_pending > 0 ? kStepDelayShort : kStepDelayLong);
+ return OnDemandUpdateInternal(id);
}
-void CrxUpdateService::OnUpdateCheckFailed(int error,
- const std::string& error_message) {
+bool CrxUpdateService::OnDemandUpdateInternal(const std::string& id) {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(error);
- size_t count = ChangeItemStatus(CrxUpdateItem::State::kChecking,
- CrxUpdateItem::State::kNoUpdate);
- DCHECK_GT(count, 0ul);
- VLOG(1) << "Update check failed.";
- ScheduleNextRun(kStepDelayLong);
-}
-// Called when progress is being made downloading a CRX. The progress may
-// not monotonically increase due to how the CRX downloader switches between
-// different downloaders and fallback urls.
-void CrxUpdateService::DownloadProgress(
- const std::string& component_id,
- const CrxDownloader::Result& download_result) {
- DCHECK(thread_checker_.CalledOnValidThread());
- NotifyObservers(Observer::Events::COMPONENT_UPDATE_DOWNLOADING, component_id);
+ update_client_->Install(
+ id, base::Bind(&CrxUpdateService::OnUpdate, base::Unretained(this)),
+ base::Bind(&CrxUpdateService::OnUpdateComplete, base::Unretained(this)));
+
+ return true;
}
-// Called when the CRX package has been downloaded to a temporary location.
-// Here we fire the notifications and schedule the component-specific installer
-// to be called in the file thread.
-void CrxUpdateService::DownloadComplete(
- scoped_ptr<CRXContext> crx_context,
- const CrxDownloader::Result& download_result) {
+bool CrxUpdateService::CheckForUpdates() {
DCHECK(thread_checker_.CalledOnValidThread());
-
- CrxUpdateItem* crx = FindUpdateItemById(crx_context->id);
-
- DCHECK(crx->state == CrxUpdateItem::State::kDownloadingDiff ||
- crx->state == CrxUpdateItem::State::kDownloading);
-
- AppendDownloadMetrics(crx_downloader_->download_metrics(),
- &crx->download_metrics);
-
- crx_downloader_.reset();
-
- if (download_result.error) {
- if (crx->state == CrxUpdateItem::State::kDownloadingDiff) {
- crx->diff_error_category = kNetworkError;
- crx->diff_error_code = download_result.error;
- crx->diff_update_failed = true;
- size_t count = ChangeItemStatus(CrxUpdateItem::State::kDownloadingDiff,
- CrxUpdateItem::State::kCanUpdate);
- DCHECK_EQ(count, 1ul);
-
- ScheduleNextRun(kStepDelayShort);
- return;
- }
- crx->error_category = kNetworkError;
- crx->error_code = download_result.error;
- size_t count = ChangeItemStatus(CrxUpdateItem::State::kDownloading,
- CrxUpdateItem::State::kNoUpdate);
- DCHECK_EQ(count, 1ul);
-
- // At this point, since both the differential and the full downloads failed,
- // the update for this component has finished with an error.
- ping_manager_->OnUpdateComplete(crx);
-
- // Move on to the next update, if there is one available.
- ScheduleNextRun(kStepDelayMedium);
- } else {
- size_t count = 0;
- if (crx->state == CrxUpdateItem::State::kDownloadingDiff) {
- count = ChangeItemStatus(CrxUpdateItem::State::kDownloadingDiff,
- CrxUpdateItem::State::kUpdatingDiff);
- } else {
- count = ChangeItemStatus(CrxUpdateItem::State::kDownloading,
- CrxUpdateItem::State::kUpdating);
- }
- DCHECK_EQ(count, 1ul);
-
- // Why unretained? See comment at top of file.
- blocking_task_runner_->PostDelayedTask(
- FROM_HERE,
- base::Bind(&CrxUpdateService::Install,
- base::Unretained(this),
- base::Passed(&crx_context),
- download_result.response),
- base::TimeDelta::FromMilliseconds(config_->StepDelay()));
+ std::vector<std::string> ids;
+ for (const auto id : components_order_) {
+ DCHECK(components_.find(id) != components_.end());
+ ids.push_back(id);
}
-}
-// Install consists of digital signature verification, unpacking and then
-// calling the component specific installer. All that is handled by the
-// |unpacker_|. If there is an error this function is in charge of deleting
-// the files created.
-void CrxUpdateService::Install(scoped_ptr<CRXContext> context,
- const base::FilePath& crx_path) {
- // This function owns the file at |crx_path| and the |context| object.
- unpacker_ = new ComponentUnpacker(context->pk_hash,
- crx_path,
- context->fingerprint,
- context->installer,
- config_->CreateOutOfProcessPatcher(),
- blocking_task_runner_);
- unpacker_->Unpack(base::Bind(&CrxUpdateService::EndUnpacking,
- base::Unretained(this),
- context->id,
- crx_path));
+ update_client_->Update(
+ ids, base::Bind(&CrxUpdateService::OnUpdate, base::Unretained(this)),
+ base::Bind(&CrxUpdateService::OnUpdateComplete, base::Unretained(this)));
+
+ return true;
}
-void CrxUpdateService::EndUnpacking(const std::string& component_id,
- const base::FilePath& crx_path,
- ComponentUnpacker::Error error,
- int extended_error) {
- if (!update_client::DeleteFileAndEmptyParentDirectory(crx_path))
- NOTREACHED() << crx_path.value();
- main_task_runner_->PostDelayedTask(
- FROM_HERE,
- base::Bind(&CrxUpdateService::DoneInstalling,
- base::Unretained(this),
- component_id,
- error,
- extended_error),
- base::TimeDelta::FromMilliseconds(config_->StepDelay()));
- // Reset the unpacker last, otherwise we free our own arguments.
- unpacker_ = NULL;
+scoped_refptr<base::SequencedTaskRunner>
+CrxUpdateService::GetSequencedTaskRunner() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return blocking_task_runner_;
}
-// Installation has been completed. Adjust the component state and
-// schedule the next check. Schedule a short delay before trying the full
-// update when the differential update failed.
-void CrxUpdateService::DoneInstalling(const std::string& component_id,
- ComponentUnpacker::Error error,
- int extra_code) {
+bool CrxUpdateService::GetComponentDetails(const std::string& id,
+ CrxUpdateItem* item) const {
DCHECK(thread_checker_.CalledOnValidThread());
- ErrorCategory error_category = kErrorNone;
- switch (error) {
- case ComponentUnpacker::kNone:
- break;
- case ComponentUnpacker::kInstallerError:
- error_category = kInstallError;
- break;
- default:
- error_category = kUnpackError;
- break;
+ // First, if this component is currently being updated, return its state from
+ // the update client.
+ if (update_client_->GetCrxUpdateState(id, item))
+ return true;
+
+ // Otherwise, return the last seen state of the component, if such a
+ // state exists.
+ const auto component_states_it = component_states_.find(id);
+ if (component_states_it != component_states_.end()) {
+ *item = component_states_it->second;
+ return true;
}
- const bool is_success = error == ComponentUnpacker::kNone;
-
- CrxUpdateItem* item = FindUpdateItemById(component_id);
+ return false;
+}
- if (item->state == CrxUpdateItem::State::kUpdatingDiff && !is_success) {
- item->diff_error_category = error_category;
- item->diff_error_code = error;
- item->diff_extra_code1 = extra_code;
- item->diff_update_failed = true;
- size_t count = ChangeItemStatus(CrxUpdateItem::State::kUpdatingDiff,
- CrxUpdateItem::State::kCanUpdate);
- DCHECK_EQ(count, 1ul);
- ScheduleNextRun(kStepDelayShort);
- return;
- }
+void CrxUpdateService::OnUpdate(const std::vector<std::string>& ids,
+ std::vector<CrxComponent>* components) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(components->empty());
- if (is_success) {
- item->component.version = item->next_version;
- item->component.fingerprint = item->next_fp;
- ChangeItemState(item, CrxUpdateItem::State::kUpdated);
- } else {
- item->error_category = error_category;
- item->error_code = error;
- item->extra_code1 = extra_code;
- ChangeItemState(item, CrxUpdateItem::State::kNoUpdate);
+ for (const auto& id : ids) {
+ const auto registered_component(GetComponent(id));
+ if (registered_component) {
+ components->push_back(*registered_component);
+ }
}
-
- ping_manager_->OnUpdateComplete(item);
-
- // Move on to the next update, if there is one available.
- ScheduleNextRun(kStepDelayMedium);
}
-void CrxUpdateService::NotifyObservers(Observer::Events event,
- const std::string& id) {
+void CrxUpdateService::OnUpdateComplete(int error) {
DCHECK(thread_checker_.CalledOnValidThread());
- FOR_EACH_OBSERVER(Observer, observer_list_, OnEvent(event, id));
-}
+ VLOG(1) << "Update completed with error " << error;
-ComponentUpdateService::Status CrxUpdateService::OnDemandUpdateWithCooldown(
- CrxUpdateItem* uit) {
- if (!uit)
- return Status::kError;
-
- // Check if the request is too soon.
- base::TimeDelta delta = base::Time::Now() - uit->last_check;
- if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay()))
- return Status::kError;
-
- return OnDemandUpdateInternal(uit);
+ for (const auto id : components_pending_unregistration_) {
+ if (!update_client_->IsUpdating(id)) {
+ const auto component = GetComponent(id);
+ if (component)
+ DoUnregisterComponent(*component);
+ }
+ }
}
-ComponentUpdateService::Status CrxUpdateService::OnDemandUpdateInternal(
- CrxUpdateItem* uit) {
- if (!uit)
- return Status::kError;
-
- uit->on_demand = true;
-
- // If there is an update available for this item, then continue processing
- // the update. This is an artifact of how update checks are done: in addition
- // to the on-demand item, the update check may include other items as well.
- if (uit->state != CrxUpdateItem::State::kCanUpdate) {
- Status service_status = GetServiceStatus(uit->state);
- // If the item is already in the process of being updated, there is
- // no point in this call, so return Status::kInProgress.
- if (service_status == Status::kInProgress)
- return service_status;
-
- // Otherwise the item was already checked a while back (or it is new),
- // set its state to kNew to give it a slightly higher priority.
- ChangeItemState(uit, CrxUpdateItem::State::kNew);
- }
+void CrxUpdateService::OnEvent(Events event, const std::string& id) {
+ DCHECK(thread_checker_.CalledOnValidThread());
- // In case the current delay is long, set the timer to a shorter value
- // to get the ball rolling.
- if (timer_.IsRunning()) {
- timer_.Stop();
- timer_.Start(FROM_HERE,
- base::TimeDelta::FromSeconds(config_->StepDelay()),
- this,
- &CrxUpdateService::ProcessPendingItems);
+ // Unblock all throttles for the component.
+ if (event == Observer::Events::COMPONENT_UPDATED ||
+ event == Observer::Events::COMPONENT_NOT_UPDATED) {
+ auto callbacks = ready_callbacks_.equal_range(id);
+ for (auto it = callbacks.first; it != callbacks.second; ++it) {
+ it->second.Run();
+ }
+ ready_callbacks_.erase(id);
}
- return Status::kOk;
-}
+ CrxUpdateItem update_item;
+ if (!update_client_->GetCrxUpdateState(id, &update_item))
+ return;
-ComponentUpdateService::Status CrxUpdateService::GetServiceStatus(
- CrxUpdateItem::State state) {
- switch (state) {
- case CrxUpdateItem::State::kChecking:
- case CrxUpdateItem::State::kCanUpdate:
- case CrxUpdateItem::State::kDownloadingDiff:
- case CrxUpdateItem::State::kDownloading:
- case CrxUpdateItem::State::kDownloaded:
- case CrxUpdateItem::State::kUpdatingDiff:
- case CrxUpdateItem::State::kUpdating:
- return Status::kInProgress;
- case CrxUpdateItem::State::kNew:
- case CrxUpdateItem::State::kUpdated:
- case CrxUpdateItem::State::kUpToDate:
- case CrxUpdateItem::State::kNoUpdate:
- return Status::kOk;
- case CrxUpdateItem::State::kLastStatus:
- NOTREACHED() << static_cast<int>(state);
+ // Update the state of the item.
+ auto it = component_states_.find(id);
+ DCHECK(it != component_states_.end());
+ it->second = update_item;
+
+ // Update the component registration with the new version.
+ if (event == Observer::Events::COMPONENT_UPDATED) {
+ auto component(const_cast<CrxComponent*>(GetComponent(id)));
+ if (component) {
+ component->version = update_item.next_version;
+ component->fingerprint = update_item.next_fp;
+ }
}
- return Status::kError;
}
///////////////////////////////////////////////////////////////////////////////
// The component update factory. Using the component updater as a singleton
// is the job of the browser process.
+// TODO(sorin): consider making this a singleton.
scoped_ptr<ComponentUpdateService> ComponentUpdateServiceFactory(
const scoped_refptr<Configurator>& config) {
DCHECK(config);
- return scoped_ptr<ComponentUpdateService>(new CrxUpdateService(config));
+ auto update_client = update_client::UpdateClientFactory(config);
+ return scoped_ptr<ComponentUpdateService>(
+ new CrxUpdateService(config, update_client.Pass()));
}
} // namespace component_updater
diff --git a/components/component_updater/component_updater_service.h b/components/component_updater/component_updater_service.h
index 450508a..e667445 100644
--- a/components/component_updater/component_updater_service.h
+++ b/components/component_updater/component_updater_service.h
@@ -15,6 +15,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/version.h"
+#include "components/update_client/update_client.h"
#include "url/gurl.h"
class ComponentsUI;
@@ -46,6 +47,10 @@ namespace component_updater {
class OnDemandUpdater;
+using Configurator = update_client::Configurator;
+using CrxComponent = update_client::CrxComponent;
+using CrxUpdateItem = update_client::CrxUpdateItem;
+
// The component update service is in charge of installing or upgrading
// select parts of chrome. Each part is called a component and managed by
// instances of CrxComponent registered using RegisterComponent(). On the
@@ -63,47 +68,7 @@ class OnDemandUpdater;
// All methods are safe to call ONLY from the browser's main thread.
class ComponentUpdateService {
public:
- enum class Status { kOk, kReplaced, kInProgress, kError };
-
- // Defines an interface to observe ComponentUpdateService. It provides
- // notifications when state changes occur for the service or for the
- // registered components.
- class Observer {
- public:
- enum class Events {
- // Sent when the component updater starts doing update checks.
- COMPONENT_UPDATER_STARTED,
-
- // Sent when the component updater is going to take a long nap.
- COMPONENT_UPDATER_SLEEPING,
-
- // Sent when there is a new version of a registered component. After
- // the notification is sent the component will be downloaded.
- COMPONENT_UPDATE_FOUND,
-
- // Sent when the new component has been downloaded and an installation
- // or upgrade is about to be attempted.
- COMPONENT_UPDATE_READY,
-
- // Sent when a component has been successfully updated.
- COMPONENT_UPDATED,
-
- // Sent when a component has not been updated following an update check:
- // either there was no update available, or an update failed.
- COMPONENT_NOT_UPDATED,
-
- // Sent when component bytes are being downloaded.
- COMPONENT_UPDATE_DOWNLOADING,
- };
-
- virtual ~Observer() {}
-
- // The component updater service will call this function when an interesting
- // state change happens. If the |id| is specified, then the event is fired
- // on behalf of a specific component. The implementors of this interface are
- // expected to filter the relevant events based on the component id.
- virtual void OnEvent(Events event, const std::string& id) = 0;
- };
+ using Observer = update_client::UpdateClient::Observer;
// Adds an observer for this class. An observer should not be added more
// than once. The caller retains the ownership of the observer object.
@@ -113,26 +78,20 @@ class ComponentUpdateService {
// the observers are being notified.
virtual void RemoveObserver(Observer* observer) = 0;
- // Start doing update checks and installing new versions of registered
- // components after Configurator::InitialDelay() seconds.
- virtual Status Start() = 0;
-
- // Stop doing update checks. In-flight requests and pending installations
- // will not be canceled.
- virtual Status Stop() = 0;
-
- // Add component to be checked for updates. You can call this method
- // before calling Start().
- virtual Status RegisterComponent(
- const update_client::CrxComponent& component) = 0;
+ // Add component to be checked for updates.
+ virtual bool RegisterComponent(const CrxComponent& component) = 0;
// Unregisters the component with the given ID. This means that the component
// is not going to be included in future update checks. If a download or
// update operation for the component is currently in progress, it will
// silently finish without triggering the next step.
// Note that the installer for the component is responsible for removing any
- // existing versions of the component from disk.
- virtual Status UnregisterComponent(const std::string& crx_id) = 0;
+ // existing versions of the component from disk. Returns true if the
+ // uninstall has completed successfully and the component files have been
+ // removed, or if the uninstalled has been deferred because the component
+ // is being updated. Returns false if the component id is not known or the
+ /// uninstall encountered an error.
+ virtual bool UnregisterComponent(const std::string& id) = 0;
// Returns a list of registered components.
virtual std::vector<std::string> GetComponentIDs() const = 0;
@@ -141,7 +100,7 @@ class ComponentUpdateService {
// proactively triggered outside the normal component update service schedule.
virtual OnDemandUpdater& GetOnDemandUpdater() = 0;
- // This method is used to trigger an on-demand update for component |crx_id|.
+ // This method is used to trigger an on-demand update for component |id|.
// This can be used when loading a resource that depends on this component.
//
// |callback| is called on the main thread once the on-demand update is
@@ -153,7 +112,7 @@ class ComponentUpdateService {
// to be defensive against programming bugs, usually triggered by web fetches,
// where the on-demand functionality is invoked too often. If this function
// is called while still on cooldown, |callback| will be called immediately.
- virtual void MaybeThrottle(const std::string& crx_id,
+ virtual void MaybeThrottle(const std::string& id,
const base::Closure& callback) = 0;
// Returns a task runner suitable for use by component installers.
@@ -164,9 +123,8 @@ class ComponentUpdateService {
private:
// Returns details about registered component in the |item| parameter. The
// function returns true in case of success and false in case of errors.
- virtual bool GetComponentDetails(
- const std::string& component_id,
- update_client::CrxUpdateItem* item) const = 0;
+ virtual bool GetComponentDetails(const std::string& id,
+ CrxUpdateItem* item) const = 0;
friend class ::ComponentsUI;
};
@@ -182,19 +140,20 @@ class OnDemandUpdater {
friend class SupervisedUserWhitelistInstaller;
friend class ::ComponentsUI;
- // Triggers an update check for a component. |component_id| is a value
+ // Triggers an update check for a component. |id| is a value
// returned by GetCrxComponentID(). If an update for this component is already
// in progress, the function returns |kInProgress|. If an update is available,
// the update will be applied. The caller can subscribe to component update
// service notifications to get an indication about the outcome of the
// on-demand update. The function does not implement any cooldown interval.
- virtual ComponentUpdateService::Status OnDemandUpdate(
- const std::string& component_id) = 0;
+ // TODO(sorin): improve this API so that the result of this non-blocking
+ // call is provided by a callback.
+ virtual bool OnDemandUpdate(const std::string& id) = 0;
};
// Creates the component updater.
scoped_ptr<ComponentUpdateService> ComponentUpdateServiceFactory(
- const scoped_refptr<update_client::Configurator>& config);
+ const scoped_refptr<Configurator>& config);
} // namespace component_updater
diff --git a/components/component_updater/component_updater_service_internal.h b/components/component_updater/component_updater_service_internal.h
new file mode 100644
index 0000000..c91332c
--- /dev/null
+++ b/components/component_updater/component_updater_service_internal.h
@@ -0,0 +1,111 @@
+// 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.
+
+#ifndef COMPONENTS_COMPONENT_UPDATER_COMPONENT_UPDATER_SERVICE_INTERNAL_H_
+#define COMPONENTS_COMPONENT_UPDATER_COMPONENT_UPDATER_SERVICE_INTERNAL_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_checker.h"
+#include "components/component_updater/timer.h"
+
+namespace component_updater {
+
+class OnDemandUpdater;
+
+using CrxInstaller = update_client::CrxInstaller;
+using UpdateClient = update_client::UpdateClient;
+
+class CrxUpdateService : public ComponentUpdateService,
+ public ComponentUpdateService::Observer,
+ public OnDemandUpdater {
+ using Observer = ComponentUpdateService::Observer;
+
+ public:
+ CrxUpdateService(const scoped_refptr<Configurator>& config,
+ const scoped_refptr<UpdateClient>& update_client);
+ ~CrxUpdateService() override;
+
+ // Overrides for ComponentUpdateService.
+ void AddObserver(Observer* observer) override;
+ void RemoveObserver(Observer* observer) override;
+ bool RegisterComponent(const CrxComponent& component) override;
+ bool UnregisterComponent(const std::string& id) override;
+ std::vector<std::string> GetComponentIDs() const override;
+ OnDemandUpdater& GetOnDemandUpdater() override;
+ void MaybeThrottle(const std::string& id,
+ const base::Closure& callback) override;
+ scoped_refptr<base::SequencedTaskRunner> GetSequencedTaskRunner() override;
+ bool OnDemandUpdate(const std::string& id) override;
+ bool GetComponentDetails(const std::string& id,
+ CrxUpdateItem* item) const override;
+
+ // Overrides for Observer.
+ void OnEvent(Events event, const std::string& id) override;
+
+ private:
+ void Start();
+ void Stop();
+
+ bool CheckForUpdates();
+
+ bool OnDemandUpdateInternal(const std::string& id);
+ bool OnDemandUpdateWithCooldown(const std::string& id);
+
+ bool DoUnregisterComponent(const CrxComponent& component);
+
+ const CrxComponent* GetComponent(const std::string& id) const;
+
+ const CrxUpdateItem* GetComponentState(const std::string& id) const;
+
+ void OnUpdate(const std::vector<std::string>& ids,
+ std::vector<CrxComponent>* components);
+ void OnUpdateComplete(int error);
+
+ base::ThreadChecker thread_checker_;
+
+ scoped_refptr<Configurator> config_;
+
+ scoped_refptr<UpdateClient> update_client_;
+
+ Timer timer_;
+
+ // A collection of every registered component.
+ using Components = std::map<std::string, CrxComponent>;
+ Components components_;
+
+ // Maintains the order in which components have been registered. The position
+ // of a component id in this sequence indicates the priority of the component.
+ // The sooner the component gets registered, the higher its priority, and
+ // the closer this component is to the beginning of the vector.
+ std::vector<std::string> components_order_;
+
+ // Contains the components pending unregistration. If a component is not
+ // busy installing or updating, it can be unregistered right away. Otherwise,
+ // the component will be lazily unregistered after the its operations have
+ // completed.
+ std::vector<std::string> components_pending_unregistration_;
+
+ // Contains the active resource throttles associated with a given component.
+ using ResourceThrottleCallbacks = std::multimap<std::string, base::Closure>;
+ ResourceThrottleCallbacks ready_callbacks_;
+
+ // Contains the state of the component.
+ using ComponentStates = std::map<std::string, CrxUpdateItem>;
+ ComponentStates component_states_;
+
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(CrxUpdateService);
+};
+
+} // namespace component_updater
+
+#endif // COMPONENTS_COMPONENT_UPDATER_COMPONENT_UPDATER_SERVICE_INTERNAL_H_
diff --git a/components/component_updater/component_updater_service_unittest.cc b/components/component_updater/component_updater_service_unittest.cc
new file mode 100644
index 0000000..597135b
--- /dev/null
+++ b/components/component_updater/component_updater_service_unittest.cc
@@ -0,0 +1,355 @@
+// 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 <limits>
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.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"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/values.h"
+#include "components/component_updater/component_updater_service.h"
+#include "components/component_updater/component_updater_service_internal.h"
+#include "components/update_client/test_configurator.h"
+#include "components/update_client/test_installer.h"
+#include "components/update_client/update_client.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using Configurator = update_client::Configurator;
+using TestConfigurator = update_client::TestConfigurator;
+using UpdateClient = update_client::UpdateClient;
+
+using ::testing::_;
+using ::testing::AnyNumber;
+using ::testing::Invoke;
+using ::testing::Mock;
+using ::testing::Return;
+
+namespace component_updater {
+
+class MockInstaller : public CrxInstaller {
+ public:
+ MockInstaller();
+
+ 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());
+
+ private:
+ ~MockInstaller() override;
+};
+
+class MockUpdateClient : public UpdateClient {
+ public:
+ MockUpdateClient();
+ MOCK_METHOD1(AddObserver, void(Observer* observer));
+ MOCK_METHOD1(RemoveObserver, void(Observer* observer));
+ MOCK_METHOD3(Install,
+ void(const std::string& id,
+ const CrxDataCallback& crx_data_callback,
+ const CompletionCallback& completion_callback));
+ MOCK_METHOD3(Update,
+ void(const std::vector<std::string>& ids,
+ const CrxDataCallback& crx_data_callback,
+ const CompletionCallback& completion_callback));
+ MOCK_CONST_METHOD2(GetCrxUpdateState,
+ bool(const std::string& id, CrxUpdateItem* update_item));
+ MOCK_CONST_METHOD1(IsUpdating, bool(const std::string& id));
+
+ private:
+ ~MockUpdateClient() override;
+};
+
+class MockServiceObserver : public ServiceObserver {
+ public:
+ MockServiceObserver();
+ ~MockServiceObserver() override;
+
+ MOCK_METHOD2(OnEvent, void(Events event, const std::string&));
+};
+
+class ComponentUpdaterTest : public testing::Test {
+ public:
+ ComponentUpdaterTest();
+ ~ComponentUpdaterTest() override;
+
+ void SetUp() override;
+
+ void TearDown() override;
+
+ // Makes the full path to a component updater test file.
+ const base::FilePath test_file(const char* file);
+
+ MockUpdateClient& update_client() { return *update_client_; }
+ ComponentUpdateService& component_updater() { return *component_updater_; }
+ scoped_refptr<TestConfigurator> configurator() const { return config_; }
+ base::Closure quit_closure() const { return quit_closure_; }
+ static void ReadyCallback() {}
+
+ protected:
+ void RunThreads();
+
+ private:
+ static const int kNumWorkerThreads_ = 2;
+
+ base::MessageLoopForUI message_loop_;
+ base::RunLoop runloop_;
+ base::Closure quit_closure_;
+
+ scoped_refptr<base::SequencedWorkerPool> worker_pool_;
+
+ scoped_refptr<TestConfigurator> config_;
+ scoped_refptr<MockUpdateClient> update_client_;
+ scoped_ptr<ComponentUpdateService> component_updater_;
+
+ DISALLOW_COPY_AND_ASSIGN(ComponentUpdaterTest);
+};
+
+class OnDemandTester {
+ public:
+ static bool OnDemand(ComponentUpdateService* cus, const std::string& id);
+};
+
+MockInstaller::MockInstaller() {
+}
+
+MockInstaller::~MockInstaller() {
+}
+
+MockUpdateClient::MockUpdateClient() {
+}
+
+MockUpdateClient::~MockUpdateClient() {
+}
+
+MockServiceObserver::MockServiceObserver() {
+}
+
+MockServiceObserver::~MockServiceObserver() {
+}
+
+bool OnDemandTester::OnDemand(ComponentUpdateService* cus,
+ const std::string& id) {
+ return cus->GetOnDemandUpdater().OnDemandUpdate(id);
+}
+
+scoped_ptr<ComponentUpdateService> TestComponentUpdateServiceFactory(
+ const scoped_refptr<Configurator>& config) {
+ DCHECK(config);
+ return scoped_ptr<ComponentUpdateService>(
+ new CrxUpdateService(config, new MockUpdateClient()));
+}
+
+ComponentUpdaterTest::ComponentUpdaterTest()
+ : worker_pool_(new base::SequencedWorkerPool(kNumWorkerThreads_, "test")) {
+ quit_closure_ = runloop_.QuitClosure();
+
+ config_ = new TestConfigurator(
+ worker_pool_->GetSequencedTaskRunner(worker_pool_->GetSequenceToken()),
+ message_loop_.task_runner());
+
+ update_client_ = new MockUpdateClient();
+ EXPECT_CALL(update_client(), AddObserver(_)).Times(1);
+ component_updater_.reset(new CrxUpdateService(config_, update_client_));
+}
+
+ComponentUpdaterTest::~ComponentUpdaterTest() {
+ EXPECT_CALL(update_client(), RemoveObserver(_)).Times(1);
+ worker_pool_->Shutdown();
+ component_updater_.reset();
+}
+
+void ComponentUpdaterTest::SetUp() {
+}
+
+void ComponentUpdaterTest::TearDown() {
+}
+
+void ComponentUpdaterTest::RunThreads() {
+ runloop_.Run();
+}
+
+TEST_F(ComponentUpdaterTest, AddObserver) {
+ MockServiceObserver observer;
+ EXPECT_CALL(update_client(), AddObserver(&observer)).Times(1);
+ component_updater().AddObserver(&observer);
+}
+
+TEST_F(ComponentUpdaterTest, RemoveObserver) {
+ MockServiceObserver observer;
+ EXPECT_CALL(update_client(), RemoveObserver(&observer)).Times(1);
+ component_updater().RemoveObserver(&observer);
+}
+
+// Tests that UpdateClient::Update is called by the timer loop when
+// components are registered, and the component update starts.
+// Also tests that Uninstall is called when a component is unregistered.
+TEST_F(ComponentUpdaterTest, RegisterComponent) {
+ class LoopHandler {
+ public:
+ LoopHandler(int max_cnt, const base::Closure& quit_closure)
+ : max_cnt_(max_cnt), quit_closure_(quit_closure) {}
+
+ void OnUpdate(const std::vector<std::string>& ids,
+ const UpdateClient::CrxDataCallback& crx_data_callback,
+ const UpdateClient::CompletionCallback& completion_callback) {
+ static int cnt = 0;
+ ++cnt;
+ if (cnt >= max_cnt_)
+ quit_closure_.Run();
+ }
+
+ private:
+ const int max_cnt_;
+ base::Closure quit_closure_;
+ };
+
+ scoped_refptr<MockInstaller> installer(new MockInstaller());
+ EXPECT_CALL(*installer, Uninstall()).WillOnce(Return(true));
+
+ using update_client::jebg_hash;
+ using update_client::abag_hash;
+
+ const std::string id1 = "abagagagagagagagagagagagagagagag";
+ const std::string id2 = "jebgalgnebhfojomionfpkfelancnnkf";
+ std::vector<std::string> ids;
+ ids.push_back(id1);
+ ids.push_back(id2);
+
+ CrxComponent crx_component1;
+ crx_component1.pk_hash.assign(abag_hash, abag_hash + arraysize(abag_hash));
+ crx_component1.version = Version("1.0");
+ crx_component1.installer = installer;
+
+ CrxComponent crx_component2;
+ crx_component2.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
+ crx_component2.version = Version("0.9");
+ crx_component2.installer = installer;
+
+ // Quit after two update checks have fired.
+ LoopHandler loop_handler(2, quit_closure());
+ EXPECT_CALL(update_client(), Update(ids, _, _))
+ .WillRepeatedly(Invoke(&loop_handler, &LoopHandler::OnUpdate));
+
+ EXPECT_CALL(update_client(), IsUpdating(id1)).Times(1);
+
+ EXPECT_TRUE(component_updater().RegisterComponent(crx_component1));
+ EXPECT_TRUE(component_updater().RegisterComponent(crx_component2));
+
+ RunThreads();
+
+ EXPECT_TRUE(component_updater().UnregisterComponent(id1));
+}
+
+// Tests that on-demand updates invoke UpdateClient::Install.
+TEST_F(ComponentUpdaterTest, OnDemandUpdate) {
+ class LoopHandler {
+ public:
+ LoopHandler(int max_cnt, const base::Closure& quit_closure)
+ : max_cnt_(max_cnt), quit_closure_(quit_closure) {}
+
+ void OnInstall(
+ const std::string& ids,
+ const UpdateClient::CrxDataCallback& crx_data_callback,
+ const UpdateClient::CompletionCallback& completion_callback) {
+ static int cnt = 0;
+ ++cnt;
+ if (cnt >= max_cnt_)
+ quit_closure_.Run();
+ }
+
+ private:
+ const int max_cnt_;
+ base::Closure quit_closure_;
+ };
+
+ auto config = configurator();
+ config->SetInitialDelay(3600);
+
+ auto& cus = component_updater();
+
+ const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
+ EXPECT_FALSE(OnDemandTester::OnDemand(&cus, id));
+
+ scoped_refptr<MockInstaller> installer(new MockInstaller());
+
+ using update_client::jebg_hash;
+ CrxComponent crx_component;
+ crx_component.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
+ crx_component.version = Version("0.9");
+ crx_component.installer = installer;
+
+ LoopHandler loop_handler(1, quit_closure());
+ EXPECT_CALL(update_client(),
+ Install("jebgalgnebhfojomionfpkfelancnnkf", _, _))
+ .WillOnce(Invoke(&loop_handler, &LoopHandler::OnInstall));
+
+ EXPECT_TRUE(cus.RegisterComponent(crx_component));
+ EXPECT_TRUE(OnDemandTester::OnDemand(&cus, id));
+
+ RunThreads();
+}
+
+// Tests that throttling an update invokes UpdateClient::Install.
+TEST_F(ComponentUpdaterTest, MaybeThrottle) {
+ class LoopHandler {
+ public:
+ LoopHandler(int max_cnt, const base::Closure& quit_closure)
+ : max_cnt_(max_cnt), quit_closure_(quit_closure) {}
+
+ void OnInstall(
+ const std::string& ids,
+ const UpdateClient::CrxDataCallback& crx_data_callback,
+ const UpdateClient::CompletionCallback& completion_callback) {
+ static int cnt = 0;
+ ++cnt;
+ if (cnt >= max_cnt_)
+ quit_closure_.Run();
+ }
+
+ private:
+ const int max_cnt_;
+ base::Closure quit_closure_;
+ };
+
+ auto config = configurator();
+ config->SetInitialDelay(3600);
+
+ scoped_refptr<MockInstaller> installer(new MockInstaller());
+
+ using update_client::jebg_hash;
+ CrxComponent crx_component;
+ crx_component.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
+ crx_component.version = Version("0.9");
+ crx_component.installer = installer;
+
+ LoopHandler loop_handler(1, quit_closure());
+ EXPECT_CALL(update_client(),
+ Install("jebgalgnebhfojomionfpkfelancnnkf", _, _))
+ .WillOnce(Invoke(&loop_handler, &LoopHandler::OnInstall));
+
+ EXPECT_TRUE(component_updater().RegisterComponent(crx_component));
+ component_updater().MaybeThrottle(
+ "jebgalgnebhfojomionfpkfelancnnkf",
+ base::Bind(&ComponentUpdaterTest::ReadyCallback));
+
+ RunThreads();
+}
+
+} // namespace component_updater
diff --git a/components/component_updater/default_component_installer.cc b/components/component_updater/default_component_installer.cc
index 36844fb..56f5ca1 100644
--- a/components/component_updater/default_component_installer.cc
+++ b/components/component_updater/default_component_installer.cc
@@ -82,8 +82,6 @@ bool DefaultComponentInstaller::InstallHelper(
bool DefaultComponentInstaller::Install(const base::DictionaryValue& manifest,
const base::FilePath& unpack_path) {
- DCHECK(task_runner_->RunsTasksOnCurrentThread());
-
std::string manifest_version;
manifest.GetStringASCII("version", &manifest_version);
base::Version version(manifest_version.c_str());
@@ -127,6 +125,7 @@ bool DefaultComponentInstaller::GetInstalledFile(
}
bool DefaultComponentInstaller::Uninstall() {
+ DCHECK(thread_checker_.CalledOnValidThread());
task_runner_->PostTask(
FROM_HERE,
base::Bind(&DefaultComponentInstaller::UninstallOnTaskRunner, this));
@@ -248,9 +247,7 @@ void DefaultComponentInstaller::FinishRegistration(
crx.version = current_version_;
crx.fingerprint = current_fingerprint_;
installer_traits_->GetHash(&crx.pk_hash);
- ComponentUpdateService::Status status = cus->RegisterComponent(crx);
- if (status != ComponentUpdateService::Status::kOk &&
- status != ComponentUpdateService::Status::kReplaced) {
+ if (!cus->RegisterComponent(crx)) {
NOTREACHED() << "Component registration failed for "
<< installer_traits_->GetName();
return;
diff --git a/components/component_updater/timer.cc b/components/component_updater/timer.cc
new file mode 100644
index 0000000..e3c79ec
--- /dev/null
+++ b/components/component_updater/timer.cc
@@ -0,0 +1,47 @@
+// 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 "components/component_updater/timer.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+
+namespace component_updater {
+
+Timer::Timer() : timer_(false, false) {
+}
+
+Timer::~Timer() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ Stop();
+}
+
+void Timer::Start(base::TimeDelta initial_delay,
+ base::TimeDelta delay,
+ const base::Closure& user_task) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ delay_ = delay;
+ user_task_ = user_task;
+
+ timer_.Start(FROM_HERE, initial_delay,
+ base::Bind(&Timer::OnDelay, base::Unretained(this)));
+}
+
+void Timer::Stop() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ timer_.Stop();
+}
+
+void Timer::OnDelay() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ user_task_.Run();
+
+ timer_.Start(FROM_HERE, delay_,
+ base::Bind(&Timer::OnDelay, base::Unretained(this)));
+}
+
+} // namespace component_updater
diff --git a/components/component_updater/timer.h b/components/component_updater/timer.h
new file mode 100644
index 0000000..8b72899
--- /dev/null
+++ b/components/component_updater/timer.h
@@ -0,0 +1,42 @@
+// 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.
+
+#ifndef COMPONENTS_COMPONENT_UPDATER_TIMER_H_
+#define COMPONENTS_COMPONENT_UPDATER_TIMER_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+
+namespace component_updater {
+
+class Timer {
+ public:
+ Timer();
+ ~Timer();
+
+ void Start(base::TimeDelta initial_delay,
+ base::TimeDelta delay,
+ const base::Closure& user_task);
+
+ void Stop();
+
+ private:
+ void OnDelay();
+
+ base::ThreadChecker thread_checker_;
+
+ base::Timer timer_;
+
+ base::TimeDelta delay_;
+ base::Closure user_task_;
+
+ DISALLOW_COPY_AND_ASSIGN(Timer);
+};
+
+} // namespace component_updater
+
+#endif // COMPONENTS_COMPONENT_UPDATER_TIMER_H_
diff --git a/components/component_updater/timer_unittest.cc b/components/component_updater/timer_unittest.cc
new file mode 100644
index 0000000..2c80e84
--- /dev/null
+++ b/components/component_updater/timer_unittest.cc
@@ -0,0 +1,61 @@
+// 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 <string>
+
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/time/time.h"
+#include "components/component_updater/timer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::string;
+
+namespace component_updater {
+
+class ComponentUpdaterTimerTest : public testing::Test {
+ public:
+ ComponentUpdaterTimerTest() {}
+ ~ComponentUpdaterTimerTest() override {}
+
+ private:
+ base::MessageLoopForUI message_loop_;
+};
+
+TEST_F(ComponentUpdaterTimerTest, Start) {
+ class TimerClientFake {
+ public:
+ TimerClientFake(int max_count, const base::Closure& quit_closure)
+ : max_count_(max_count), quit_closure_(quit_closure), count_(0) {}
+
+ void OnTimerEvent() {
+ ++count_;
+ if (count_ >= max_count_)
+ quit_closure_.Run();
+ }
+
+ int count() const { return count_; }
+
+ private:
+ const int max_count_;
+ const base::Closure quit_closure_;
+
+ int count_;
+ };
+
+ base::RunLoop run_loop;
+ TimerClientFake timer_client_fake(3, run_loop.QuitClosure());
+ EXPECT_EQ(0, timer_client_fake.count());
+
+ Timer timer;
+ const base::TimeDelta delay(base::TimeDelta::FromMilliseconds(1));
+ timer.Start(delay, delay, base::Bind(&TimerClientFake::OnTimerEvent,
+ base::Unretained(&timer_client_fake)));
+ run_loop.Run();
+ timer.Stop();
+
+ EXPECT_EQ(3, timer_client_fake.count());
+}
+
+} // namespace component_updater
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index 00d8805..a32b943 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -90,6 +90,10 @@
'cloud_devices/common/cloud_devices_urls_unittest.cc',
'cloud_devices/common/printer_description_unittest.cc',
],
+ 'component_updater_unittest_sources': [
+ 'component_updater/component_updater_service_unittest.cc',
+ 'component_updater/timer_unittest.cc',
+ ],
'content_settings_unittest_sources': [
'content_settings/core/browser/content_settings_mock_provider.cc',
'content_settings/core/browser/content_settings_mock_provider.h',
@@ -662,6 +666,7 @@
'<@(browser_watcher_unittest_sources)',
'<@(captive_portal_unittest_sources)',
'<@(cloud_devices_unittest_sources)',
+ '<@(component_updater_unittest_sources)',
'<@(content_settings_unittest_sources)',
'<@(crash_unittest_sources)',
'<@(crx_file_unittest_sources)',
@@ -748,6 +753,7 @@
'components.gyp:bookmarks_test_support',
'components.gyp:captive_portal_test_support',
'components.gyp:cloud_devices_common',
+ 'components.gyp:component_updater',
'components.gyp:content_settings_core_browser',
'components.gyp:content_settings_core_common',
'components.gyp:content_settings_core_test_support',
diff --git a/components/update_client/action.cc b/components/update_client/action.cc
index 4a11efe..3cdce79 100644
--- a/components/update_client/action.cc
+++ b/components/update_client/action.cc
@@ -20,6 +20,8 @@
namespace update_client {
+using Events = UpdateClient::Observer::Events;
+
namespace {
// Returns true if a differential update is available, it has not failed yet,
diff --git a/components/update_client/action_update.cc b/components/update_client/action_update.cc
index 7aefb43..ed912c8 100644
--- a/components/update_client/action_update.cc
+++ b/components/update_client/action_update.cc
@@ -88,22 +88,22 @@ void ActionUpdate::Run(UpdateContext* update_context, Callback callback) {
}
void ActionUpdate::DownloadProgress(
- const std::string& crx_id,
+ const std::string& id,
const CrxDownloader::Result& download_result) {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(crx_id == update_context_->queue.front());
+ DCHECK(id == update_context_->queue.front());
using Events = UpdateClient::Observer::Events;
- NotifyObservers(Events::COMPONENT_UPDATE_DOWNLOADING, crx_id);
+ NotifyObservers(Events::COMPONENT_UPDATE_DOWNLOADING, id);
}
void ActionUpdate::DownloadComplete(
- const std::string& crx_id,
+ const std::string& id,
const CrxDownloader::Result& download_result) {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(crx_id == update_context_->queue.front());
+ DCHECK(id == update_context_->queue.front());
- CrxUpdateItem* item = FindUpdateItemById(crx_id);
+ CrxUpdateItem* item = FindUpdateItemById(id);
DCHECK(item);
AppendDownloadMetrics(update_context_->crx_downloader->download_metrics(),
@@ -115,7 +115,7 @@ void ActionUpdate::DownloadComplete(
OnDownloadSuccess(item, download_result);
update_context_->main_task_runner->PostDelayedTask(
FROM_HERE, base::Bind(&ActionUpdate::Install, base::Unretained(this),
- crx_id, download_result.response),
+ id, download_result.response),
base::TimeDelta::FromMilliseconds(
update_context_->config->StepDelay()));
}
@@ -123,12 +123,12 @@ void ActionUpdate::DownloadComplete(
update_context_->crx_downloader.reset();
}
-void ActionUpdate::Install(const std::string& crx_id,
+void ActionUpdate::Install(const std::string& id,
const base::FilePath& crx_path) {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(crx_id == update_context_->queue.front());
+ DCHECK(id == update_context_->queue.front());
- CrxUpdateItem* item = FindUpdateItemById(crx_id);
+ CrxUpdateItem* item = FindUpdateItemById(id);
DCHECK(item);
OnInstallStart(item);
@@ -168,13 +168,13 @@ void ActionUpdate::EndUnpackingOnBlockingTaskRunner(
base::TimeDelta::FromMilliseconds(update_context->config->StepDelay()));
}
-void ActionUpdate::DoneInstalling(const std::string& crx_id,
+void ActionUpdate::DoneInstalling(const std::string& id,
ComponentUnpacker::Error error,
int extended_error) {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(crx_id == update_context_->queue.front());
+ DCHECK(id == update_context_->queue.front());
- CrxUpdateItem* item = FindUpdateItemById(crx_id);
+ CrxUpdateItem* item = FindUpdateItemById(id);
DCHECK(item);
if (error == ComponentUnpacker::kNone)
diff --git a/components/update_client/action_update.h b/components/update_client/action_update.h
index 8b33444..ddee94b 100644
--- a/components/update_client/action_update.h
+++ b/components/update_client/action_update.h
@@ -53,14 +53,14 @@ class ActionUpdate : public Action, protected ActionImpl {
// Called when progress is being made downloading a CRX. The progress may
// not monotonically increase due to how the CRX downloader switches between
// different downloaders and fallback urls.
- void DownloadProgress(const std::string& crx_id,
+ void DownloadProgress(const std::string& id,
const CrxDownloader::Result& download_result);
// Called when the CRX package has been downloaded to a temporary location.
- void DownloadComplete(const std::string& crx_id,
+ void DownloadComplete(const std::string& id,
const CrxDownloader::Result& download_result);
- void Install(const std::string& crx_id, const base::FilePath& crx_path);
+ void Install(const std::string& id, const base::FilePath& crx_path);
// TODO(sorin): refactor the public interface of ComponentUnpacker so
// that these calls can run on the main thread.
@@ -74,7 +74,7 @@ class ActionUpdate : public Action, protected ActionImpl {
ComponentUnpacker::Error error,
int extended_error);
- void DoneInstalling(const std::string& crx_id,
+ void DoneInstalling(const std::string& id,
ComponentUnpacker::Error error,
int extended_error);
diff --git a/components/update_client/action_update_check.cc b/components/update_client/action_update_check.cc
index c480de8..d68940e 100644
--- a/components/update_client/action_update_check.cc
+++ b/components/update_client/action_update_check.cc
@@ -71,6 +71,7 @@ void ActionUpdateCheck::Run(UpdateContext* update_context, Callback callback) {
item->next_version = Version();
item->previous_fp = crx_component.fingerprint;
item->next_fp.clear();
+ item->on_demand = update_context->is_foreground;
item->diff_update_failed = false;
item->error_category = 0;
item->error_code = 0;
@@ -80,9 +81,10 @@ void ActionUpdateCheck::Run(UpdateContext* update_context, Callback callback) {
item->diff_extra_code1 = 0;
item->download_metrics.clear();
- ChangeItemState(item.get(), CrxUpdateItem::State::kChecking);
+ update_context_->update_items.push_back(item.get());
- update_context_->update_items.push_back(item.release());
+ ChangeItemState(item.get(), CrxUpdateItem::State::kChecking);
+ ignore_result(item.release());
}
update_checker_->CheckForUpdates(
diff --git a/components/update_client/configurator.h b/components/update_client/configurator.h
index c4c763f..4bb103e 100644
--- a/components/update_client/configurator.h
+++ b/components/update_client/configurator.h
@@ -37,20 +37,11 @@ class Configurator : public base::RefCountedThreadSafe<Configurator> {
virtual int InitialDelay() const = 0;
// Delay in seconds to every subsequent update check. 0 means don't check.
- // This function is a mutator for testing purposes.
- virtual int NextCheckDelay() = 0;
+ virtual int NextCheckDelay() const = 0;
// Delay in seconds from each task step. Used to smooth out CPU/IO usage.
virtual int StepDelay() const = 0;
- // Delay in seconds between applying updates for different components, if
- // several updates are available at a given time. This function is a mutator
- // for testing purposes.
- virtual int StepDelayMedium() = 0;
-
- // Minimum delta time in seconds before checking again the same component.
- virtual int MinimumReCheckWait() const = 0;
-
// Minimum delta time in seconds before an on-demand check is allowed
// for the same component.
virtual int OnDemandDelay() const = 0;
diff --git a/components/update_client/crx_update_item.h b/components/update_client/crx_update_item.h
index f066ca2..a9cf171 100644
--- a/components/update_client/crx_update_item.h
+++ b/components/update_client/crx_update_item.h
@@ -75,10 +75,6 @@ struct CrxUpdateItem {
// enforce conditions or notify observers of the change.
State state;
- // True if the component was recently unregistered and will be uninstalled
- // soon (after the currently operation is finished, if there is one).
- bool unregistered;
-
std::string id;
CrxComponent component;
@@ -115,8 +111,6 @@ struct CrxUpdateItem {
std::vector<CrxDownloader::DownloadMetrics> download_metrics;
- std::vector<base::Closure> ready_callbacks;
-
CrxUpdateItem();
~CrxUpdateItem();
diff --git a/components/update_client/task.h b/components/update_client/task.h
index 51b6890..52af752 100644
--- a/components/update_client/task.h
+++ b/components/update_client/task.h
@@ -19,10 +19,9 @@ class Task;
// together.
class Task {
public:
- using Callback = base::Callback<void(Task* task, int error)>;
virtual ~Task() {}
- virtual void Run(const Callback& callback) = 0;
+ virtual void Run() = 0;
};
} // namespace update_client
diff --git a/components/update_client/task_update.cc b/components/update_client/task_update.cc
index 2cbf001..ca8e35f 100644
--- a/components/update_client/task_update.cc
+++ b/components/update_client/task_update.cc
@@ -13,27 +13,29 @@
namespace update_client {
TaskUpdate::TaskUpdate(UpdateEngine* update_engine,
+ bool is_foreground,
const std::vector<std::string>& ids,
- const UpdateClient::CrxDataCallback& crx_data_callback)
+ const UpdateClient::CrxDataCallback& crx_data_callback,
+ const Callback& callback)
: update_engine_(update_engine),
+ is_foreground_(is_foreground),
ids_(ids),
- crx_data_callback_(crx_data_callback) {
+ crx_data_callback_(crx_data_callback),
+ callback_(callback) {
}
TaskUpdate::~TaskUpdate() {
DCHECK(thread_checker_.CalledOnValidThread());
}
-void TaskUpdate::Run(const Callback& callback) {
+void TaskUpdate::Run() {
DCHECK(thread_checker_.CalledOnValidThread());
- callback_ = callback;
-
if (ids_.empty())
RunComplete(-1);
update_engine_->Update(
- ids_, crx_data_callback_,
+ is_foreground_, ids_, crx_data_callback_,
base::Bind(&TaskUpdate::RunComplete, base::Unretained(this)));
}
diff --git a/components/update_client/task_update.h b/components/update_client/task_update.h
index 7a91c28..2cfac4f 100644
--- a/components/update_client/task_update.h
+++ b/components/update_client/task_update.h
@@ -22,12 +22,23 @@ class UpdateEngine;
// Defines a specialized task for updating a group of CRXs.
class TaskUpdate : public Task {
public:
+ using Callback = base::Callback<void(Task* task, int error)>;
+
+ // |update_engine| is injected here to handle the task.
+ // |is_foreground| is true when the update task is initiated by the user,
+ // most likely as a result of an on-demand call.
+ // |ids| represents the CRXs to be updated by this task.
+ // |crx_data_callback| is called to get update data for the these CRXs.
+ // |callback| is called to return the execution flow back to creator of
+ // this task when the task is done.
TaskUpdate(UpdateEngine* update_engine,
+ bool is_foreground,
const std::vector<std::string>& ids,
- const UpdateClient::CrxDataCallback& crx_data_callback);
+ const UpdateClient::CrxDataCallback& crx_data_callback,
+ const Callback& callback);
~TaskUpdate() override;
- void Run(const Callback& callback) override;
+ void Run() override;
private:
// Called when the Run function associated with this task has completed.
@@ -37,12 +48,10 @@ class TaskUpdate : public Task {
UpdateEngine* update_engine_; // Not owned by this class.
+ const bool is_foreground_;
const std::vector<std::string> ids_;
const UpdateClient::CrxDataCallback crx_data_callback_;
-
- // Called to return the execution flow back to the caller of the
- // Run function when this task has completed .
- Callback callback_;
+ const Callback callback_;
DISALLOW_COPY_AND_ASSIGN(TaskUpdate);
};
diff --git a/components/update_client/test_configurator.cc b/components/update_client/test_configurator.cc
index 9cd59e4..a1dc0e5 100644
--- a/components/update_client/test_configurator.cc
+++ b/components/update_client/test_configurator.cc
@@ -4,7 +4,6 @@
#include "components/update_client/test_configurator.h"
-#include "base/run_loop.h"
#include "base/version.h"
#include "components/update_client/component_patcher_operation.h"
#include "url/gurl.h"
@@ -27,8 +26,6 @@ TestConfigurator::TestConfigurator(
const scoped_refptr<base::SingleThreadTaskRunner>& network_task_runner)
: worker_task_runner_(worker_task_runner),
initial_time_(0),
- times_(1),
- recheck_time_(0),
ondemand_time_(0),
context_(new net::TestURLRequestContextGetter(network_task_runner)) {
}
@@ -40,15 +37,7 @@ int TestConfigurator::InitialDelay() const {
return initial_time_;
}
-int TestConfigurator::NextCheckDelay() {
- // This is called when a new full cycle of checking for updates is going
- // to happen. In test we normally only test one cycle so it is a good
- // time to break from the test messageloop Run() method so the test can
- // finish.
- if (--times_ <= 0) {
- quit_closure_.Run();
- return 0;
- }
+int TestConfigurator::NextCheckDelay() const {
return 1;
}
@@ -56,14 +45,6 @@ int TestConfigurator::StepDelay() const {
return 0;
}
-int TestConfigurator::StepDelayMedium() {
- return NextCheckDelay();
-}
-
-int TestConfigurator::MinimumReCheckWait() const {
- return recheck_time_;
-}
-
int TestConfigurator::OnDemandDelay() const {
return ondemand_time_;
}
@@ -122,23 +103,10 @@ bool TestConfigurator::UseBackgroundDownloader() const {
return false;
}
-// Set how many update checks are called, the default value is just once.
-void TestConfigurator::SetLoopCount(int times) {
- times_ = times;
-}
-
-void TestConfigurator::SetRecheckTime(int seconds) {
- recheck_time_ = seconds;
-}
-
void TestConfigurator::SetOnDemandTime(int seconds) {
ondemand_time_ = seconds;
}
-void TestConfigurator::SetQuitClosure(const base::Closure& quit_closure) {
- quit_closure_ = quit_closure;
-}
-
void TestConfigurator::SetInitialDelay(int seconds) {
initial_time_ = seconds;
}
diff --git a/components/update_client/test_configurator.h b/components/update_client/test_configurator.h
index 6e441e7..8d67046 100644
--- a/components/update_client/test_configurator.h
+++ b/components/update_client/test_configurator.h
@@ -9,8 +9,6 @@
#include <utility>
#include <vector>
-#include "base/callback.h"
-#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "components/update_client/configurator.h"
@@ -58,10 +56,8 @@ class TestConfigurator : public Configurator {
// Overrrides for Configurator.
int InitialDelay() const override;
- int NextCheckDelay() override;
+ int NextCheckDelay() const override;
int StepDelay() const override;
- int StepDelayMedium() override;
- int MinimumReCheckWait() const override;
int OnDemandDelay() const override;
int UpdateDelay() const override;
std::vector<GURL> UpdateUrl() const override;
@@ -81,10 +77,7 @@ class TestConfigurator : public Configurator {
scoped_refptr<base::SingleThreadTaskRunner> GetSingleThreadTaskRunner()
const override;
- void SetLoopCount(int times);
- void SetRecheckTime(int seconds);
void SetOnDemandTime(int seconds);
- void SetQuitClosure(const base::Closure& quit_closure);
void SetInitialDelay(int seconds);
private:
@@ -96,12 +89,9 @@ class TestConfigurator : public Configurator {
scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_;
int initial_time_;
- int times_;
- int recheck_time_;
int ondemand_time_;
scoped_refptr<net::TestURLRequestContextGetter> context_;
- base::Closure quit_closure_;
DISALLOW_COPY_AND_ASSIGN(TestConfigurator);
};
diff --git a/components/update_client/update_client.cc b/components/update_client/update_client.cc
index ce857e1..55b096e 100644
--- a/components/update_client/update_client.cc
+++ b/components/update_client/update_client.cc
@@ -38,7 +38,6 @@ namespace update_client {
CrxUpdateItem::CrxUpdateItem()
: state(State::kNew),
- unregistered(false),
on_demand(false),
diff_update_failed(false),
error_category(0),
@@ -58,6 +57,12 @@ CrxComponent::CrxComponent() : allow_background_download(true) {
CrxComponent::~CrxComponent() {
}
+// It is important that an instance of the UpdateClient binds an unretained
+// pointer to itself. Otherwise, a life time circular dependency between this
+// instance and its inner members prevents the destruction of this instance.
+// Using unretained references is allowed in this case since the life time of
+// the UpdateClient instance exceeds the life time of its inner members,
+// including any thread objects that might execute callbacks bound to it.
UpdateClientImpl::UpdateClientImpl(
const scoped_refptr<Configurator>& config,
scoped_ptr<PingManager> ping_manager,
@@ -92,11 +97,15 @@ void UpdateClientImpl::Install(const std::string& id,
std::vector<std::string> ids;
ids.push_back(id);
- scoped_ptr<TaskUpdate> task(
- new TaskUpdate(update_engine_.get(), ids, crx_data_callback));
+ // Partially applies |completion_callback| to OnTaskComplete, so this
+ // argument is available when the task completes, along with the task itself.
+ const auto callback =
+ base::Bind(&UpdateClientImpl::OnTaskComplete, this, completion_callback);
+ scoped_ptr<TaskUpdate> task(new TaskUpdate(update_engine_.get(), true, ids,
+ crx_data_callback, callback));
auto it = tasks_.insert(task.release()).first;
- RunTask(*it, completion_callback);
+ RunTask(*it);
}
void UpdateClientImpl::Update(const std::vector<std::string>& ids,
@@ -104,24 +113,23 @@ void UpdateClientImpl::Update(const std::vector<std::string>& ids,
const CompletionCallback& completion_callback) {
DCHECK(thread_checker_.CalledOnValidThread());
- scoped_ptr<TaskUpdate> task(
- new TaskUpdate(update_engine_.get(), ids, crx_data_callback));
+ const auto callback =
+ base::Bind(&UpdateClientImpl::OnTaskComplete, this, completion_callback);
+ scoped_ptr<TaskUpdate> task(new TaskUpdate(update_engine_.get(), false, ids,
+ crx_data_callback, callback));
+
if (tasks_.empty()) {
auto it = tasks_.insert(task.release()).first;
- RunTask(*it, completion_callback);
+ RunTask(*it);
} else {
task_queue_.push(task.release());
}
}
-void UpdateClientImpl::RunTask(Task* task,
- const CompletionCallback& completion_callback) {
+void UpdateClientImpl::RunTask(Task* task) {
DCHECK(thread_checker_.CalledOnValidThread());
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&Task::Run, base::Unretained(task),
- base::Bind(&UpdateClientImpl::OnTaskComplete,
- base::Unretained(this), completion_callback)));
+ FROM_HERE, base::Bind(&Task::Run, base::Unretained(task)));
}
void UpdateClientImpl::OnTaskComplete(
@@ -138,7 +146,7 @@ void UpdateClientImpl::OnTaskComplete(
delete task;
if (!task_queue_.empty()) {
- RunTask(task_queue_.front(), completion_callback);
+ RunTask(task_queue_.front());
task_queue_.pop();
}
}
@@ -168,12 +176,11 @@ bool UpdateClientImpl::IsUpdating(const std::string& id) const {
return update_engine_->IsUpdating(id);
}
-scoped_ptr<UpdateClient> UpdateClientFactory(
+scoped_refptr<UpdateClient> UpdateClientFactory(
const scoped_refptr<Configurator>& config) {
scoped_ptr<PingManager> ping_manager(new PingManager(*config));
- return scoped_ptr<UpdateClient>(
- new UpdateClientImpl(config, ping_manager.Pass(), &UpdateChecker::Create,
- &CrxDownloader::Create));
+ return new UpdateClientImpl(config, ping_manager.Pass(),
+ &UpdateChecker::Create, &CrxDownloader::Create);
}
} // namespace update_client
diff --git a/components/update_client/update_client.h b/components/update_client/update_client.h
index 100bbcc..29b80e0 100644
--- a/components/update_client/update_client.h
+++ b/components/update_client/update_client.h
@@ -200,8 +200,11 @@ struct CrxComponent {
bool allow_background_download;
};
-// All methods are safe to call only from the browser's main thread.
-class UpdateClient {
+// All methods are safe to call only from the browser's main thread. Once an
+// instance of this class is created, the reference to it must be released
+// only after the thread pools of the browser process have been destroyed and
+// the browser process has gone single-threaded.
+class UpdateClient : public base::RefCounted<UpdateClient> {
public:
using CrxDataCallback =
base::Callback<void(const std::vector<std::string>& ids,
@@ -283,12 +286,14 @@ class UpdateClient {
virtual bool IsUpdating(const std::string& id) const = 0;
+ protected:
+ friend class base::RefCounted<UpdateClient>;
+
virtual ~UpdateClient() {}
};
// Creates an instance of the update client.
-// TODO(sorin): make UpdateClient a ref counted type.
-scoped_ptr<UpdateClient> UpdateClientFactory(
+scoped_refptr<UpdateClient> UpdateClientFactory(
const scoped_refptr<Configurator>& config);
} // namespace update_client
diff --git a/components/update_client/update_client_internal.h b/components/update_client/update_client_internal.h
index 94caf04..0ace882 100644
--- a/components/update_client/update_client_internal.h
+++ b/components/update_client/update_client_internal.h
@@ -37,7 +37,6 @@ class UpdateClientImpl : public UpdateClient {
scoped_ptr<PingManager> ping_manager,
UpdateChecker::Factory update_checker_factory,
CrxDownloader::Factory crx_downloader_factory);
- ~UpdateClientImpl() override;
// Overrides for UpdateClient.
void AddObserver(Observer* observer) override;
@@ -53,7 +52,9 @@ class UpdateClientImpl : public UpdateClient {
bool IsUpdating(const std::string& id) const override;
private:
- void RunTask(Task* task, const CompletionCallback& completion_callback);
+ ~UpdateClientImpl() override;
+
+ void RunTask(Task* task);
void OnTaskComplete(const CompletionCallback& completion_callback,
Task* task,
int error);
diff --git a/components/update_client/update_client_unittest.cc b/components/update_client/update_client_unittest.cc
index 52f43fa..bda4008 100644
--- a/components/update_client/update_client_unittest.cc
+++ b/components/update_client/update_client_unittest.cc
@@ -12,9 +12,8 @@
#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "base/run_loop.h"
-#include "base/test/sequenced_worker_pool_owner.h"
#include "base/thread_task_runner_handle.h"
-#include "base/threading/thread.h"
+#include "base/threading/sequenced_worker_pool.h"
#include "base/values.h"
#include "base/version.h"
#include "components/update_client/crx_update_item.h"
@@ -65,6 +64,31 @@ class MockObserver : public UpdateClient::Observer {
MOCK_METHOD2(OnEvent, void(Events event, const std::string&));
};
+class OnDemandTester {
+ public:
+ OnDemandTester(const scoped_refptr<UpdateClient>& update_client,
+ bool expected_value);
+
+ void CheckOnDemand(Events event, const std::string&);
+
+ private:
+ const scoped_refptr<UpdateClient> update_client_;
+ const bool expected_value_;
+};
+
+OnDemandTester::OnDemandTester(const scoped_refptr<UpdateClient>& update_client,
+ bool expected_value)
+ : update_client_(update_client), expected_value_(expected_value) {
+}
+
+void OnDemandTester::CheckOnDemand(Events event, const std::string& id) {
+ if (event == Events::COMPONENT_CHECKING_FOR_UPDATES) {
+ CrxUpdateItem update_item;
+ EXPECT_TRUE(update_client_->GetCrxUpdateState(id, &update_item));
+ EXPECT_EQ(update_item.on_demand, expected_value_);
+ }
+}
+
class FakePingManagerImpl : public PingManager {
public:
explicit FakePingManagerImpl(const Configurator& config);
@@ -113,6 +137,7 @@ class UpdateClientTest : public testing::Test {
protected:
void RunThreads();
+ void StopWorkerPool();
// Returns the full path to a test file.
static base::FilePath TestFilePath(const char* file);
@@ -128,8 +153,7 @@ class UpdateClientTest : public testing::Test {
base::RunLoop runloop_;
base::Closure quit_closure_;
- scoped_ptr<base::SequencedWorkerPoolOwner> worker_pool_;
- scoped_ptr<base::Thread> thread_;
+ scoped_refptr<base::SequencedWorkerPool> worker_pool_;
scoped_refptr<update_client::Configurator> config_;
@@ -137,29 +161,25 @@ class UpdateClientTest : public testing::Test {
};
UpdateClientTest::UpdateClientTest()
- : worker_pool_(
- new base::SequencedWorkerPoolOwner(kNumWorkerThreads_, "test")),
- thread_(new base::Thread("test")) {
+ : worker_pool_(new base::SequencedWorkerPool(kNumWorkerThreads_, "test")) {
quit_closure_ = runloop_.QuitClosure();
- thread_->Start();
-
- auto pool = worker_pool_->pool();
config_ = new TestConfigurator(
- pool->GetSequencedTaskRunner(pool->GetSequenceToken()),
- thread_->task_runner());
+ worker_pool_->GetSequencedTaskRunner(worker_pool_->GetSequenceToken()),
+ message_loop_.task_runner());
}
UpdateClientTest::~UpdateClientTest() {
- config_ = nullptr;
- thread_->Stop();
- worker_pool_->pool()->Shutdown();
}
void UpdateClientTest::RunThreads() {
runloop_.Run();
}
+void UpdateClientTest::StopWorkerPool() {
+ worker_pool_->Shutdown();
+}
+
base::FilePath UpdateClientTest::TestFilePath(const char* file) {
base::FilePath path;
PathService::Get(base::DIR_SOURCE_ROOT, &path);
@@ -237,11 +257,17 @@ TEST_F(UpdateClientTest, OneCrxNoUpdate) {
};
scoped_ptr<PingManager> ping_manager(new FakePingManager(*config()));
- scoped_ptr<UpdateClient> update_client(new UpdateClientImpl(
+ scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
config(), ping_manager.Pass(), &FakeUpdateChecker::Create,
&FakeCrxDownloader::Create));
+ // Verify that calling Update does not set ondemand.
+ OnDemandTester ondemand_tester(update_client, false);
+
MockObserver observer;
+ ON_CALL(observer, OnEvent(_, _))
+ .WillByDefault(Invoke(&ondemand_tester, &OnDemandTester::CheckOnDemand));
+
InSequence seq;
EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
"jebgalgnebhfojomionfpkfelancnnkf")).Times(1);
@@ -260,6 +286,8 @@ TEST_F(UpdateClientTest, OneCrxNoUpdate) {
RunThreads();
update_client->RemoveObserver(&observer);
+
+ StopWorkerPool();
}
// Tests the scenario where two CRXs are checked for updates. On CRX has
@@ -403,7 +431,7 @@ TEST_F(UpdateClientTest, TwoCrxUpdateNoUpdate) {
};
scoped_ptr<PingManager> ping_manager(new FakePingManager(*config()));
- scoped_ptr<UpdateClient> update_client(new UpdateClientImpl(
+ scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
config(), ping_manager.Pass(), &FakeUpdateChecker::Create,
&FakeCrxDownloader::Create));
@@ -442,6 +470,8 @@ TEST_F(UpdateClientTest, TwoCrxUpdateNoUpdate) {
RunThreads();
update_client->RemoveObserver(&observer);
+
+ StopWorkerPool();
}
// Tests the update check for two CRXs scenario. Both CRXs have updates.
@@ -632,7 +662,7 @@ TEST_F(UpdateClientTest, TwoCrxUpdate) {
};
scoped_ptr<FakePingManager> ping_manager(new FakePingManager(*config()));
- scoped_ptr<UpdateClient> update_client(new UpdateClientImpl(
+ scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
config(), ping_manager.Pass(), &FakeUpdateChecker::Create,
&FakeCrxDownloader::Create));
@@ -679,6 +709,8 @@ TEST_F(UpdateClientTest, TwoCrxUpdate) {
RunThreads();
update_client->RemoveObserver(&observer);
+
+ StopWorkerPool();
}
// Tests the differential update scenario for one CRX.
@@ -893,7 +925,7 @@ TEST_F(UpdateClientTest, OneCrxDiffUpdate) {
};
scoped_ptr<FakePingManager> ping_manager(new FakePingManager(*config()));
- scoped_ptr<UpdateClient> update_client(new UpdateClientImpl(
+ scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
config(), ping_manager.Pass(), &FakeUpdateChecker::Create,
&FakeCrxDownloader::Create));
@@ -944,6 +976,8 @@ TEST_F(UpdateClientTest, OneCrxDiffUpdate) {
}
update_client->RemoveObserver(&observer);
+
+ StopWorkerPool();
}
// Tests the update scenario for one CRX where the CRX installer returns
@@ -1106,7 +1140,7 @@ TEST_F(UpdateClientTest, OneCrxInstallError) {
};
scoped_ptr<PingManager> ping_manager(new FakePingManager(*config()));
- scoped_ptr<UpdateClient> update_client(new UpdateClientImpl(
+ scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
config(), ping_manager.Pass(), &FakeUpdateChecker::Create,
&FakeCrxDownloader::Create));
@@ -1137,6 +1171,8 @@ TEST_F(UpdateClientTest, OneCrxInstallError) {
RunThreads();
update_client->RemoveObserver(&observer);
+
+ StopWorkerPool();
}
// Tests the fallback from differential to full update scenario for one CRX.
@@ -1367,7 +1403,7 @@ TEST_F(UpdateClientTest, OneCrxDiffUpdateFailsFullUpdateSucceeds) {
};
scoped_ptr<FakePingManager> ping_manager(new FakePingManager(*config()));
- scoped_ptr<UpdateClient> update_client(new UpdateClientImpl(
+ scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
config(), ping_manager.Pass(), &FakeUpdateChecker::Create,
&FakeCrxDownloader::Create));
@@ -1421,6 +1457,289 @@ TEST_F(UpdateClientTest, OneCrxDiffUpdateFailsFullUpdateSucceeds) {
}
update_client->RemoveObserver(&observer);
+
+ StopWorkerPool();
+}
+
+// Tests the queuing of update checks. In this scenario, two update checks are
+// done for one CRX. The second update check call is queued up and will run
+// after the first check has completed. The CRX has no updates.
+TEST_F(UpdateClientTest, OneCrxNoUpdateQueuedCall) {
+ 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) {
+ static int num_call = 0;
+ ++num_call;
+
+ EXPECT_EQ(0, error);
+
+ if (num_call == 2)
+ 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_refptr<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);
+ 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()));
+ update_client->Update(
+ ids, base::Bind(&DataCallbackFake::Callback),
+ base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
+
+ RunThreads();
+
+ update_client->RemoveObserver(&observer);
+
+ StopWorkerPool();
+}
+
+// Tests the install of one CRX.
+TEST_F(UpdateClientTest, OneCrxInstall) {
+ 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.0");
+ 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 {
+ /*
+ 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;
+ 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 {
+ 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(1U, ping_items.size());
+ EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id);
+ EXPECT_TRUE(base::Version("0.0").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<FakePingManager> ping_manager(new FakePingManager(*config()));
+ scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
+ config(), ping_manager.Pass(), &FakeUpdateChecker::Create,
+ &FakeCrxDownloader::Create));
+
+ // Verify that calling Install sets ondemand.
+ OnDemandTester ondemand_tester(update_client, true);
+
+ MockObserver observer;
+ ON_CALL(observer, OnEvent(_, _))
+ .WillByDefault(Invoke(&ondemand_tester, &OnDemandTester::CheckOnDemand));
+
+ 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);
+
+ update_client->AddObserver(&observer);
+
+ update_client->Install(
+ std::string("jebgalgnebhfojomionfpkfelancnnkf"),
+ base::Bind(&DataCallbackFake::Callback),
+ base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
+
+ RunThreads();
+
+ update_client->RemoveObserver(&observer);
+
+ StopWorkerPool();
}
} // namespace update_client
diff --git a/components/update_client/update_engine.cc b/components/update_client/update_engine.cc
index 4c64fde..d4515d6 100644
--- a/components/update_client/update_engine.cc
+++ b/components/update_client/update_engine.cc
@@ -20,6 +20,7 @@ namespace update_client {
UpdateContext::UpdateContext(
const scoped_refptr<Configurator>& config,
+ bool is_foreground,
const std::vector<std::string>& ids,
const UpdateClient::CrxDataCallback& crx_data_callback,
const UpdateEngine::NotifyObserversCallback& notify_observers_callback,
@@ -28,6 +29,7 @@ UpdateContext::UpdateContext(
CrxDownloader::Factory crx_downloader_factory,
PingManager* ping_manager)
: config(config),
+ is_foreground(is_foreground),
ids(ids),
crx_data_callback(crx_data_callback),
notify_observers_callback(notify_observers_callback),
@@ -93,14 +95,16 @@ bool UpdateEngine::GetUpdateState(const std::string& id,
}
void UpdateEngine::Update(
+ bool is_foreground,
const std::vector<std::string>& ids,
const UpdateClient::CrxDataCallback& crx_data_callback,
const CompletionCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
scoped_ptr<UpdateContext> update_context(new UpdateContext(
- config_, ids, crx_data_callback, notify_observers_callback_, callback,
- update_checker_factory_, crx_downloader_factory_, ping_manager_));
+ config_, is_foreground, ids, crx_data_callback,
+ notify_observers_callback_, callback, update_checker_factory_,
+ crx_downloader_factory_, ping_manager_));
CrxUpdateItem update_item;
scoped_ptr<ActionUpdateCheck> update_check_action(new ActionUpdateCheck(
diff --git a/components/update_client/update_engine.h b/components/update_client/update_engine.h
index e902a54..c5457f4 100644
--- a/components/update_client/update_engine.h
+++ b/components/update_client/update_engine.h
@@ -61,7 +61,8 @@ class UpdateEngine {
bool GetUpdateState(const std::string& id, CrxUpdateItem* update_state);
- void Update(const std::vector<std::string>& ids,
+ void Update(bool is_foreground,
+ const std::vector<std::string>& ids,
const UpdateClient::CrxDataCallback& crx_data_callback,
const CompletionCallback& update_callback);
@@ -91,6 +92,7 @@ class UpdateEngine {
struct UpdateContext {
UpdateContext(
const scoped_refptr<Configurator>& config,
+ bool is_foreground,
const std::vector<std::string>& ids,
const UpdateClient::CrxDataCallback& crx_data_callback,
const UpdateEngine::NotifyObserversCallback& notify_observers_callback,
@@ -103,6 +105,9 @@ struct UpdateContext {
scoped_refptr<Configurator> config;
+ // True if this update has been initiated by the user.
+ bool is_foreground;
+
// Contains the ids of all CRXs in this context.
const std::vector<std::string> ids;