OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "mojo/edk/test/multiprocess_test_helper.h" | 5 #include "mojo/edk/test/multiprocess_test_helper.h" |
6 | 6 |
| 7 #include <functional> |
7 #include <utility> | 8 #include <utility> |
8 | 9 |
| 10 #include "base/bind.h" |
9 #include "base/command_line.h" | 11 #include "base/command_line.h" |
10 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/memory/ref_counted.h" |
11 #include "base/process/kill.h" | 14 #include "base/process/kill.h" |
12 #include "base/process/process_handle.h" | 15 #include "base/process/process_handle.h" |
| 16 #include "base/run_loop.h" |
| 17 #include "base/strings/stringprintf.h" |
| 18 #include "base/task_runner.h" |
| 19 #include "base/thread_task_runner_handle.h" |
13 #include "build/build_config.h" | 20 #include "build/build_config.h" |
14 #include "mojo/edk/embedder/embedder.h" | 21 #include "mojo/edk/embedder/embedder.h" |
15 #include "mojo/edk/embedder/platform_channel_pair.h" | 22 #include "mojo/edk/embedder/platform_channel_pair.h" |
| 23 #include "testing/gtest/include/gtest/gtest.h" |
16 | 24 |
17 #if defined(OS_WIN) | 25 #if defined(OS_WIN) |
18 #include "base/win/windows_version.h" | 26 #include "base/win/windows_version.h" |
19 #endif | 27 #endif |
20 | 28 |
21 namespace mojo { | 29 namespace mojo { |
22 namespace edk { | 30 namespace edk { |
23 namespace test { | 31 namespace test { |
24 | 32 |
25 const char kBrokerHandleSwitch[] = "broker-handle"; | 33 namespace { |
26 | 34 |
27 MultiprocessTestHelper::MultiprocessTestHelper() { | 35 const char kMojoPrimordialPipeToken[] = "mojo-primordial-pipe-token"; |
28 platform_channel_pair_.reset(new PlatformChannelPair()); | 36 |
29 server_platform_handle = platform_channel_pair_->PassServerHandle(); | 37 void RunHandlerOnMainThread(std::function<int(MojoHandle)> handler, |
30 broker_platform_channel_pair_.reset(new PlatformChannelPair()); | 38 int* exit_code, |
| 39 const base::Closure& quit_closure, |
| 40 ScopedMessagePipeHandle pipe) { |
| 41 *exit_code = handler(pipe.get().value()); |
| 42 quit_closure.Run(); |
31 } | 43 } |
32 | 44 |
| 45 void RunHandler(std::function<int(MojoHandle)> handler, |
| 46 int* exit_code, |
| 47 const base::Closure& quit_closure, |
| 48 scoped_refptr<base::TaskRunner> task_runner, |
| 49 ScopedMessagePipeHandle pipe) { |
| 50 task_runner->PostTask( |
| 51 FROM_HERE, |
| 52 base::Bind(&RunHandlerOnMainThread, handler, base::Unretained(exit_code), |
| 53 quit_closure, base::Passed(&pipe))); |
| 54 } |
| 55 |
| 56 int RunClientFunction(std::function<int(MojoHandle)> handler) { |
| 57 base::MessageLoop message_loop; |
| 58 base::RunLoop run_loop; |
| 59 int exit_code = 0; |
| 60 CHECK(!MultiprocessTestHelper::primordial_pipe_token.empty()); |
| 61 CreateChildMessagePipe( |
| 62 MultiprocessTestHelper::primordial_pipe_token, |
| 63 base::Bind(&RunHandler, handler, base::Unretained(&exit_code), |
| 64 run_loop.QuitClosure(), base::ThreadTaskRunnerHandle::Get())); |
| 65 run_loop.Run(); |
| 66 return exit_code; |
| 67 } |
| 68 |
| 69 } // namespace |
| 70 |
| 71 MultiprocessTestHelper::MultiprocessTestHelper() {} |
| 72 |
33 MultiprocessTestHelper::~MultiprocessTestHelper() { | 73 MultiprocessTestHelper::~MultiprocessTestHelper() { |
34 CHECK(!test_child_.IsValid()); | 74 CHECK(!test_child_.IsValid()); |
35 server_platform_handle.reset(); | |
36 platform_channel_pair_.reset(); | |
37 } | 75 } |
38 | 76 |
39 void MultiprocessTestHelper::StartChild(const std::string& test_child_name) { | 77 void MultiprocessTestHelper::StartChild(const std::string& test_child_name, |
40 StartChildWithExtraSwitch(test_child_name, std::string(), std::string()); | 78 const HandlerCallback& callback) { |
| 79 StartChildWithExtraSwitch( |
| 80 test_child_name, std::string(), std::string(), callback); |
41 } | 81 } |
42 | 82 |
43 void MultiprocessTestHelper::StartChildWithExtraSwitch( | 83 void MultiprocessTestHelper::StartChildWithExtraSwitch( |
44 const std::string& test_child_name, | 84 const std::string& test_child_name, |
45 const std::string& switch_string, | 85 const std::string& switch_string, |
46 const std::string& switch_value) { | 86 const std::string& switch_value, |
47 CHECK(platform_channel_pair_); | 87 const HandlerCallback& callback) { |
48 CHECK(!test_child_name.empty()); | 88 CHECK(!test_child_name.empty()); |
49 CHECK(!test_child_.IsValid()); | 89 CHECK(!test_child_.IsValid()); |
50 | 90 |
51 std::string test_child_main = test_child_name + "TestChildMain"; | 91 std::string test_child_main = test_child_name + "TestChildMain"; |
52 | 92 |
53 base::CommandLine command_line( | 93 base::CommandLine command_line( |
54 base::GetMultiProcessTestChildBaseCommandLine()); | 94 base::GetMultiProcessTestChildBaseCommandLine()); |
| 95 |
| 96 PlatformChannelPair channel; |
55 HandlePassingInformation handle_passing_info; | 97 HandlePassingInformation handle_passing_info; |
56 platform_channel_pair_->PrepareToPassClientHandleToChildProcess( | 98 channel.PrepareToPassClientHandleToChildProcess(&command_line, |
57 &command_line, &handle_passing_info); | 99 &handle_passing_info); |
58 | 100 |
59 std::string broker_handle = broker_platform_channel_pair_-> | 101 std::string pipe_token = mojo::edk::GenerateRandomToken(); |
60 PrepareToPassClientHandleToChildProcessAsString(&handle_passing_info); | 102 command_line.AppendSwitchASCII(kMojoPrimordialPipeToken, pipe_token); |
61 command_line.AppendSwitchASCII(kBrokerHandleSwitch, broker_handle); | |
62 | 103 |
63 if (!switch_string.empty()) { | 104 if (!switch_string.empty()) { |
64 CHECK(!command_line.HasSwitch(switch_string)); | 105 CHECK(!command_line.HasSwitch(switch_string)); |
65 if (!switch_value.empty()) | 106 if (!switch_value.empty()) |
66 command_line.AppendSwitchASCII(switch_string, switch_value); | 107 command_line.AppendSwitchASCII(switch_string, switch_value); |
67 else | 108 else |
68 command_line.AppendSwitch(switch_string); | 109 command_line.AppendSwitch(switch_string); |
69 } | 110 } |
70 | 111 |
71 base::LaunchOptions options; | 112 base::LaunchOptions options; |
72 #if defined(OS_POSIX) | 113 #if defined(OS_POSIX) |
73 options.fds_to_remap = &handle_passing_info; | 114 options.fds_to_remap = &handle_passing_info; |
74 #elif defined(OS_WIN) | 115 #elif defined(OS_WIN) |
75 options.start_hidden = true; | 116 options.start_hidden = true; |
76 if (base::win::GetVersion() >= base::win::VERSION_VISTA) | 117 if (base::win::GetVersion() >= base::win::VERSION_VISTA) |
77 options.handles_to_inherit = &handle_passing_info; | 118 options.handles_to_inherit = &handle_passing_info; |
78 else | 119 else |
79 options.inherit_handles = true; | 120 options.inherit_handles = true; |
80 #else | 121 #else |
81 #error "Not supported yet." | 122 #error "Not supported yet." |
82 #endif | 123 #endif |
83 | 124 |
84 test_child_ = | 125 test_child_ = |
85 base::SpawnMultiProcessTestChild(test_child_main, command_line, options); | 126 base::SpawnMultiProcessTestChild(test_child_main, command_line, options); |
86 platform_channel_pair_->ChildProcessLaunched(); | 127 channel.ChildProcessLaunched(); |
87 | 128 |
88 broker_platform_channel_pair_->ChildProcessLaunched(); | 129 ChildProcessLaunched(test_child_.Handle(), channel.PassServerHandle()); |
89 ChildProcessLaunched(test_child_.Handle(), | 130 CreateParentMessagePipe(pipe_token, callback); |
90 broker_platform_channel_pair_->PassServerHandle()); | |
91 | 131 |
92 CHECK(test_child_.IsValid()); | 132 CHECK(test_child_.IsValid()); |
93 } | 133 } |
94 | 134 |
95 int MultiprocessTestHelper::WaitForChildShutdown() { | 135 int MultiprocessTestHelper::WaitForChildShutdown() { |
96 CHECK(test_child_.IsValid()); | 136 CHECK(test_child_.IsValid()); |
97 | 137 |
98 int rv = -1; | 138 int rv = -1; |
99 CHECK( | 139 CHECK( |
100 test_child_.WaitForExitWithTimeout(TestTimeouts::action_timeout(), &rv)); | 140 test_child_.WaitForExitWithTimeout(TestTimeouts::action_timeout(), &rv)); |
101 test_child_.Close(); | 141 test_child_.Close(); |
102 return rv; | 142 return rv; |
103 } | 143 } |
104 | 144 |
105 bool MultiprocessTestHelper::WaitForChildTestShutdown() { | 145 bool MultiprocessTestHelper::WaitForChildTestShutdown() { |
106 return WaitForChildShutdown() == 0; | 146 return WaitForChildShutdown() == 0; |
107 } | 147 } |
108 | 148 |
109 // static | 149 // static |
110 void MultiprocessTestHelper::ChildSetup() { | 150 void MultiprocessTestHelper::ChildSetup() { |
111 CHECK(base::CommandLine::InitializedForCurrentProcess()); | 151 CHECK(base::CommandLine::InitializedForCurrentProcess()); |
112 client_platform_handle = | 152 |
| 153 primordial_pipe_token = base::CommandLine::ForCurrentProcess() |
| 154 ->GetSwitchValueASCII(kMojoPrimordialPipeToken); |
| 155 CHECK(!primordial_pipe_token.empty()); |
| 156 |
| 157 SetParentPipeHandle( |
113 PlatformChannelPair::PassClientHandleFromParentProcess( | 158 PlatformChannelPair::PassClientHandleFromParentProcess( |
114 *base::CommandLine::ForCurrentProcess()); | 159 *base::CommandLine::ForCurrentProcess())); |
115 | |
116 std::string broker_handle_str = | |
117 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | |
118 kBrokerHandleSwitch); | |
119 ScopedPlatformHandle broker_handle = | |
120 PlatformChannelPair::PassClientHandleFromParentProcessFromString( | |
121 broker_handle_str); | |
122 SetParentPipeHandle(std::move(broker_handle)); | |
123 } | 160 } |
124 | 161 |
125 // static | 162 // static |
126 ScopedPlatformHandle MultiprocessTestHelper::client_platform_handle; | 163 int MultiprocessTestHelper::RunClientMain( |
| 164 const base::Callback<int(MojoHandle)>& main) { |
| 165 return RunClientFunction([main](MojoHandle handle){ |
| 166 return main.Run(handle); |
| 167 }); |
| 168 } |
| 169 |
| 170 // static |
| 171 int MultiprocessTestHelper::RunClientTestMain( |
| 172 const base::Callback<void(MojoHandle)>& main) { |
| 173 return RunClientFunction([main](MojoHandle handle) { |
| 174 main.Run(handle); |
| 175 return (::testing::Test::HasFatalFailure() || |
| 176 ::testing::Test::HasNonfatalFailure()) ? 1 : 0; |
| 177 }); |
| 178 } |
| 179 |
| 180 // static |
| 181 std::string MultiprocessTestHelper::primordial_pipe_token; |
127 | 182 |
128 } // namespace test | 183 } // namespace test |
129 } // namespace edk | 184 } // namespace edk |
130 } // namespace mojo | 185 } // namespace mojo |
OLD | NEW |