summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorrafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-16 23:13:55 +0000
committerrafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-16 23:13:55 +0000
commita902489dc0a391b0bfa92b8a172aa6369b568436 (patch)
treedf5210dd269a1b5ba952a66f40e1740592da1cf6 /chrome
parent560541ea404af23c1e91f0ef83b4ed11022a84c7 (diff)
downloadchromium_src-a902489dc0a391b0bfa92b8a172aa6369b568436.zip
chromium_src-a902489dc0a391b0bfa92b8a172aa6369b568436.tar.gz
chromium_src-a902489dc0a391b0bfa92b8a172aa6369b568436.tar.bz2
submitted on behalf of rogerta (Roger Tawa).
Original issue: http://codereview.chromium.org/119325 r=rafaelw,Jói,stoyan,aa Review URL: http://codereview.chromium.org/125206 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18555 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-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.cc178
-rwxr-xr-xchrome/test/data/extensions/uitest/event_sink/manifest.json5
-rwxr-xr-xchrome/test/data/extensions/uitest/event_sink/test.html79
7 files changed, 323 insertions, 2 deletions
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc
index 9445b92..7cde178 100755
--- a/chrome/browser/automation/automation_provider.cc
+++ b/chrome/browser/automation/automation_provider.cc
@@ -7,6 +7,7 @@
#include "app/l10n_util.h"
#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"
@@ -18,6 +19,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"
@@ -28,6 +30,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"
@@ -2682,13 +2685,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;
}
@@ -2696,6 +2704,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 ccf580d..6701655 100644
--- a/chrome/browser/automation/automation_provider.h
+++ b/chrome/browser/automation/automation_provider.h
@@ -462,6 +462,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 4f5d870..359ba9a 100644
--- a/chrome/browser/extensions/extension_uitest.cc
+++ b/chrome/browser/extensions/extension_uitest.cc
@@ -9,6 +9,7 @@
#include "base/values.h"
#include "chrome/browser/automation/extension_automation_constants.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension.h"
#include "chrome/test/automation/automation_proxy_uitest.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
@@ -20,6 +21,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
@@ -280,4 +283,179 @@ 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. See the comment in
+ // TEST_F(BrowserEventExtensionTest, RunTest) to understand where the
+ // extension Id comes from.
+ tab_->HandleMessageFromExternalHost(
+ "{\"rqid\":0, \"extid\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\","
+ " \"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) {
+ // The extension for this test does not specify a "key" property in its
+ // manifest file. Therefore, the extension system will automatically assign
+ // it an Id. To make this test consistent and non-flaky, the genetated Id
+ // counter is reset before the test so that we can hardcode the first Id
+ // that will be generated.
+ Extension::ResetGeneratedIdCounter();
+ TestWithURL(GURL(
+ "chrome-extension://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/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
diff --git a/chrome/test/data/extensions/uitest/event_sink/manifest.json b/chrome/test/data/extensions/uitest/event_sink/manifest.json
new file mode 100755
index 0000000..830243d
--- /dev/null
+++ b/chrome/test/data/extensions/uitest/event_sink/manifest.json
@@ -0,0 +1,5 @@
+{
+ "version": "1.0.0.0",
+ "name": "Browser Event Sink Test Extension",
+ "description": "An extension UITest for testing the sending of browser events."
+}
diff --git a/chrome/test/data/extensions/uitest/event_sink/test.html b/chrome/test/data/extensions/uitest/event_sink/test.html
new file mode 100755
index 0000000..2520d48
--- /dev/null
+++ b/chrome/test/data/extensions/uitest/event_sink/test.html
@@ -0,0 +1,79 @@
+HOLA!!!
+
+<script type="text/javascript">
+ // This extension registers for all tab and window events, and whenever one
+ // is received, it calls postMessage to send it back to the test automation
+ // driver.
+
+ // Wait for the automation server to create a port so that we can communicate
+ // back to it.
+ var portToAutomation;
+ chrome.self.onConnect.addListener(function(port) {
+ portToAutomation = port;
+ portToAutomation.postMessage('ACK');
+ });
+
+ // Window events.
+ chrome.windows.onCreated.addListener(function(windowId) {
+ portToAutomation.postMessage(chrome.windows.onCreated.eventName_);
+ });
+ chrome.windows.onRemoved.addListener(function(windowId) {
+ portToAutomation.postMessage(chrome.windows.onRemoved.eventName_);
+ });
+ chrome.windows.onFocusChanged.addListener(function(windowId) {
+ portToAutomation.postMessage(chrome.windows.onFocusChanged.eventName_);
+ });
+
+ // Tab events.
+ chrome.tabs.onCreated.addListener(function(tab) {
+ portToAutomation.postMessage(chrome.tabs.onCreated.eventName_);
+ });
+ chrome.tabs.onUpdated.addListener(function(tabId, info) {
+ portToAutomation.postMessage(chrome.tabs.onUpdated.eventName_);
+ });
+ chrome.tabs.onMoved.addListener(function(tabId, info) {
+ portToAutomation.postMessage(chrome.tabs.onMoved.eventName_);
+ });
+ chrome.tabs.onSelectionChanged.addListener(function(tabId, info) {
+ portToAutomation.postMessage(chrome.tabs.onSelectionChanged.eventName_);
+ });
+ chrome.tabs.onAttached.addListener(function(tabId, info) {
+ portToAutomation.postMessage(chrome.tabs.onAttached.eventName_);
+ });
+ chrome.tabs.onDetached.addListener(function(tabId, info) {
+ portToAutomation.postMessage(chrome.tabs.onDetached.eventName_);
+ });
+ chrome.tabs.onRemoved.addListener(function(tabId) {
+ portToAutomation.postMessage(chrome.tabs.onRemoved.eventName_);
+ });
+
+ // Page action events.
+ chrome.pageActions.onExecute.addListener(function(info) {
+ portToAutomation.postMessage(chrome.pageActions.onExecute.eventName_);
+ });
+
+ // Bookmark events.
+ chrome.bookmarks.onAdded.addListener(function(info) {
+ portToAutomation.postMessage(chrome.bookmarks.onAdded.eventName_);
+ });
+ chrome.bookmarks.onRemoved.addListener(function(info) {
+ portToAutomation.postMessage(chrome.bookmarks.onRemoved.eventName_);
+ });
+ chrome.bookmarks.onChanged.addListener(function(bookmarkId, info) {
+ portToAutomation.postMessage(chrome.bookmarks.onChanged.eventName_);
+ });
+ chrome.bookmarks.onMoved.addListener(function(info) {
+ portToAutomation.postMessage(chrome.bookmarks.onMoved.eventName_);
+ });
+ chrome.bookmarks.onChildrenReordered.addListener(function(bookmarkId,
+ children) {
+ portToAutomation.postMessage(
+ chrome.bookmarks.onChildrenReordered.eventName_);
+ });
+
+ // Call chrome window api. The result of this api is not important, as this
+ // is used only to let the automation test driver know that this page is
+ // loaded and ready to receive events.
+ chrome.windows.getCurrent(function() {});
+ document.write('DONE');
+</script>