• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2009 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/values.h"
6 #include "chrome/browser/extensions/extension_message_service.h"
7 #include "chrome/common/extensions/extension_messages.h"
8 #include "chrome/common/render_messages.h"
9 #include "chrome/renderer/extensions/event_bindings.h"
10 #include "chrome/renderer/extensions/renderer_extension_bindings.h"
11 #include "chrome/test/render_view_test.h"
12 #include "content/common/view_messages.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 
DispatchOnConnect(int source_port_id,const std::string & name,const std::string & tab_json)15 static void DispatchOnConnect(int source_port_id, const std::string& name,
16                               const std::string& tab_json) {
17   ListValue args;
18   args.Set(0, Value::CreateIntegerValue(source_port_id));
19   args.Set(1, Value::CreateStringValue(name));
20   args.Set(2, Value::CreateStringValue(tab_json));
21   // Testing extensionId. Set in EventBindings::HandleContextCreated.
22   // We use the same id for source & target to similute an extension "talking
23   // to itself".
24   args.Set(3, Value::CreateStringValue(EventBindings::kTestingExtensionId));
25   args.Set(4, Value::CreateStringValue(EventBindings::kTestingExtensionId));
26   RendererExtensionBindings::Invoke(
27       "", ExtensionMessageService::kDispatchOnConnect, args, NULL, GURL());
28 }
29 
DispatchOnDisconnect(int source_port_id)30 static void DispatchOnDisconnect(int source_port_id) {
31   ListValue args;
32   args.Set(0, Value::CreateIntegerValue(source_port_id));
33   RendererExtensionBindings::Invoke(
34       "", ExtensionMessageService::kDispatchOnDisconnect, args, NULL, GURL());
35 }
36 
DispatchOnMessage(const std::string & message,int source_port_id)37 static void DispatchOnMessage(const std::string& message, int source_port_id) {
38   ListValue args;
39   args.Set(0, Value::CreateStringValue(message));
40   args.Set(1, Value::CreateIntegerValue(source_port_id));
41   RendererExtensionBindings::Invoke(
42       "", ExtensionMessageService::kDispatchOnMessage, args, NULL, GURL());
43 }
44 
45 // Tests that the bindings for opening a channel to an extension and sending
46 // and receiving messages through that channel all works.
TEST_F(RenderViewTest,ExtensionMessagesOpenChannel)47 TEST_F(RenderViewTest, ExtensionMessagesOpenChannel) {
48   render_thread_.sink().ClearMessages();
49   LoadHTML("<body></body>");
50   ExecuteJavaScript(
51     "var port = chrome.extension.connect({name:'testName'});"
52     "port.onMessage.addListener(doOnMessage);"
53     "port.postMessage({message: 'content ready'});"
54     "function doOnMessage(msg, port) {"
55     "  alert('content got: ' + msg.val);"
56     "}");
57 
58   // Verify that we opened a channel and sent a message through it.
59   const IPC::Message* open_channel_msg =
60       render_thread_.sink().GetUniqueMessageMatching(
61           ExtensionHostMsg_OpenChannelToExtension::ID);
62   ASSERT_TRUE(open_channel_msg);
63   void* iter = IPC::SyncMessage::GetDataIterator(open_channel_msg);
64   ExtensionHostMsg_OpenChannelToExtension::SendParam open_params;
65   ASSERT_TRUE(IPC::ReadParam(open_channel_msg, &iter, &open_params));
66   EXPECT_EQ("testName", open_params.d);
67 
68   const IPC::Message* post_msg =
69       render_thread_.sink().GetUniqueMessageMatching(
70           ExtensionHostMsg_PostMessage::ID);
71   ASSERT_TRUE(post_msg);
72   ExtensionHostMsg_PostMessage::Param post_params;
73   ExtensionHostMsg_PostMessage::Read(post_msg, &post_params);
74   EXPECT_EQ("{\"message\":\"content ready\"}", post_params.b);
75 
76   // Now simulate getting a message back from the other side.
77   render_thread_.sink().ClearMessages();
78   const int kPortId = 0;
79   DispatchOnMessage("{\"val\": 42}", kPortId);
80 
81   // Verify that we got it.
82   const IPC::Message* alert_msg =
83       render_thread_.sink().GetUniqueMessageMatching(
84           ViewHostMsg_RunJavaScriptMessage::ID);
85   ASSERT_TRUE(alert_msg);
86   iter = IPC::SyncMessage::GetDataIterator(alert_msg);
87   ViewHostMsg_RunJavaScriptMessage::SendParam alert_param;
88   ASSERT_TRUE(IPC::ReadParam(alert_msg, &iter, &alert_param));
89   EXPECT_EQ(L"content got: 42", alert_param.a);
90 }
91 
92 // Tests that the bindings for handling a new channel connection and channel
93 // closing all works.
TEST_F(RenderViewTest,ExtensionMessagesOnConnect)94 TEST_F(RenderViewTest, ExtensionMessagesOnConnect) {
95   LoadHTML("<body></body>");
96   ExecuteJavaScript(
97     "chrome.extension.onConnect.addListener(function (port) {"
98     "  port.test = 24;"
99     "  port.onMessage.addListener(doOnMessage);"
100     "  port.onDisconnect.addListener(doOnDisconnect);"
101     "  port.postMessage({message: 'onconnect from ' + port.tab.url + "
102     "                   ' name ' + port.name});"
103     "});"
104     "function doOnMessage(msg, port) {"
105     "  alert('got: ' + msg.val);"
106     "}"
107     "function doOnDisconnect(port) {"
108     "  alert('disconnected: ' + port.test);"
109     "}");
110 
111   render_thread_.sink().ClearMessages();
112 
113   // Simulate a new connection being opened.
114   const int kPortId = 0;
115   const std::string kPortName = "testName";
116   DispatchOnConnect(kPortId, kPortName, "{\"url\":\"foo://bar\"}");
117 
118   // Verify that we handled the new connection by posting a message.
119   const IPC::Message* post_msg =
120       render_thread_.sink().GetUniqueMessageMatching(
121           ExtensionHostMsg_PostMessage::ID);
122   ASSERT_TRUE(post_msg);
123   ExtensionHostMsg_PostMessage::Param post_params;
124   ExtensionHostMsg_PostMessage::Read(post_msg, &post_params);
125   std::string expected_msg =
126       "{\"message\":\"onconnect from foo://bar name " + kPortName + "\"}";
127   EXPECT_EQ(expected_msg, post_params.b);
128 
129   // Now simulate getting a message back from the channel opener.
130   render_thread_.sink().ClearMessages();
131   DispatchOnMessage("{\"val\": 42}", kPortId);
132 
133   // Verify that we got it.
134   const IPC::Message* alert_msg =
135       render_thread_.sink().GetUniqueMessageMatching(
136           ViewHostMsg_RunJavaScriptMessage::ID);
137   ASSERT_TRUE(alert_msg);
138   void* iter = IPC::SyncMessage::GetDataIterator(alert_msg);
139   ViewHostMsg_RunJavaScriptMessage::SendParam alert_param;
140   ASSERT_TRUE(IPC::ReadParam(alert_msg, &iter, &alert_param));
141   EXPECT_EQ(L"got: 42", alert_param.a);
142 
143   // Now simulate the channel closing.
144   render_thread_.sink().ClearMessages();
145   DispatchOnDisconnect(kPortId);
146 
147   // Verify that we got it.
148   alert_msg =
149       render_thread_.sink().GetUniqueMessageMatching(
150           ViewHostMsg_RunJavaScriptMessage::ID);
151   ASSERT_TRUE(alert_msg);
152   iter = IPC::SyncMessage::GetDataIterator(alert_msg);
153   ASSERT_TRUE(IPC::ReadParam(alert_msg, &iter, &alert_param));
154   EXPECT_EQ(L"disconnected: 24", alert_param.a);
155 }
156