extension_info_map_unittest.cc revision ca12bfac764ba476d6cd062bf1dde12cc64c3f40
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/json/json_file_value_serializer.h"
6#include "base/message_loop/message_loop.h"
7#include "base/path_service.h"
8#include "chrome/browser/extensions/extension_info_map.h"
9#include "chrome/common/chrome_paths.h"
10#include "chrome/common/extensions/extension.h"
11#include "chrome/common/extensions/extension_manifest_constants.h"
12#include "content/public/test/test_browser_thread.h"
13#include "testing/gtest/include/gtest/gtest.h"
14
15using content::BrowserThread;
16using extensions::APIPermission;
17using extensions::Extension;
18using extensions::Manifest;
19
20namespace keys = extension_manifest_keys;
21
22namespace {
23
24class ExtensionInfoMapTest : public testing::Test {
25 public:
26  ExtensionInfoMapTest()
27      : ui_thread_(BrowserThread::UI, &message_loop_),
28        io_thread_(BrowserThread::IO, &message_loop_) {
29  }
30
31 private:
32  base::MessageLoop message_loop_;
33  content::TestBrowserThread ui_thread_;
34  content::TestBrowserThread io_thread_;
35};
36
37// Returns a barebones test Extension object with the given name.
38static scoped_refptr<Extension> CreateExtension(const std::string& name) {
39#if defined(OS_WIN)
40  base::FilePath path(FILE_PATH_LITERAL("c:\\foo"));
41#elif defined(OS_POSIX)
42  base::FilePath path(FILE_PATH_LITERAL("/foo"));
43#endif
44
45  DictionaryValue manifest;
46  manifest.SetString(keys::kVersion, "1.0.0.0");
47  manifest.SetString(keys::kName, name);
48
49  std::string error;
50  scoped_refptr<Extension> extension = Extension::Create(
51      path.AppendASCII(name), Manifest::INVALID_LOCATION, manifest,
52      Extension::NO_FLAGS, &error);
53  EXPECT_TRUE(extension.get()) << error;
54
55  return extension;
56}
57
58static scoped_refptr<Extension> LoadManifest(const std::string& dir,
59                                             const std::string& test_file) {
60  base::FilePath path;
61  PathService::Get(chrome::DIR_TEST_DATA, &path);
62  path = path.AppendASCII("extensions")
63             .AppendASCII(dir)
64             .AppendASCII(test_file);
65
66  JSONFileValueSerializer serializer(path);
67  scoped_ptr<Value> result(serializer.Deserialize(NULL, NULL));
68  if (!result)
69    return NULL;
70
71  std::string error;
72  scoped_refptr<Extension> extension = Extension::Create(
73      path, Manifest::INVALID_LOCATION,
74      *static_cast<DictionaryValue*>(result.get()),
75      Extension::NO_FLAGS, &error);
76  EXPECT_TRUE(extension.get()) << error;
77
78  return extension;
79}
80
81// Test that the ExtensionInfoMap handles refcounting properly.
82TEST_F(ExtensionInfoMapTest, RefCounting) {
83  scoped_refptr<ExtensionInfoMap> info_map(new ExtensionInfoMap());
84
85  // New extensions should have a single reference holding onto them.
86  scoped_refptr<Extension> extension1(CreateExtension("extension1"));
87  scoped_refptr<Extension> extension2(CreateExtension("extension2"));
88  scoped_refptr<Extension> extension3(CreateExtension("extension3"));
89  EXPECT_TRUE(extension1->HasOneRef());
90  EXPECT_TRUE(extension2->HasOneRef());
91  EXPECT_TRUE(extension3->HasOneRef());
92
93  // Add a ref to each extension and give it to the info map.
94  info_map->AddExtension(extension1.get(), base::Time(), false);
95  info_map->AddExtension(extension2.get(), base::Time(), false);
96  info_map->AddExtension(extension3.get(), base::Time(), false);
97
98  // Release extension1, and the info map should have the only ref.
99  const Extension* weak_extension1 = extension1.get();
100  extension1 = NULL;
101  EXPECT_TRUE(weak_extension1->HasOneRef());
102
103  // Remove extension2, and the extension2 object should have the only ref.
104  info_map->RemoveExtension(
105      extension2->id(), extension_misc::UNLOAD_REASON_UNINSTALL);
106  EXPECT_TRUE(extension2->HasOneRef());
107
108  // Delete the info map, and the extension3 object should have the only ref.
109  info_map = NULL;
110  EXPECT_TRUE(extension3->HasOneRef());
111}
112
113// Tests that we can query a few extension properties from the ExtensionInfoMap.
114TEST_F(ExtensionInfoMapTest, Properties) {
115  scoped_refptr<ExtensionInfoMap> info_map(new ExtensionInfoMap());
116
117  scoped_refptr<Extension> extension1(CreateExtension("extension1"));
118  scoped_refptr<Extension> extension2(CreateExtension("extension2"));
119
120  info_map->AddExtension(extension1.get(), base::Time(), false);
121  info_map->AddExtension(extension2.get(), base::Time(), false);
122
123  EXPECT_EQ(2u, info_map->extensions().size());
124  EXPECT_EQ(extension1.get(), info_map->extensions().GetByID(extension1->id()));
125  EXPECT_EQ(extension2.get(), info_map->extensions().GetByID(extension2->id()));
126}
127
128// Tests CheckURLAccessToExtensionPermission given both extension and app URLs.
129TEST_F(ExtensionInfoMapTest, CheckPermissions) {
130  scoped_refptr<ExtensionInfoMap> info_map(new ExtensionInfoMap());
131
132  scoped_refptr<Extension> app(LoadManifest("manifest_tests",
133                                            "valid_app.json"));
134  scoped_refptr<Extension> extension(LoadManifest("manifest_tests",
135                                                  "tabs_extension.json"));
136
137  GURL app_url("http://www.google.com/mail/foo.html");
138  ASSERT_TRUE(app->is_app());
139  ASSERT_TRUE(app->web_extent().MatchesURL(app_url));
140
141  info_map->AddExtension(app.get(), base::Time(), false);
142  info_map->AddExtension(extension.get(), base::Time(), false);
143
144  // The app should have the notifications permission, either from a
145  // chrome-extension URL or from its web extent.
146  const Extension* match = info_map->extensions().GetExtensionOrAppByURL(
147      app->GetResourceURL("a.html"));
148  EXPECT_TRUE(match &&
149      match->HasAPIPermission(APIPermission::kNotification));
150  match = info_map->extensions().GetExtensionOrAppByURL(app_url);
151  EXPECT_TRUE(match &&
152      match->HasAPIPermission(APIPermission::kNotification));
153  EXPECT_FALSE(match &&
154      match->HasAPIPermission(APIPermission::kTab));
155
156  // The extension should have the tabs permission.
157  match = info_map->extensions().GetExtensionOrAppByURL(
158      extension->GetResourceURL("a.html"));
159  EXPECT_TRUE(match &&
160      match->HasAPIPermission(APIPermission::kTab));
161  EXPECT_FALSE(match &&
162      match->HasAPIPermission(APIPermission::kNotification));
163
164  // Random URL should not have any permissions.
165  GURL evil_url("http://evil.com/a.html");
166  match = info_map->extensions().GetExtensionOrAppByURL(evil_url);
167  EXPECT_FALSE(match);
168}
169
170}  // namespace
171