| // Copyright 2015 The Cobalt Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "cobalt/webdriver/script_executor.h" |
| |
| #include "base/files/file_path.h" |
| #include "base/files/file_util.h" |
| #include "base/lazy_instance.h" |
| #include "base/path_service.h" |
| #include "cobalt/script/source_code.h" |
| |
| namespace cobalt { |
| namespace webdriver { |
| namespace { |
| // Path to the script to initialize the script execution harness. |
| const char kWebDriverInitScriptPath[] = "webdriver/webdriver-init.js"; |
| |
| // Wrapper around a scoped_refptr<script::SourceCode> instance. The script |
| // at kWebDriverInitScriptPath will be loaded from disk and a new |
| // script::SourceCode will be created. |
| class LazySourceLoader { |
| public: |
| LazySourceLoader() { |
| base::FilePath exe_path; |
| if (!base::PathService::Get(base::DIR_EXE, &exe_path)) { |
| NOTREACHED() << "Failed to get EXE path."; |
| return; |
| } |
| base::FilePath script_path = exe_path.Append(kWebDriverInitScriptPath); |
| std::string script_contents; |
| if (!base::ReadFileToString(script_path, &script_contents)) { |
| NOTREACHED() << "Failed to read script contents."; |
| return; |
| } |
| source_code_ = script::SourceCode::CreateSourceCode( |
| script_contents.c_str(), |
| base::SourceLocation(kWebDriverInitScriptPath, 1, 1)); |
| } |
| const scoped_refptr<script::SourceCode>& source_code() { |
| return source_code_; |
| } |
| |
| private: |
| scoped_refptr<script::SourceCode> source_code_; |
| }; |
| |
| // The script only needs to be loaded once, so allow it to persist as a |
| // LazyInstance and be shared amongst different WindowDriver instances. |
| base::LazyInstance<LazySourceLoader>::DestructorAtExit lazy_source_loader = |
| LAZY_INSTANCE_INITIALIZER; |
| } // namespace |
| |
| void ScriptExecutor::LoadExecutorSourceCode() { lazy_source_loader.Get(); } |
| |
| scoped_refptr<ScriptExecutor> ScriptExecutor::Create( |
| ElementMapping* element_mapping, |
| const scoped_refptr<script::GlobalEnvironment>& global_environment) { |
| // This could be NULL if there was an error loading the harness source from |
| // disk. |
| scoped_refptr<script::SourceCode> source = |
| lazy_source_loader.Get().source_code(); |
| if (!source) { |
| return NULL; |
| } |
| |
| // Create a new ScriptExecutor and bind it to the global object. |
| scoped_refptr<ScriptExecutor> script_executor = |
| new ScriptExecutor(element_mapping); |
| global_environment->Bind("webdriverExecutor", script_executor); |
| |
| // Evaluate the harness initialization script. |
| std::string result; |
| if (!global_environment->EvaluateScript(source, &result)) { |
| return NULL; |
| } |
| |
| // The initialization script should have set this. |
| DCHECK(script_executor->execute_script_harness()); |
| return script_executor; |
| } |
| |
| bool ScriptExecutor::Execute( |
| const scoped_refptr<ScriptExecutorParams>& params, |
| ScriptExecutorResult::ResultHandler* result_handler) { |
| DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
| scoped_refptr<ScriptExecutorResult> executor_result( |
| new ScriptExecutorResult(result_handler)); |
| return ExecuteInternal(params, executor_result); |
| } |
| |
| void ScriptExecutor::set_execute_script_harness( |
| const ExecuteFunctionCallbackHolder& callback) { |
| DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
| execute_callback_.emplace(this, callback); |
| } |
| |
| const ScriptExecutor::ExecuteFunctionCallbackHolder* |
| ScriptExecutor::execute_script_harness() { |
| DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
| if (execute_callback_) { |
| return &(execute_callback_->referenced_value()); |
| } else { |
| return NULL; |
| } |
| } |
| |
| scoped_refptr<dom::Element> ScriptExecutor::IdToElement(const std::string& id) { |
| DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
| DCHECK(element_mapping_); |
| return element_mapping_->IdToElement(protocol::ElementId(id)); |
| } |
| |
| std::string ScriptExecutor::ElementToId( |
| const scoped_refptr<dom::Element>& element) { |
| DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
| DCHECK(element_mapping_); |
| return element_mapping_->ElementToId(element).id(); |
| } |
| |
| bool ScriptExecutor::ExecuteInternal( |
| const scoped_refptr<ScriptExecutorParams>& params, |
| const scoped_refptr<ScriptExecutorResult>& result_handler) { |
| DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
| DCHECK(params); |
| DCHECK(result_handler); |
| ExecuteFunctionCallback::ReturnValue callback_result = |
| execute_callback_->value().Run(params, result_handler); |
| return !callback_result.exception; |
| } |
| |
| } // namespace webdriver |
| } // namespace cobalt |