1 // Copyright (c) 2012 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/bind.h" 6 #include "base/json/json_writer.h" 7 #include "base/memory/ref_counted.h" 8 #include "base/run_loop.h" 9 #include "chrome/browser/extensions/api/storage/settings_frontend.h" 10 #include "chrome/browser/extensions/api/storage/settings_namespace.h" 11 #include "chrome/browser/extensions/api/storage/settings_sync_util.h" 12 #include "chrome/browser/extensions/extension_apitest.h" 13 #include "chrome/browser/extensions/extension_service.h" 14 #include "chrome/browser/extensions/extension_system.h" 15 #include "chrome/browser/extensions/extension_system_factory.h" 16 #include "chrome/browser/extensions/extension_test_message_listener.h" 17 #include "chrome/browser/profiles/profile.h" 18 #include "chrome/browser/ui/browser.h" 19 #include "chrome/common/extensions/value_builder.h" 20 #include "chrome/test/base/ui_test_utils.h" 21 #include "sync/api/sync_change.h" 22 #include "sync/api/sync_change_processor.h" 23 #include "sync/api/sync_error_factory.h" 24 #include "sync/api/sync_error_factory_mock.h" 25 #include "testing/gmock/include/gmock/gmock.h" 26 27 #if defined(ENABLE_CONFIGURATION_POLICY) 28 #include "chrome/browser/policy/browser_policy_connector.h" 29 #include "chrome/browser/policy/mock_configuration_policy_provider.h" 30 #include "chrome/browser/policy/policy_bundle.h" 31 #include "chrome/browser/policy/policy_domain_descriptor.h" 32 #include "chrome/browser/policy/policy_map.h" 33 #include "chrome/browser/policy/policy_service.h" 34 #include "chrome/browser/policy/profile_policy_connector.h" 35 #include "chrome/browser/policy/profile_policy_connector_factory.h" 36 #endif 37 38 namespace extensions { 39 40 using settings_namespace::FromString; 41 using settings_namespace::LOCAL; 42 using settings_namespace::MANAGED; 43 using settings_namespace::Namespace; 44 using settings_namespace::SYNC; 45 using settings_namespace::ToString; 46 using testing::AnyNumber; 47 using testing::Return; 48 using testing::_; 49 50 namespace { 51 52 // TODO(kalman): test both EXTENSION_SETTINGS and APP_SETTINGS. 53 const syncer::ModelType kModelType = syncer::EXTENSION_SETTINGS; 54 55 // The managed_storage extension has a key defined in its manifest, so that 56 // its extension ID is well-known and the policy system can push policies for 57 // the extension. 58 const char kManagedStorageExtensionId[] = "kjmkgkdkpedkejedfhmfcenooemhbpbo"; 59 60 class NoopSyncChangeProcessor : public syncer::SyncChangeProcessor { 61 public: 62 virtual syncer::SyncError ProcessSyncChanges( 63 const tracked_objects::Location& from_here, 64 const syncer::SyncChangeList& change_list) OVERRIDE { 65 return syncer::SyncError(); 66 } 67 68 virtual ~NoopSyncChangeProcessor() {}; 69 }; 70 71 class SyncChangeProcessorDelegate : public syncer::SyncChangeProcessor { 72 public: 73 explicit SyncChangeProcessorDelegate(syncer::SyncChangeProcessor* recipient) 74 : recipient_(recipient) { 75 DCHECK(recipient_); 76 } 77 virtual ~SyncChangeProcessorDelegate() {} 78 79 // syncer::SyncChangeProcessor implementation. 80 virtual syncer::SyncError ProcessSyncChanges( 81 const tracked_objects::Location& from_here, 82 const syncer::SyncChangeList& change_list) OVERRIDE { 83 return recipient_->ProcessSyncChanges(from_here, change_list); 84 } 85 86 private: 87 // The recipient of all sync changes. 88 syncer::SyncChangeProcessor* recipient_; 89 90 DISALLOW_COPY_AND_ASSIGN(SyncChangeProcessorDelegate); 91 }; 92 93 } // namespace 94 95 class ExtensionSettingsApiTest : public ExtensionApiTest { 96 protected: 97 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 98 ExtensionApiTest::SetUpInProcessBrowserTestFixture(); 99 100 #if defined(ENABLE_CONFIGURATION_POLICY) 101 EXPECT_CALL(policy_provider_, IsInitializationComplete(_)) 102 .WillRepeatedly(Return(true)); 103 EXPECT_CALL(policy_provider_, RegisterPolicyDomain(_)).Times(AnyNumber()); 104 policy::BrowserPolicyConnector::SetPolicyProviderForTesting( 105 &policy_provider_); 106 #endif 107 } 108 109 void ReplyWhenSatisfied( 110 Namespace settings_namespace, 111 const std::string& normal_action, 112 const std::string& incognito_action) { 113 MaybeLoadAndReplyWhenSatisfied( 114 settings_namespace, normal_action, incognito_action, NULL, false); 115 } 116 117 const Extension* LoadAndReplyWhenSatisfied( 118 Namespace settings_namespace, 119 const std::string& normal_action, 120 const std::string& incognito_action, 121 const std::string& extension_dir) { 122 return MaybeLoadAndReplyWhenSatisfied( 123 settings_namespace, 124 normal_action, 125 incognito_action, 126 &extension_dir, 127 false); 128 } 129 130 void FinalReplyWhenSatisfied( 131 Namespace settings_namespace, 132 const std::string& normal_action, 133 const std::string& incognito_action) { 134 MaybeLoadAndReplyWhenSatisfied( 135 settings_namespace, normal_action, incognito_action, NULL, true); 136 } 137 138 void InitSync(syncer::SyncChangeProcessor* sync_processor) { 139 base::MessageLoop::current()->RunUntilIdle(); 140 InitSyncWithSyncableService( 141 sync_processor, 142 browser()->profile()->GetExtensionService()->settings_frontend()-> 143 GetBackendForSync(kModelType)); 144 } 145 146 void SendChanges(const syncer::SyncChangeList& change_list) { 147 base::MessageLoop::current()->RunUntilIdle(); 148 SendChangesToSyncableService( 149 change_list, 150 browser()->profile()->GetExtensionService()->settings_frontend()-> 151 GetBackendForSync(kModelType)); 152 } 153 154 #if defined(ENABLE_CONFIGURATION_POLICY) 155 void SetPolicies(const base::DictionaryValue& policies) { 156 scoped_ptr<policy::PolicyBundle> bundle(new policy::PolicyBundle()); 157 policy::PolicyMap& policy_map = bundle->Get(policy::PolicyNamespace( 158 policy::POLICY_DOMAIN_EXTENSIONS, kManagedStorageExtensionId)); 159 policy_map.LoadFrom( 160 &policies, policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER); 161 policy_provider_.UpdatePolicy(bundle.Pass()); 162 } 163 #endif 164 165 private: 166 const Extension* MaybeLoadAndReplyWhenSatisfied( 167 Namespace settings_namespace, 168 const std::string& normal_action, 169 const std::string& incognito_action, 170 // May be NULL to imply not loading the extension. 171 const std::string* extension_dir, 172 bool is_final_action) { 173 ExtensionTestMessageListener listener("waiting", true); 174 ExtensionTestMessageListener listener_incognito("waiting_incognito", true); 175 176 // Only load the extension after the listeners have been set up, to avoid 177 // initialisation race conditions. 178 const Extension* extension = NULL; 179 if (extension_dir) { 180 extension = LoadExtensionIncognito( 181 test_data_dir_.AppendASCII("settings").AppendASCII(*extension_dir)); 182 EXPECT_TRUE(extension); 183 } 184 185 EXPECT_TRUE(listener.WaitUntilSatisfied()); 186 EXPECT_TRUE(listener_incognito.WaitUntilSatisfied()); 187 188 listener.Reply( 189 CreateMessage(settings_namespace, normal_action, is_final_action)); 190 listener_incognito.Reply( 191 CreateMessage(settings_namespace, incognito_action, is_final_action)); 192 return extension; 193 } 194 195 std::string CreateMessage( 196 Namespace settings_namespace, 197 const std::string& action, 198 bool is_final_action) { 199 scoped_ptr<base::DictionaryValue> message(new base::DictionaryValue()); 200 message->SetString("namespace", ToString(settings_namespace)); 201 message->SetString("action", action); 202 message->SetBoolean("isFinalAction", is_final_action); 203 std::string message_json; 204 base::JSONWriter::Write(message.get(), &message_json); 205 return message_json; 206 } 207 208 void InitSyncWithSyncableService( 209 syncer::SyncChangeProcessor* sync_processor, 210 syncer::SyncableService* settings_service) { 211 EXPECT_FALSE(settings_service->MergeDataAndStartSyncing( 212 kModelType, 213 syncer::SyncDataList(), 214 scoped_ptr<syncer::SyncChangeProcessor>( 215 new SyncChangeProcessorDelegate(sync_processor)), 216 scoped_ptr<syncer::SyncErrorFactory>( 217 new syncer::SyncErrorFactoryMock())).error().IsSet()); 218 } 219 220 void SendChangesToSyncableService( 221 const syncer::SyncChangeList& change_list, 222 syncer::SyncableService* settings_service) { 223 EXPECT_FALSE( 224 settings_service->ProcessSyncChanges(FROM_HERE, change_list).IsSet()); 225 } 226 227 protected: 228 #if defined(ENABLE_CONFIGURATION_POLICY) 229 policy::MockConfigurationPolicyProvider policy_provider_; 230 #endif 231 }; 232 233 // Flaky. http://crbug.com/248032 234 IN_PROC_BROWSER_TEST_F(ExtensionSettingsApiTest, DISABLED_SimpleTest) { 235 ASSERT_TRUE(RunExtensionTest("settings/simple_test")) << message_; 236 } 237 238 // Structure of this test taken from IncognitoSplitMode. 239 // Note that only split-mode incognito is tested, because spanning mode 240 // incognito looks the same as normal mode when the only API activity comes 241 // from background pages. 242 IN_PROC_BROWSER_TEST_F(ExtensionSettingsApiTest, SplitModeIncognito) { 243 // We need 2 ResultCatchers because we'll be running the same test in both 244 // regular and incognito mode. 245 ResultCatcher catcher, catcher_incognito; 246 catcher.RestrictToProfile(browser()->profile()); 247 catcher_incognito.RestrictToProfile( 248 browser()->profile()->GetOffTheRecordProfile()); 249 250 LoadAndReplyWhenSatisfied(SYNC, 251 "assertEmpty", "assertEmpty", "split_incognito"); 252 ReplyWhenSatisfied(SYNC, "noop", "setFoo"); 253 ReplyWhenSatisfied(SYNC, "assertFoo", "assertFoo"); 254 ReplyWhenSatisfied(SYNC, "clear", "noop"); 255 ReplyWhenSatisfied(SYNC, "assertEmpty", "assertEmpty"); 256 ReplyWhenSatisfied(SYNC, "setFoo", "noop"); 257 ReplyWhenSatisfied(SYNC, "assertFoo", "assertFoo"); 258 ReplyWhenSatisfied(SYNC, "noop", "removeFoo"); 259 FinalReplyWhenSatisfied(SYNC, "assertEmpty", "assertEmpty"); 260 261 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 262 EXPECT_TRUE(catcher_incognito.GetNextResult()) << catcher.message(); 263 } 264 265 IN_PROC_BROWSER_TEST_F(ExtensionSettingsApiTest, 266 OnChangedNotificationsBetweenBackgroundPages) { 267 // We need 2 ResultCatchers because we'll be running the same test in both 268 // regular and incognito mode. 269 ResultCatcher catcher, catcher_incognito; 270 catcher.RestrictToProfile(browser()->profile()); 271 catcher_incognito.RestrictToProfile( 272 browser()->profile()->GetOffTheRecordProfile()); 273 274 LoadAndReplyWhenSatisfied(SYNC, 275 "assertNoNotifications", "assertNoNotifications", "split_incognito"); 276 ReplyWhenSatisfied(SYNC, "noop", "setFoo"); 277 ReplyWhenSatisfied(SYNC, 278 "assertAddFooNotification", "assertAddFooNotification"); 279 ReplyWhenSatisfied(SYNC, "clearNotifications", "clearNotifications"); 280 ReplyWhenSatisfied(SYNC, "removeFoo", "noop"); 281 FinalReplyWhenSatisfied(SYNC, 282 "assertDeleteFooNotification", "assertDeleteFooNotification"); 283 284 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 285 EXPECT_TRUE(catcher_incognito.GetNextResult()) << catcher.message(); 286 } 287 288 IN_PROC_BROWSER_TEST_F(ExtensionSettingsApiTest, 289 SyncAndLocalAreasAreSeparate) { 290 // We need 2 ResultCatchers because we'll be running the same test in both 291 // regular and incognito mode. 292 ResultCatcher catcher, catcher_incognito; 293 catcher.RestrictToProfile(browser()->profile()); 294 catcher_incognito.RestrictToProfile( 295 browser()->profile()->GetOffTheRecordProfile()); 296 297 LoadAndReplyWhenSatisfied(SYNC, 298 "assertNoNotifications", "assertNoNotifications", "split_incognito"); 299 300 ReplyWhenSatisfied(SYNC, "noop", "setFoo"); 301 ReplyWhenSatisfied(SYNC, "assertFoo", "assertFoo"); 302 ReplyWhenSatisfied(SYNC, 303 "assertAddFooNotification", "assertAddFooNotification"); 304 ReplyWhenSatisfied(LOCAL, "assertEmpty", "assertEmpty"); 305 ReplyWhenSatisfied(LOCAL, "assertNoNotifications", "assertNoNotifications"); 306 307 ReplyWhenSatisfied(SYNC, "clearNotifications", "clearNotifications"); 308 309 ReplyWhenSatisfied(LOCAL, "setFoo", "noop"); 310 ReplyWhenSatisfied(LOCAL, "assertFoo", "assertFoo"); 311 ReplyWhenSatisfied(LOCAL, 312 "assertAddFooNotification", "assertAddFooNotification"); 313 ReplyWhenSatisfied(SYNC, "assertFoo", "assertFoo"); 314 ReplyWhenSatisfied(SYNC, "assertNoNotifications", "assertNoNotifications"); 315 316 ReplyWhenSatisfied(LOCAL, "clearNotifications", "clearNotifications"); 317 318 ReplyWhenSatisfied(LOCAL, "noop", "removeFoo"); 319 ReplyWhenSatisfied(LOCAL, "assertEmpty", "assertEmpty"); 320 ReplyWhenSatisfied(LOCAL, 321 "assertDeleteFooNotification", "assertDeleteFooNotification"); 322 ReplyWhenSatisfied(SYNC, "assertFoo", "assertFoo"); 323 ReplyWhenSatisfied(SYNC, "assertNoNotifications", "assertNoNotifications"); 324 325 ReplyWhenSatisfied(LOCAL, "clearNotifications", "clearNotifications"); 326 327 ReplyWhenSatisfied(SYNC, "removeFoo", "noop"); 328 ReplyWhenSatisfied(SYNC, "assertEmpty", "assertEmpty"); 329 ReplyWhenSatisfied(SYNC, 330 "assertDeleteFooNotification", "assertDeleteFooNotification"); 331 ReplyWhenSatisfied(LOCAL, "assertNoNotifications", "assertNoNotifications"); 332 FinalReplyWhenSatisfied(LOCAL, "assertEmpty", "assertEmpty"); 333 334 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 335 EXPECT_TRUE(catcher_incognito.GetNextResult()) << catcher.message(); 336 } 337 338 // Disabled, see crbug.com/101110 339 IN_PROC_BROWSER_TEST_F(ExtensionSettingsApiTest, 340 DISABLED_OnChangedNotificationsFromSync) { 341 // We need 2 ResultCatchers because we'll be running the same test in both 342 // regular and incognito mode. 343 ResultCatcher catcher, catcher_incognito; 344 catcher.RestrictToProfile(browser()->profile()); 345 catcher_incognito.RestrictToProfile( 346 browser()->profile()->GetOffTheRecordProfile()); 347 348 const Extension* extension = 349 LoadAndReplyWhenSatisfied(SYNC, 350 "assertNoNotifications", "assertNoNotifications", "split_incognito"); 351 const std::string& extension_id = extension->id(); 352 353 NoopSyncChangeProcessor sync_processor; 354 InitSync(&sync_processor); 355 356 // Set "foo" to "bar" via sync. 357 syncer::SyncChangeList sync_changes; 358 StringValue bar("bar"); 359 sync_changes.push_back(settings_sync_util::CreateAdd( 360 extension_id, "foo", bar, kModelType)); 361 SendChanges(sync_changes); 362 363 ReplyWhenSatisfied(SYNC, 364 "assertAddFooNotification", "assertAddFooNotification"); 365 ReplyWhenSatisfied(SYNC, "clearNotifications", "clearNotifications"); 366 367 // Remove "foo" via sync. 368 sync_changes.clear(); 369 sync_changes.push_back(settings_sync_util::CreateDelete( 370 extension_id, "foo", kModelType)); 371 SendChanges(sync_changes); 372 373 FinalReplyWhenSatisfied(SYNC, 374 "assertDeleteFooNotification", "assertDeleteFooNotification"); 375 376 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 377 EXPECT_TRUE(catcher_incognito.GetNextResult()) << catcher.message(); 378 } 379 380 // Disabled, see crbug.com/101110 381 // 382 // TODO: boring test, already done in the unit tests. What we really should be 383 // be testing is that the areas don't overlap. 384 IN_PROC_BROWSER_TEST_F(ExtensionSettingsApiTest, 385 DISABLED_OnChangedNotificationsFromSyncNotSentToLocal) { 386 // We need 2 ResultCatchers because we'll be running the same test in both 387 // regular and incognito mode. 388 ResultCatcher catcher, catcher_incognito; 389 catcher.RestrictToProfile(browser()->profile()); 390 catcher_incognito.RestrictToProfile( 391 browser()->profile()->GetOffTheRecordProfile()); 392 393 const Extension* extension = 394 LoadAndReplyWhenSatisfied(LOCAL, 395 "assertNoNotifications", "assertNoNotifications", "split_incognito"); 396 const std::string& extension_id = extension->id(); 397 398 NoopSyncChangeProcessor sync_processor; 399 InitSync(&sync_processor); 400 401 // Set "foo" to "bar" via sync. 402 syncer::SyncChangeList sync_changes; 403 StringValue bar("bar"); 404 sync_changes.push_back(settings_sync_util::CreateAdd( 405 extension_id, "foo", bar, kModelType)); 406 SendChanges(sync_changes); 407 408 ReplyWhenSatisfied(LOCAL, "assertNoNotifications", "assertNoNotifications"); 409 410 // Remove "foo" via sync. 411 sync_changes.clear(); 412 sync_changes.push_back(settings_sync_util::CreateDelete( 413 extension_id, "foo", kModelType)); 414 SendChanges(sync_changes); 415 416 FinalReplyWhenSatisfied(LOCAL, 417 "assertNoNotifications", "assertNoNotifications"); 418 419 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 420 EXPECT_TRUE(catcher_incognito.GetNextResult()) << catcher.message(); 421 } 422 423 IN_PROC_BROWSER_TEST_F(ExtensionSettingsApiTest, IsStorageEnabled) { 424 SettingsFrontend* frontend = 425 browser()->profile()->GetExtensionService()->settings_frontend(); 426 EXPECT_TRUE(frontend->IsStorageEnabled(LOCAL)); 427 EXPECT_TRUE(frontend->IsStorageEnabled(SYNC)); 428 429 #if defined(ENABLE_CONFIGURATION_POLICY) 430 EXPECT_TRUE(frontend->IsStorageEnabled(MANAGED)); 431 #else 432 EXPECT_FALSE(frontend->IsStorageEnabled(MANAGED)); 433 #endif 434 } 435 436 #if defined(ENABLE_CONFIGURATION_POLICY) 437 438 IN_PROC_BROWSER_TEST_F(ExtensionSettingsApiTest, PolicyDomainDescriptor) { 439 // Verifies that the PolicyDomainDescriptor for the extensions domain is 440 // created on startup. 441 Profile* profile = browser()->profile(); 442 ExtensionSystem* extension_system = 443 ExtensionSystemFactory::GetForProfile(profile); 444 if (!extension_system->ready().is_signaled()) { 445 // Wait until the extension system is ready. 446 base::RunLoop run_loop; 447 extension_system->ready().Post(FROM_HERE, run_loop.QuitClosure()); 448 run_loop.Run(); 449 ASSERT_TRUE(extension_system->ready().is_signaled()); 450 } 451 452 policy::ProfilePolicyConnector* connector = 453 policy::ProfilePolicyConnectorFactory::GetForProfile(profile); 454 policy::PolicyService* service = connector->policy_service(); 455 scoped_refptr<const policy::PolicyDomainDescriptor> descriptor = 456 service->GetPolicyDomainDescriptor(policy::POLICY_DOMAIN_EXTENSIONS); 457 EXPECT_TRUE(descriptor.get()); 458 } 459 460 IN_PROC_BROWSER_TEST_F(ExtensionSettingsApiTest, ManagedStorage) { 461 // Set policies for the test extension. 462 scoped_ptr<base::DictionaryValue> policy = extensions::DictionaryBuilder() 463 .Set("string-policy", "value") 464 .Set("int-policy", -123) 465 .Set("double-policy", 456e7) 466 .SetBoolean("boolean-policy", true) 467 .Set("list-policy", extensions::ListBuilder() 468 .Append("one") 469 .Append("two") 470 .Append("three")) 471 .Set("dict-policy", extensions::DictionaryBuilder() 472 .Set("list", extensions::ListBuilder() 473 .Append(extensions::DictionaryBuilder() 474 .Set("one", 1) 475 .Set("two", 2)) 476 .Append(extensions::DictionaryBuilder() 477 .Set("three", 3)))) 478 .Build(); 479 SetPolicies(*policy); 480 // Now run the extension. 481 ASSERT_TRUE(RunExtensionTest("settings/managed_storage")) << message_; 482 } 483 484 IN_PROC_BROWSER_TEST_F(ExtensionSettingsApiTest, PRE_ManagedStorageEvents) { 485 ResultCatcher catcher; 486 487 // This test starts without any test extensions installed. 488 EXPECT_FALSE(GetSingleLoadedExtension()); 489 message_.clear(); 490 491 // Set policies for the test extension. 492 scoped_ptr<base::DictionaryValue> policy = extensions::DictionaryBuilder() 493 .Set("constant-policy", "aaa") 494 .Set("changes-policy", "bbb") 495 .Set("deleted-policy", "ccc") 496 .Build(); 497 SetPolicies(*policy); 498 499 ExtensionTestMessageListener ready_listener("ready", false); 500 // Load the extension to install the event listener. 501 const Extension* extension = LoadExtension( 502 test_data_dir_.AppendASCII("settings/managed_storage_events")); 503 ASSERT_TRUE(extension); 504 // Wait until the extension sends the "ready" message. 505 ASSERT_TRUE(ready_listener.WaitUntilSatisfied()); 506 507 // Now change the policies and wait until the extension is done. 508 policy = extensions::DictionaryBuilder() 509 .Set("constant-policy", "aaa") 510 .Set("changes-policy", "ddd") 511 .Set("new-policy", "eee") 512 .Build(); 513 SetPolicies(*policy); 514 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 515 } 516 517 #if defined(OS_CHROMEOS) || defined(OS_WIN) 518 // Flakily times out. http://crbug.com/171477 519 #define MAYBE_ManagedStorageEvents DISABLED_ManagedStorageEvents 520 #else 521 #define MAYBE_ManagedStorageEvents ManagedStorageEvents 522 #endif 523 524 IN_PROC_BROWSER_TEST_F(ExtensionSettingsApiTest, MAYBE_ManagedStorageEvents) { 525 // This test runs after PRE_ManagedStorageEvents without having deleted the 526 // profile, so the extension is still around. While the browser restarted the 527 // policy went back to the empty default, and so the extension should receive 528 // the corresponding change events. 529 530 ResultCatcher catcher; 531 532 // Verify that the test extension is still installed. 533 const Extension* extension = GetSingleLoadedExtension(); 534 ASSERT_TRUE(extension); 535 EXPECT_EQ(kManagedStorageExtensionId, extension->id()); 536 537 // Running the test again skips the onInstalled callback, and just triggers 538 // the onChanged notification. 539 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 540 } 541 542 #endif // defined(ENABLE_CONFIGURATION_POLICY) 543 544 IN_PROC_BROWSER_TEST_F(ExtensionSettingsApiTest, ManagedStorageDisabled) { 545 // Disable the 'managed' namespace. This is redundant when 546 // ENABLE_CONFIGURATION_POLICY is not defined. 547 SettingsFrontend* frontend = 548 browser()->profile()->GetExtensionService()->settings_frontend(); 549 frontend->DisableStorageForTesting(MANAGED); 550 EXPECT_FALSE(frontend->IsStorageEnabled(MANAGED)); 551 // Now run the extension. 552 ASSERT_TRUE(RunExtensionTest("settings/managed_storage_disabled")) 553 << message_; 554 } 555 556 } // namespace extensions 557