| 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 <functional> |
| 8 #include <set> | 8 #include <set> |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 #endif | 32 #endif |
| 33 | 33 |
| 34 namespace mojo { | 34 namespace mojo { |
| 35 namespace edk { | 35 namespace edk { |
| 36 namespace test { | 36 namespace test { |
| 37 | 37 |
| 38 namespace { | 38 namespace { |
| 39 | 39 |
| 40 const char kMojoPrimordialPipeToken[] = "mojo-primordial-pipe-token"; | 40 const char kMojoPrimordialPipeToken[] = "mojo-primordial-pipe-token"; |
| 41 | 41 |
| 42 int RunClientFunction(std::function<int(MojoHandle)> handler) { | 42 template <typename Func> |
| 43 CHECK(!MultiprocessTestHelper::primordial_pipe_token.empty()); | 43 int RunClientFunction(Func handler) { |
| 44 ScopedMessagePipeHandle pipe = CreateChildMessagePipe( | 44 CHECK(MultiprocessTestHelper::primordial_pipe.is_valid()); |
| 45 MultiprocessTestHelper::primordial_pipe_token); | 45 ScopedMessagePipeHandle pipe = |
| 46 std::move(MultiprocessTestHelper::primordial_pipe); |
| 46 return handler(pipe.get().value()); | 47 return handler(pipe.get().value()); |
| 47 } | 48 } |
| 48 | 49 |
| 49 } // namespace | 50 } // namespace |
| 50 | 51 |
| 51 MultiprocessTestHelper::MultiprocessTestHelper() {} | 52 MultiprocessTestHelper::MultiprocessTestHelper() {} |
| 52 | 53 |
| 53 MultiprocessTestHelper::~MultiprocessTestHelper() { | 54 MultiprocessTestHelper::~MultiprocessTestHelper() { |
| 54 CHECK(!test_child_.IsValid()); | 55 CHECK(!test_child_.IsValid()); |
| 55 } | 56 } |
| 56 | 57 |
| 57 ScopedMessagePipeHandle MultiprocessTestHelper::StartChild( | 58 ScopedMessagePipeHandle MultiprocessTestHelper::StartChild( |
| 58 const std::string& test_child_name) { | 59 const std::string& test_child_name, |
| 59 return StartChildWithExtraSwitch( | 60 LaunchType launch_type) { |
| 60 test_child_name, std::string(), std::string()); | 61 return StartChildWithExtraSwitch(test_child_name, std::string(), |
| 62 std::string(), launch_type); |
| 61 } | 63 } |
| 62 | 64 |
| 63 ScopedMessagePipeHandle MultiprocessTestHelper::StartChildWithExtraSwitch( | 65 ScopedMessagePipeHandle MultiprocessTestHelper::StartChildWithExtraSwitch( |
| 64 const std::string& test_child_name, | 66 const std::string& test_child_name, |
| 65 const std::string& switch_string, | 67 const std::string& switch_string, |
| 66 const std::string& switch_value) { | 68 const std::string& switch_value, |
| 69 LaunchType launch_type) { |
| 67 CHECK(!test_child_name.empty()); | 70 CHECK(!test_child_name.empty()); |
| 68 CHECK(!test_child_.IsValid()); | 71 CHECK(!test_child_.IsValid()); |
| 69 | 72 |
| 70 std::string test_child_main = test_child_name + "TestChildMain"; | 73 std::string test_child_main = test_child_name + "TestChildMain"; |
| 71 | 74 |
| 72 // Manually construct the new child's commandline to avoid copying unwanted | 75 // Manually construct the new child's commandline to avoid copying unwanted |
| 73 // values. | 76 // values. |
| 74 base::CommandLine command_line( | 77 base::CommandLine command_line( |
| 75 base::GetMultiProcessTestChildBaseCommandLine().GetProgram()); | 78 base::GetMultiProcessTestChildBaseCommandLine().GetProgram()); |
| 76 | 79 |
| 77 std::set<std::string> uninherited_args; | 80 std::set<std::string> uninherited_args; |
| 78 uninherited_args.insert("mojo-platform-channel-handle"); | 81 uninherited_args.insert("mojo-platform-channel-handle"); |
| 79 uninherited_args.insert(switches::kTestChildProcess); | 82 uninherited_args.insert(switches::kTestChildProcess); |
| 80 | 83 |
| 81 // Copy commandline switches from the parent process, except for the | 84 // Copy commandline switches from the parent process, except for the |
| 82 // multiprocess client name and mojo message pipe handle; this allows test | 85 // multiprocess client name and mojo message pipe handle; this allows test |
| 83 // clients to spawn other test clients. | 86 // clients to spawn other test clients. |
| 84 for (const auto& entry : | 87 for (const auto& entry : |
| 85 base::CommandLine::ForCurrentProcess()->GetSwitches()) { | 88 base::CommandLine::ForCurrentProcess()->GetSwitches()) { |
| 86 if (uninherited_args.find(entry.first) == uninherited_args.end()) | 89 if (uninherited_args.find(entry.first) == uninherited_args.end()) |
| 87 command_line.AppendSwitchNative(entry.first, entry.second); | 90 command_line.AppendSwitchNative(entry.first, entry.second); |
| 88 } | 91 } |
| 89 | 92 |
| 90 PlatformChannelPair channel; | 93 PlatformChannelPair channel; |
| 91 HandlePassingInformation handle_passing_info; | 94 HandlePassingInformation handle_passing_info; |
| 92 channel.PrepareToPassClientHandleToChildProcess(&command_line, | 95 channel.PrepareToPassClientHandleToChildProcess(&command_line, |
| 93 &handle_passing_info); | 96 &handle_passing_info); |
| 94 | 97 |
| 95 std::string pipe_token = mojo::edk::GenerateRandomToken(); | 98 std::string pipe_token = mojo::edk::GenerateRandomToken(); |
| 96 command_line.AppendSwitchASCII(kMojoPrimordialPipeToken, pipe_token); | 99 if (launch_type == LaunchType::CHILD) |
| 100 command_line.AppendSwitchASCII(kMojoPrimordialPipeToken, pipe_token); |
| 97 | 101 |
| 98 if (!switch_string.empty()) { | 102 if (!switch_string.empty()) { |
| 99 CHECK(!command_line.HasSwitch(switch_string)); | 103 CHECK(!command_line.HasSwitch(switch_string)); |
| 100 if (!switch_value.empty()) | 104 if (!switch_value.empty()) |
| 101 command_line.AppendSwitchASCII(switch_string, switch_value); | 105 command_line.AppendSwitchASCII(switch_string, switch_value); |
| 102 else | 106 else |
| 103 command_line.AppendSwitch(switch_string); | 107 command_line.AppendSwitch(switch_string); |
| 104 } | 108 } |
| 105 | 109 |
| 106 base::LaunchOptions options; | 110 base::LaunchOptions options; |
| 107 #if defined(OS_POSIX) | 111 #if defined(OS_POSIX) |
| 108 options.fds_to_remap = &handle_passing_info; | 112 options.fds_to_remap = &handle_passing_info; |
| 109 #elif defined(OS_WIN) | 113 #elif defined(OS_WIN) |
| 110 options.start_hidden = true; | 114 options.start_hidden = true; |
| 111 if (base::win::GetVersion() >= base::win::VERSION_VISTA) | 115 if (base::win::GetVersion() >= base::win::VERSION_VISTA) |
| 112 options.handles_to_inherit = &handle_passing_info; | 116 options.handles_to_inherit = &handle_passing_info; |
| 113 else | 117 else |
| 114 options.inherit_handles = true; | 118 options.inherit_handles = true; |
| 115 #else | 119 #else |
| 116 #error "Not supported yet." | 120 #error "Not supported yet." |
| 117 #endif | 121 #endif |
| 118 | 122 |
| 123 ScopedMessagePipeHandle pipe; |
| 119 std::string child_token = mojo::edk::GenerateRandomToken(); | 124 std::string child_token = mojo::edk::GenerateRandomToken(); |
| 120 ScopedMessagePipeHandle pipe = CreateParentMessagePipe(pipe_token, | 125 if (launch_type == LaunchType::CHILD) |
| 121 child_token); | 126 pipe = CreateParentMessagePipe(pipe_token, child_token); |
| 127 else if (launch_type == LaunchType::PEER) |
| 128 pipe = ConnectToPeerProcess(channel.PassServerHandle()); |
| 122 | 129 |
| 123 test_child_ = | 130 test_child_ = |
| 124 base::SpawnMultiProcessTestChild(test_child_main, command_line, options); | 131 base::SpawnMultiProcessTestChild(test_child_main, command_line, options); |
| 125 channel.ChildProcessLaunched(); | 132 channel.ChildProcessLaunched(); |
| 126 | 133 |
| 127 ChildProcessLaunched(test_child_.Handle(), channel.PassServerHandle(), | 134 if (launch_type == LaunchType::CHILD) { |
| 128 child_token, process_error_callback_); | 135 ChildProcessLaunched(test_child_.Handle(), channel.PassServerHandle(), |
| 136 child_token, process_error_callback_); |
| 137 } |
| 138 |
| 129 CHECK(test_child_.IsValid()); | 139 CHECK(test_child_.IsValid()); |
| 130 | |
| 131 return pipe; | 140 return pipe; |
| 132 } | 141 } |
| 133 | 142 |
| 134 int MultiprocessTestHelper::WaitForChildShutdown() { | 143 int MultiprocessTestHelper::WaitForChildShutdown() { |
| 135 CHECK(test_child_.IsValid()); | 144 CHECK(test_child_.IsValid()); |
| 136 | 145 |
| 137 int rv = -1; | 146 int rv = -1; |
| 138 #if defined(OS_ANDROID) | 147 #if defined(OS_ANDROID) |
| 139 // On Android, we need to use a special function to wait for the child. | 148 // On Android, we need to use a special function to wait for the child. |
| 140 CHECK(AndroidWaitForChildExitWithTimeout( | 149 CHECK(AndroidWaitForChildExitWithTimeout( |
| 141 test_child_, TestTimeouts::action_timeout(), &rv)); | 150 test_child_, TestTimeouts::action_timeout(), &rv)); |
| 142 #else | 151 #else |
| 143 CHECK( | 152 CHECK( |
| 144 test_child_.WaitForExitWithTimeout(TestTimeouts::action_timeout(), &rv)); | 153 test_child_.WaitForExitWithTimeout(TestTimeouts::action_timeout(), &rv)); |
| 145 #endif | 154 #endif |
| 146 test_child_.Close(); | 155 test_child_.Close(); |
| 147 return rv; | 156 return rv; |
| 148 } | 157 } |
| 149 | 158 |
| 150 bool MultiprocessTestHelper::WaitForChildTestShutdown() { | 159 bool MultiprocessTestHelper::WaitForChildTestShutdown() { |
| 151 return WaitForChildShutdown() == 0; | 160 return WaitForChildShutdown() == 0; |
| 152 } | 161 } |
| 153 | 162 |
| 154 // static | 163 // static |
| 155 void MultiprocessTestHelper::ChildSetup() { | 164 void MultiprocessTestHelper::ChildSetup() { |
| 156 CHECK(base::CommandLine::InitializedForCurrentProcess()); | 165 CHECK(base::CommandLine::InitializedForCurrentProcess()); |
| 157 | 166 |
| 158 primordial_pipe_token = base::CommandLine::ForCurrentProcess() | 167 std::string primordial_pipe_token = |
| 159 ->GetSwitchValueASCII(kMojoPrimordialPipeToken); | 168 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| 160 CHECK(!primordial_pipe_token.empty()); | 169 kMojoPrimordialPipeToken); |
| 161 | 170 if (!primordial_pipe_token.empty()) { |
| 171 primordial_pipe = CreateChildMessagePipe(primordial_pipe_token); |
| 162 #if defined(OS_MACOSX) && !defined(OS_IOS) | 172 #if defined(OS_MACOSX) && !defined(OS_IOS) |
| 163 CHECK(base::MachPortBroker::ChildSendTaskPortToParent("mojo_test")); | 173 CHECK(base::MachPortBroker::ChildSendTaskPortToParent("mojo_test")); |
| 164 #endif | 174 #endif |
| 165 | 175 SetParentPipeHandle(PlatformChannelPair::PassClientHandleFromParentProcess( |
| 166 SetParentPipeHandle( | 176 *base::CommandLine::ForCurrentProcess())); |
| 167 PlatformChannelPair::PassClientHandleFromParentProcess( | 177 } else { |
| 168 *base::CommandLine::ForCurrentProcess())); | 178 primordial_pipe = ConnectToPeerProcess( |
| 179 PlatformChannelPair::PassClientHandleFromParentProcess( |
| 180 *base::CommandLine::ForCurrentProcess())); |
| 181 } |
| 169 } | 182 } |
| 170 | 183 |
| 171 // static | 184 // static |
| 172 int MultiprocessTestHelper::RunClientMain( | 185 int MultiprocessTestHelper::RunClientMain( |
| 173 const base::Callback<int(MojoHandle)>& main) { | 186 const base::Callback<int(MojoHandle)>& main) { |
| 174 return RunClientFunction([main](MojoHandle handle){ | 187 return RunClientFunction([main](MojoHandle handle){ |
| 175 return main.Run(handle); | 188 return main.Run(handle); |
| 176 }); | 189 }); |
| 177 } | 190 } |
| 178 | 191 |
| 179 // static | 192 // static |
| 180 int MultiprocessTestHelper::RunClientTestMain( | 193 int MultiprocessTestHelper::RunClientTestMain( |
| 181 const base::Callback<void(MojoHandle)>& main) { | 194 const base::Callback<void(MojoHandle)>& main) { |
| 182 return RunClientFunction([main](MojoHandle handle) { | 195 return RunClientFunction([main](MojoHandle handle) { |
| 183 main.Run(handle); | 196 main.Run(handle); |
| 184 return (::testing::Test::HasFatalFailure() || | 197 return (::testing::Test::HasFatalFailure() || |
| 185 ::testing::Test::HasNonfatalFailure()) ? 1 : 0; | 198 ::testing::Test::HasNonfatalFailure()) ? 1 : 0; |
| 186 }); | 199 }); |
| 187 } | 200 } |
| 188 | 201 |
| 189 // static | 202 // static |
| 190 std::string MultiprocessTestHelper::primordial_pipe_token; | 203 mojo::ScopedMessagePipeHandle MultiprocessTestHelper::primordial_pipe; |
| 191 | 204 |
| 192 } // namespace test | 205 } // namespace test |
| 193 } // namespace edk | 206 } // namespace edk |
| 194 } // namespace mojo | 207 } // namespace mojo |
| OLD | NEW |