Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5236)

Unified Diff: chrome/test/webdriver/session.cc

Issue 3064012: Base implementation of WebDriver for Chrome. This checkin includes... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/test/webdriver/session.h ('k') | chrome/test/webdriver/session_manager.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/test/webdriver/session.cc
===================================================================
--- chrome/test/webdriver/session.cc (revision 0)
+++ chrome/test/webdriver/session.cc (revision 0)
@@ -0,0 +1,288 @@
+// Copyright (c) 2010 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/test/webdriver/session_manager.h"
+
+#ifdef OS_POSIX
+#include <unistd.h>
+#endif
+#ifdef OS_WIN
+#include <windows.h>
+#include <shellapi.h>
+#endif
+
+#include <stdlib.h>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/process.h"
+#include "base/process_util.h"
+#include "base/string_util.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+
+#include "chrome/app/chrome_dll_resource.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/webdriver/utility_functions.h"
+
+#include "third_party/webdriver/atoms.h"
+
+namespace webdriver {
+
+#ifdef OS_WIN
+namespace {
+std::string GetTempPath() {
+ DWORD result = ::GetTempPath(0, L"");
+ if (result == 0)
+ LOG(ERROR) << "Could not get system temp path" << std::endl;
+
+ std::vector<TCHAR> tempPath(result + 1);
+ result = ::GetTempPath(static_cast<DWORD>(tempPath.size()), &tempPath[0]);
+ if ((result == 0) || (result >= tempPath.size())) {
+ LOG(ERROR) << "Could not get system temp path" << std::endl;
+ NOTREACHED();
+ }
+ return std::string(tempPath.begin(),
+ tempPath.begin() + static_cast<std::size_t>(result));
+}
+} // namespace
+#endif
+
+Session::Session(const std::string& id, AutomationProxy* proxy)
+ : id_(id), proxy_(proxy), process_(base::kNullProcessHandle),
+ window_num_(0), implicit_wait_(0), current_frame_xpath_(L"") {
+}
+
+bool Session::Init(base::ProcessHandle process_handle) {
+ CHECK(process_.handle() == base::kNullProcessHandle)
+ << "Session has already been initialized";
+ process_.set_handle(process_handle);
+
+ if (!proxy_->WaitForInitialLoads()) {
+ LOG(WARNING) << "Failed to wait for initial loads" << std::endl;
+ return false;
+ }
+
+ if (!WaitForLaunch()) {
+ return false;
+ }
+
+ return LoadProxies();
+}
+
+scoped_refptr<WindowProxy> Session::GetWindow() {
+ return ActivateTab() ? browser_->GetWindow() : NULL;
+}
+
+scoped_refptr<TabProxy> Session::ActivateTab() {
+ int tab_index;
+ if (!tab_->GetTabIndex(&tab_index) ||
+ !browser_->ActivateTab(tab_index)) {
+ LOG(ERROR) << "Failed to session tab";
+ return NULL;
+ }
+ return tab_;
+}
+
+bool Session::WaitForLaunch() {
+ AutomationLaunchResult result = proxy_->WaitForAppLaunch();
+ if (result == AUTOMATION_SUCCESS) {
+ LOG(INFO) << "Automation setup is a success" << std::endl;
+ } else if (result == AUTOMATION_TIMEOUT) {
+ LOG(WARNING) << "Timeout, automation setup failed" << std::endl;
+ return false;
+ } else {
+ LOG(WARNING) << "Failure in automation setup" << std::endl;
+ return false;
+ }
+
+ LOG(INFO) << proxy_->channel_id() << std::endl;
+ if (!proxy_->OpenNewBrowserWindow(Browser::TYPE_NORMAL, true)) {
+ LOG(WARNING) << "Failed to open a new browser window" << std::endl;
+ return false;
+ }
+ return true;
+}
+
+bool Session::LoadProxies() {
+ scoped_refptr<BrowserProxy> browser = proxy_->GetBrowserWindow(0);
+ if (!browser.get()) {
+ LOG(WARNING) << "Failed to get browser window.";
+ return false;
+ }
+
+ scoped_refptr<TabProxy> tab = browser->GetActiveTab();
+ if (!tab->NavigateToURL(GURL("about://config/"))) {
+ LOG(WARNING) << "Could not navigate to about://config/" << std::endl;
+ return false;
+ }
+
+ SetBrowserAndTab(0, browser, tab);
+ return true;
+}
+
+void Session::SetBrowserAndTab(const int window_num,
+ const scoped_refptr<BrowserProxy>& browser,
+ const scoped_refptr<TabProxy>& tab) {
+ window_num_ = window_num;
+ browser_ = browser;
+ tab_ = tab;
+ current_frame_xpath_ = L"";
+
+ int tab_num;
+ LOG_IF(WARNING, !tab->GetTabIndex(&tab_num) || !browser->ActivateTab(tab_num))
+ << "Failed to activate tab";
+}
+
+bool Session::CreateTemporaryProfileDirectory() {
+ memset(tmp_profile_dir_, 0, sizeof tmp_profile_dir_);
+#ifdef OS_POSIX
+ strncat(tmp_profile_dir_, "/tmp/webdriverXXXXXX", sizeof tmp_profile_dir_);
+ if (mkdtemp(tmp_profile_dir_) == NULL) {
+ LOG(ERROR) << "mkdtemp failed";
+ return false;
+ }
+#elif OS_WIN
+ DWORD ret;
+ ProfileDir temp_dir;
+
+ ret = GetTempPathA(sizeof temp_dir, temp_dir);
+ if (ret == 0 || ret > sizeof temp_dir) {
+ LOG(ERROR) << "Could not find the temp directory" << std::endl;
+ return false;
+ }
+
+ ret = GetTempFileNameA(temp_dir, // directory for tmp files
+ "webdriver", // temp file name prefix
+ static_cast<int>(time(NULL)) % 65535 + 1,
+ tmp_profile_dir_); // buffer for name
+
+ if (ret ==0) {
+ LOG(ERROR) << "Could not generate temp directory name" << std::endl;
+ return false;
+ }
+
+ if (!CreateDirectoryA(tmp_profile_dir_, NULL)) {
+ DWORD dw = GetLastError();
+ LOG(ERROR) << "Error code: " << dw << std::endl;
+ return false;
+ }
+#endif
+ LOG(INFO) << "Using temporary profile directory: " << tmp_profile_dir_;
+ return true;
+}
+
+#ifdef OS_WIN
+bool DeleteDirectory(const char* directory) {
+ SHFILEOPSTRUCT fileop;
+ size_t convertedChars;
+ int len = strlen(directory);
+ wchar_t *pszFrom = new wchar_t[len+2];
+ memset(&fileop, 0, sizeof fileop);
+ memset(pszFrom, 0, sizeof pszFrom);
+
+ mbstowcs_s(&convertedChars, pszFrom, len+2, directory, len);
+ fileop.wFunc = FO_DELETE; // delete operation
+ // source file name as double null terminated string
+ fileop.pFrom = (LPCWSTR) pszFrom;
+ fileop.fFlags = FOF_NOCONFIRMATION|FOF_SILENT; // do not prompt the user
+ fileop.fAnyOperationsAborted = FALSE;
+
+ int ret = SHFileOperation(&fileop);
+ delete pszFrom;
+ return (ret == 0);
+}
+#endif
+
+void Session::Terminate() {
+ if (!proxy_->SetFilteredInet(false)) {
+ LOG(ERROR) << "Error in closing down session" << std::endl;
+ }
+
+#ifdef OS_WIN
+ if (!DeleteDirectory(tmp_profile_dir_)) {
+ LOG(ERROR) << "Could not clean up temp directory: "
+ << tmp_profile_dir_ << std::endl;
+ }
+#else
+ if (rmdir(tmp_profile_dir_)) {
+ LOG(ERROR) << "Could not clean up temp directory: "
+ << tmp_profile_dir_ << std::endl;
+ }
+#endif
+ process_.Terminate(EXIT_SUCCESS);
+}
+
+ErrorCode Session::ExecuteScript(const std::wstring& script,
+ const ListValue* const args,
+ Value** value) {
+ std::string args_as_json;
+ base::JSONWriter::Write(static_cast<const Value* const>(args),
+ /*pretty_print=*/false,
+ &args_as_json);
+
+ std::wstring jscript = L"window.domAutomationController.send(";
+ jscript.append(L"(function(){")
+ // Every injected script is fed through the executeScript atom. This atom
+ // will catch any errors that are thrown and convert them to the
+ // appropriate JSON structure.
+ .append(build_atom(EXECUTE_SCRIPT, sizeof EXECUTE_SCRIPT))
+ .append(L"var result = executeScript(function(){")
+ .append(script)
+ .append(L"},")
+ .append(ASCIIToWide(args_as_json))
+ .append(L");return JSON.stringify(result);})());");
+
+ // Should we also log the script that's being executed? It could be several KB
+ // in size and will add lots of noise to the logs.
+ LOG(INFO) << "Executing script in frame: " << current_frame_xpath_;
+
+ std::wstring result;
+ scoped_refptr<TabProxy> tab = ActivateTab();
+ if (!tab->ExecuteAndExtractString(current_frame_xpath_, jscript, &result)) {
+ *value = Value::CreateStringValue(
+ "Unknown internal script execution failure");
+ return kUnknownError;
+ }
+
+ LOG(INFO) << "...script result: " << result;
+ std::string temp = WideToASCII(result);
+ scoped_ptr<Value> r(base::JSONReader::ReadAndReturnError(
+ temp, true, NULL, NULL));
+ if (!r.get()) {
+ *value = Value::CreateStringValue(
+ "Internal script execution error: failed to parse script result");
+ return kUnknownError;
+ }
+
+ if (r->GetType() != Value::TYPE_DICTIONARY) {
+ std::ostringstream stream;
+ stream << "Internal script execution error: script result must be a "
+ << print_valuetype(Value::TYPE_DICTIONARY)
+ << ", but was "
+ << print_valuetype(r->GetType()) << ": " << result;
+ *value = Value::CreateStringValue(stream.str());
+ return kUnknownError;
+ }
+
+ DictionaryValue* result_dict = static_cast<DictionaryValue*>(r.get());
+
+ Value* tmp;
+ if (result_dict->Get("value", &tmp)) {
+ // result_dict owns the returned value, so we need to make a copy.
+ *value = tmp->DeepCopy();
+ } else {
+ // "value" was not defined in the returned dictionary, set to null.
+ *value = Value::CreateNullValue();
+ }
+
+ int status;
+ if (!result_dict->GetInteger("status", &status)) {
+ NOTREACHED() << "...script did not return a status flag.";
+ }
+ return static_cast<ErrorCode>(status);
+}
+} // namespace webdriver
Property changes on: chrome/test/webdriver/session.cc
___________________________________________________________________
Added: svn:eol-style
+ LF
« no previous file with comments | « chrome/test/webdriver/session.h ('k') | chrome/test/webdriver/session_manager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698