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