GSaha567/seq_level_training_data
052
1text,length,is_long_context,metric_val,label_metric2"// Copyright 2015 The Chromium Authors. All rights reserved.3// Use of this source code is governed by a BSD-style license that can be4// found in the LICENSE file.5 6#include ""chrome/browser/extensions/api/developer_private/developer_private_api.h""7 8#include <memory>9#include <utility>10 11#include ""base/bind.h""12#include ""base/files/file_util.h""13#include ""base/macros.h""14#include ""base/scoped_observer.h""15#include ""base/stl_util.h""16#include ""base/strings/stringprintf.h""17#include ""chrome/browser/extensions/chrome_test_extension_loader.h""18#include ""chrome/browser/extensions/error_console/error_console.h""19#include ""chrome/browser/extensions/extension_function_test_utils.h""20#include ""chrome/browser/extensions/extension_management.h""21#include ""chrome/browser/extensions/extension_management_test_util.h""22#include ""chrome/browser/extensions/extension_service.h""23#include ""chrome/browser/extensions/extension_service_test_with_install.h""24#include ""chrome/browser/extensions/extension_util.h""25#include ""chrome/browser/extensions/permissions_test_util.h""26#include ""chrome/browser/extensions/permissions_updater.h""27#include ""chrome/browser/extensions/scripting_permissions_modifier.h""28#include ""chrome/browser/ui/browser.h""29#include ""chrome/common/extensions/api/developer_private.h""30#include ""chrome/common/pref_names.h""31#include ""chrome/test/base/test_browser_window.h""32#include ""chrome/test/base/testing_profile.h""33#include ""components/crx_file/id_util.h""34#include ""components/policy/core/common/mock_configuration_policy_provider.h""35#include ""components/sync_preferences/testing_pref_service_syncable.h""36#include ""content/public/browser/notification_service.h""37#include ""content/public/test/web_contents_tester.h""38#include ""extensions/browser/api_test_utils.h""39#include ""extensions/browser/event_router.h""40#include ""extensions/browser/event_router_factory.h""41#include ""extensions/browser/extension_dialog_auto_confirm.h""42#include ""extensions/browser/extension_error_test_util.h""43#include ""extensions/browser/extension_prefs.h""44#include ""extensions/browser/extension_registry.h""45#include ""extensions/browser/extension_registry_observer.h""46#include ""extensions/browser/extension_util.h""47#include ""extensions/browser/install/extension_install_ui.h""48#include ""extensions/browser/mock_external_provider.h""49#include ""extensions/browser/notification_types.h""50#include ""extensions/browser/test_event_router_observer.h""51#include ""extensions/browser/test_extension_registry_observer.h""52#include ""extensions/common/extension.h""53#include ""extensions/common/extension_builder.h""54#include ""extensions/common/extension_id.h""55#include ""extensions/common/extension_set.h""56#include ""extensions/common/manifest_constants.h""57#include ""extensions/common/permissions/permission_set.h""58#include ""extensions/common/permissions/permissions_data.h""59#include ""extensions/common/value_builder.h""60#include ""extensions/test/test_extension_dir.h""61#include ""services/data_decoder/data_decoder_service.h""62#include ""services/service_manager/public/cpp/test/test_connector_factory.h""63 64namespace extensions {65 66namespace {67 68const char kGoodCrx[] = ""ldnnhddmnhbkjipkidpdiheffobcpfmf"";69constexpr char kInvalidHost[] = ""invalid host"";70constexpr char kInvalidHostError[] = ""Invalid host."";71 72std::unique_ptr<KeyedService> BuildAPI(content::BrowserContext* context) {73 return std::make_unique<DeveloperPrivateAPI>(context);74}75 76std::unique_ptr<KeyedService> BuildEventRouter(77 content::BrowserContext* profile) {78 return std::make_unique<EventRouter>(profile, ExtensionPrefs::Get(profile));79}80 81bool HasPrefsPermission(bool (*has_pref)(const std::string&,82 content::BrowserContext*),83 content::BrowserContext* context,84 const std::string& id) {85 return has_pref(id, context);86}87 88bool WasPermissionsUpdatedEventDispatched(89 const TestEventRouterObserver& observer,90 const ExtensionId& extension_id) {91 const std::string kEventName =92 api::developer_private::OnItemStateChanged::kEventName;93 const auto& event_map = observer.events();94 auto iter = event_map.find(kEventName);95 if (iter == event_map.end())96 return false;97 98 const Event& event = *iter->second;99 CHECK(event.event_args);100 CHECK_GE(1u, event.event_args->GetList().size());101 std::unique_ptr<api::developer_private::EventData> event_data =102 api::developer_private::EventData::FromValue(103 event.event_args->GetList()[0]);104 if (!event_data)105 return false;106 107 if (event_data->item_id != extension_id ||108 event_data->event_type !=109 api::developer_private::EVENT_TYPE_PERMISSIONS_CHANGED) {110 return false;111 }112 113 return true;114}115 116} // namespace117 118class DeveloperPrivateApiUnitTest : public ExtensionServiceTestWithInstall {119 protected:120 DeveloperPrivateApiUnitTest() {}121 ~DeveloperPrivateApiUnitTest() override {}122 123 void AddMockExternalProvider(124 std::unique_ptr<ExternalProviderInterface> provider) {125 service()->AddProviderForTesting(std::move(provider));126 }127 128 // A wrapper around extension_function_test_utils::RunFunction that runs with129 // the associated browser, no flags, and can take stack-allocated arguments.130 bool RunFunction(const scoped_refptr<ExtensionFunction>& function,131 const base::ListValue& args);132 133 // Loads an unpacked extension that is backed by a real directory, allowing134 // it to be reloaded.135 const Extension* LoadUnpackedExtension();136 137 // Loads an extension with no real directory; this is faster, but means the138 // extension can't be reloaded.139 const Extension* LoadSimpleExtension();140 141 // Tests modifying the extension's configuration.142 void TestExtensionPrefSetting(const base::RepeatingCallback<bool()>& has_pref,143 const std::string& key,144 const std::string& extension_id);145 146 testing::AssertionResult TestPackExtensionFunction(147 const base::ListValue& args,148 api::developer_private::PackStatus expected_status,149 int expected_flags);150 151 // Execute the updateProfileConfiguration API call with a specified152 // dev_mode. This is done from the webui when the user checks the153 // ""Developer Mode"" checkbox.154 void UpdateProfileConfigurationDevMode(bool dev_mode);155 156 // Execute the getProfileConfiguration API and parse its result into a157 // ProfileInfo structure for further verification in the calling test.158 // Will reset the profile_info unique_ptr.159 // Uses ASSERT_* inside - callers should use ASSERT_NO_FATAL_FAILURE.160 void GetProfileConfiguration(161 std::unique_ptr<api::developer_private::ProfileInfo>* profile_info);162 163 // Runs the API function to update host access for the given |extension| to164 // |new_access|.165 void RunUpdateHostAccess(const Extension& extension,166 base::StringPiece new_access);167 168 virtual bool ProfileIsSupervised() const { return false; }169 170 Browser* browser() { return browser_.get(); }171 172 private:173 // ExtensionServiceTestBase:174 void SetUp() override;175 void TearDown() override;176 177 // The browser (and accompanying window).178 std::unique_ptr<TestBrowserWindow> browser_window_;179 std::unique_ptr<Browser> browser_;180 181 std::vector<std::unique_ptr<TestExtensionDir>> test_extension_dirs_;182 policy::MockConfigurationPolicyProvider mock_policy_provider_;183 184 DISALLOW_COPY_AND_ASSIGN(DeveloperPrivateApiUnitTest);185};186 187bool DeveloperPrivateApiUnitTest::RunFunction(188 const scoped_refptr<ExtensionFunction>& function,189 const base::ListValue& args) {190 return extension_function_test_utils::RunFunction(191 function.get(), args.CreateDeepCopy(), browser(), api_test_utils::NONE);192}193 194const Extension* DeveloperPrivateApiUnitTest::LoadUnpackedExtension() {195 constexpr char kManifest[] =196 R""({197 ""name"": ""foo"",198 ""version"": ""1.0"",199 ""manifest_version"": 2,200 ""permissions"": [""*://*/*""]201 })"";202 203 test_extension_dirs_.push_back(std::make_unique<TestExtensionDir>());204 TestExtensionDir* dir = test_extension_dirs_.back().get();205 dir->WriteManifest(kManifest);206 207 ChromeTestExtensionLoader loader(profile());208 // The fact that unpacked extensions get file access by default is an209 // irrelevant detail to these tests. Disable it.210 loader.set_allow_file_access(false);211 212 return loader.LoadExtension(dir->UnpackedPath()).get();213}214 215const Extension* DeveloperPrivateApiUnitTest::LoadSimpleExtension() {216 const char kName[] = ""extension name"";217 const char kVersion[] = ""1.0.0.1"";218 std::string id = crx_file::id_util::GenerateId(kName);219 DictionaryBuilder manifest;220 manifest.Set(""name"", kName)221 .Set(""version"", kVersion)222 .Set(""manifest_version"", 2)223 .Set(""description"", ""an extension"");224 scoped_refptr<const Extension> extension =225 ExtensionBuilder()226 .SetManifest(manifest.Build())227 .SetLocation(Manifest::INTERNAL)228 .SetID(id)229 .Build();230 service()->AddExtension(extension.get());231 return extension.get();232}233 234void DeveloperPrivateApiUnitTest::TestExtensionPrefSetting(235 const base::RepeatingCallback<bool()>& has_pref,236 const std::string& key,237 const std::string& extension_id) {238 scoped_refptr<ExtensionFunction> function(239 new api::DeveloperPrivateUpdateExtensionConfigurationFunction());240 241 EXPECT_FALSE(has_pref.Run()) << key;242 243 {244 auto parameters = std::make_unique<base::DictionaryValue>();245 parameters->SetString(""extensionId"", extension_id);246 parameters->SetBoolean(key, true);247 248 base::ListValue args;249 args.Append(std::move(parameters));250 EXPECT_FALSE(RunFunction(function, args)) << key;251 EXPECT_EQ(""This action requires a user gesture."", function->GetError());252 253 function = new api::DeveloperPrivateUpdateExtensionConfigurationFunction();254 function->set_source_context_type(Feature::WEBUI_CONTEXT);255 EXPECT_TRUE(RunFunction(function, args)) << key;256 EXPECT_TRUE(has_pref.Run()) << key;257 258 ExtensionFunction::ScopedUserGestureForTests scoped_user_gesture;259 function = new api::DeveloperPrivateUpdateExtensionConfigurationFunction();260 EXPECT_TRUE(RunFunction(function, args)) << key;261 EXPECT_TRUE(has_pref.Run()) << key;262 }263 264 {265 auto parameters = std::make_unique<base::DictionaryValue>();266 parameters->SetString(""extensionId"", extension_id);267 parameters->SetBoolean(key, false);268 269 base::ListValue args;270 args.Append(std::move(parameters));271 272 ExtensionFunction::ScopedUserGestureForTests scoped_user_gesture;273 function = new api::DeveloperPrivateUpdateExtensionConfigurationFunction();274 EXPECT_TRUE(RunFunction(function, args)) << key;275 EXPECT_FALSE(has_pref.Run()) << key;276 }277}278 279testing::AssertionResult DeveloperPrivateApiUnitTest::TestPackExtensionFunction(280 const base::ListValue& args,281 api::developer_private::PackStatus expected_status,282 int expected_flags) {283 scoped_refptr<ExtensionFunction> function(284 new api::DeveloperPrivatePackDirectoryFunction());285 if (!RunFunction(function, args))286 return testing::AssertionFailure() << ""Could not run function."";287 288 // Extract the result. We don't have to test this here, since it's verified as289 // part of the general extension api system.290 const base::Value* response_value = nullptr;291 CHECK(function->GetResultList()->Get(0u, &response_value));292 std::unique_ptr<api::developer_private::PackDirectoryResponse> response =293 api::developer_private::PackDirectoryResponse::FromValue(*response_value);294 CHECK(response);295 296 if (response->status != expected_status) {297 return testing::AssertionFailure() << ""Expected status: "" <<298 expected_status << "", found status: "" << response->status <<299 "", message: "" << response->message;300 }301 302 if (response->override_flags != expected_flags) {303 return testing::AssertionFailure() << ""Expected flags: "" <<304 expected_flags << "", found flags: "" << response->override_flags;305 }306 307 return testing::AssertionSuccess();308}309 310void DeveloperPrivateApiUnitTest::UpdateProfileConfigurationDevMode(311 bool dev_mode) {312 scoped_refptr<ExtensionFunction> function(313 new api::DeveloperPrivateUpdateProfileConfigurationFunction());314 std::unique_ptr<base::ListValue> args =315 ListBuilder()316 .Append(DictionaryBuilder().Set(""inDeveloperMode"", dev_mode).Build())317 .Build();318 EXPECT_TRUE(RunFunction(function, *args)) << function->GetError();319}320 321void DeveloperPrivateApiUnitTest::GetProfileConfiguration(322 std::unique_ptr<api::developer_private::ProfileInfo>* profile_info) {323 scoped_refptr<ExtensionFunction> function(324 new api::DeveloperPrivateGetProfileConfigurationFunction());325 base::ListValue args;326 EXPECT_TRUE(RunFunction(function, args)) << function->GetError();327 328 ASSERT_TRUE(function->GetResultList());329 ASSERT_EQ(1u, function->GetResultList()->GetSize());330 const base::Value* response_value = nullptr;331 function->GetResultList()->Get(0u, &response_value);332 *profile_info =333 api::developer_private::ProfileInfo::FromValue(*response_value);334}335 336void DeveloperPrivateApiUnitTest::RunUpdateHostAccess(337 const Extension& extension,338 base::StringPiece new_access) {339 SCOPED_TRACE(new_access);340 ExtensionFunction::ScopedUserGestureForTests scoped_user_gesture;341 scoped_refptr<ExtensionFunction> function = base::MakeRefCounted<342 api::DeveloperPrivateUpdateExtensionConfigurationFunction>();343 std::string args =344 base::StringPrintf(R""([{""extensionId"": ""%s"", ""hostAccess"": ""%s""}])"",345 extension.id().c_str(), new_access.data());346 EXPECT_TRUE(api_test_utils::RunFunction(function.get(), args, profile()))347 << function->GetError();348}349 350void DeveloperPrivateApiUnitTest::SetUp() {351 ExtensionServiceTestBase::SetUp();352 353 // By not specifying a pref_file filepath, we get a354 // sync_preferences::TestingPrefServiceSyncable355 // - see BuildTestingProfile in extension_service_test_base.cc.356 ExtensionServiceInitParams init_params = CreateDefaultInitParams();357 init_params.pref_file.clear();358 init_params.profile_is_supervised = ProfileIsSupervised();359 InitializeExtensionService(init_params);360 361 browser_window_.reset(new TestBrowserWindow());362 Browser::CreateParams params(profile(), true);363 params.type = Browser::TYPE_NORMAL;364 params.window = browser_window_.get();365 browser_.reset(Browser::Create(params));366 367 // Allow the API to be created.368 EventRouterFactory::GetInstance()->SetTestingFactory(369 profile(), base::BindRepeating(&BuildEventRouter));370 371 DeveloperPrivateAPI::GetFactoryInstance()->SetTestingFactory(372 profile(), base::BindRepeating(&BuildAPI));373 374 // Loading unpacked extensions through the developerPrivate API requires375 // developer mode to be enabled.376 profile()->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, true);377}378 379void DeveloperPrivateApiUnitTest::TearDown() {380 test_extension_dirs_.clear();381 browser_.reset();382 browser_window_.reset();383 ExtensionServiceTestBase::TearDown();384}385 386// Test developerPrivate.updateExtensionConfiguration.387TEST_F(DeveloperPrivateApiUnitTest,388 DeveloperPrivateUpdateExtensionConfiguration) {389 // Sadly, we need a ""real"" directory here, because toggling prefs causes390 // a reload (which needs a path).391 const Extension* extension = LoadUnpackedExtension();392 const std::string& id = extension->id();393 394 ScriptingPermissionsModifier(profile(), base::WrapRefCounted(extension))395 .SetWithholdHostPermissions(true);396 397 TestExtensionPrefSetting(398 base::BindRepeating(&HasPrefsPermission, &util::IsIncognitoEnabled,399 profile(), id),400 ""incognitoAccess"", id);401 TestExtensionPrefSetting(402 base::BindRepeating(&HasPrefsPermission, &util::AllowFileAccess,403 profile(), id),404 ""fileAccess"", id);405}406 407// Test developerPrivate.reload.408TEST_F(DeveloperPrivateApiUnitTest, DeveloperPrivateReload) {409 const Extension* extension = LoadUnpackedExtension();410 std::string extension_id = extension->id();411 scoped_refptr<ExtensionFunction> function(412 new api::DeveloperPrivateReloadFunction());413 base::ListValue reload_args;414 reload_args.AppendString(extension_id);415 416 TestExtensionRegistryObserver registry_observer(registry());417 EXPECT_TRUE(RunFunction(function, reload_args));418 scoped_refptr<const Extension> unloaded_extension =419 registry_observer.WaitForExtensionUnloaded();420 EXPECT_EQ(extension, unloaded_extension);421 scoped_refptr<const Extension> reloaded_extension =422 registry_observer.WaitForExtensionLoaded();423 EXPECT_EQ(extension_id, reloaded_extension->id());424}425 426// Test developerPrivate.packDirectory.427TEST_F(DeveloperPrivateApiUnitTest, DeveloperPrivatePackFunction) {428 // Use a temp dir isolating the extension dir and its generated files.429 base::ScopedTempDir temp_dir;430 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());431 base::FilePath root_path = data_dir().AppendASCII(""simple_with_popup"");432 ASSERT_TRUE(base::CopyDirectory(root_path, temp_dir.GetPath(), true));433 434 base::FilePath temp_root_path =435 temp_dir.GetPath().Append(root_path.BaseName());436 base::FilePath crx_path =437 temp_dir.GetPath().AppendASCII(""simple_with_popup.crx"");438 base::FilePath pem_path =439 temp_dir.GetPath().AppendASCII(""simple_with_popup.pem"");440 441 EXPECT_FALSE(base::PathExists(crx_path))442 << ""crx should not exist before the test is run!"";443 EXPECT_FALSE(base::PathExists(pem_path))444 << ""pem should not exist before the test is run!"";445 446 // First, test a directory that should pack properly.447 base::ListValue pack_args;448 pack_args.AppendString(temp_root_path.AsUTF8Unsafe());449 EXPECT_TRUE(TestPackExtensionFunction(450 pack_args, api::developer_private::PACK_STATUS_SUCCESS, 0));451 452 // Should have created crx file and pem file.453 EXPECT_TRUE(base::PathExists(crx_path));454 EXPECT_TRUE(base::PathExists(pem_path));455 456 // Deliberately don't cleanup the files, and append the pem path.457 pack_args.AppendString(pem_path.AsUTF8Unsafe());458 459 // Try to pack again - we should get a warning abot overwriting the crx.460 EXPECT_TRUE(TestPackExtensionFunction(461 pack_args,462 api::developer_private::PACK_STATUS_WARNING,463 ExtensionCreator::kOverwriteCRX));464 465 // Try to pack again, with the overwrite flag; this should succeed.466 pack_args.AppendInteger(ExtensionCreator::kOverwriteCRX);467 EXPECT_TRUE(TestPackExtensionFunction(468 pack_args, api::developer_private::PACK_STATUS_SUCCESS, 0));469 470 // Try to pack a final time when omitting (an existing) pem file. We should471 // get an error.472 base::DeleteFile(crx_path);473 EXPECT_TRUE(pack_args.Remove(1u, nullptr)); // Remove the pem key argument.474 EXPECT_TRUE(pack_args.Remove(1u, nullptr)); // Remove the flags argument.475 EXPECT_TRUE(TestPackExtensionFunction(476 pack_args, api::developer_private::PACK_STATUS_ERROR, 0));477}478 479// Test developerPrivate.choosePath.480TEST_F(DeveloperPrivateApiUnitTest, DeveloperPrivateChoosePath) {481 std::unique_ptr<content::WebContents> web_contents(482 content::WebContentsTester::CreateTestWebContents(profile(), nullptr));483 484 base::FilePath expected_dir_path =485 data_dir().AppendASCII(""simple_with_popup"");486 api::EntryPicker::SkipPickerAndAlwaysSelectPathForTest(&expected_dir_path);487 488 // Try selecting a directory.489 base::ListValue choose_args;490 choose_args.AppendString(""FOLDER"");491 choose_args.AppendString(""LOAD"");492 scoped_refptr<ExtensionFunction> function(493 new api::DeveloperPrivateChoosePathFunction());494 function->SetRenderFrameHost(web_contents->GetMainFrame());495 EXPECT_TRUE(RunFunction(function, choose_args)) << function->GetError();496 std::string path;497 EXPECT_TRUE(function->GetResultList() &&498 function->GetResultList()->GetString(0, &path));499 EXPECT_EQ(path, expected_dir_path.AsUTF8Unsafe());500 501 // Try selecting a pem file.502 base::FilePath expected_file_path =503 data_dir().AppendASCII(""simple_with_popup.pem"");504 api::EntryPicker::SkipPickerAndAlwaysSelectPathForTest(&expected_file_path);505 choose_args.Clear();506 choose_args.AppendString(""FILE"");507 choose_args.AppendString(""PEM"");508 function = new api::DeveloperPrivateChoosePathFunction();509 function->SetRenderFrameHost(web_contents->GetMainFrame());510 EXPECT_TRUE(RunFunction(function, choose_args)) << function->GetError();511 EXPECT_TRUE(function->GetResultList() &&512 function->GetResultList()->GetString(0, &path));513 EXPECT_EQ(path, expected_file_path.AsUTF8Unsafe());514 515 // Try canceling the file dialog.516 api::EntryPicker::SkipPickerAndAlwaysCancelForTest();517 function = new api::DeveloperPrivateChoosePathFunction();518 function->SetRenderFrameHost(web_contents->GetMainFrame());519 EXPECT_FALSE(RunFunction(function, choose_args));520 EXPECT_EQ(std::string(""File selection was canceled.""), function->GetError());521}522 523// Test developerPrivate.loadUnpacked.524TEST_F(DeveloperPrivateApiUnitTest, DeveloperPrivateLoadUnpacked) {525 std::unique_ptr<content::WebContents> web_contents(526 content::WebContentsTester::CreateTestWebContents(profile(), nullptr));527 528 base::FilePath path = data_dir().AppendASCII(""simple_with_popup"");529 api::EntryPicker::SkipPickerAndAlwaysSelectPathForTest(&path);530 531 // Try loading a good extension (it should succeed, and the extension should532 // be added).533 scoped_refptr<ExtensionFunction> function(534 new api::DeveloperPrivateLoadUnpackedFunction());535 function->SetRenderFrameHost(web_contents->GetMainFrame());536 ExtensionIdSet current_ids = registry()->enabled_extensions().GetIDs();537 EXPECT_TRUE(RunFunction(function, base::ListValue())) << function->GetError();538 // We should have added one new extension.539 ExtensionIdSet id_difference = base::STLSetDifference<ExtensionIdSet>(540 registry()->enabled_extensions().GetIDs(), current_ids);541 ASSERT_EQ(1u, id_difference.size());542 // The new extension should have the same path.543 EXPECT_EQ(544 path,545 registry()->enabled_extensions().GetByID(*id_difference.begin())->path());546 547 path = data_dir().AppendASCII(""empty_manifest"");548 api::EntryPicker::SkipPickerAndAlwaysSelectPathForTest(&path);549 550 // Try loading a bad extension (it should fail, and we should get an error).551 function = new api::DeveloperPrivateLoadUnpackedFunction();552 function->SetRenderFrameHost(web_contents->GetMainFrame());553 base::ListValue unpacked_args;554 std::unique_ptr<base::DictionaryValue> options(new base::DictionaryValue());555 options->SetBoolean(""failQuietly"", true);556 unpacked_args.Append(std::move(options));557 current_ids = registry()->enabled_extensions().GetIDs();558 EXPECT_FALSE(RunFunction(function, unpacked_args));559 EXPECT_EQ(manifest_errors::kManifestUnreadable, function->GetError());560 // We should have no new extensions installed.561 EXPECT_EQ(0u, base::STLSetDifference<ExtensionIdSet>(562 registry()->enabled_extensions().GetIDs(),563 current_ids).size());564}565 566TEST_F(DeveloperPrivateApiUnitTest, DeveloperPrivateLoadUnpackedLoadError) {567 std::unique_ptr<content::WebContents> web_contents(568 content::WebContentsTester::CreateTestWebContents(profile(), nullptr));569 570 {571 // Load an extension with a clear manifest error ('version' is invalid).572 TestExtensionDir dir;573 dir.WriteManifest(574 R""({575 ""name"": ""foo"",576 ""description"": ""bar"",577 ""version"": 1,578 ""manifest_version"": 2579 })"");580 base::FilePath path = dir.UnpackedPath();581 api::EntryPicker::SkipPickerAndAlwaysSelectPathForTest(&path);582 583 scoped_refptr<ExtensionFunction> function(584 new api::DeveloperPrivateLoadUnpackedFunction());585 function->SetRenderFrameHost(web_contents->GetMainFrame());586 std::unique_ptr<base::Value> result =587 api_test_utils::RunFunctionAndReturnSingleResult(588 function.get(),589 ""[{\\""failQuietly\\"": true, \\""populateError\\"": true}]"", profile());590 // The loadError result should be populated.591 ASSERT_TRUE(result);592 std::unique_ptr<api::developer_private::LoadError> error =593 api::developer_private::LoadError::FromValue(*result);594 ASSERT_TRUE(error);595 ASSERT_TRUE(error->source);596 // The source should have *something* (rely on file highlighter tests for597 // the correct population).598 EXPECT_FALSE(error->source->before_highlight.empty());599 // The error should be appropriate (mentioning that version was invalid).600 EXPECT_TRUE(error->error.find(""version"") != std::string::npos)601 << error->error;602 }603 604 {605 // Load an extension with no manifest.606 TestExtensionDir dir;607 base::FilePath path = dir.UnpackedPath();608 api::EntryPicker::SkipPickerAndAlwaysSelectPathForTest(&path);609 610 scoped_refptr<ExtensionFunction> function(611 new api::DeveloperPrivateLoadUnpackedFunction());612 function->SetRenderFrameHost(web_contents->GetMainFrame());613 std::unique_ptr<base::Value> result =614 api_test_utils::RunFunctionAndReturnSingleResult(615 function.get(),616 ""[{\\""failQuietly\\"": true, \\""populateError\\"": true}]"", profile());617 // The load error should be populated.618 ASSERT_TRUE(result);619 std::unique_ptr<api::developer_private::LoadError> error =620 api::developer_private::LoadError::FromValue(*result);621 ASSERT_TRUE(error);622 // The file source should be empty.623 ASSERT_TRUE(error->source);624 EXPECT_TRUE(error->source->before_highlight.empty());625 EXPECT_TRUE(error->source->highlight.empty());626 EXPECT_TRUE(error->source->after_highlight.empty());627 }628 629 {630 // Load a valid extension.631 TestExtensionDir dir;632 dir.WriteManifest(633 R""({634 ""name"": ""foo"",635 ""description"": ""bar"",636 ""version"": ""1.0"",637 ""manifest_version"": 2638 })"");639 base::FilePath path = dir.UnpackedPath();640 api::EntryPicker::SkipPickerAndAlwaysSelectPathForTest(&path);641 642 scoped_refptr<ExtensionFunction> function(643 new api::DeveloperPrivateLoadUnpackedFunction());644 function->SetRenderFrameHost(web_contents->GetMainFrame());645 std::unique_ptr<base::Value> result =646 api_test_utils::RunFunctionAndReturnSingleResult(647 function.get(),648 ""[{\\""failQuietly\\"": true, \\""populateError\\"": true}]"", profile());649 // There should be no load error.650 ASSERT_FALSE(result);651 }652}653 654// Test that the retryGuid supplied by loadUnpacked works correctly.655TEST_F(DeveloperPrivateApiUnitTest, LoadUnpackedRetryId) {656 std::unique_ptr<content::WebContents> web_contents(657 content::WebContentsTester::CreateTestWebContents(profile(), nullptr));658 659 // Load an extension with a clear manifest error ('version' is invalid).660 TestExtensionDir dir;661 dir.WriteManifest(662 R""({663 ""name"": ""foo"",664 ""description"": ""bar"",665 ""version"": 1,666 ""manifest_version"": 2667 })"");668 base::FilePath path = dir.UnpackedPath();669 api::EntryPicker::SkipPickerAndAlwaysSelectPathForTest(&path);670 671 DeveloperPrivateAPI::UnpackedRetryId retry_guid;672 {673 // Trying to load the extension should result in a load error with the674 // retry id populated.675 scoped_refptr<ExtensionFunction> function(676 new api::DeveloperPrivateLoadUnpackedFunction());677 function->SetRenderFrameHost(web_contents->GetMainFrame());678 std::unique_ptr<base::Value> result =679 api_test_utils::RunFunctionAndReturnSingleResult(680 function.get(),681 ""[{\\""failQuietly\\"": true, \\""populateError\\"": true}]"", profile());682 ASSERT_TRUE(result);683 std::unique_ptr<api::developer_private::LoadError> error =684 api::developer_private::LoadError::FromValue(*result);685 ASSERT_TRUE(error);686 EXPECT_FALSE(error->retry_guid.empty());687 retry_guid = error->retry_guid;688 }689 690 {691 // Trying to reload the same extension, again to fail, should result in the692 // same retry id. This is somewhat an implementation detail, but is693 // important to ensure we don't allocate crazy numbers of ids if the user694 // just retries continuously.695 scoped_refptr<ExtensionFunction> function(696 new api::DeveloperPrivateLoadUnpackedFunction());697 function->SetRenderFrameHost(web_contents->GetMainFrame());698 std::unique_ptr<base::Value> result =699 api_test_utils::RunFunctionAndReturnSingleResult(700 function.get(),701 ""[{\\""failQuietly\\"": true, \\""populateError\\"": true}]"", profile());702 ASSERT_TRUE(result);703 std::unique_ptr<api::developer_private::LoadError> error =704 api::developer_private::LoadError::FromValue(*result);705 ASSERT_TRUE(error);706 EXPECT_EQ(retry_guid, error->retry_guid);707 }708 709 {710 // Try loading a different directory. The retry id should be different; this711 // also tests loading a second extension with one retry currently712 // ""in-flight"" (i.e., unresolved).713 TestExtensionDir second_dir;714 second_dir.WriteManifest(715 R""({716 ""name"": ""foo"",717 ""description"": ""bar"",718 ""version"": 1,719 ""manifest_version"": 2720 })"");721 base::FilePath second_path = second_dir.UnpackedPath();722 api::EntryPicker::SkipPickerAndAlwaysSelectPathForTest(&second_path);723 724 scoped_refptr<ExtensionFunction> function(725 new api::DeveloperPrivateLoadUnpackedFunction());726 function->SetRenderFrameHost(web_contents->GetMainFrame());727 std::unique_ptr<base::Value> result =728 api_test_utils::RunFunctionAndReturnSingleResult(729 function.get(),730 ""[{\\""failQuietly\\"": true, \\""populateError\\"": true}]"", profile());731 // The loadError result should be populated.732 ASSERT_TRUE(result);733 std::unique_ptr<api::developer_private::LoadError> error =734 api::developer_private::LoadError::FromValue(*result);735 ASSERT_TRUE(error);736 EXPECT_NE(retry_guid, error->retry_guid);737 }738 739 // Correct the manifest to make the extension valid.740 dir.WriteManifest(741 R""({742 ""name"": ""foo"",743 ""description"": ""bar"",744 ""version"": ""1.0"",745 ""manifest_version"": 2746 })"");747 748 // Set the picker to choose an invalid path (the picker should be skipped if749 // we supply a retry id).750 base::FilePath empty_path;751 api::EntryPicker::SkipPickerAndAlwaysSelectPathForTest(&empty_path);752 753 {754 // Try reloading the extension by supplying the retry id. It should succeed.755 scoped_refptr<ExtensionFunction> function(756 new api::DeveloperPrivateLoadUnpackedFunction());757 function->SetRenderFrameHost(web_contents->GetMainFrame());758 TestExtensionRegistryObserver observer(registry());759 api_test_utils::RunFunction(function.get(),760 base::StringPrintf(""[{\\""failQuietly\\"": true,""761 ""\\""populateError\\"": true,""762 ""\\""retryGuid\\"": \\""%s\\""}]"",763 retry_guid.c_str()),764 profile());765 scoped_refptr<const Extension> extension =766 observer.WaitForExtensionLoaded();767 ASSERT_TRUE(extension);768 EXPECT_EQ(extension->path(), path);769 }770 771 {772 // Try supplying an invalid retry id. It should fail with an error.773 scoped_refptr<ExtensionFunction> function(774 new api::DeveloperPrivateLoadUnpackedFunction());775 function->SetRenderFrameHost(web_contents->GetMainFrame());776 std::string error = api_test_utils::RunFunctionAndReturnError(777 function.get(),778 ""[{\\""failQuietly\\"": true,""779 ""\\""populateError\\"": true,""780 ""\\""retryGuid\\"": \\""invalid id\\""}]"",781 profile());782 EXPECT_EQ(""Invalid retry id"", error);783 }784}785 786// Tests calling ""reload"" on an unpacked extension with a manifest error,787// resulting in the reload failing. The reload call should then respond with788// the load error, which includes a retry GUID to be passed to loadUnpacked().789TEST_F(DeveloperPrivateApiUnitTest, ReloadBadExtensionToLoadUnpackedRetry) {790 std::unique_ptr<content::WebContents> web_contents(791 content::WebContentsTester::CreateTestWebContents(profile(), nullptr));792 793 // A broken manifest (version's value should be a string).794 constexpr const char kBadManifest[] =795 R""({796 ""name"": ""foo"",797 ""description"": ""bar"",798 ""version"": 1,799 ""manifest_version"": 2800 })"";801 constexpr const char kGoodManifest[] =802 R""({803 ""name"": ""foo"",804 ""description"": ""bar"",805 ""version"": ""1"",806 ""manifest_version"": 2807 })"";808 809 // Create a good unpacked extension.810 TestExtensionDir dir;811 dir.WriteManifest(kGoodManifest);812 base::FilePath path = dir.UnpackedPath();813 api::EntryPicker::SkipPickerAndAlwaysSelectPathForTest(&path);814 815 scoped_refptr<const Extension> extension;816 {817 ChromeTestExtensionLoader loader(profile());818 loader.set_pack_extension(false);819 extension = loader.LoadExtension(path);820 }821 ASSERT_TRUE(extension);822 const ExtensionId id = extension->id();823 824 std::string reload_args = base::StringPrintf(825 R""([""%s"", {""failQuietly"": true, ""populateErrorForUnpacked"":true}])"",826 id.c_str());827 828 {829 // Try reloading while the manifest is still good. This should succeed, and830 // the extension should still be enabled. Additionally, the function should831 // wait for the reload to complete, so we should see an unload and reload.832 class UnloadedRegistryObserver : public ExtensionRegistryObserver {833 public:834 UnloadedRegistryObserver(const base::FilePath& expected_path,835 ExtensionRegistry* registry)836 : expected_path_(expected_path), observer_(this) {837 observer_.Add(registry);838 }839 840 void OnExtensionUnloaded(content::BrowserContext* browser_context,841 const Extension* extension,842 UnloadedExtensionReason reason) override {843 ASSERT_FALSE(saw_unload_);844 saw_unload_ = extension->path() == expected_path_;845 }846 847 bool saw_unload() const { return saw_unload_; }848 849 private:850 bool saw_unload_ = false;851 base::FilePath expected_path_;852 ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver> observer_;853 854 DISALLOW_COPY_AND_ASSIGN(UnloadedRegistryObserver);855 };856 857 UnloadedRegistryObserver unload_observer(path, registry());858 auto function =859 base::MakeRefCounted<api::DeveloperPrivateReloadFunction>();860 function->SetRenderFrameHost(web_contents->GetMainFrame());861 api_test_utils::RunFunction(function.get(), reload_args, profile());862 // Note: no need to validate a saw_load()-type method because the presence863 // in enabled_extensions() indicates the extension was loaded.864 EXPECT_TRUE(unload_observer.saw_unload());865 EXPECT_TRUE(registry()->enabled_extensions().Contains(id));866 }867 868 dir.WriteManifest(kBadManifest);869 870 DeveloperPrivateAPI::UnpackedRetryId retry_guid;871 {872 // Trying to load the extension should result in a load error with the873 // retry GUID populated.874 auto function = base::MakeRefCounted<api::DeveloperPrivateReloadFunction>();875 function->SetRenderFrameHost(web_contents->GetMainFrame());876 std::unique_ptr<base::Value> result =877 api_test_utils::RunFunctionAndReturnSingleResult(878 function.get(), reload_args, profile());879 ASSERT_TRUE(result);880 std::unique_ptr<api::developer_private::LoadError> error =881 api::developer_private::LoadError::FromValue(*result);882 ASSERT_TRUE(error);883 EXPECT_FALSE(error->retry_guid.empty());884 retry_guid = error->retry_guid;885 EXPECT_TRUE(registry()->disabled_extensions().Contains(id));886 }887 888 dir.WriteManifest(kGoodManifest);889 {890 // Try reloading the extension by supplying the retry id. It should succeed,891 // and the extension should be enabled again.892 auto function =893 base::MakeRefCounted<api::DeveloperPrivateLoadUnpackedFunction>();894 function->SetRenderFrameHost(web_contents->GetMainFrame());895 TestExtensionRegistryObserver observer(registry());896 std::string args =897 base::StringPrintf(R""([{""failQuietly"": true, ""populateError"": true,898 ""retryGuid"": ""%s""}])"",899 retry_guid.c_str());900 api_test_utils::RunFunction(function.get(), args, profile());901 scoped_refptr<const Extension> extension =902 observer.WaitForExtensionLoaded();903 ASSERT_TRUE(extension);904 EXPECT_EQ(extension->path(), path);905 EXPECT_TRUE(registry()->enabled_extensions().Contains(id));906 }907}908 909TEST_F(DeveloperPrivateApiUnitTest,910 DeveloperPrivateNotifyDragInstallInProgress) {911 std::unique_ptr<content::WebContents> web_contents(912 content::WebContentsTester::CreateTestWebContents(profile(), nullptr));913 914 TestExtensionDir dir;915 dir.WriteManifest(916 R""({917 ""name"": ""foo"",918 ""description"": ""bar"",919 ""version"": ""1"",920 ""manifest_version"": 2921 })"");922 base::FilePath path = dir.UnpackedPath();923 api::DeveloperPrivateNotifyDragInstallInProgressFunction::924 SetDropPathForTesting(&path);925 926 {927 auto function = base::MakeRefCounted<928 api::DeveloperPrivateNotifyDragInstallInProgressFunction>();929 function->SetRenderFrameHost(web_contents->GetMainFrame());930 api_test_utils::RunFunction(function.get(), ""[]"", profile());931 }932 933 // Set the picker to choose an invalid path (the picker should be skipped if934 // we supply a retry id).935 base::FilePath empty_path;936 api::EntryPicker::SkipPickerAndAlwaysSelectPathForTest(&empty_path);937 938 constexpr char kLoadUnpackedArgs[] =939 R""([{""failQuietly"": true,940 ""populateError"": true,941 ""useDraggedPath"": true}])"";942 943 {944 // Try reloading the extension by supplying the retry id. It should succeed.945 auto function =946 base::MakeRefCounted<api::DeveloperPrivateLoadUnpackedFunction>();947 function->SetRenderFrameHost(web_contents->GetMainFrame());948 TestExtensionRegistryObserver observer(registry());949 api_test_utils::RunFunction(function.get(), kLoadUnpackedArgs, profile());950 scoped_refptr<const Extension> extension =951 observer.WaitForExtensionLoaded();952 ASSERT_TRUE(extension);953 EXPECT_EQ(extension->path(), path);954 }955 956 // Next, ensure that nothing catastrophic happens if the file that was dropped957 // was not a directory. In theory, this shouldn't happen (the JS validates the958 // file), but it could in the case of a compromised renderer, JS bug, etc.959 base::FilePath invalid_path = path.AppendASCII(""manifest.json"");960 api::DeveloperPrivateNotifyDragInstallInProgressFunction::961 SetDropPathForTesting(&invalid_path);962 {963 auto function = base::MakeRefCounted<964 api::DeveloperPrivateNotifyDragInstallInProgressFunction>();965 function->SetRenderFrameHost(web_contents->GetMainFrame());966 std::unique_ptr<base::Value> result =967 api_test_utils::RunFunctionAndReturnSingleResult(function.get(), ""[]"",968 profile());969 }970 971 {972 // Trying to load the bad extension (the path points to the manifest, not973 // the directory) should result in a load error.974 auto function =975 base::MakeRefCounted<api::DeveloperPrivateLoadUnpackedFunction>();976 function->SetRenderFrameHost(web_contents->GetMainFrame());977 TestExtensionRegistryObserver observer(registry());978 std::unique_ptr<base::Value> result =979 api_test_utils::RunFunctionAndReturnSingleResult(980 function.get(), kLoadUnpackedArgs, profile());981 ASSERT_TRUE(result);982 EXPECT_TRUE(api::developer_private::LoadError::FromValue(*result));983 }984 985 // Cleanup.986 api::DeveloperPrivateNotifyDragInstallInProgressFunction::987 SetDropPathForTesting(nullptr);988 api::EntryPicker::SkipPickerAndAlwaysSelectPathForTest(nullptr);989}990 991// Test developerPrivate.requestFileSource.992TEST_F(DeveloperPrivateApiUnitTest, DeveloperPrivateRequestFileSource) {993 // Testing of this function seems light, but that's because it basically just994 // forwards to reading a file to a string, and highlighting it - both of which995 // are already tested separately.996 const Extension* extension = LoadUnpackedExtension();997 const char kErrorMessage[] = ""Something went wrong"";998 api::developer_private::RequestFileSourceProperties properties;999 properties.extension_id = extension->id();1000 properties.path_suffix = ""manifest.json"";1001 properties.message = kErrorMessage;1002 properties.manifest_key.reset(new std::string(""name""));1003 1004 scoped_refptr<ExtensionFunction> function(1005 new api::DeveloperPrivateRequestFileSourceFunction());1006 base::ListValue file_source_args;1007 file_source_args.Append(properties.ToValue());1008 EXPECT_TRUE(RunFunction(function, file_source_args)) << function->GetError();1009 1010 const base::Value* response_value = nullptr;1011 ASSERT_TRUE(function->GetResultList()->Get(0u, &response_value));1012 std::unique_ptr<api::developer_private::RequestFileSourceResponse> response =1013 api::developer_private::RequestFileSourceResponse::FromValue(1014 *response_value);1015 EXPECT_FALSE(response->before_highlight.empty());1016 EXPECT_EQ(""\\""name\\"": \\""foo\\"""", response->highlight);1017 EXPECT_FALSE(response->after_highlight.empty());1018 EXPECT_EQ(""foo: manifest.json"", response->title);1019 EXPECT_EQ(kErrorMessage, response->message);1020}1021 1022// Test developerPrivate.getExtensionsInfo.1023TEST_F(DeveloperPrivateApiUnitTest, DeveloperPrivateGetExtensionsInfo) {1024 LoadSimpleExtension();1025 1026 // The test here isn't so much about the generated value (that's tested in1027 // ExtensionInfoGenerator's unittest), but rather just to make sure we can1028 // serialize/deserialize the result - which implicity tests that everything1029 // has a sane value.1030 scoped_refptr<ExtensionFunction> function(1031 new api::DeveloperPrivateGetExtensionsInfoFunction());1032 EXPECT_TRUE(RunFunction(function, base::ListValue())) << function->GetError();1033 const base::ListValue* results = function->GetResultList();1034 ASSERT_EQ(1u, results->GetSize());1035 const base::ListValue* list = nullptr;1036 ASSERT_TRUE(results->GetList(0u, &list));1037 ASSERT_EQ(1u, list->GetSize());1038 const base::Value* value = nullptr;1039 ASSERT_TRUE(list->Get(0u, &value));1040 std::unique_ptr<api::developer_private::ExtensionInfo> info =1041 api::developer_private::ExtensionInfo::FromValue(*value);1042 ASSERT_TRUE(info);1043 1044 // As a sanity check, also run the GetItemsInfo and make sure it returns a1045 // sane value.1046 function = new api::DeveloperPrivateGetItemsInfoFunction();1047 base::ListValue args;1048 args.AppendBoolean(false);1049 args.AppendBoolean(false);1050 EXPECT_TRUE(RunFunction(function, args)) << function->GetError();1051 results = function->GetResultList();1052 ASSERT_EQ(1u, results->GetSize());1053 ASSERT_TRUE(results->GetList(0u, &list));1054 ASSERT_EQ(1u, list->GetSize());1055 ASSERT_TRUE(list->Get(0u, &value));1056 std::unique_ptr<api::developer_private::ItemInfo> item_info =1057 api::developer_private::ItemInfo::FromValue(*value);1058 ASSERT_TRUE(item_info);1059}1060 1061// Test developerPrivate.deleteExtensionErrors.1062TEST_F(DeveloperPrivateApiUnitTest, DeveloperPrivateDeleteExtensionErrors) {1063 profile()->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, true);1064 const Extension* extension = LoadSimpleExtension();1065 1066 // Report some errors.1067 ErrorConsole* error_console = ErrorConsole::Get(profile());1068 error_console->SetReportingAllForExtension(extension->id(), true);1069 error_console->ReportError(1070 error_test_util::CreateNewRuntimeError(extension->id(), ""foo""));1071 error_console->ReportError(1072 error_test_util::CreateNewRuntimeError(extension->id(), ""bar""));1073 error_console->ReportError(1074 error_test_util::CreateNewManifestError(extension->id(), ""baz""));1075 EXPECT_EQ(3u, error_console->GetErrorsForExtension(extension->id()).size());1076 1077 // Start by removing all errors for the extension of a given type (manifest).1078 std::string type_string = api::developer_private::ToString(1079 api::developer_private::ERROR_TYPE_MANIFEST);1080 std::unique_ptr<base::ListValue> args =1081 ListBuilder()1082 .Append(DictionaryBuilder()1083 .Set(""extensionId"", extension->id())1084 .Set(""type"", type_string)1085 .Build())1086 .Build();1087 scoped_refptr<ExtensionFunction> function =1088 new api::DeveloperPrivateDeleteExtensionErrorsFunction();1089 EXPECT_TRUE(RunFunction(function, *args)) << function->GetError();1090 // Two errors should remain.1091 const ErrorList& error_list =1092 error_console->GetErrorsForExtension(extension->id());1093 ASSERT_EQ(2u, error_list.size());1094 1095 // Next remove errors by id.1096 int error_id = error_list[0]->id();1097 args =1098 ListBuilder()1099 .Append(DictionaryBuilder()1100 .Set(""extensionId"", extension->id())1101 .Set(""errorIds"", ListBuilder().Append(error_id).Build())1102 .Build())1103 .Build();1104 function = new api::DeveloperPrivateDeleteExtensionErrorsFunction();1105 EXPECT_TRUE(RunFunction(function, *args)) << function->GetError();1106 // And then there was one.1107 EXPECT_EQ(1u, error_console->GetErrorsForExtension(extension->id()).size());1108 1109 // Finally remove all errors for the extension.1110 args =1111 ListBuilder()1112 .Append(1113 DictionaryBuilder().Set(""extensionId"", extension->id()).Build())1114 .Build();1115 function = new api::DeveloperPrivateDeleteExtensionErrorsFunction();1116 EXPECT_TRUE(RunFunction(function, *args)) << function->GetError();1117 // No more errors!1118 EXPECT_TRUE(error_console->GetErrorsForExtension(extension->id()).empty());1119}1120 1121// Tests that developerPrivate.repair does not succeed for a non-corrupted1122// extension.1123TEST_F(DeveloperPrivateApiUnitTest, RepairNotBrokenExtension) {1124 base::FilePath extension_path = data_dir().AppendASCII(""good.crx"");1125 const Extension* extension = InstallCRX(extension_path, INSTALL_NEW);1126 1127 // Attempt to repair the good extension, expect failure.1128 std::unique_ptr<base::ListValue> args =1129 ListBuilder().Append(extension->id()).Build();1130 scoped_refptr<ExtensionFunction> function =1131 new api::DeveloperPrivateRepairExtensionFunction();1132 EXPECT_FALSE(RunFunction(function, *args));1133 EXPECT_EQ(""Cannot repair a healthy extension."", function->GetError());1134}1135 1136// Tests that developerPrivate.private cannot repair a policy-installed1137// extension.1138// Regression test for https://crbug.com/577959.1139TEST_F(DeveloperPrivateApiUnitTest, RepairPolicyExtension) {1140 std::string extension_id(kGoodCrx);1141 1142 // Set up a mock provider with a policy extension.1143 std::unique_ptr<MockExternalProvider> mock_provider =1144 std::make_unique<MockExternalProvider>(1145 service(), Manifest::EXTERNAL_POLICY_DOWNLOAD);1146 MockExternalProvider* mock_provider_ptr = mock_provider.get();1147 AddMockExternalProvider(std::move(mock_provider));1148 mock_provider_ptr->UpdateOrAddExtension(extension_id, ""1.0.0.0"",1149 data_dir().AppendASCII(""good.crx""));1150 // Reloading extensions should find our externally registered extension1151 // and install it.1152 content::WindowedNotificationObserver observer(1153 extensions::NOTIFICATION_CRX_INSTALLER_DONE,1154 content::NotificationService::AllSources());1155 service()->CheckForExternalUpdates();1156 observer.Wait();1157 1158 // Attempt to repair the good extension, expect failure.1159 std::unique_ptr<base::ListValue> args =1160 ListBuilder().Append(extension_id).Build();1161 scoped_refptr<ExtensionFunction> function =1162 new api::DeveloperPrivateRepairExtensionFunction();1163 EXPECT_FALSE(RunFunction(function, *args));1164 EXPECT_EQ(""Cannot repair a healthy extension."", function->GetError());1165 1166 // Corrupt the extension , still expect repair failure because this is a1167 // policy extension.1168 service()->DisableExtension(extension_id, disable_reason::DISABLE_CORRUPTED);1169 args = ListBuilder().Append(extension_id).Build();1170 function = new api::DeveloperPrivateRepairExtensionFunction();1171 EXPECT_FALSE(RunFunction(function, *args));1172 EXPECT_EQ(""Cannot repair a policy-installed extension."",1173 function->GetError());1174}1175 1176// Test developerPrivate.updateProfileConfiguration: Try to turn on devMode1177// when DeveloperToolsAvailability policy disallows developer tools.1178TEST_F(DeveloperPrivateApiUnitTest, DeveloperPrivateDevModeDisabledPolicy) {1179 testing_pref_service()->SetManagedPref(prefs::kExtensionsUIDeveloperMode,1180 std::make_unique<base::Value>(false));1181 1182 UpdateProfileConfigurationDevMode(true);1183 1184 EXPECT_FALSE(1185 profile()->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode));1186 1187 std::unique_ptr<api::developer_private::ProfileInfo> profile_info;1188 ASSERT_NO_FATAL_FAILURE(GetProfileConfiguration(&profile_info));1189 EXPECT_FALSE(profile_info->in_developer_mode);1190 EXPECT_TRUE(profile_info->is_developer_mode_controlled_by_policy);1191}1192 1193// Test developerPrivate.updateProfileConfiguration: Try to turn on devMode1194// (without DeveloperToolsAvailability policy).1195TEST_F(DeveloperPrivateApiUnitTest, DeveloperPrivateDevMode) {1196 UpdateProfileConfigurationDevMode(false);1197 EXPECT_FALSE(1198 profile()->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode));1199 {1200 std::unique_ptr<api::developer_private::ProfileInfo> profile_info;