summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions/extension_messages_unittest.cc
blob: 5d06654ac931327cf087977725b1747e1fc87aee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/common/render_messages.h"
#include "chrome/renderer/extensions/event_bindings.h"
#include "chrome/renderer/extensions/renderer_extension_bindings.h"
#include "chrome/test/render_view_test.h"
#include "testing/gtest/include/gtest/gtest.h"

static void DispatchOnConnect(int source_port_id, const std::string& name,
                              const std::string& tab_json) {
  ListValue args;
  args.Set(0, Value::CreateIntegerValue(source_port_id));
  args.Set(1, Value::CreateStringValue(name));
  args.Set(2, Value::CreateStringValue(tab_json));
  args.Set(3, Value::CreateStringValue(""));  // extension ID is empty for tests
  args.Set(4, Value::CreateStringValue(""));  // extension ID is empty for tests
  RendererExtensionBindings::Invoke(
      ExtensionMessageService::kDispatchOnConnect, args, NULL, false);
}

static void DispatchOnDisconnect(int source_port_id) {
  ListValue args;
  args.Set(0, Value::CreateIntegerValue(source_port_id));
  RendererExtensionBindings::Invoke(
      ExtensionMessageService::kDispatchOnDisconnect, args, NULL, false);
}

static void DispatchOnMessage(const std::string& message, int source_port_id) {
  ListValue args;
  args.Set(0, Value::CreateStringValue(message));
  args.Set(1, Value::CreateIntegerValue(source_port_id));
  RendererExtensionBindings::Invoke(
      ExtensionMessageService::kDispatchOnMessage, args, NULL, false);
}

// Tests that the bindings for opening a channel to an extension and sending
// and receiving messages through that channel all works.
TEST_F(RenderViewTest, ExtensionMessagesOpenChannel) {
  render_thread_.sink().ClearMessages();
  LoadHTML("<body></body>");
  ExecuteJavaScript(
    "var port = chrome.extension.connect({name:'testName'});"
    "port.onMessage.addListener(doOnMessage);"
    "port.postMessage({message: 'content ready'});"
    "function doOnMessage(msg, port) {"
    "  alert('content got: ' + msg.val);"
    "}");

  // Verify that we opened a channel and sent a message through it.
  const IPC::Message* open_channel_msg =
      render_thread_.sink().GetUniqueMessageMatching(
          ViewHostMsg_OpenChannelToExtension::ID);
  ASSERT_TRUE(open_channel_msg);
  void* iter = IPC::SyncMessage::GetDataIterator(open_channel_msg);
  ViewHostMsg_OpenChannelToExtension::SendParam open_params;
  ASSERT_TRUE(IPC::ReadParam(open_channel_msg, &iter, &open_params));
  EXPECT_EQ("testName", open_params.d);

  const IPC::Message* post_msg =
      render_thread_.sink().GetUniqueMessageMatching(
          ViewHostMsg_ExtensionPostMessage::ID);
  ASSERT_TRUE(post_msg);
  ViewHostMsg_ExtensionPostMessage::Param post_params;
  ViewHostMsg_ExtensionPostMessage::Read(post_msg, &post_params);
  EXPECT_EQ("{\"message\":\"content ready\"}", post_params.b);

  // Now simulate getting a message back from the other side.
  render_thread_.sink().ClearMessages();
  const int kPortId = 0;
  DispatchOnMessage("{\"val\": 42}", kPortId);

  // Verify that we got it.
  const IPC::Message* alert_msg =
      render_thread_.sink().GetUniqueMessageMatching(
          ViewHostMsg_RunJavaScriptMessage::ID);
  ASSERT_TRUE(alert_msg);
  iter = IPC::SyncMessage::GetDataIterator(alert_msg);
  ViewHostMsg_RunJavaScriptMessage::SendParam alert_param;
  ASSERT_TRUE(IPC::ReadParam(alert_msg, &iter, &alert_param));
  EXPECT_EQ(L"content got: 42", alert_param.a);
}

// Tests that the bindings for handling a new channel connection and channel
// closing all works.
TEST_F(RenderViewTest, ExtensionMessagesOnConnect) {
  LoadHTML("<body></body>");
  ExecuteJavaScript(
    "chrome.extension.onConnect.addListener(function (port) {"
    "  port.test = 24;"
    "  port.onMessage.addListener(doOnMessage);"
    "  port.onDisconnect.addListener(doOnDisconnect);"
    "  port.postMessage({message: 'onconnect from ' + port.tab.url + "
    "                   ' name ' + port.name});"
    "});"
    "function doOnMessage(msg, port) {"
    "  alert('got: ' + msg.val);"
    "}"
    "function doOnDisconnect(port) {"
    "  alert('disconnected: ' + port.test);"
    "}");

  render_thread_.sink().ClearMessages();

  // Simulate a new connection being opened.
  const int kPortId = 0;
  const std::string kPortName = "testName";
  DispatchOnConnect(kPortId, kPortName, "{\"url\":\"foo://bar\"}");

  // Verify that we handled the new connection by posting a message.
  const IPC::Message* post_msg =
      render_thread_.sink().GetUniqueMessageMatching(
          ViewHostMsg_ExtensionPostMessage::ID);
  ASSERT_TRUE(post_msg);
  ViewHostMsg_ExtensionPostMessage::Param post_params;
  ViewHostMsg_ExtensionPostMessage::Read(post_msg, &post_params);
  std::string expected_msg =
      "{\"message\":\"onconnect from foo://bar name " + kPortName + "\"}";
  EXPECT_EQ(expected_msg, post_params.b);

  // Now simulate getting a message back from the channel opener.
  render_thread_.sink().ClearMessages();
  DispatchOnMessage("{\"val\": 42}", kPortId);

  // Verify that we got it.
  const IPC::Message* alert_msg =
      render_thread_.sink().GetUniqueMessageMatching(
          ViewHostMsg_RunJavaScriptMessage::ID);
  ASSERT_TRUE(alert_msg);
  void* iter = IPC::SyncMessage::GetDataIterator(alert_msg);
  ViewHostMsg_RunJavaScriptMessage::SendParam alert_param;
  ASSERT_TRUE(IPC::ReadParam(alert_msg, &iter, &alert_param));
  EXPECT_EQ(L"got: 42", alert_param.a);

  // Now simulate the channel closing.
  render_thread_.sink().ClearMessages();
  DispatchOnDisconnect(kPortId);

  // Verify that we got it.
  alert_msg =
      render_thread_.sink().GetUniqueMessageMatching(
          ViewHostMsg_RunJavaScriptMessage::ID);
  ASSERT_TRUE(alert_msg);
  iter = IPC::SyncMessage::GetDataIterator(alert_msg);
  ASSERT_TRUE(IPC::ReadParam(alert_msg, &iter, &alert_param));
  EXPECT_EQ(L"disconnected: 24", alert_param.a);
}