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

Side by Side Diff: chrome/test/base/mojo_test_connector.cc

Issue 1806353003: Adds option to run browser tests in mash (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: cleanup Created 4 years, 9 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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/base/mojo_test_connector.h"
6
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/command_line.h"
10 #include "base/run_loop.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "base/threading/thread.h"
14 #include "content/public/common/content_switches.h"
15 #include "content/public/test/test_launcher.h"
16 #include "mojo/edk/embedder/embedder.h"
17 #include "mojo/edk/embedder/platform_channel_pair.h"
18 #include "mojo/edk/embedder/process_delegate.h"
19 #include "mojo/public/cpp/bindings/interface_request.h"
20 #include "mojo/services/catalog/store.h"
21 #include "mojo/shell/background/tests/test_catalog_store.h"
22 #include "mojo/shell/public/cpp/connector.h"
23 #include "mojo/shell/public/cpp/shell_client.h"
24 #include "mojo/shell/public/cpp/shell_connection.h"
25 #include "mojo/shell/runner/common/client_util.h"
26 #include "mojo/shell/runner/common/switches.h"
27 #include "mojo/shell/shell.h"
28 #include "mojo/shell/switches.h"
29
30 using mojo::shell::mojom::ShellClient;
31 using mojo::shell::mojom::ShellClientPtr;
32
33 namespace {
34
35 const char kTestRunnerName[] = "mojo:test-runner";
36 const char kTestName[] = "exe:chrome";
37
38 // Returns the Dictionary value of |parent| under the specified key, creating
39 // and adding as necessary.
40 base::DictionaryValue* EnsureDictionary(base::DictionaryValue* parent,
41 const char* key) {
42 base::DictionaryValue* dictionary = nullptr;
43 if (parent->GetDictionary(key, &dictionary))
44 return dictionary;
45
46 scoped_ptr<base::DictionaryValue> owned_dictionary(
47 new base::DictionaryValue);
48 dictionary = owned_dictionary.get();
49 parent->Set(key, std::move(owned_dictionary));
50 return dictionary;
51 }
52
53 // This builds a permissive catalog with the addition of the 'instance_name'
54 // permission.
55 scoped_ptr<mojo::shell::TestCatalogStore> BuildTestCatalogStore() {
56 scoped_ptr<base::ListValue> apps(new base::ListValue);
57 scoped_ptr<base::DictionaryValue> test_app_config =
58 mojo::shell::BuildPermissiveSerializedAppInfo(kTestRunnerName, "test");
59 base::DictionaryValue* capabilities =
60 EnsureDictionary(test_app_config.get(),
61 catalog::Store::kCapabilitiesKey);
62 base::DictionaryValue* required_capabilities =
63 EnsureDictionary(capabilities,
64 catalog::Store::kCapabilities_RequiredKey);
65 scoped_ptr<base::ListValue> required_shell_classes(new base::ListValue);
66 required_shell_classes->AppendString("instance_name");
67 required_shell_classes->AppendString("client_process");
68 scoped_ptr<base::DictionaryValue> shell_caps(
69 new base::DictionaryValue);
70 shell_caps->Set(catalog::Store::kCapabilities_ClassesKey,
71 std::move(required_shell_classes));
72 required_capabilities->Set("mojo:shell", std::move(shell_caps));
73 apps->Append(std::move(test_app_config));
74 return make_scoped_ptr(new mojo::shell::TestCatalogStore(std::move(apps)));
75 }
76
77 // BackgroundTestState maintains all the state necessary to bind the test to
78 // mojo. This class is only used on the thread created by BackgroundShell.
79 class BackgroundTestState {
80 public:
81 BackgroundTestState() {}
82 ~BackgroundTestState() {}
83
84 // Prepares the command line and other setup for connecting the test to mojo.
85 // Must be paired with a clal to ChildProcessLaunched().
86 void Connect(base::CommandLine* command_line,
87 mojo::shell::Shell* shell,
88 const std::string& instance,
89 base::TestLauncher::LaunchOptions* test_launch_options) {
90 command_line->AppendSwitch(MojoTestConnector::kTestSwitch);
91 command_line->AppendSwitch(switches::kWaitForMojoShell);
92 command_line->AppendSwitch(switches::kChildProcess);
93 mojo_ipc_channel_.reset(new mojo::edk::PlatformChannelPair);
94 mojo_ipc_channel_->PrepareToPassClientHandleToChildProcess(
95 command_line, &handle_passing_info_);
96 #if defined(OS_WIN)
97 test_launch_options->inherit_handles = true;
98 test_launch_options->handles_to_inherit = &handle_passing_info_;
99 #if defined(OFFICIAL_BUILD)
100 CHECK(false) << "Launching mojo process with inherit_handles is insecure!";
101 #endif
102 #elif defined(OS_POSIX)
103 test_launch_options->fds_to_remap = &handle_passing_info_;
104 #else
105 #error "Unsupported"
106 #endif
107 mojo::shell::mojom::ShellClientPtr client =
108 mojo::shell::PassShellClientRequestOnCommandLine(command_line);
109
110 scoped_ptr<mojo::shell::ConnectParams> params(
111 new mojo::shell::ConnectParams);
112 params->set_source(mojo::shell::CreateShellIdentity());
113 params->set_target(
114 mojo::Identity(kTestName, mojo::shell::mojom::kRootUserID, instance));
115
116 mojo::shell::mojom::ClientProcessConnectionPtr client_process_connection =
117 mojo::shell::mojom::ClientProcessConnection::New();
118 client_process_connection->shell_client =
119 client.PassInterface().PassHandle();
120 client_process_connection->pid_receiver_request =
121 mojo::GetProxy(&pid_receiver_).PassMessagePipe();
122 params->set_client_process_connection(std::move(client_process_connection));
123 shell->Connect(std::move(params));
124 }
125
126 // Called after the test process has launched. Completes the registration done
127 // in Connect().
128 void ChildProcessLaunched(base::ProcessHandle handle, base::ProcessId pid) {
129 pid_receiver_->SetPID(pid);
130 mojo_ipc_channel_->ChildProcessLaunched();
131 mojo::edk::ChildProcessLaunched(
132 handle, mojo::edk::ScopedPlatformHandle(mojo::edk::PlatformHandle(
133 mojo_ipc_channel_->PassServerHandle().release().handle)));
134 }
135
136 private:
137 // Used to back the NodeChannel between the parent and child node.
138 scoped_ptr<mojo::edk::PlatformChannelPair> mojo_ipc_channel_;
139
140 mojo::edk::HandlePassingInformation handle_passing_info_;
141
142 mojo::shell::mojom::PIDReceiverPtr pid_receiver_;
143
144 DISALLOW_COPY_AND_ASSIGN(BackgroundTestState);
145 };
146
147 // Called used destroy BackgroundTestState on the background thread.
148 void DestroyBackgroundStateOnBackgroundThread(
149 scoped_ptr<BackgroundTestState> state,
150 mojo::shell::Shell* shell) {}
151
152 // State created per test. Manages creation of the corresponding
153 // BackgroundTestState and making sure processing runs on the right threads.
154 class MojoTestState : public content::TestState {
155 public:
156 explicit MojoTestState(mojo::shell::BackgroundShell* background_shell)
157 : background_shell_(background_shell) {}
158
159 ~MojoTestState() override {
160 DCHECK(background_state_);
161 // BackgroundState needs to be destroyed on the background thread. We're
162 // guaranteed |background_shell_| has been created by the time we reach
163 // here as Init() blocks until |background_shell_| has been created.
164 background_shell_->ExecuteOnShellThread(
165 base::Bind(&DestroyBackgroundStateOnBackgroundThread,
166 base::Passed(&background_state_)));
167 }
168
169 void Init(base::CommandLine* command_line,
170 base::TestLauncher::LaunchOptions* test_launch_options) {
171 base::WaitableEvent signal(true, false);
172 background_shell_->ExecuteOnShellThread(base::Bind(
173 &MojoTestState::BindOnBackgroundThread, base::Unretained(this), &signal,
174 command_line, test_launch_options));
175 signal.Wait();
176 }
177
178 private:
179 // content::TestState:
180 void ChildProcessLaunched(base::ProcessHandle handle,
181 base::ProcessId pid) override {
182 // This is called on a random thread. We need to ensure BackgroundTestState
183 // is only called on the background thread, and we wait for
184 // ChildProcessLaunchedOnBackgroundThread() to be run before continuing so
185 // that |handle| is still valid.
186 base::WaitableEvent signal(true, false);
187 background_shell_->ExecuteOnShellThread(
188 base::Bind(&MojoTestState::ChildProcessLaunchedOnBackgroundThread,
189 base::Unretained(this),
190 handle, pid, &signal));
191 signal.Wait();
192 }
193
194 void ChildProcessLaunchedOnBackgroundThread(
195 base::ProcessHandle handle,
196 base::ProcessId pid,
197 base::WaitableEvent* signal,
198 mojo::shell::Shell* shell) {
199 background_state_->ChildProcessLaunched(handle, pid);
200 signal->Signal();
201 }
202
203 void BindOnBackgroundThread(
204 base::WaitableEvent* signal,
205 base::CommandLine* command_line,
206 base::TestLauncher::LaunchOptions* test_launch_options,
207 mojo::shell::Shell* shell) {
208 static int instance_id = 0;
209 const std::string instance_name = "instance-" +
210 base::IntToString(instance_id++);
211 background_state_.reset(new BackgroundTestState);
212 background_state_->Connect(command_line, shell, instance_name,
213 test_launch_options);
214 signal->Signal();
215 }
216
217 mojo::shell::BackgroundShell* background_shell_;
218 scoped_ptr<BackgroundTestState> background_state_;
219
220 DISALLOW_COPY_AND_ASSIGN(MojoTestState);
221 };
222
223 } // namespace
224
225 // static
226 const char MojoTestConnector::kTestSwitch[] = "is_test";
227
228 MojoTestConnector::MojoTestConnector() {}
229
230 mojo::shell::mojom::ShellClientRequest MojoTestConnector::Init() {
231 scoped_ptr<mojo::shell::BackgroundShell::InitParams> init_params(
232 new mojo::shell::BackgroundShell::InitParams);
233 init_params->catalog_store = BuildTestCatalogStore();
234 // When running in single_process mode chrome initializes the edk.
235 init_params->init_edk = !base::CommandLine::ForCurrentProcess()->HasSwitch(
236 content::kSingleProcessTestsFlag);
237 background_shell_.Init(std::move(init_params));
238 return background_shell_.CreateShellClientRequest(kTestRunnerName);
239 }
240
241 MojoTestConnector::~MojoTestConnector() {}
242
243 scoped_ptr<content::TestState> MojoTestConnector::PrepareForTest(
244 base::CommandLine* command_line,
245 base::TestLauncher::LaunchOptions* test_launch_options) {
246 scoped_ptr<MojoTestState> test_state(new MojoTestState(&background_shell_));
247 test_state->Init(command_line, test_launch_options);
248 return std::move(test_state);
249 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698