OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/test/chromedriver/chromedriver.h" | |
6 | |
7 #include "base/json/json_reader.h" | |
8 #include "base/json/json_writer.h" | |
9 #include "base/lazy_instance.h" | |
10 #include "base/memory/scoped_ptr.h" | |
11 #include "base/synchronization/lock.h" | |
12 #include "base/values.h" | |
13 #include "chrome/test/chromedriver/chrome/status.h" | |
14 #include "chrome/test/chromedriver/command_executor.h" | |
15 | |
16 namespace { | |
17 | |
18 // Guards |g_executor_initialized|. | |
19 base::LazyInstance<base::Lock> g_lazy_lock = LAZY_INSTANCE_INITIALIZER; | |
20 bool g_executor_initialized = false; | |
21 CommandExecutor* g_command_executor = NULL; | |
22 | |
23 void SetResponse(StatusCode status, | |
24 const base::Value* value, | |
25 const std::string& session_id, | |
26 std::string* response) { | |
27 base::DictionaryValue response_dict; | |
28 response_dict.SetInteger("status", status); | |
29 response_dict.Set("value", value->DeepCopy()); | |
30 response_dict.SetString("sessionId", session_id); | |
31 std::string json; | |
32 base::JSONWriter::Write(&response_dict, response); | |
33 } | |
34 | |
35 void SetError(const std::string& error_msg, | |
36 std::string* response) { | |
37 base::DictionaryValue value; | |
38 value.SetString("message", error_msg); | |
39 SetResponse(kUnknownError, &value, std::string(), response); | |
40 } | |
41 | |
42 } // namespace | |
43 | |
44 void Init(scoped_ptr<CommandExecutor> executor) { | |
45 g_command_executor = executor.release(); | |
46 // We do not call CommandExecutor::Init here because you can't do some things | |
47 // (e.g., creating threads) during DLL loading on Windows. | |
48 } | |
49 | |
50 void ExecuteCommand(const std::string& command, std::string* response) { | |
51 CHECK(g_command_executor); | |
52 { | |
53 base::AutoLock(g_lazy_lock.Get()); | |
54 if (!g_executor_initialized) { | |
55 g_command_executor->Init(); | |
56 g_executor_initialized = true; | |
57 } | |
58 } | |
59 std::string error_msg; | |
60 scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError( | |
61 command, 0, NULL, &error_msg)); | |
62 if (!value.get()) { | |
63 SetError("failed to parse command: " + error_msg, response); | |
64 return; | |
65 } | |
66 base::DictionaryValue* command_dict; | |
67 if (!value->GetAsDictionary(&command_dict)) { | |
68 SetError("invalid command (must be dictionary)", response); | |
69 return; | |
70 } | |
71 std::string name; | |
72 if (!command_dict->GetString("name", &name)) { | |
73 SetError("invalid command (must contain 'name' of type string)", response); | |
74 return; | |
75 } | |
76 base::DictionaryValue* params; | |
77 if (!command_dict->GetDictionary("parameters", ¶ms)) { | |
78 SetError("invalid command (must contain 'parameters' of type dict)", | |
79 response); | |
80 return; | |
81 } | |
82 std::string session_id; | |
83 if (!command_dict->GetString("sessionId", &session_id)) { | |
84 SetError("invalid command (must contain 'sessionId' of type string)", | |
85 response); | |
86 return; | |
87 } | |
88 StatusCode out_status = kOk; | |
89 scoped_ptr<base::Value> out_value; | |
90 std::string out_session_id; | |
91 g_command_executor->ExecuteCommand( | |
92 name, *params, session_id, &out_status, &out_value, &out_session_id); | |
93 SetResponse(out_status, out_value.get(), out_session_id, response); | |
94 } | |
95 | |
96 void Shutdown() { | |
97 // TODO: Move this out to a separate doc. | |
98 // On shutdown, it is nice to quit all running sessions so that we don't | |
99 // have leftover Chrome processes and temporary user data dirs. | |
100 // To do this, we execute the quitAll command. | |
101 // Alternative shutdown behaviors: | |
102 // 1. If the user doesn't quit the session, don't clean it up. | |
103 // This is what the FF driver does, except the temp dir is | |
104 // cleaned up in FF because the client side is responsible for creating | |
105 // the temp directory, not the driver. | |
106 // 2. Separate helper process that we spawn that is in charge of | |
107 // launching processes and creating temporary files. This process | |
108 // communicates to the helper via a socket. The helper process | |
109 // kills all processes and deletes temp files if it sees the parent | |
110 // die and then exits itself. This is more complicated, but it guarantees | |
111 // that the processes and temp dirs are cleaned up, even if this process | |
112 // exits abnormally. | |
113 // 3. Add Chrome command-line switch for socket/pipe that Chrome listens | |
114 // to and exits if the pipe is closed. This is how the old | |
115 // TestingAutomationProvider worked. However, this doesn't clean up | |
116 // temp directories, unless we make Chrome clean its own directory too. | |
117 // If Chrome crashes the directory would be leaked. | |
118 base::DictionaryValue params; | |
119 StatusCode status_code; | |
120 scoped_ptr<base::Value> value; | |
121 std::string session_id; | |
122 g_command_executor->ExecuteCommand( | |
123 "quitAll", params, std::string(), &status_code, &value, &session_id); | |
124 delete g_command_executor; | |
125 } | |
OLD | NEW |