1// Copyright (c) 2011 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 "chrome/browser/extensions/test_extension_prefs.h"
6
7#include "base/file_util.h"
8#include "base/memory/scoped_ptr.h"
9#include "base/message_loop.h"
10#include "base/message_loop_proxy.h"
11#include "base/values.h"
12#include "base/synchronization/waitable_event.h"
13#include "chrome/browser/extensions/extension_pref_store.h"
14#include "chrome/browser/extensions/extension_pref_value_map.h"
15#include "chrome/browser/extensions/extension_prefs.h"
16#include "chrome/browser/prefs/pref_service.h"
17#include "chrome/browser/prefs/pref_service_mock_builder.h"
18#include "chrome/browser/prefs/pref_value_store.h"
19#include "chrome/common/extensions/extension.h"
20#include "chrome/common/extensions/extension_constants.h"
21#include "chrome/common/json_pref_store.h"
22#include "chrome/test/signaling_task.h"
23#include "content/browser/browser_thread.h"
24#include "testing/gtest/include/gtest/gtest.h"
25
26namespace {
27
28// Mock ExtensionPrefs class with artificial clock to guarantee that no two
29// extensions get the same installation time stamp and we can reliably
30// assert the installation order in the tests below.
31class MockExtensionPrefs : public ExtensionPrefs {
32 public:
33  MockExtensionPrefs(PrefService* prefs,
34                     const FilePath& root_dir,
35                     ExtensionPrefValueMap* extension_pref_value_map)
36    : ExtensionPrefs(prefs, root_dir, extension_pref_value_map),
37      currentTime(base::Time::Now()) {}
38  ~MockExtensionPrefs() {}
39
40 protected:
41  mutable base::Time currentTime;
42
43  virtual base::Time GetCurrentTime() const {
44    currentTime += base::TimeDelta::FromSeconds(10);
45    return currentTime;
46  }
47};
48
49}  // namespace
50
51TestExtensionPrefs::TestExtensionPrefs() : pref_service_(NULL) {
52  EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
53  preferences_file_ = temp_dir_.path().AppendASCII("Preferences");
54  extensions_dir_ = temp_dir_.path().AppendASCII("Extensions");
55  EXPECT_TRUE(file_util::CreateDirectory(extensions_dir_));
56
57  RecreateExtensionPrefs();
58}
59
60TestExtensionPrefs::~TestExtensionPrefs() {}
61
62void TestExtensionPrefs::RecreateExtensionPrefs() {
63  // We persist and reload the PrefService's PrefStores because this process
64  // deletes all empty dictionaries. The ExtensionPrefs implementation
65  // needs to be able to handle this situation.
66  if (pref_service_.get()) {
67    // The PrefService writes its persistent file on the file thread, so we
68    // need to wait for any pending I/O to complete before creating a new
69    // PrefService.
70    base::WaitableEvent io_finished(false, false);
71    pref_service_->SavePersistentPrefs();
72    EXPECT_TRUE(BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
73                                        new SignalingTask(&io_finished)));
74
75    // If the FILE thread is in fact the current thread (possible in testing
76    // scenarios), we have to ensure the task has a chance to run. If the FILE
77    // thread is a different thread, the test must ensure that thread is running
78    // (otherwise the Wait below will hang).
79    MessageLoop::current()->RunAllPending();
80
81    EXPECT_TRUE(io_finished.Wait());
82  }
83
84  extension_pref_value_map_.reset(new ExtensionPrefValueMap);
85  PrefServiceMockBuilder builder;
86  builder.WithUserFilePrefs(preferences_file_);
87  builder.WithExtensionPrefs(
88      new ExtensionPrefStore(extension_pref_value_map_.get(), false));
89  pref_service_.reset(builder.Create());
90  ExtensionPrefs::RegisterUserPrefs(pref_service_.get());
91
92  prefs_.reset(new MockExtensionPrefs(pref_service_.get(),
93                                      temp_dir_.path(),
94                                      extension_pref_value_map_.get()));
95}
96
97scoped_refptr<Extension> TestExtensionPrefs::AddExtension(std::string name) {
98  DictionaryValue dictionary;
99  dictionary.SetString(extension_manifest_keys::kName, name);
100  dictionary.SetString(extension_manifest_keys::kVersion, "0.1");
101  return AddExtensionWithManifest(dictionary, Extension::INTERNAL);
102}
103
104scoped_refptr<Extension> TestExtensionPrefs::AddExtensionWithManifest(
105    const DictionaryValue& manifest, Extension::Location location) {
106  std::string name;
107  EXPECT_TRUE(manifest.GetString(extension_manifest_keys::kName, &name));
108  FilePath path =  extensions_dir_.AppendASCII(name);
109  std::string errors;
110  scoped_refptr<Extension> extension = Extension::Create(
111      path, location, manifest, Extension::STRICT_ERROR_CHECKS, &errors);
112  EXPECT_TRUE(extension);
113  if (!extension)
114    return NULL;
115
116  EXPECT_TRUE(Extension::IdIsValid(extension->id()));
117  const bool kInitialIncognitoEnabled = false;
118  prefs_->OnExtensionInstalled(extension, Extension::ENABLED,
119                               kInitialIncognitoEnabled);
120  return extension;
121}
122
123std::string TestExtensionPrefs::AddExtensionAndReturnId(std::string name) {
124  scoped_refptr<Extension> extension(AddExtension(name));
125  return extension->id();
126}
127
128PrefService* TestExtensionPrefs::CreateIncognitoPrefService() const {
129  return pref_service_->CreateIncognitoPrefService(
130      new ExtensionPrefStore(extension_pref_value_map_.get(), true));
131}
132