Make default apps cache multiprofile friendly
[chromium-blink-merge.git] / chrome / browser / extensions / extension_messages_apitest.cc
blobcf70ec604dcbcfebf15436291f6594685f90f64f
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.
5 #include "base/files/file_path.h"
6 #include "base/path_service.h"
7 #include "base/strings/string_number_conversions.h"
8 #include "base/strings/stringprintf.h"
9 #include "base/values.h"
10 #include "chrome/browser/chrome_notification_types.h"
11 #include "chrome/browser/extensions/event_router.h"
12 #include "chrome/browser/extensions/extension_apitest.h"
13 #include "chrome/browser/extensions/extension_prefs.h"
14 #include "chrome/browser/extensions/extension_system.h"
15 #include "chrome/browser/extensions/test_extension_dir.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/tabs/tab_strip_model.h"
19 #include "chrome/common/chrome_paths.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/test/base/ui_test_utils.h"
22 #include "content/public/browser/notification_registrar.h"
23 #include "content/public/browser/notification_service.h"
24 #include "content/public/test/browser_test_utils.h"
25 #include "net/dns/mock_host_resolver.h"
26 #include "net/test/embedded_test_server/embedded_test_server.h"
27 #include "url/gurl.h"
29 namespace extensions {
30 namespace {
32 class MessageSender : public content::NotificationObserver {
33 public:
34 MessageSender() {
35 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
36 content::NotificationService::AllSources());
39 private:
40 static scoped_ptr<base::ListValue> BuildEventArguments(
41 const bool last_message,
42 const std::string& data) {
43 DictionaryValue* event = new DictionaryValue();
44 event->SetBoolean("lastMessage", last_message);
45 event->SetString("data", data);
46 scoped_ptr<base::ListValue> arguments(new base::ListValue());
47 arguments->Append(event);
48 return arguments.Pass();
51 static scoped_ptr<Event> BuildEvent(scoped_ptr<base::ListValue> event_args,
52 Profile* profile,
53 GURL event_url) {
54 scoped_ptr<Event> event(new Event("test.onMessage", event_args.Pass()));
55 event->restrict_to_profile = profile;
56 event->event_url = event_url;
57 return event.Pass();
60 virtual void Observe(int type,
61 const content::NotificationSource& source,
62 const content::NotificationDetails& details) OVERRIDE {
63 EventRouter* event_router = ExtensionSystem::Get(
64 content::Source<Profile>(source).ptr())->event_router();
66 // Sends four messages to the extension. All but the third message sent
67 // from the origin http://b.com/ are supposed to arrive.
68 event_router->BroadcastEvent(BuildEvent(
69 BuildEventArguments(false, "no restriction"),
70 content::Source<Profile>(source).ptr(),
71 GURL()));
72 event_router->BroadcastEvent(BuildEvent(
73 BuildEventArguments(false, "http://a.com/"),
74 content::Source<Profile>(source).ptr(),
75 GURL("http://a.com/")));
76 event_router->BroadcastEvent(BuildEvent(
77 BuildEventArguments(false, "http://b.com/"),
78 content::Source<Profile>(source).ptr(),
79 GURL("http://b.com/")));
80 event_router->BroadcastEvent(BuildEvent(
81 BuildEventArguments(true, "last message"),
82 content::Source<Profile>(source).ptr(),
83 GURL()));
86 content::NotificationRegistrar registrar_;
89 // Tests that message passing between extensions and content scripts works.
90 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Messaging) {
91 ASSERT_TRUE(StartEmbeddedTestServer());
92 ASSERT_TRUE(RunExtensionTest("messaging/connect")) << message_;
95 // Tests that message passing from one extension to another works.
96 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MessagingExternal) {
97 ASSERT_TRUE(LoadExtension(
98 test_data_dir_.AppendASCII("..").AppendASCII("good")
99 .AppendASCII("Extensions")
100 .AppendASCII("bjafgdebaacbbbecmhlhpofkepfkgcpa")
101 .AppendASCII("1.0")));
103 ASSERT_TRUE(RunExtensionTest("messaging/connect_external")) << message_;
106 // Tests that messages with event_urls are only passed to extensions with
107 // appropriate permissions.
108 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MessagingEventURL) {
109 MessageSender sender;
110 ASSERT_TRUE(RunExtensionTest("messaging/event_url")) << message_;
113 // Tests connecting from a panel to its extension.
114 class PanelMessagingTest : public ExtensionApiTest {
115 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
116 ExtensionApiTest::SetUpCommandLine(command_line);
117 command_line->AppendSwitch(switches::kEnablePanels);
121 IN_PROC_BROWSER_TEST_F(PanelMessagingTest, MessagingPanel) {
122 ASSERT_TRUE(RunExtensionTest("messaging/connect_panel")) << message_;
125 // Tests externally_connectable between a web page and an extension.
127 // TODO(kalman): Test between extensions. This is already tested in this file,
128 // but not with externally_connectable set in the manifest.
130 // TODO(kalman): Test with host permissions.
131 class ExternallyConnectableMessagingTest : public ExtensionApiTest {
132 protected:
133 // Result codes from the test. These must match up with |results| in
134 // c/t/d/extensions/api_test/externally_connectable/assertions.json.
135 enum Result {
136 OK = 0,
137 NAMESPACE_NOT_DEFINED = 1,
138 FUNCTION_NOT_DEFINED = 2,
139 COULD_NOT_ESTABLISH_CONNECTION_ERROR = 3,
140 OTHER_ERROR = 4,
141 INCORRECT_RESPONSE_SENDER = 5,
142 INCORRECT_RESPONSE_MESSAGE = 6,
145 bool AppendIframe(const GURL& src) {
146 bool result;
147 CHECK(content::ExecuteScriptAndExtractBool(
148 browser()->tab_strip_model()->GetActiveWebContents(),
149 "actions.appendIframe('" + src.spec() + "');", &result));
150 return result;
153 Result CanConnectAndSendMessages(const std::string& extension_id) {
154 return CanConnectAndSendMessages(browser(), extension_id, "");
157 Result CanConnectAndSendMessages(const std::string& extension_id,
158 const char* frame_xpath,
159 const char* message) {
160 return CanConnectAndSendMessages(browser(), extension_id, frame_xpath,
161 message);
164 Result CanConnectAndSendMessages(Browser* browser,
165 const std::string& extension_id) {
166 return CanConnectAndSendMessages(browser, extension_id, "");
169 Result CanConnectAndSendMessages(const std::string& extension_id,
170 const char* frame_xpath) {
171 return CanConnectAndSendMessages(browser(), extension_id, frame_xpath);
174 Result CanConnectAndSendMessages(Browser* browser,
175 const std::string& extension_id,
176 const char* frame_xpath,
177 const char* message = NULL) {
178 int result;
179 std::string args = "'" + extension_id + "'";
180 if (message)
181 args += std::string(", '") + message + "'";
182 CHECK(content::ExecuteScriptInFrameAndExtractInt(
183 browser->tab_strip_model()->GetActiveWebContents(),
184 frame_xpath,
185 base::StringPrintf("assertions.canConnectAndSendMessages(%s)",
186 args.c_str()).c_str(),
187 &result));
188 return static_cast<Result>(result);
191 testing::AssertionResult AreAnyNonWebApisDefined() {
192 return AreAnyNonWebApisDefined("");
195 testing::AssertionResult AreAnyNonWebApisDefined(const char* frame_xpath) {
196 // All runtime API methods are non-web except for sendRequest and connect.
197 const char* non_messaging_apis[] = {
198 "getBackgroundPage",
199 "getManifest",
200 "getURL",
201 "reload",
202 "requestUpdateCheck",
203 "connectNative",
204 "sendNativeMessage",
205 "onStartup",
206 "onInstalled",
207 "onSuspend",
208 "onSuspendCanceled",
209 "onUpdateAvailable",
210 "onBrowserUpdateAvailable",
211 "onConnect",
212 "onConnectExternal",
213 "onMessage",
214 "onMessageExternal",
215 "onRestartRequired",
216 "id",
219 // Turn the array into a JS array, which effectively gets eval()ed.
220 std::string as_js_array;
221 for (size_t i = 0; i < arraysize(non_messaging_apis); ++i) {
222 as_js_array += as_js_array.empty() ? "[" : ",";
223 as_js_array += base::StringPrintf("'%s'", non_messaging_apis[i]);
225 as_js_array += "]";
227 bool any_defined;
228 CHECK(content::ExecuteScriptInFrameAndExtractBool(
229 browser()->tab_strip_model()->GetActiveWebContents(),
230 frame_xpath,
231 "assertions.areAnyRuntimePropertiesDefined(" + as_js_array + ")",
232 &any_defined));
233 return any_defined ?
234 testing::AssertionSuccess() : testing::AssertionFailure();
237 GURL GetURLForPath(const std::string& host, const std::string& path) {
238 std::string port = base::IntToString(embedded_test_server()->port());
239 GURL::Replacements replacements;
240 replacements.SetHostStr(host);
241 replacements.SetPortStr(port);
242 return embedded_test_server()->GetURL(path).ReplaceComponents(replacements);
245 GURL chromium_org_url() {
246 return GetURLForPath("www.chromium.org", "/chromium.org.html");
249 GURL google_com_url() {
250 return GetURLForPath("www.google.com", "/google.com.html");
253 const Extension* LoadChromiumConnectableExtension() {
254 const Extension* extension =
255 LoadExtensionIntoDir(&web_connectable_dir_, base::StringPrintf(
257 " \"name\": \"chromium_connectable\","
258 " %s,"
259 " \"externally_connectable\": {"
260 " \"matches\": [\"*://*.chromium.org:*/*\"]"
261 " }"
262 "}",
263 common_manifest()));
264 CHECK(extension);
265 return extension;
268 const Extension* LoadNotConnectableExtension() {
269 const Extension* extension =
270 LoadExtensionIntoDir(&not_connectable_dir_, base::StringPrintf(
272 " \"name\": \"not_connectable\","
273 " %s"
274 "}",
275 common_manifest()));
276 CHECK(extension);
277 return extension;
280 void InitializeTestServer() {
281 base::FilePath test_data;
282 EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data));
283 embedded_test_server()->ServeFilesFromDirectory(test_data.AppendASCII(
284 "extensions/api_test/messaging/externally_connectable/sites"));
285 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
286 host_resolver()->AddRule("*", embedded_test_server()->base_url().host());
289 const char* close_background_message() {
290 return "closeBackgroundPage";
293 private:
294 const Extension* LoadExtensionIntoDir(TestExtensionDir* dir,
295 const std::string& manifest) {
296 dir->WriteManifest(manifest);
297 dir->WriteFile(FILE_PATH_LITERAL("background.js"),
298 base::StringPrintf(
299 "function maybeClose(message) {\n"
300 " if (message.indexOf('%s') >= 0)\n"
301 " window.setTimeout(function() { window.close() }, 0);\n"
302 "}\n"
303 "chrome.runtime.onMessageExternal.addListener(\n"
304 " function(message, sender, reply) {\n"
305 " reply({ message: message, sender: sender });\n"
306 " maybeClose(message);\n"
307 "});\n"
308 "chrome.runtime.onConnectExternal.addListener(function(port) {\n"
309 " port.onMessage.addListener(function(message) {\n"
310 " port.postMessage({ message: message, sender: port.sender });\n"
311 " maybeClose(message);\n"
312 " });\n"
313 "});\n",
314 close_background_message()));
315 return LoadExtension(dir->unpacked_path());
318 const char* common_manifest() {
319 return "\"version\": \"1.0\","
320 "\"background\": {"
321 " \"scripts\": [\"background.js\"],"
322 " \"persistent\": false"
323 "},"
324 "\"manifest_version\": 2";
327 TestExtensionDir web_connectable_dir_;
328 TestExtensionDir not_connectable_dir_;
331 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest, NotInstalled) {
332 InitializeTestServer();
334 const char kFakeId[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
336 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
337 EXPECT_EQ(NAMESPACE_NOT_DEFINED, CanConnectAndSendMessages(kFakeId));
338 EXPECT_FALSE(AreAnyNonWebApisDefined());
340 ui_test_utils::NavigateToURL(browser(), google_com_url());
341 EXPECT_EQ(NAMESPACE_NOT_DEFINED, CanConnectAndSendMessages(kFakeId));
342 EXPECT_FALSE(AreAnyNonWebApisDefined());
345 // Tests two extensions on the same sites: one web connectable, one not.
346 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
347 WebConnectableAndNotConnectable) {
348 InitializeTestServer();
350 // Install the web connectable extension. chromium.org can connect to it,
351 // google.com can't.
352 const Extension* chromium_connectable = LoadChromiumConnectableExtension();
354 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
355 EXPECT_EQ(OK, CanConnectAndSendMessages(chromium_connectable->id()));
356 EXPECT_FALSE(AreAnyNonWebApisDefined());
358 ui_test_utils::NavigateToURL(browser(), google_com_url());
359 EXPECT_EQ(NAMESPACE_NOT_DEFINED,
360 CanConnectAndSendMessages(chromium_connectable->id()));
361 EXPECT_FALSE(AreAnyNonWebApisDefined());
363 // Install the non-connectable extension. Nothing can connect to it.
364 const Extension* not_connectable = LoadNotConnectableExtension();
366 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
367 // Namespace will be defined here because |chromium_connectable| can connect
368 // to it - so this will be the "cannot establish connection" error.
369 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
370 CanConnectAndSendMessages(not_connectable->id()));
371 EXPECT_FALSE(AreAnyNonWebApisDefined());
373 ui_test_utils::NavigateToURL(browser(), google_com_url());
374 EXPECT_EQ(NAMESPACE_NOT_DEFINED,
375 CanConnectAndSendMessages(not_connectable->id()));
376 EXPECT_FALSE(AreAnyNonWebApisDefined());
379 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
380 BackgroundPageClosesOnMessageReceipt) {
381 InitializeTestServer();
383 // Install the web connectable extension.
384 const Extension* chromium_connectable = LoadChromiumConnectableExtension();
386 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
387 // If the background page closes after receipt of the message, it will still
388 // reply to this message...
389 EXPECT_EQ(OK, CanConnectAndSendMessages(chromium_connectable->id(),
391 close_background_message()));
392 // and be re-opened by receipt of a subsequent message.
393 EXPECT_EQ(OK, CanConnectAndSendMessages(chromium_connectable->id()));
396 // Tests that enabling and disabling an extension makes the runtime bindings
397 // appear and disappear.
399 // TODO(kalman): Test with multiple extensions that can be accessed by the same
400 // host.
401 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
402 EnablingAndDisabling) {
403 InitializeTestServer();
405 const Extension* chromium_connectable = LoadChromiumConnectableExtension();
406 const Extension* not_connectable = LoadNotConnectableExtension();
408 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
409 EXPECT_EQ(OK, CanConnectAndSendMessages(chromium_connectable->id()));
410 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
411 CanConnectAndSendMessages(not_connectable->id()));
413 DisableExtension(chromium_connectable->id());
414 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
415 CanConnectAndSendMessages(chromium_connectable->id()));
417 EnableExtension(chromium_connectable->id());
418 EXPECT_EQ(OK, CanConnectAndSendMessages(chromium_connectable->id()));
419 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
420 CanConnectAndSendMessages(not_connectable->id()));
423 // Tests connection from incognito tabs. Spanning mode only.
425 // TODO(kalman): ensure that we exercise split vs spanning incognito logic
426 // somewhere. This is a test that should be shared with the content script logic
427 // so it's not really our specific concern for web connectable.
428 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest, FromIncognito) {
429 InitializeTestServer();
431 const Extension* chromium_connectable = LoadChromiumConnectableExtension();
433 Browser* incognito_browser = ui_test_utils::OpenURLOffTheRecord(
434 profile()->GetOffTheRecordProfile(),
435 chromium_org_url());
437 // No connection because incognito enabled hasn't been set.
438 const std::string& id = chromium_connectable->id();
439 EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
440 CanConnectAndSendMessages(incognito_browser, id));
442 // Then yes.
443 ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(id, true);
444 EXPECT_EQ(OK, CanConnectAndSendMessages(incognito_browser, id));
447 // Tests a connection from an iframe within a tab which doesn't have
448 // permission. Iframe should work.
449 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
450 FromIframeWithPermission) {
451 InitializeTestServer();
453 const Extension* extension = LoadChromiumConnectableExtension();
455 ui_test_utils::NavigateToURL(browser(), google_com_url());
456 EXPECT_EQ(NAMESPACE_NOT_DEFINED, CanConnectAndSendMessages(extension->id()));
457 EXPECT_FALSE(AreAnyNonWebApisDefined());
459 ASSERT_TRUE(AppendIframe(chromium_org_url()));
461 const char* frame_xpath = "//iframe[1]";
462 EXPECT_EQ(OK, CanConnectAndSendMessages(extension->id(), frame_xpath));
463 EXPECT_FALSE(AreAnyNonWebApisDefined(frame_xpath));
466 // Tests connection from an iframe without permission within a tab that does.
467 // Iframe shouldn't work.
468 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
469 FromIframeWithoutPermission) {
470 InitializeTestServer();
472 const Extension* extension = LoadChromiumConnectableExtension();
474 ui_test_utils::NavigateToURL(browser(), chromium_org_url());
475 EXPECT_EQ(OK, CanConnectAndSendMessages(extension->id()));
476 EXPECT_FALSE(AreAnyNonWebApisDefined());
478 ASSERT_TRUE(AppendIframe(google_com_url()));
480 const char* frame_xpath = "//iframe[1]";
481 EXPECT_EQ(NAMESPACE_NOT_DEFINED,
482 CanConnectAndSendMessages(extension->id(), frame_xpath));
483 EXPECT_FALSE(AreAnyNonWebApisDefined(frame_xpath));
486 } // namespace
487 }; // namespace extensions