| 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
|
|
|
|
|