Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 1 | // Copyright 2018 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "base/command_line.h" |
Sorin Jianu | 55587d3 | 2018-11-14 21:43:27 | [diff] [blame] | 6 | #include "base/json/json_reader.h" |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 7 | #include "base/run_loop.h" |
Lei Zhang | fe5b8693 | 2019-02-01 17:26:59 | [diff] [blame] | 8 | #include "base/strings/stringprintf.h" |
John Abd-El-Malek | 1a9c3607 | 2018-08-14 03:09:53 | [diff] [blame] | 9 | #include "base/test/bind_test_util.h" |
Devlin Cronin | 15291e9c | 2018-06-07 21:37:48 | [diff] [blame] | 10 | #include "base/test/metrics/histogram_tester.h" |
Gabriel Charette | c710874 | 2019-08-23 03:31:40 | [diff] [blame] | 11 | #include "base/test/task_environment.h" |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 12 | #include "chrome/browser/extensions/content_verifier_test_utils.h" |
| 13 | #include "chrome/browser/extensions/extension_management_test_util.h" |
| 14 | #include "chrome/browser/extensions/extension_service.h" |
| 15 | #include "chrome/browser/extensions/updater/chrome_update_client_config.h" |
| 16 | #include "chrome/browser/extensions/updater/extension_update_client_base_browsertest.h" |
| 17 | #include "chrome/browser/extensions/updater/extension_updater.h" |
| 18 | #include "chrome/common/chrome_switches.h" |
| 19 | #include "components/policy/core/browser/browser_policy_connector.h" |
| 20 | #include "components/policy/core/common/mock_configuration_policy_provider.h" |
Sorin Jianu | 86ee558e | 2019-02-18 17:01:50 | [diff] [blame] | 21 | #include "components/update_client/net/url_loader_post_interceptor.h" |
Minh X. Nguyen | b3d3db3 | 2018-06-04 22:59:56 | [diff] [blame] | 22 | #include "content/public/test/browser_test_utils.h" |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 23 | #include "extensions/browser/content_verifier.h" |
| 24 | #include "extensions/browser/extension_registry.h" |
| 25 | #include "extensions/browser/external_install_info.h" |
| 26 | #include "extensions/browser/mock_external_provider.h" |
| 27 | #include "extensions/browser/test_extension_registry_observer.h" |
| 28 | #include "extensions/browser/updater/extension_downloader.h" |
| 29 | #include "extensions/browser/updater/manifest_fetch_data.h" |
Minh X. Nguyen | b3d3db3 | 2018-06-04 22:59:56 | [diff] [blame] | 30 | #include "extensions/common/extension_updater_uma.h" |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 31 | #include "extensions/common/extension_urls.h" |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 32 | |
| 33 | namespace extensions { |
| 34 | |
| 35 | namespace { |
| 36 | |
Joshua Pawlicki | a3314d3c | 2018-08-22 17:14:35 | [diff] [blame] | 37 | const char kExtensionId[] = "aohghmighlieiainnegkcijnfilokake"; |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 38 | |
| 39 | using UpdateClientEvents = update_client::UpdateClient::Observer::Events; |
| 40 | |
| 41 | } // namespace |
| 42 | |
Joshua Pawlicki | 8ac3932 | 2019-04-04 21:22:46 | [diff] [blame] | 43 | class UpdateServiceTest : public ExtensionUpdateClientBaseTest { |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 44 | public: |
Joshua Pawlicki | 8ac3932 | 2019-04-04 21:22:46 | [diff] [blame] | 45 | UpdateServiceTest() : ExtensionUpdateClientBaseTest() {} |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 46 | ~UpdateServiceTest() override {} |
| 47 | |
| 48 | void SetUpCommandLine(base::CommandLine* command_line) override { |
| 49 | ExtensionUpdateClientBaseTest::SetUpCommandLine(command_line); |
| 50 | command_line->AppendSwitchASCII( |
| 51 | switches::kExtensionContentVerification, |
| 52 | switches::kExtensionContentVerificationEnforce); |
| 53 | } |
| 54 | |
| 55 | bool ShouldEnableContentVerification() override { return true; } |
| 56 | }; |
| 57 | |
Joshua Pawlicki | 8ac3932 | 2019-04-04 21:22:46 | [diff] [blame] | 58 | IN_PROC_BROWSER_TEST_F(UpdateServiceTest, NoUpdate) { |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 59 | // Verify that UpdateService runs correctly when there's no update. |
| 60 | base::ScopedAllowBlockingForTesting allow_io; |
Minh X. Nguyen | b3d3db3 | 2018-06-04 22:59:56 | [diff] [blame] | 61 | base::HistogramTester histogram_tester; |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 62 | |
| 63 | // Mock a no-update response. |
Joshua Pawlicki | 8ac3932 | 2019-04-04 21:22:46 | [diff] [blame] | 64 | ASSERT_TRUE(update_interceptor_->ExpectRequest( |
| 65 | std::make_unique<update_client::PartialMatch>(R"("updatecheck":{)"), |
| 66 | test_data_dir_.AppendASCII("updater/updatecheck_reply_noupdate_1.json"))); |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 67 | |
| 68 | const base::FilePath crx_path = test_data_dir_.AppendASCII("updater/v1.crx"); |
| 69 | const Extension* extension = |
| 70 | InstallExtension(crx_path, 1, Manifest::EXTERNAL_POLICY_DOWNLOAD); |
| 71 | ASSERT_TRUE(extension); |
| 72 | EXPECT_EQ(kExtensionId, extension->id()); |
| 73 | |
| 74 | extensions::ExtensionUpdater::CheckParams params; |
| 75 | params.ids = {kExtensionId}; |
Minh X. Nguyen | 722b968 | 2018-04-25 21:46:48 | [diff] [blame] | 76 | extension_service()->updater()->CheckNow(std::move(params)); |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 77 | |
Minh X. Nguyen | b3d3db3 | 2018-06-04 22:59:56 | [diff] [blame] | 78 | // UpdateService should emit a not-updated event. |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 79 | EXPECT_EQ(UpdateClientEvents::COMPONENT_NOT_UPDATED, |
| 80 | WaitOnComponentUpdaterCompleteEvent(kExtensionId)); |
| 81 | |
Minh X. Nguyen | b3d3db3 | 2018-06-04 22:59:56 | [diff] [blame] | 82 | content::FetchHistogramsFromChildProcesses(); |
Minh X. Nguyen | 42c0d70 | 2018-06-13 18:23:35 | [diff] [blame] | 83 | EXPECT_THAT(histogram_tester.GetAllSamples( |
| 84 | "Extensions.ExtensionUpdaterRawUpdateCalls"), |
| 85 | testing::ElementsAre(base::Bucket(1, 1))); |
Minh X. Nguyen | b3d3db3 | 2018-06-04 22:59:56 | [diff] [blame] | 86 | EXPECT_THAT( |
| 87 | histogram_tester.GetAllSamples("Extensions.ExtensionUpdaterUpdateCalls"), |
| 88 | testing::ElementsAre(base::Bucket(1, 1))); |
| 89 | EXPECT_THAT( |
| 90 | histogram_tester.GetAllSamples( |
| 91 | "Extensions.ExtensionUpdaterUpdateResults"), |
| 92 | testing::ElementsAre(base::Bucket( |
| 93 | static_cast<int>(ExtensionUpdaterUpdateResult::NO_UPDATE), 1))); |
| 94 | histogram_tester.ExpectTotalCount( |
| 95 | "Extensions.UnifiedExtensionUpdaterUpdateCheckErrors", 0); |
| 96 | |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 97 | ASSERT_EQ(1, update_interceptor_->GetCount()) |
| 98 | << update_interceptor_->GetRequestsAsString(); |
| 99 | |
| 100 | // No update, thus no download nor ping activities. |
John Abd-El-Malek | 1a9c3607 | 2018-08-14 03:09:53 | [diff] [blame] | 101 | EXPECT_EQ(0, get_interceptor_count()); |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 102 | EXPECT_EQ(0, ping_interceptor_->GetCount()) |
| 103 | << ping_interceptor_->GetRequestsAsString(); |
| 104 | |
| 105 | const std::string update_request = |
Antonio Gomes | b616250 | 2018-06-28 20:21:55 | [diff] [blame] | 106 | std::get<0>(update_interceptor_->GetRequests()[0]); |
Lei Zhang | e8d7e982 | 2019-02-20 05:40:44 | [diff] [blame] | 107 | const auto root = base::JSONReader::Read(update_request); |
| 108 | ASSERT_TRUE(root); |
Sorin Jianu | 55587d3 | 2018-11-14 21:43:27 | [diff] [blame] | 109 | const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0]; |
| 110 | EXPECT_EQ(kExtensionId, app.FindKey("appid")->GetString()); |
| 111 | EXPECT_EQ("0.10", app.FindKey("version")->GetString()); |
| 112 | EXPECT_TRUE(app.FindKey("enabled")->GetBool()); |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 113 | } |
| 114 | |
Joshua Pawlicki | 8ac3932 | 2019-04-04 21:22:46 | [diff] [blame] | 115 | IN_PROC_BROWSER_TEST_F(UpdateServiceTest, UpdateCheckError) { |
Minh X. Nguyen | b3d3db3 | 2018-06-04 22:59:56 | [diff] [blame] | 116 | // Verify that UpdateService works correctly when there's an error in the |
| 117 | // update check phase. |
| 118 | base::ScopedAllowBlockingForTesting allow_io; |
| 119 | base::HistogramTester histogram_tester; |
| 120 | |
| 121 | // Mock an update check error. |
Sorin Jianu | 55587d3 | 2018-11-14 21:43:27 | [diff] [blame] | 122 | ASSERT_TRUE(update_interceptor_->ExpectRequest( |
| 123 | std::make_unique<update_client::PartialMatch>(R"("updatecheck":{)"), |
| 124 | net::HTTP_FORBIDDEN)); |
Minh X. Nguyen | b3d3db3 | 2018-06-04 22:59:56 | [diff] [blame] | 125 | |
| 126 | const base::FilePath crx_path = test_data_dir_.AppendASCII("updater/v1.crx"); |
| 127 | const Extension* extension = |
| 128 | InstallExtension(crx_path, 1, Manifest::EXTERNAL_POLICY_DOWNLOAD); |
| 129 | ASSERT_TRUE(extension); |
| 130 | EXPECT_EQ(kExtensionId, extension->id()); |
| 131 | |
| 132 | extensions::ExtensionUpdater::CheckParams params; |
| 133 | params.ids = {kExtensionId}; |
| 134 | extension_service()->updater()->CheckNow(std::move(params)); |
| 135 | |
| 136 | // UpdateService should emit an error update event. |
| 137 | EXPECT_EQ(UpdateClientEvents::COMPONENT_UPDATE_ERROR, |
| 138 | WaitOnComponentUpdaterCompleteEvent(kExtensionId)); |
| 139 | |
| 140 | content::FetchHistogramsFromChildProcesses(); |
| 141 | EXPECT_THAT( |
| 142 | histogram_tester.GetAllSamples("Extensions.ExtensionUpdaterUpdateCalls"), |
| 143 | testing::ElementsAre(base::Bucket(1, 1))); |
Minh X. Nguyen | 42c0d70 | 2018-06-13 18:23:35 | [diff] [blame] | 144 | EXPECT_THAT(histogram_tester.GetAllSamples( |
| 145 | "Extensions.ExtensionUpdaterRawUpdateCalls"), |
| 146 | testing::ElementsAre(base::Bucket(1, 1))); |
Minh X. Nguyen | b3d3db3 | 2018-06-04 22:59:56 | [diff] [blame] | 147 | EXPECT_THAT( |
| 148 | histogram_tester.GetAllSamples( |
| 149 | "Extensions.ExtensionUpdaterUpdateResults"), |
| 150 | testing::ElementsAre(base::Bucket( |
| 151 | static_cast<int>(ExtensionUpdaterUpdateResult::UPDATE_CHECK_ERROR), |
| 152 | 1))); |
| 153 | EXPECT_THAT(histogram_tester.GetAllSamples( |
| 154 | "Extensions.UnifiedExtensionUpdaterUpdateCheckErrors"), |
| 155 | testing::ElementsAre(base::Bucket(403, 1))); |
| 156 | |
| 157 | ASSERT_EQ(1, update_interceptor_->GetCount()) |
| 158 | << update_interceptor_->GetRequestsAsString(); |
| 159 | |
| 160 | // Error, thus no download nor ping activities. |
John Abd-El-Malek | 1a9c3607 | 2018-08-14 03:09:53 | [diff] [blame] | 161 | EXPECT_EQ(0, get_interceptor_count()); |
Minh X. Nguyen | b3d3db3 | 2018-06-04 22:59:56 | [diff] [blame] | 162 | EXPECT_EQ(0, ping_interceptor_->GetCount()) |
| 163 | << ping_interceptor_->GetRequestsAsString(); |
| 164 | |
| 165 | const std::string update_request = |
Antonio Gomes | b616250 | 2018-06-28 20:21:55 | [diff] [blame] | 166 | std::get<0>(update_interceptor_->GetRequests()[0]); |
Lei Zhang | e8d7e982 | 2019-02-20 05:40:44 | [diff] [blame] | 167 | const auto root = base::JSONReader::Read(update_request); |
| 168 | ASSERT_TRUE(root); |
Sorin Jianu | 55587d3 | 2018-11-14 21:43:27 | [diff] [blame] | 169 | const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0]; |
| 170 | EXPECT_EQ(kExtensionId, app.FindKey("appid")->GetString()); |
| 171 | EXPECT_EQ("0.10", app.FindKey("version")->GetString()); |
| 172 | EXPECT_TRUE(app.FindKey("enabled")->GetBool()); |
Minh X. Nguyen | b3d3db3 | 2018-06-04 22:59:56 | [diff] [blame] | 173 | } |
| 174 | |
Joshua Pawlicki | 8ac3932 | 2019-04-04 21:22:46 | [diff] [blame] | 175 | IN_PROC_BROWSER_TEST_F(UpdateServiceTest, TwoUpdateCheckErrors) { |
Minh X. Nguyen | b3d3db3 | 2018-06-04 22:59:56 | [diff] [blame] | 176 | // Verify that the UMA counters are emitted properly when there are 2 update |
| 177 | // checks with different number of extensions, both of which result in errors. |
| 178 | base::ScopedAllowBlockingForTesting allow_io; |
| 179 | base::HistogramTester histogram_tester; |
| 180 | |
| 181 | // Mock update check errors. |
Sorin Jianu | 55587d3 | 2018-11-14 21:43:27 | [diff] [blame] | 182 | ASSERT_TRUE(update_interceptor_->ExpectRequest( |
| 183 | std::make_unique<update_client::PartialMatch>(R"("updatecheck":{)"), |
| 184 | net::HTTP_NOT_MODIFIED)); |
| 185 | ASSERT_TRUE(update_interceptor_->ExpectRequest( |
| 186 | std::make_unique<update_client::PartialMatch>(R"("updatecheck":{)"), |
| 187 | net::HTTP_USE_PROXY)); |
Minh X. Nguyen | b3d3db3 | 2018-06-04 22:59:56 | [diff] [blame] | 188 | |
| 189 | const base::FilePath crx_path1 = test_data_dir_.AppendASCII("updater/v1.crx"); |
| 190 | const base::FilePath crx_path2 = test_data_dir_.AppendASCII("updater/v2.crx"); |
| 191 | const Extension* extension1 = |
| 192 | InstallExtension(crx_path1, 1, Manifest::EXTERNAL_POLICY_DOWNLOAD); |
| 193 | const Extension* extension2 = |
| 194 | InstallExtension(crx_path2, 1, Manifest::EXTERNAL_POLICY_DOWNLOAD); |
| 195 | ASSERT_TRUE(extension1 && extension2); |
| 196 | |
| 197 | extensions::ExtensionUpdater::CheckParams params; |
| 198 | |
| 199 | base::RunLoop run_loop1; |
| 200 | params.ids = {extension1->id(), extension2->id()}; |
| 201 | params.callback = run_loop1.QuitClosure(); |
| 202 | extension_service()->updater()->CheckNow(std::move(params)); |
| 203 | run_loop1.Run(); |
| 204 | |
| 205 | base::RunLoop run_loop2; |
| 206 | params.ids = {extension1->id()}; |
| 207 | params.callback = run_loop2.QuitClosure(); |
| 208 | extension_service()->updater()->CheckNow(std::move(params)); |
| 209 | run_loop2.Run(); |
| 210 | |
| 211 | content::FetchHistogramsFromChildProcesses(); |
Minh X. Nguyen | 42c0d70 | 2018-06-13 18:23:35 | [diff] [blame] | 212 | EXPECT_THAT(histogram_tester.GetAllSamples( |
| 213 | "Extensions.ExtensionUpdaterRawUpdateCalls"), |
| 214 | testing::ElementsAre(base::Bucket(1, 1), base::Bucket(2, 1))); |
Minh X. Nguyen | b3d3db3 | 2018-06-04 22:59:56 | [diff] [blame] | 215 | EXPECT_THAT( |
| 216 | histogram_tester.GetAllSamples("Extensions.ExtensionUpdaterUpdateCalls"), |
| 217 | testing::ElementsAre(base::Bucket(1, 1), base::Bucket(2, 1))); |
| 218 | EXPECT_THAT( |
| 219 | histogram_tester.GetAllSamples( |
| 220 | "Extensions.ExtensionUpdaterUpdateResults"), |
| 221 | testing::ElementsAre(base::Bucket( |
| 222 | static_cast<int>(ExtensionUpdaterUpdateResult::UPDATE_CHECK_ERROR), |
| 223 | 3))); |
| 224 | EXPECT_THAT(histogram_tester.GetAllSamples( |
| 225 | "Extensions.UnifiedExtensionUpdaterUpdateCheckErrors"), |
| 226 | testing::ElementsAre(base::Bucket(304, 2), base::Bucket(305, 1))); |
| 227 | |
| 228 | ASSERT_EQ(2, update_interceptor_->GetCount()) |
| 229 | << update_interceptor_->GetRequestsAsString(); |
| 230 | |
| 231 | // Error, thus no download nor ping activities. |
John Abd-El-Malek | 1a9c3607 | 2018-08-14 03:09:53 | [diff] [blame] | 232 | EXPECT_EQ(0, get_interceptor_count()); |
Minh X. Nguyen | b3d3db3 | 2018-06-04 22:59:56 | [diff] [blame] | 233 | EXPECT_EQ(0, ping_interceptor_->GetCount()) |
| 234 | << ping_interceptor_->GetRequestsAsString(); |
| 235 | } |
| 236 | |
Joshua Pawlicki | 8ac3932 | 2019-04-04 21:22:46 | [diff] [blame] | 237 | IN_PROC_BROWSER_TEST_F(UpdateServiceTest, SuccessfulUpdate) { |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 238 | base::ScopedAllowBlockingForTesting allow_io; |
Minh X. Nguyen | b3d3db3 | 2018-06-04 22:59:56 | [diff] [blame] | 239 | base::HistogramTester histogram_tester; |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 240 | |
| 241 | // Mock an update response. |
Sorin Jianu | 55587d3 | 2018-11-14 21:43:27 | [diff] [blame] | 242 | const base::FilePath update_response = |
| 243 | test_data_dir_.AppendASCII("updater/updatecheck_reply_update_1.json"); |
| 244 | const base::FilePath ping_response = |
| 245 | test_data_dir_.AppendASCII("updater/ping_reply_1.json"); |
| 246 | ASSERT_TRUE(update_interceptor_->ExpectRequest( |
| 247 | std::make_unique<update_client::PartialMatch>(R"("updatecheck":{)"), |
| 248 | update_response)); |
| 249 | ASSERT_TRUE(ping_interceptor_->ExpectRequest( |
| 250 | std::make_unique<update_client::PartialMatch>(R"("eventtype":)"), |
| 251 | ping_response)); |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 252 | |
Sorin Jianu | 55587d3 | 2018-11-14 21:43:27 | [diff] [blame] | 253 | const base::FilePath crx_path = test_data_dir_.AppendASCII("updater/v1.crx"); |
John Abd-El-Malek | 1a9c3607 | 2018-08-14 03:09:53 | [diff] [blame] | 254 | set_interceptor_hook(base::BindLambdaForTesting( |
| 255 | [&](content::URLLoaderInterceptor::RequestParams* params) { |
| 256 | if (params->url_request.url.path() != "/download/v1.crx") |
| 257 | return false; |
| 258 | |
| 259 | content::URLLoaderInterceptor::WriteResponse(crx_path, |
| 260 | params->client.get()); |
| 261 | return true; |
| 262 | })); |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 263 | |
| 264 | const Extension* extension = |
| 265 | InstallExtension(crx_path, 1, Manifest::EXTERNAL_POLICY_DOWNLOAD); |
| 266 | ASSERT_TRUE(extension); |
| 267 | EXPECT_EQ(kExtensionId, extension->id()); |
| 268 | |
| 269 | base::RunLoop run_loop; |
| 270 | |
| 271 | extensions::ExtensionUpdater::CheckParams params; |
| 272 | params.ids = {kExtensionId}; |
Minh X. Nguyen | 722b968 | 2018-04-25 21:46:48 | [diff] [blame] | 273 | params.callback = run_loop.QuitClosure(); |
| 274 | extension_service()->updater()->CheckNow(std::move(params)); |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 275 | |
| 276 | EXPECT_EQ(UpdateClientEvents::COMPONENT_UPDATED, |
| 277 | WaitOnComponentUpdaterCompleteEvent(kExtensionId)); |
| 278 | |
| 279 | run_loop.Run(); |
| 280 | |
Minh X. Nguyen | b3d3db3 | 2018-06-04 22:59:56 | [diff] [blame] | 281 | content::FetchHistogramsFromChildProcesses(); |
Hajime Hoshi | c7a8a7c4 | 2019-01-09 00:58:03 | [diff] [blame] | 282 | EXPECT_THAT(histogram_tester.GetAllSamples( |
| 283 | "Extensions.ExtensionUpdaterRawUpdateCalls"), |
| 284 | testing::ElementsAre(base::Bucket(1, 1))); |
Minh X. Nguyen | b3d3db3 | 2018-06-04 22:59:56 | [diff] [blame] | 285 | EXPECT_THAT( |
| 286 | histogram_tester.GetAllSamples("Extensions.ExtensionUpdaterUpdateCalls"), |
| 287 | testing::ElementsAre(base::Bucket(1, 1))); |
| 288 | EXPECT_THAT( |
| 289 | histogram_tester.GetAllSamples( |
| 290 | "Extensions.ExtensionUpdaterUpdateResults"), |
| 291 | testing::ElementsAre(base::Bucket( |
| 292 | static_cast<int>(ExtensionUpdaterUpdateResult::UPDATE_SUCCESS), 1))); |
| 293 | histogram_tester.ExpectTotalCount( |
| 294 | "Extensions.UnifiedExtensionUpdaterUpdateCheckErrors", 0); |
| 295 | |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 296 | ASSERT_EQ(1, update_interceptor_->GetCount()) |
| 297 | << update_interceptor_->GetRequestsAsString(); |
John Abd-El-Malek | 1a9c3607 | 2018-08-14 03:09:53 | [diff] [blame] | 298 | EXPECT_EQ(1, get_interceptor_count()); |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 299 | |
| 300 | const std::string update_request = |
Antonio Gomes | b616250 | 2018-06-28 20:21:55 | [diff] [blame] | 301 | std::get<0>(update_interceptor_->GetRequests()[0]); |
Lei Zhang | e8d7e982 | 2019-02-20 05:40:44 | [diff] [blame] | 302 | const auto root = base::JSONReader::Read(update_request); |
| 303 | ASSERT_TRUE(root); |
Sorin Jianu | 55587d3 | 2018-11-14 21:43:27 | [diff] [blame] | 304 | const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0]; |
| 305 | EXPECT_EQ(kExtensionId, app.FindKey("appid")->GetString()); |
| 306 | EXPECT_EQ("0.10", app.FindKey("version")->GetString()); |
| 307 | EXPECT_TRUE(app.FindKey("enabled")->GetBool()); |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 308 | } |
| 309 | |
Joshua Pawlicki | 8ac3932 | 2019-04-04 21:22:46 | [diff] [blame] | 310 | IN_PROC_BROWSER_TEST_F(UpdateServiceTest, PolicyCorrupted) { |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 311 | base::ScopedAllowBlockingForTesting allow_io; |
| 312 | |
| 313 | ExtensionSystem* system = ExtensionSystem::Get(profile()); |
| 314 | ExtensionService* service = extension_service(); |
| 315 | |
Sorin Jianu | 55587d3 | 2018-11-14 21:43:27 | [diff] [blame] | 316 | const base::FilePath update_response = |
| 317 | test_data_dir_.AppendASCII("updater/updatecheck_reply_update_1.json"); |
| 318 | const base::FilePath ping_response = |
| 319 | test_data_dir_.AppendASCII("updater/ping_reply_1.json"); |
| 320 | ASSERT_TRUE(update_interceptor_->ExpectRequest( |
| 321 | std::make_unique<update_client::PartialMatch>(R"("updatecheck":{)"), |
| 322 | update_response)); |
| 323 | ASSERT_TRUE(ping_interceptor_->ExpectRequest( |
| 324 | std::make_unique<update_client::PartialMatch>(R"("eventtype":)"), |
| 325 | ping_response)); |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 326 | |
Sorin Jianu | 55587d3 | 2018-11-14 21:43:27 | [diff] [blame] | 327 | const base::FilePath crx_path = test_data_dir_.AppendASCII("updater/v1.crx"); |
John Abd-El-Malek | 1a9c3607 | 2018-08-14 03:09:53 | [diff] [blame] | 328 | set_interceptor_hook(base::BindLambdaForTesting( |
| 329 | [&](content::URLLoaderInterceptor::RequestParams* params) { |
| 330 | if (params->url_request.url.path() != "/download/v1.crx") |
| 331 | return false; |
| 332 | |
| 333 | content::URLLoaderInterceptor::WriteResponse(crx_path, |
| 334 | params->client.get()); |
| 335 | return true; |
| 336 | })); |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 337 | |
| 338 | // Setup fake policy and update check objects. |
| 339 | content_verifier_test::ForceInstallProvider policy(kExtensionId); |
| 340 | system->management_policy()->RegisterProvider(&policy); |
| 341 | auto external_provider = std::make_unique<MockExternalProvider>( |
| 342 | service, Manifest::EXTERNAL_POLICY_DOWNLOAD); |
| 343 | external_provider->UpdateOrAddExtension( |
| 344 | std::make_unique<ExternalInstallInfoUpdateUrl>( |
| 345 | kExtensionId, std::string() /* install_parameter */, |
| 346 | extension_urls::GetWebstoreUpdateUrl(), |
| 347 | Manifest::EXTERNAL_POLICY_DOWNLOAD, 0 /* creation_flags */, |
| 348 | true /* mark_acknowledged */)); |
| 349 | service->AddProviderForTesting(std::move(external_provider)); |
| 350 | |
| 351 | const Extension* extension = |
| 352 | InstallExtension(crx_path, 1, Manifest::EXTERNAL_POLICY_DOWNLOAD); |
| 353 | ASSERT_TRUE(extension); |
| 354 | EXPECT_EQ(kExtensionId, extension->id()); |
| 355 | |
| 356 | TestExtensionRegistryObserver registry_observer( |
| 357 | ExtensionRegistry::Get(profile()), kExtensionId); |
| 358 | ContentVerifier* verifier = system->content_verifier(); |
Oleg Davydov | 9b465ba | 2019-07-02 12:28:08 | [diff] [blame] | 359 | verifier->VerifyFailedForTest(kExtensionId, ContentVerifyJob::HASH_MISMATCH); |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 360 | |
| 361 | // Make sure the extension first got disabled due to corruption. |
| 362 | EXPECT_TRUE(registry_observer.WaitForExtensionUnloaded()); |
| 363 | ExtensionPrefs* prefs = ExtensionPrefs::Get(profile()); |
| 364 | int reasons = prefs->GetDisableReasons(kExtensionId); |
| 365 | EXPECT_TRUE(reasons & disable_reason::DISABLE_CORRUPTED); |
| 366 | |
| 367 | // Make sure the extension then got re-installed, and that after reinstall it |
| 368 | // is no longer disabled due to corruption. |
| 369 | EXPECT_EQ(UpdateClientEvents::COMPONENT_UPDATED, |
| 370 | WaitOnComponentUpdaterCompleteEvent(kExtensionId)); |
| 371 | |
| 372 | reasons = prefs->GetDisableReasons(kExtensionId); |
| 373 | EXPECT_FALSE(reasons & disable_reason::DISABLE_CORRUPTED); |
| 374 | |
| 375 | ASSERT_EQ(1, update_interceptor_->GetCount()) |
| 376 | << update_interceptor_->GetRequestsAsString(); |
John Abd-El-Malek | 1a9c3607 | 2018-08-14 03:09:53 | [diff] [blame] | 377 | EXPECT_EQ(1, get_interceptor_count()); |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 378 | |
| 379 | // Make sure that the update check request is formed correctly when the |
| 380 | // extension is corrupted: |
| 381 | // - version="0.0.0.0" |
| 382 | // - installsource="reinstall" |
Minh X. Nguyen | fc16497e | 2018-04-24 16:05:35 | [diff] [blame] | 383 | // - installedby="policy" |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 384 | // - enabled="0" |
| 385 | // - <disabled reason="1024"/> |
| 386 | const std::string update_request = |
Antonio Gomes | b616250 | 2018-06-28 20:21:55 | [diff] [blame] | 387 | std::get<0>(update_interceptor_->GetRequests()[0]); |
Lei Zhang | e8d7e982 | 2019-02-20 05:40:44 | [diff] [blame] | 388 | const auto root = base::JSONReader::Read(update_request); |
| 389 | ASSERT_TRUE(root); |
Sorin Jianu | 55587d3 | 2018-11-14 21:43:27 | [diff] [blame] | 390 | const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0]; |
| 391 | EXPECT_EQ(kExtensionId, app.FindKey("appid")->GetString()); |
| 392 | EXPECT_EQ("0.0.0.0", app.FindKey("version")->GetString()); |
| 393 | EXPECT_EQ("reinstall", app.FindKey("installsource")->GetString()); |
| 394 | EXPECT_EQ("policy", app.FindKey("installedby")->GetString()); |
| 395 | EXPECT_FALSE(app.FindKey("enabled")->GetBool()); |
| 396 | const auto& disabled = app.FindKey("disabled")->GetList()[0]; |
| 397 | EXPECT_EQ(disable_reason::DISABLE_CORRUPTED, |
| 398 | disabled.FindKey("reason")->GetInt()); |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 399 | } |
| 400 | |
Joshua Pawlicki | 8ac3932 | 2019-04-04 21:22:46 | [diff] [blame] | 401 | IN_PROC_BROWSER_TEST_F(UpdateServiceTest, UninstallExtensionWhileUpdating) { |
Minh X. Nguyen | ad500fb | 2018-05-03 17:31:02 | [diff] [blame] | 402 | // This test is to verify that the extension updater engine (update client) |
| 403 | // works correctly when an extension is uninstalled when the extension updater |
| 404 | // is in progress. |
| 405 | base::ScopedAllowBlockingForTesting allow_io; |
| 406 | |
| 407 | const base::FilePath crx_path = test_data_dir_.AppendASCII("updater/v1.crx"); |
| 408 | |
| 409 | const Extension* extension = |
| 410 | InstallExtension(crx_path, 1, Manifest::EXTERNAL_POLICY_DOWNLOAD); |
| 411 | ASSERT_TRUE(extension); |
| 412 | EXPECT_EQ(kExtensionId, extension->id()); |
| 413 | |
| 414 | base::RunLoop run_loop; |
| 415 | |
| 416 | extensions::ExtensionUpdater::CheckParams params; |
| 417 | params.ids = {kExtensionId}; |
| 418 | params.callback = run_loop.QuitClosure(); |
| 419 | extension_service()->updater()->CheckNow(std::move(params)); |
| 420 | |
| 421 | // Uninstall the extension right before the message loop is executed to |
| 422 | // emulate uninstalling an extension in the middle of an extension update. |
| 423 | extension_service()->UninstallExtension( |
| 424 | kExtensionId, extensions::UNINSTALL_REASON_COMPONENT_REMOVED, nullptr); |
| 425 | |
| 426 | // Update client should issue an update error event for this extension. |
| 427 | ASSERT_EQ(UpdateClientEvents::COMPONENT_UPDATE_ERROR, |
| 428 | WaitOnComponentUpdaterCompleteEvent(kExtensionId)); |
| 429 | |
| 430 | run_loop.Run(); |
| 431 | |
| 432 | EXPECT_EQ(0, update_interceptor_->GetCount()) |
| 433 | << update_interceptor_->GetRequestsAsString(); |
John Abd-El-Malek | 1a9c3607 | 2018-08-14 03:09:53 | [diff] [blame] | 434 | EXPECT_EQ(0, get_interceptor_count()); |
Minh X. Nguyen | ad500fb | 2018-05-03 17:31:02 | [diff] [blame] | 435 | } |
| 436 | |
Sorin Jianu | 55587d3 | 2018-11-14 21:43:27 | [diff] [blame] | 437 | class PolicyUpdateServiceTest : public ExtensionUpdateClientBaseTest, |
| 438 | public testing::WithParamInterface<bool> { |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 439 | public: |
Joshua Pawlicki | 8ac3932 | 2019-04-04 21:22:46 | [diff] [blame] | 440 | PolicyUpdateServiceTest() : ExtensionUpdateClientBaseTest() {} |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 441 | ~PolicyUpdateServiceTest() override {} |
| 442 | |
| 443 | void SetUpCommandLine(base::CommandLine* command_line) override { |
| 444 | ExtensionUpdateClientBaseTest::SetUpCommandLine(command_line); |
| 445 | command_line->AppendSwitchASCII( |
| 446 | switches::kExtensionContentVerification, |
| 447 | switches::kExtensionContentVerificationEnforce); |
| 448 | } |
| 449 | |
| 450 | void SetUpInProcessBrowserTestFixture() override { |
| 451 | ExtensionUpdateClientBaseTest::SetUpInProcessBrowserTestFixture(); |
| 452 | |
| 453 | EXPECT_CALL(policy_provider_, IsInitializationComplete(testing::_)) |
| 454 | .WillRepeatedly(testing::Return(true)); |
| 455 | |
| 456 | policy::BrowserPolicyConnector::SetPolicyProviderForTesting( |
| 457 | &policy_provider_); |
Takashi Toyoshima | 52f2467 | 2019-03-05 05:36:36 | [diff] [blame] | 458 | // ExtensionManagementPolicyUpdater requires a single-threaded context to |
| 459 | // call RunLoop::RunUntilIdle internally, and it isn't ready at this setup |
| 460 | // moment. |
Gabriel Charette | 694c3c33 | 2019-08-19 14:53:05 | [diff] [blame] | 461 | base::test::TaskEnvironment env; |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 462 | ExtensionManagementPolicyUpdater management_policy(&policy_provider_); |
| 463 | management_policy.SetIndividualExtensionAutoInstalled( |
| 464 | id_, extension_urls::kChromeWebstoreUpdateURL, true /* forced */); |
| 465 | |
| 466 | // The policy will force the new install of an extension, which the |
| 467 | // component updater doesn't support yet. We still rely on the old updater |
| 468 | // to install a new extension. |
| 469 | const base::FilePath crx_path = |
| 470 | test_data_dir_.AppendASCII("updater/v1.crx"); |
| 471 | ExtensionDownloader::set_test_delegate(&downloader_); |
| 472 | downloader_.AddResponse(id_, "2", crx_path); |
| 473 | } |
| 474 | |
| 475 | void SetUpNetworkInterceptors() override { |
| 476 | ExtensionUpdateClientBaseTest::SetUpNetworkInterceptors(); |
| 477 | |
| 478 | const base::FilePath crx_path = |
| 479 | test_data_dir_.AppendASCII("updater/v1.crx"); |
John Abd-El-Malek | 1a9c3607 | 2018-08-14 03:09:53 | [diff] [blame] | 480 | set_interceptor_hook(base::BindLambdaForTesting( |
| 481 | [=](content::URLLoaderInterceptor::RequestParams* params) { |
| 482 | if (params->url_request.url.path() != "/download/v1.crx") |
| 483 | return false; |
| 484 | |
| 485 | content::URLLoaderInterceptor::WriteResponse(crx_path, |
| 486 | params->client.get()); |
| 487 | return true; |
| 488 | })); |
Sorin Jianu | 55587d3 | 2018-11-14 21:43:27 | [diff] [blame] | 489 | const base::FilePath update_response = |
| 490 | test_data_dir_.AppendASCII("updater/updatecheck_reply_update_1.json"); |
| 491 | const base::FilePath ping_response = |
| 492 | test_data_dir_.AppendASCII("updater/ping_reply_1.json"); |
| 493 | |
| 494 | ASSERT_TRUE(update_interceptor_->ExpectRequest( |
| 495 | std::make_unique<update_client::PartialMatch>(R"("updatecheck":{)"), |
| 496 | update_response)); |
| 497 | ASSERT_TRUE(update_interceptor_->ExpectRequest( |
| 498 | std::make_unique<update_client::PartialMatch>(R"("updatecheck":{)"), |
| 499 | update_response)); |
| 500 | ASSERT_TRUE(update_interceptor_->ExpectRequest( |
| 501 | std::make_unique<update_client::PartialMatch>(R"("updatecheck":{)"), |
| 502 | update_response)); |
| 503 | ASSERT_TRUE(update_interceptor_->ExpectRequest( |
| 504 | std::make_unique<update_client::PartialMatch>(R"("updatecheck":{)"), |
| 505 | update_response)); |
| 506 | ASSERT_TRUE(ping_interceptor_->ExpectRequest( |
| 507 | std::make_unique<update_client::PartialMatch>(R"("eventtype":)"), |
| 508 | ping_response)); |
| 509 | ASSERT_TRUE(ping_interceptor_->ExpectRequest( |
| 510 | std::make_unique<update_client::PartialMatch>(R"("eventtype":)"), |
| 511 | ping_response)); |
| 512 | ASSERT_TRUE(ping_interceptor_->ExpectRequest( |
| 513 | std::make_unique<update_client::PartialMatch>(R"("eventtype":)"), |
| 514 | ping_response)); |
| 515 | ASSERT_TRUE(ping_interceptor_->ExpectRequest( |
| 516 | std::make_unique<update_client::PartialMatch>(R"("eventtype":)"), |
| 517 | ping_response)); |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 518 | } |
| 519 | |
| 520 | std::vector<GURL> GetUpdateUrls() const override { |
Antonio Gomes | b616250 | 2018-06-28 20:21:55 | [diff] [blame] | 521 | return { |
| 522 | https_server_for_update_.GetURL("/policy-updatehost/service/update")}; |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 523 | } |
| 524 | |
| 525 | std::vector<GURL> GetPingUrls() const override { |
Antonio Gomes | b616250 | 2018-06-28 20:21:55 | [diff] [blame] | 526 | return {https_server_for_ping_.GetURL("/policy-pinghost/service/ping")}; |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 527 | } |
| 528 | |
| 529 | protected: |
| 530 | // The id of the extension we want to have force-installed. |
Joshua Pawlicki | a3314d3c | 2018-08-22 17:14:35 | [diff] [blame] | 531 | std::string id_ = "aohghmighlieiainnegkcijnfilokake"; |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 532 | |
| 533 | private: |
| 534 | policy::MockConfigurationPolicyProvider policy_provider_; |
| 535 | content_verifier_test::DownloaderTestDelegate downloader_; |
| 536 | }; |
| 537 | |
| 538 | // Tests that if CheckForExternalUpdates() fails, then we retry reinstalling |
| 539 | // corrupted policy extensions. For example: if network is unavailable, |
| 540 | // CheckForExternalUpdates() will fail. |
Joshua Pawlicki | 8ac3932 | 2019-04-04 21:22:46 | [diff] [blame] | 541 | IN_PROC_BROWSER_TEST_F(PolicyUpdateServiceTest, FailedUpdateRetries) { |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 542 | ExtensionRegistry* registry = ExtensionRegistry::Get(profile()); |
| 543 | ExtensionService* service = extension_service(); |
| 544 | ContentVerifier* verifier = |
| 545 | ExtensionSystem::Get(profile())->content_verifier(); |
| 546 | |
| 547 | // Wait for the extension to be installed by the policy we set up in |
| 548 | // SetUpInProcessBrowserTestFixture. |
| 549 | if (!registry->GetInstalledExtension(id_)) { |
| 550 | TestExtensionRegistryObserver registry_observer(registry, id_); |
| 551 | EXPECT_TRUE(registry_observer.WaitForExtensionInstalled()); |
| 552 | } |
| 553 | |
| 554 | content_verifier_test::DelayTracker delay_tracker; |
| 555 | service->set_external_updates_disabled_for_test(true); |
| 556 | TestExtensionRegistryObserver registry_observer(registry, id_); |
Oleg Davydov | 9b465ba | 2019-07-02 12:28:08 | [diff] [blame] | 557 | verifier->VerifyFailedForTest(id_, ContentVerifyJob::HASH_MISMATCH); |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 558 | EXPECT_TRUE(registry_observer.WaitForExtensionUnloaded()); |
| 559 | |
| 560 | const std::vector<base::TimeDelta>& calls = delay_tracker.calls(); |
| 561 | ASSERT_EQ(1u, calls.size()); |
| 562 | EXPECT_EQ(base::TimeDelta(), delay_tracker.calls()[0]); |
| 563 | |
| 564 | delay_tracker.Proceed(); |
| 565 | |
| 566 | // Remove the override and set ExtensionService to update again. The extension |
| 567 | // should be now installed. |
| 568 | service->set_external_updates_disabled_for_test(false); |
| 569 | delay_tracker.StopWatching(); |
| 570 | delay_tracker.Proceed(); |
| 571 | |
| 572 | EXPECT_EQ(UpdateClientEvents::COMPONENT_UPDATED, |
| 573 | WaitOnComponentUpdaterCompleteEvent(id_)); |
| 574 | |
| 575 | ASSERT_EQ(1, update_interceptor_->GetCount()) |
| 576 | << update_interceptor_->GetRequestsAsString(); |
John Abd-El-Malek | 1a9c3607 | 2018-08-14 03:09:53 | [diff] [blame] | 577 | EXPECT_EQ(1, get_interceptor_count()); |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 578 | |
| 579 | // Make sure that the update check request is formed correctly when the |
| 580 | // extension is corrupted: |
| 581 | // - version="0.0.0.0" |
| 582 | // - installsource="reinstall" |
Minh X. Nguyen | fc16497e | 2018-04-24 16:05:35 | [diff] [blame] | 583 | // - installedby="policy" |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 584 | // - enabled="0" |
| 585 | // - <disabled reason="1024"/> |
| 586 | const std::string update_request = |
Antonio Gomes | b616250 | 2018-06-28 20:21:55 | [diff] [blame] | 587 | std::get<0>(update_interceptor_->GetRequests()[0]); |
Lei Zhang | e8d7e982 | 2019-02-20 05:40:44 | [diff] [blame] | 588 | const auto root = base::JSONReader::Read(update_request); |
| 589 | ASSERT_TRUE(root); |
Sorin Jianu | 55587d3 | 2018-11-14 21:43:27 | [diff] [blame] | 590 | const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0]; |
| 591 | EXPECT_EQ(id_, app.FindKey("appid")->GetString()); |
| 592 | EXPECT_EQ("0.0.0.0", app.FindKey("version")->GetString()); |
| 593 | EXPECT_EQ("reinstall", app.FindKey("installsource")->GetString()); |
| 594 | EXPECT_EQ("policy", app.FindKey("installedby")->GetString()); |
| 595 | EXPECT_FALSE(app.FindKey("enabled")->GetBool()); |
| 596 | const auto& disabled = app.FindKey("disabled")->GetList()[0]; |
| 597 | EXPECT_EQ(disable_reason::DISABLE_CORRUPTED, |
| 598 | disabled.FindKey("reason")->GetInt()); |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 599 | } |
| 600 | |
Joshua Pawlicki | 8ac3932 | 2019-04-04 21:22:46 | [diff] [blame] | 601 | IN_PROC_BROWSER_TEST_F(PolicyUpdateServiceTest, Backoff) { |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 602 | ExtensionRegistry* registry = ExtensionRegistry::Get(profile()); |
| 603 | ContentVerifier* verifier = |
| 604 | ExtensionSystem::Get(profile())->content_verifier(); |
| 605 | |
| 606 | // Wait for the extension to be installed by the policy we set up in |
| 607 | // SetUpInProcessBrowserTestFixture. |
| 608 | if (!registry->GetInstalledExtension(id_)) { |
| 609 | TestExtensionRegistryObserver registry_observer(registry, id_); |
| 610 | EXPECT_TRUE(registry_observer.WaitForExtensionInstalled()); |
| 611 | } |
| 612 | |
| 613 | // Setup to intercept reinstall action, so we can see what the delay would |
| 614 | // have been for the real action. |
| 615 | content_verifier_test::DelayTracker delay_tracker; |
| 616 | |
| 617 | // Do 4 iterations of disabling followed by reinstall. |
| 618 | const size_t iterations = 4; |
| 619 | for (size_t i = 0; i < iterations; i++) { |
| 620 | TestExtensionRegistryObserver registry_observer(registry, id_); |
Oleg Davydov | 9b465ba | 2019-07-02 12:28:08 | [diff] [blame] | 621 | verifier->VerifyFailedForTest(id_, ContentVerifyJob::HASH_MISMATCH); |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 622 | EXPECT_TRUE(registry_observer.WaitForExtensionUnloaded()); |
| 623 | // Resolve the request to |delay_tracker|, so the reinstallation can |
| 624 | // proceed. |
| 625 | delay_tracker.Proceed(); |
| 626 | EXPECT_EQ(UpdateClientEvents::COMPONENT_UPDATED, |
| 627 | WaitOnComponentUpdaterCompleteEvent(id_)); |
| 628 | } |
| 629 | |
| 630 | ASSERT_EQ(4, update_interceptor_->GetCount()) |
| 631 | << update_interceptor_->GetRequestsAsString(); |
John Abd-El-Malek | 1a9c3607 | 2018-08-14 03:09:53 | [diff] [blame] | 632 | EXPECT_EQ(4, get_interceptor_count()); |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 633 | |
| 634 | const std::vector<base::TimeDelta>& calls = delay_tracker.calls(); |
| 635 | |
| 636 | // After |delay_tracker| resolves the 4 (|iterations|) reinstallation |
| 637 | // requests, it will get an additional request (right away) for retrying |
| 638 | // reinstallation. |
| 639 | // Note: the additional request in non-test environment will arrive with |
| 640 | // a (backoff) delay. But during test, |delay_tracker| issues the request |
| 641 | // immediately. |
| 642 | ASSERT_EQ(iterations, calls.size() - 1); |
| 643 | // Assert that the first reinstall action happened with a delay of 0, and |
| 644 | // then kept growing each additional time. |
| 645 | EXPECT_EQ(base::TimeDelta(), delay_tracker.calls()[0]); |
| 646 | for (size_t i = 1; i < delay_tracker.calls().size(); i++) { |
| 647 | EXPECT_LT(calls[i - 1], calls[i]); |
| 648 | } |
| 649 | } |
| 650 | |
| 651 | // We want to test what happens at startup with a corroption-disabled policy |
| 652 | // force installed extension. So we set that up in the PRE test here. |
Joshua Pawlicki | 8ac3932 | 2019-04-04 21:22:46 | [diff] [blame] | 653 | IN_PROC_BROWSER_TEST_F(PolicyUpdateServiceTest, PRE_PolicyCorruptedOnStartup) { |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 654 | // This is to not allow any corrupted resintall to proceed. |
| 655 | content_verifier_test::DelayTracker delay_tracker; |
| 656 | ExtensionRegistry* registry = ExtensionRegistry::Get(profile()); |
| 657 | TestExtensionRegistryObserver registry_observer(registry, id_); |
| 658 | |
| 659 | // Wait for the extension to be installed by policy we set up in |
| 660 | // SetUpInProcessBrowserTestFixture. |
| 661 | if (!registry->GetInstalledExtension(id_)) |
| 662 | EXPECT_TRUE(registry_observer.WaitForExtensionInstalled()); |
| 663 | |
| 664 | // Simulate corruption of the extension so that we can test what happens |
| 665 | // at startup in the non-PRE test. |
| 666 | ContentVerifier* verifier = |
| 667 | ExtensionSystem::Get(profile())->content_verifier(); |
Oleg Davydov | 9b465ba | 2019-07-02 12:28:08 | [diff] [blame] | 668 | verifier->VerifyFailedForTest(id_, ContentVerifyJob::HASH_MISMATCH); |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 669 | EXPECT_TRUE(registry_observer.WaitForExtensionUnloaded()); |
| 670 | |
| 671 | ExtensionPrefs* prefs = ExtensionPrefs::Get(profile()); |
| 672 | int reasons = prefs->GetDisableReasons(id_); |
| 673 | EXPECT_TRUE(reasons & disable_reason::DISABLE_CORRUPTED); |
| 674 | EXPECT_EQ(1u, delay_tracker.calls().size()); |
| 675 | |
| 676 | EXPECT_EQ(0, update_interceptor_->GetCount()) |
| 677 | << update_interceptor_->GetRequestsAsString(); |
John Abd-El-Malek | 1a9c3607 | 2018-08-14 03:09:53 | [diff] [blame] | 678 | EXPECT_EQ(0, get_interceptor_count()); |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 679 | } |
| 680 | |
| 681 | // Now actually test what happens on the next startup after the PRE test above. |
Joshua Pawlicki | 8ac3932 | 2019-04-04 21:22:46 | [diff] [blame] | 682 | IN_PROC_BROWSER_TEST_F(PolicyUpdateServiceTest, PolicyCorruptedOnStartup) { |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 683 | // Depdending on timing, the extension may have already been reinstalled |
| 684 | // between SetUpInProcessBrowserTestFixture and now (usually not during local |
| 685 | // testing on a developer machine, but sometimes on a heavily loaded system |
| 686 | // such as the build waterfall / trybots). If the reinstall didn't already |
| 687 | // happen, wait for it. |
| 688 | |
| 689 | ExtensionPrefs* prefs = ExtensionPrefs::Get(profile()); |
| 690 | ExtensionRegistry* registry = ExtensionRegistry::Get(profile()); |
| 691 | int disable_reasons = prefs->GetDisableReasons(id_); |
| 692 | if (disable_reasons & disable_reason::DISABLE_CORRUPTED) { |
| 693 | EXPECT_EQ(UpdateClientEvents::COMPONENT_UPDATED, |
| 694 | WaitOnComponentUpdaterCompleteEvent(id_)); |
| 695 | disable_reasons = prefs->GetDisableReasons(id_); |
| 696 | } |
| 697 | |
| 698 | EXPECT_FALSE(disable_reasons & disable_reason::DISABLE_CORRUPTED); |
| 699 | EXPECT_TRUE(registry->enabled_extensions().Contains(id_)); |
| 700 | |
| 701 | ASSERT_EQ(1, update_interceptor_->GetCount()) |
| 702 | << update_interceptor_->GetRequestsAsString(); |
John Abd-El-Malek | 1a9c3607 | 2018-08-14 03:09:53 | [diff] [blame] | 703 | EXPECT_EQ(1, get_interceptor_count()); |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 704 | |
| 705 | const std::string update_request = |
Antonio Gomes | b616250 | 2018-06-28 20:21:55 | [diff] [blame] | 706 | std::get<0>(update_interceptor_->GetRequests()[0]); |
Lei Zhang | e8d7e982 | 2019-02-20 05:40:44 | [diff] [blame] | 707 | const auto root = base::JSONReader::Read(update_request); |
| 708 | ASSERT_TRUE(root); |
Sorin Jianu | 55587d3 | 2018-11-14 21:43:27 | [diff] [blame] | 709 | const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0]; |
| 710 | EXPECT_EQ(id_, app.FindKey("appid")->GetString()); |
| 711 | EXPECT_EQ("0.0.0.0", app.FindKey("version")->GetString()); |
| 712 | EXPECT_EQ("reinstall", app.FindKey("installsource")->GetString()); |
| 713 | EXPECT_EQ("policy", app.FindKey("installedby")->GetString()); |
| 714 | EXPECT_FALSE(app.FindKey("enabled")->GetBool()); |
| 715 | const auto& disabled = app.FindKey("disabled")->GetList()[0]; |
| 716 | EXPECT_EQ(disable_reason::DISABLE_CORRUPTED, |
| 717 | disabled.FindKey("reason")->GetInt()); |
Minh X. Nguyen | 5c8322610 | 2018-04-19 16:10:25 | [diff] [blame] | 718 | } |
| 719 | |
| 720 | } // namespace extensions |