summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authoraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-11 03:52:30 +0000
committeraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-11 03:52:30 +0000
commit6e67b73e35b3cd2946b86bb2e9766cf59026247c (patch)
tree6fd9864a011f9a6caa897dd68a2604cd4d0c9e1a /chrome/browser
parent2e49fc3cceaa87f1472fae156271e594cfa140d3 (diff)
downloadchromium_src-6e67b73e35b3cd2946b86bb2e9766cf59026247c.zip
chromium_src-6e67b73e35b3cd2946b86bb2e9766cf59026247c.tar.gz
chromium_src-6e67b73e35b3cd2946b86bb2e9766cf59026247c.tar.bz2
Add support to the automation provider to test sending browser
events to extensions. Implements an initial test that send all known window, tab, page action, and bookmark events and makes sure the extension received them. Original review: http://codereview.chromium.org/119325 Review URL: http://codereview.chromium.org/123010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18148 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rwxr-xr-xchrome/browser/automation/automation_provider.cc53
-rw-r--r--chrome/browser/automation/automation_provider.h6
-rw-r--r--chrome/browser/automation/extension_automation_constants.cc1
-rw-r--r--chrome/browser/automation/extension_automation_constants.h3
-rw-r--r--chrome/browser/extensions/extension_uitest.cc169
5 files changed, 230 insertions, 2 deletions
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc
index dcb6afe..4b2510a 100755
--- a/chrome/browser/automation/automation_provider.cc
+++ b/chrome/browser/automation/automation_provider.cc
@@ -6,6 +6,7 @@
#include "app/message_box_flags.h"
#include "base/file_version_info.h"
+#include "base/json_reader.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/stl_util-inl.h"
@@ -17,6 +18,7 @@
#include "chrome/browser/app_modal_dialog_queue.h"
#include "chrome/browser/automation/automation_extension_function.h"
#include "chrome/browser/automation/automation_provider_list.h"
+#include "chrome/browser/automation/extension_automation_constants.h"
#include "chrome/browser/automation/extension_port_container.h"
#include "chrome/browser/automation/url_request_failed_dns_job.h"
#include "chrome/browser/automation/url_request_mock_http_job.h"
@@ -26,6 +28,7 @@
#include "chrome/browser/dom_operation_notification_details.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/download/download_shelf.h"
+#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/browser/find_bar.h"
#include "chrome/browser/find_bar_controller.h"
#include "chrome/browser/find_notification_details.h"
@@ -2731,13 +2734,18 @@ void AutomationProvider::OnMessageFromExternalHost(int handle,
}
if (AutomationExtensionFunction::InterceptMessageFromExternalHost(
- view_host, message, origin, target)) {
+ view_host, message, origin, target)) {
// Message was diverted.
return;
}
if (ExtensionPortContainer::InterceptMessageFromExternalHost(message,
- origin, target, this, view_host, handle)) {
+ origin, target, this, view_host, handle)) {
+ // Message was diverted.
+ return;
+ }
+
+ if (InterceptBrowserEventMessageFromExternalHost(message, origin, target)) {
// Message was diverted.
return;
}
@@ -2745,6 +2753,47 @@ void AutomationProvider::OnMessageFromExternalHost(int handle,
view_host->ForwardMessageFromExternalHost(message, origin, target);
}
}
+
+bool AutomationProvider::InterceptBrowserEventMessageFromExternalHost(
+ const std::string& message, const std::string& origin,
+ const std::string& target) {
+ if (target !=
+ extension_automation_constants::kAutomationBrowserEventRequestTarget)
+ return false;
+
+ if (origin != extension_automation_constants::kAutomationOrigin) {
+ LOG(WARNING) << "Wrong origin on automation browser event " << origin;
+ return false;
+ }
+
+ // The message is a JSON-encoded array with two elements, both strings. The
+ // first is the name of the event to dispatch. The second is a JSON-encoding
+ // of the arguments specific to that event.
+ scoped_ptr<Value> message_value(JSONReader::Read(message, false));
+ if (!message_value.get() || !message_value->IsType(Value::TYPE_LIST)) {
+ LOG(WARNING) << "Invalid browser event specified through automation";
+ return false;
+ }
+
+ const ListValue* args = static_cast<const ListValue*>(message_value.get());
+
+ std::string event_name;
+ if (!args->GetString(0, &event_name)) {
+ LOG(WARNING) << "No browser event name specified through automation";
+ return false;
+ }
+
+ std::string json_args;
+ if (!args->GetString(1, &json_args)) {
+ LOG(WARNING) << "No browser event args specified through automation";
+ return false;
+ }
+
+ ExtensionMessageService::GetInstance(profile()->GetRequestContext())->
+ DispatchEventToRenderers(event_name.c_str(), json_args);
+
+ return true;
+}
#endif // defined(OS_WIN) || defined(OS_LINUX)
TabContents* AutomationProvider::GetTabContentsForHandle(
diff --git a/chrome/browser/automation/automation_provider.h b/chrome/browser/automation/automation_provider.h
index 174faff..bfbae83 100644
--- a/chrome/browser/automation/automation_provider.h
+++ b/chrome/browser/automation/automation_provider.h
@@ -469,6 +469,12 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>,
bool success,
HistoryService::RedirectList* redirects);
+ // Determine if the message from the external host represents a browser
+ // event, and if so dispatch it.
+ bool InterceptBrowserEventMessageFromExternalHost(const std::string& message,
+ const std::string& origin,
+ const std::string& target);
+
typedef ObserverList<NotificationObserver> NotificationObserverList;
typedef std::map<NavigationController*, LoginHandler*> LoginHandlerMap;
typedef std::map<int, ExtensionPortContainer*> PortContainerMap;
diff --git a/chrome/browser/automation/extension_automation_constants.cc b/chrome/browser/automation/extension_automation_constants.cc
index 425c634..6b99a41 100644
--- a/chrome/browser/automation/extension_automation_constants.cc
+++ b/chrome/browser/automation/extension_automation_constants.cc
@@ -24,5 +24,6 @@ const wchar_t kAutomationPortIdKey[] = L"portid";
const char kAutomationPortRequestTarget[] = "__priv_prtreq";
const char kAutomationPortResponseTarget[] = "__priv_prtres";
+const char kAutomationBrowserEventRequestTarget[] = "__priv_evtreq";
} // namespace extension_automation_constants
diff --git a/chrome/browser/automation/extension_automation_constants.h b/chrome/browser/automation/extension_automation_constants.h
index 4725bf3..06bd97d 100644
--- a/chrome/browser/automation/extension_automation_constants.h
+++ b/chrome/browser/automation/extension_automation_constants.h
@@ -35,6 +35,9 @@ extern const char kAutomationPortRequestTarget[];
// All external port message responses have this target.
extern const char kAutomationPortResponseTarget[];
+// All external browser events have this target.
+extern const char kAutomationBrowserEventRequestTarget[];
+
// The command codes for our private port protocol.
enum PrivatePortCommand {
OPEN_CHANNEL = 0,
diff --git a/chrome/browser/extensions/extension_uitest.cc b/chrome/browser/extensions/extension_uitest.cc
index 102bbac..9180966 100644
--- a/chrome/browser/extensions/extension_uitest.cc
+++ b/chrome/browser/extensions/extension_uitest.cc
@@ -20,6 +20,8 @@ static const char kTestDirectorySimpleApiCall[] =
"extensions/uitest/simple_api_call";
static const char kTestDirectoryRoundtripApiCall[] =
"extensions/uitest/roundtrip_api_call";
+static const char kTestDirectoryBrowserEvent[] =
+ "extensions/uitest/event_sink";
// Base class to test extensions almost end-to-end by including browser
// startup, manifest parsing, and the actual process model in the
@@ -279,4 +281,171 @@ TEST_F(RoundtripApiCallExtensionTest, RunTest) {
}
#endif // defined(OS_WIN)
+// This proxy is specific to BrowserEventExtensionTest.
+class BrowserEventAutomationProxy : public MultiMessageAutomationProxy {
+ public:
+ explicit BrowserEventAutomationProxy(int execution_timeout)
+ : MultiMessageAutomationProxy(execution_timeout),
+ tab_(NULL) {
+ }
+
+ // Must set before initiating test.
+ TabProxy* tab_;
+
+ // Counts the number of times we got a given event.
+ std::map<std::string, int> event_count_;
+
+ // Array containing the names of the events to fire to the extension.
+ static const char* event_names_[];
+
+ protected:
+ // Process a message received from the test extension.
+ virtual void HandleMessageFromChrome();
+
+ // Fire an event of the given name to the test extension.
+ void FireEvent(const char* event_name);
+};
+
+const char* BrowserEventAutomationProxy::event_names_[] = {
+ // Window events.
+ "window-created",
+ "window-removed",
+ "window-focus-changed",
+
+ // Tab events.
+ "tab-created",
+ "tab-updated",
+ "tab-moved",
+ "tab-selection-changed",
+ "tab-attached",
+ "tab-detached",
+ "tab-removed",
+
+ // Page action events.
+ "page-action-executed",
+
+ // Bookmark events.
+ "bookmark-added",
+ "bookmark-removed",
+ "bookmark-changed",
+ "bookmark-moved",
+ "bookmark-children-reordered",
+};
+
+void BrowserEventAutomationProxy::HandleMessageFromChrome() {
+ namespace keys = extension_automation_constants;
+ ASSERT_TRUE(tab_ != NULL);
+
+ std::string message(message());
+ std::string origin(origin());
+ std::string target(target());
+
+ ASSERT_TRUE(message.length() > 0);
+ ASSERT_STREQ(keys::kAutomationOrigin, origin.c_str());
+
+ if (target == keys::kAutomationRequestTarget) {
+ // This should be a request for the current window. We don't need to
+ // respond, as this is used only as an indication that the extension
+ // page is now loaded.
+ scoped_ptr<Value> message_value(JSONReader::Read(message, false));
+ ASSERT_TRUE(message_value->IsType(Value::TYPE_DICTIONARY));
+ DictionaryValue* message_dict =
+ reinterpret_cast<DictionaryValue*>(message_value.get());
+
+ std::string name;
+ message_dict->GetString(keys::kAutomationNameKey, &name);
+ ASSERT_STREQ(name.c_str(), "GetCurrentWindow");
+
+ // Send an OpenChannelToExtension message to chrome. Note: the JSON
+ // reader expects quoted property keys.
+ tab_->HandleMessageFromExternalHost(
+ "{\"rqid\":0, \"extid\": \"88884444789ABCDEF0123456789ABCDEF0123456\","
+ " \"connid\": 1}",
+ keys::kAutomationOrigin,
+ keys::kAutomationPortRequestTarget);
+ } else if (target == keys::kAutomationPortResponseTarget) {
+ // This is a response to the open channel request. This means we know
+ // that the port is ready to send us messages. Fire all the events now.
+ for (int i = 0; i < arraysize(event_names_); ++i) {
+ FireEvent(event_names_[i]);
+ }
+ } else if (target == keys::kAutomationPortRequestTarget) {
+ // This is the test extension calling us back. Make sure its telling
+ // us that it received an event. We do this by checking to see if the
+ // message is a simple string of one of the event names that is fired.
+ //
+ // There is a special message "ACK" which means that the extension
+ // received the port connection. This is not an event response and
+ // should happen before all events.
+ scoped_ptr<Value> message_value(JSONReader::Read(message, false));
+ ASSERT_TRUE(message_value->IsType(Value::TYPE_DICTIONARY));
+ DictionaryValue* message_dict =
+ reinterpret_cast<DictionaryValue*>(message_value.get());
+
+ std::string event_name;
+ message_dict->GetString(L"data", &event_name);
+ if (event_name == "\"ACK\"") {
+ ASSERT_EQ(0, event_count_.size());
+ } else {
+ ++event_count_[event_name];
+ }
+ }
+}
+
+void BrowserEventAutomationProxy::FireEvent(const char* event_name) {
+ namespace keys = extension_automation_constants;
+
+ // Build the event message to send to the extension. The only important
+ // part is the name, as the payload is not used by the test extension.
+ std::string message;
+ message += "[\"";
+ message += event_name;
+ message += "\", \"[]\"]";
+
+ tab_->HandleMessageFromExternalHost(
+ message,
+ keys::kAutomationOrigin,
+ keys::kAutomationBrowserEventRequestTarget);
+}
+
+class BrowserEventExtensionTest
+ : public ExtensionUITest<
+ CustomAutomationProxyTest<BrowserEventAutomationProxy>> {
+ public:
+ BrowserEventExtensionTest()
+ : ExtensionUITest<
+ CustomAutomationProxyTest<
+ BrowserEventAutomationProxy> >(kTestDirectoryBrowserEvent) {
+ }
+
+ void DoAdditionalPreNavigateSetup(TabProxy* tab) {
+ BrowserEventAutomationProxy* proxy =
+ static_cast<BrowserEventAutomationProxy*>(automation());
+ proxy->tab_ = tab;
+ }
+
+ private:
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserEventExtensionTest);
+};
+
+// TODO(port) Should become portable once
+// ExternalTabMessageLoop is ported.
+#if defined(OS_WIN)
+TEST_F(BrowserEventExtensionTest, RunTest) {
+ TestWithURL(GURL(
+ "chrome-extension://88884444789ABCDEF0123456789ABCDEF0123456/test.html"));
+ BrowserEventAutomationProxy* proxy =
+ static_cast<BrowserEventAutomationProxy*>(automation());
+
+ EXPECT_EQ(arraysize(BrowserEventAutomationProxy::event_names_),
+ proxy->event_count_.size());
+ for (std::map<std::string, int>::iterator i = proxy->event_count_.begin();
+ i != proxy->event_count_.end(); ++i) {
+ const std::pair<std::string, int>& value = *i;
+ ASSERT_EQ(1, value.second);
+ }
+}
+#endif // defined(OS_WIN)
+
} // namespace