Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "base/basictypes.h" | 5 #include "base/basictypes.h" |
| 6 #include "base/bind.h" | 6 #include "base/bind.h" |
| 7 #include "base/memory/ref_counted.h" | 7 #include "base/memory/ref_counted.h" |
| 8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
| 9 #include "base/win/scoped_handle.h" | 9 #include "base/win/scoped_handle.h" |
| 10 #include "base/win/scoped_process_information.h" | |
| 10 #include "ipc/ipc_channel.h" | 11 #include "ipc/ipc_channel.h" |
| 11 #include "ipc/ipc_channel_proxy.h" | 12 #include "ipc/ipc_channel_proxy.h" |
| 12 #include "ipc/ipc_listener.h" | 13 #include "ipc/ipc_listener.h" |
| 13 #include "ipc/ipc_message.h" | 14 #include "ipc/ipc_message.h" |
| 14 #include "remoting/base/auto_thread_task_runner.h" | 15 #include "remoting/base/auto_thread_task_runner.h" |
| 15 #include "remoting/host/chromoting_messages.h" | 16 #include "remoting/host/chromoting_messages.h" |
| 16 #include "remoting/host/host_exit_codes.h" | 17 #include "remoting/host/host_exit_codes.h" |
| 17 #include "remoting/host/win/launch_process_with_token.h" | 18 #include "remoting/host/win/launch_process_with_token.h" |
| 18 #include "remoting/host/win/worker_process_launcher.h" | 19 #include "remoting/host/win/worker_process_launcher.h" |
| 19 #include "remoting/host/worker_process_ipc_delegate.h" | 20 #include "remoting/host/worker_process_ipc_delegate.h" |
| 20 #include "testing/gmock/include/gmock/gmock.h" | 21 #include "testing/gmock/include/gmock/gmock.h" |
| 21 #include "testing/gmock_mutant.h" | 22 #include "testing/gmock_mutant.h" |
| 22 #include "testing/gtest/include/gtest/gtest.h" | 23 #include "testing/gtest/include/gtest/gtest.h" |
| 23 | 24 |
| 24 using base::win::ScopedHandle; | 25 using base::win::ScopedHandle; |
| 25 using testing::_; | 26 using testing::_; |
| 26 using testing::AnyNumber; | 27 using testing::AnyNumber; |
| 27 using testing::CreateFunctor; | 28 using testing::CreateFunctor; |
| 28 using testing::DoAll; | 29 using testing::DoAll; |
| 29 using testing::Expectation; | 30 using testing::Expectation; |
| 30 using testing::Invoke; | 31 using testing::Invoke; |
| 31 using testing::InvokeWithoutArgs; | 32 using testing::InvokeWithoutArgs; |
| 32 using testing::Return; | 33 using testing::Return; |
| 33 using testing::ReturnPointee; | |
| 34 | 34 |
| 35 namespace remoting { | 35 namespace remoting { |
| 36 | 36 |
| 37 namespace { | 37 namespace { |
| 38 | 38 |
| 39 const char kIpcSecurityDescriptor[] = "D:(A;;GA;;;AU)"; | 39 const char kIpcSecurityDescriptor[] = "D:(A;;GA;;;AU)"; |
| 40 | 40 |
| 41 class MockProcessLauncherDelegate : public WorkerProcessLauncher::Delegate { | 41 class MockProcessLauncherDelegate : public WorkerProcessLauncher::Delegate { |
| 42 public: | 42 public: |
| 43 MockProcessLauncherDelegate() {} | 43 MockProcessLauncherDelegate() {} |
| 44 virtual ~MockProcessLauncherDelegate() {} | 44 virtual ~MockProcessLauncherDelegate() {} |
| 45 | 45 |
| 46 // IPC::Sender implementation. | |
| 47 MOCK_METHOD1(Send, bool(IPC::Message*)); | |
| 48 | |
| 49 // WorkerProcessLauncher::Delegate interface. | 46 // WorkerProcessLauncher::Delegate interface. |
| 47 MOCK_METHOD1(LaunchProcess, void(WorkerProcessLauncher*)); | |
| 48 MOCK_METHOD1(Send, void(IPC::Message*)); | |
| 50 MOCK_METHOD0(CloseChannel, void()); | 49 MOCK_METHOD0(CloseChannel, void()); |
| 51 MOCK_CONST_METHOD0(GetProcessId, DWORD()); | 50 MOCK_METHOD0(KillProcess, void()); |
| 52 MOCK_CONST_METHOD1(IsPermanentError, bool(int)); | |
| 53 MOCK_METHOD1(KillProcess, void(DWORD)); | |
| 54 MOCK_METHOD2(LaunchProcess, bool(IPC::Listener*, ScopedHandle*)); | |
| 55 | 51 |
| 56 private: | 52 private: |
| 57 DISALLOW_COPY_AND_ASSIGN(MockProcessLauncherDelegate); | 53 DISALLOW_COPY_AND_ASSIGN(MockProcessLauncherDelegate); |
| 58 }; | 54 }; |
| 59 | 55 |
| 60 class MockIpcDelegate : public WorkerProcessIpcDelegate { | 56 class MockIpcDelegate : public WorkerProcessIpcDelegate { |
| 61 public: | 57 public: |
| 62 MockIpcDelegate() {} | 58 MockIpcDelegate() {} |
| 63 virtual ~MockIpcDelegate() {} | 59 virtual ~MockIpcDelegate() {} |
| 64 | 60 |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 92 IPC_MESSAGE_UNHANDLED(handled = false) | 88 IPC_MESSAGE_UNHANDLED(handled = false) |
| 93 IPC_END_MESSAGE_MAP() | 89 IPC_END_MESSAGE_MAP() |
| 94 | 90 |
| 95 EXPECT_TRUE(handled); | 91 EXPECT_TRUE(handled); |
| 96 | 92 |
| 97 return handled; | 93 return handled; |
| 98 } | 94 } |
| 99 | 95 |
| 100 } // namespace | 96 } // namespace |
| 101 | 97 |
| 102 class WorkerProcessLauncherTest : public testing::Test { | 98 class WorkerProcessLauncherTest |
| 99 : public testing::Test, | |
| 100 public IPC::Listener { | |
| 103 public: | 101 public: |
| 104 WorkerProcessLauncherTest(); | 102 WorkerProcessLauncherTest(); |
| 105 virtual ~WorkerProcessLauncherTest(); | 103 virtual ~WorkerProcessLauncherTest(); |
| 106 | 104 |
| 107 virtual void SetUp() OVERRIDE; | 105 virtual void SetUp() OVERRIDE; |
| 108 virtual void TearDown() OVERRIDE; | 106 virtual void TearDown() OVERRIDE; |
| 109 | 107 |
| 108 // IPC::Listener implementation. | |
| 109 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; | |
| 110 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE; | |
| 111 virtual void OnChannelError() OVERRIDE; | |
| 112 | |
| 110 // WorkerProcessLauncher::Delegate mocks | 113 // WorkerProcessLauncher::Delegate mocks |
| 111 void KillProcess(DWORD exit_code); | 114 void LaunchProcess( |
| 112 bool LaunchProcess(IPC::Listener* delegate, | 115 WorkerProcessLauncher* event_handler); |
| 113 ScopedHandle* process_exit_event_out); | 116 void LaunchProcessAndConnect( |
| 114 bool LaunchProcessAndConnect(IPC::Listener* delegate, | 117 WorkerProcessLauncher* event_handler); |
| 115 ScopedHandle* process_exit_event_out); | 118 void FailLaunchAndStopWorker( |
| 116 bool FailLaunchAndStopWorker(IPC::Listener* delegate, | 119 WorkerProcessLauncher* event_handler); |
| 117 ScopedHandle* process_exit_event_out); | 120 void KillProcess(); |
| 121 | |
| 122 void TerminateWorker(DWORD exit_code); | |
| 118 | 123 |
| 119 // Connects the client end of the channel (the worker process's end). | 124 // Connects the client end of the channel (the worker process's end). |
| 120 void ConnectClient(); | 125 void ConnectClient(); |
| 121 | 126 |
| 122 // Disconnects the client end of the channel. | 127 // Disconnects the client end of the channel. |
| 123 void DisconnectClient(); | 128 void DisconnectClient(); |
| 124 | 129 |
| 125 // Disconnects the server end of the channel (the launcher's end). | 130 // Disconnects the server end of the channel (the launcher's end). |
| 126 void DisconnectServer(); | 131 void DisconnectServer(); |
| 127 | 132 |
| 128 // Sends a message to the worker process. | 133 // Sends a message to the worker process. |
| 129 bool SendToProcess(IPC::Message* message); | 134 void SendToProcess(IPC::Message* message); |
| 130 | 135 |
| 131 // Sends a fake message to the launcher. | 136 // Sends a fake message to the launcher. |
| 132 void SendFakeMessageToLauncher(); | 137 void SendFakeMessageToLauncher(); |
| 133 | 138 |
| 134 // Requests the worker to crash. | 139 // Requests the worker to crash. |
| 135 void CrashWorker(); | 140 void CrashWorker(); |
| 136 | 141 |
| 137 // Starts the worker. | 142 // Starts the worker. |
| 138 void StartWorker(); | 143 void StartWorker(); |
| 139 | 144 |
| 140 // Stops the worker. | 145 // Stops the worker. |
| 141 void StopWorker(); | 146 void StopWorker(); |
| 142 | 147 |
| 143 // Quits |message_loop_|. | 148 // Quits |message_loop_|. |
| 144 void QuitMainMessageLoop(); | 149 void QuitMainMessageLoop(); |
| 145 | 150 |
| 146 protected: | 151 protected: |
| 152 void DoLaunchProcess(); | |
| 153 | |
| 147 base::MessageLoop message_loop_; | 154 base::MessageLoop message_loop_; |
| 148 scoped_refptr<AutoThreadTaskRunner> task_runner_; | 155 scoped_refptr<AutoThreadTaskRunner> task_runner_; |
| 149 | 156 |
| 150 // Receives messages sent to the worker process. | 157 // Receives messages sent to the worker process. |
| 151 MockWorkerListener client_listener_; | 158 MockWorkerListener client_listener_; |
| 152 | 159 |
| 153 // Receives messages sent from the worker process. | 160 // Receives messages sent from the worker process. |
| 154 MockIpcDelegate server_listener_; | 161 MockIpcDelegate server_listener_; |
| 155 | 162 |
| 156 // Implements WorkerProcessLauncher::Delegate. | 163 // Implements WorkerProcessLauncher::Delegate. |
| 157 scoped_ptr<MockProcessLauncherDelegate> launcher_delegate_; | 164 scoped_ptr<MockProcessLauncherDelegate> launcher_delegate_; |
| 158 | 165 |
| 159 // The name of the IPC channel. | 166 // The name of the IPC channel. |
| 160 std::string channel_name_; | 167 std::string channel_name_; |
| 161 | 168 |
| 162 // Client and server ends of the IPC channel. | 169 // Client and server ends of the IPC channel. |
| 163 scoped_ptr<IPC::ChannelProxy> channel_client_; | 170 scoped_ptr<IPC::ChannelProxy> channel_client_; |
| 164 scoped_ptr<IPC::ChannelProxy> channel_server_; | 171 scoped_ptr<IPC::ChannelProxy> channel_server_; |
| 165 | 172 |
| 166 // Returned as the worker process PID to the launcher. | 173 WorkerProcessLauncher* event_handler_; |
| 167 DWORD client_pid_; | |
| 168 | 174 |
| 169 // The worker process launcher. | 175 // The worker process launcher. |
| 170 scoped_ptr<WorkerProcessLauncher> launcher_; | 176 scoped_ptr<WorkerProcessLauncher> launcher_; |
| 171 | 177 |
| 172 // The event signalling termination of the worker process. | 178 // An event that is used to emulate the worker process's handle. |
| 173 ScopedHandle process_exit_event_; | 179 ScopedHandle worker_process_; |
| 174 | |
| 175 // True if a permanent error condition should be emulated. | |
| 176 bool permanent_error_; | |
| 177 }; | 180 }; |
| 178 | 181 |
| 179 WorkerProcessLauncherTest::WorkerProcessLauncherTest() | 182 WorkerProcessLauncherTest::WorkerProcessLauncherTest() |
| 180 : message_loop_(base::MessageLoop::TYPE_IO), | 183 : message_loop_(base::MessageLoop::TYPE_IO), |
| 181 client_pid_(GetCurrentProcessId()), | 184 event_handler_(NULL) { |
| 182 permanent_error_(false) {} | 185 } |
| 183 | 186 |
| 184 WorkerProcessLauncherTest::~WorkerProcessLauncherTest() { | 187 WorkerProcessLauncherTest::~WorkerProcessLauncherTest() { |
| 185 } | 188 } |
| 186 | 189 |
| 187 void WorkerProcessLauncherTest::SetUp() { | 190 void WorkerProcessLauncherTest::SetUp() { |
| 188 task_runner_ = new AutoThreadTaskRunner( | 191 task_runner_ = new AutoThreadTaskRunner( |
| 189 message_loop_.message_loop_proxy(), | 192 message_loop_.message_loop_proxy(), |
| 190 base::Bind(&WorkerProcessLauncherTest::QuitMainMessageLoop, | 193 base::Bind(&WorkerProcessLauncherTest::QuitMainMessageLoop, |
| 191 base::Unretained(this))); | 194 base::Unretained(this))); |
| 192 | 195 |
| 193 // Set up process launcher delegate | 196 // Set up process launcher delegate |
| 194 launcher_delegate_.reset(new MockProcessLauncherDelegate()); | 197 launcher_delegate_.reset(new MockProcessLauncherDelegate()); |
| 195 EXPECT_CALL(*launcher_delegate_, Send(_)) | 198 EXPECT_CALL(*launcher_delegate_, Send(_)) |
| 196 .Times(AnyNumber()) | 199 .Times(AnyNumber()) |
| 197 .WillRepeatedly(Invoke(this, &WorkerProcessLauncherTest::SendToProcess)); | 200 .WillRepeatedly(Invoke(this, &WorkerProcessLauncherTest::SendToProcess)); |
| 198 EXPECT_CALL(*launcher_delegate_, CloseChannel()) | 201 EXPECT_CALL(*launcher_delegate_, CloseChannel()) |
| 199 .Times(AnyNumber()) | 202 .Times(AnyNumber()) |
| 200 .WillRepeatedly(Invoke(this, | 203 .WillRepeatedly(Invoke(this, |
| 201 &WorkerProcessLauncherTest::DisconnectServer)); | 204 &WorkerProcessLauncherTest::DisconnectServer)); |
| 202 EXPECT_CALL(*launcher_delegate_, GetProcessId()) | 205 EXPECT_CALL(*launcher_delegate_, KillProcess()) |
| 203 .Times(AnyNumber()) | |
| 204 .WillRepeatedly(ReturnPointee(&client_pid_)); | |
| 205 EXPECT_CALL(*launcher_delegate_, IsPermanentError(_)) | |
| 206 .Times(AnyNumber()) | |
| 207 .WillRepeatedly(ReturnPointee(&permanent_error_)); | |
| 208 EXPECT_CALL(*launcher_delegate_, KillProcess(_)) | |
| 209 .Times(AnyNumber()) | 206 .Times(AnyNumber()) |
| 210 .WillRepeatedly(Invoke(this, &WorkerProcessLauncherTest::KillProcess)); | 207 .WillRepeatedly(Invoke(this, &WorkerProcessLauncherTest::KillProcess)); |
| 211 | 208 |
| 212 // Set up IPC delegate. | 209 // Set up IPC delegate. |
| 213 EXPECT_CALL(server_listener_, OnMessageReceived(_)) | 210 EXPECT_CALL(server_listener_, OnMessageReceived(_)) |
| 214 .Times(0); | 211 .Times(0); |
| 215 } | 212 } |
| 216 | 213 |
| 217 void WorkerProcessLauncherTest::TearDown() { | 214 void WorkerProcessLauncherTest::TearDown() { |
| 218 } | 215 } |
| 219 | 216 |
| 220 void WorkerProcessLauncherTest::KillProcess(DWORD exit_code) { | 217 bool WorkerProcessLauncherTest::OnMessageReceived(const IPC::Message& message) { |
| 221 BOOL result = SetEvent(process_exit_event_); | 218 return event_handler_->OnMessageReceived(message); |
| 222 EXPECT_TRUE(result); | |
| 223 } | 219 } |
| 224 | 220 |
| 225 bool WorkerProcessLauncherTest::LaunchProcess( | 221 void WorkerProcessLauncherTest::OnChannelConnected(int32 peer_pid) { |
| 226 IPC::Listener* delegate, | 222 event_handler_->OnChannelConnected(peer_pid); |
| 227 ScopedHandle* process_exit_event_out) { | |
| 228 process_exit_event_.Set(CreateEvent(NULL, TRUE, FALSE, NULL)); | |
| 229 if (!process_exit_event_.IsValid()) | |
| 230 return false; | |
| 231 | |
| 232 channel_name_ = IPC::Channel::GenerateUniqueRandomChannelID(); | |
| 233 ScopedHandle pipe; | |
| 234 if (!CreateIpcChannel(channel_name_, kIpcSecurityDescriptor, &pipe)) { | |
| 235 return false; | |
| 236 } | |
| 237 | |
| 238 // Wrap the pipe into an IPC channel. | |
| 239 channel_server_.reset(new IPC::ChannelProxy( | |
| 240 IPC::ChannelHandle(pipe), | |
| 241 IPC::Channel::MODE_SERVER, | |
| 242 delegate, | |
| 243 task_runner_)); | |
| 244 | |
| 245 return DuplicateHandle(GetCurrentProcess(), | |
| 246 process_exit_event_, | |
| 247 GetCurrentProcess(), | |
| 248 process_exit_event_out->Receive(), | |
| 249 0, | |
| 250 FALSE, | |
| 251 DUPLICATE_SAME_ACCESS) != FALSE; | |
| 252 } | 223 } |
| 253 | 224 |
| 254 bool WorkerProcessLauncherTest::LaunchProcessAndConnect( | 225 void WorkerProcessLauncherTest::OnChannelError() { |
| 255 IPC::Listener* delegate, | 226 event_handler_->OnChannelError(); |
| 256 ScopedHandle* process_exit_event_out) { | 227 } |
| 257 if (!LaunchProcess(delegate, process_exit_event_out)) | 228 |
| 258 return false; | 229 void WorkerProcessLauncherTest::LaunchProcess( |
| 230 WorkerProcessLauncher* event_handler) { | |
| 231 EXPECT_FALSE(event_handler_); | |
| 232 event_handler_ = event_handler; | |
| 233 | |
| 234 DoLaunchProcess(); | |
| 235 } | |
| 236 | |
| 237 void WorkerProcessLauncherTest::LaunchProcessAndConnect( | |
| 238 WorkerProcessLauncher* event_handler) { | |
| 239 EXPECT_FALSE(event_handler_); | |
| 240 event_handler_ = event_handler; | |
| 241 | |
| 242 DoLaunchProcess(); | |
| 259 | 243 |
| 260 task_runner_->PostTask( | 244 task_runner_->PostTask( |
| 261 FROM_HERE, | 245 FROM_HERE, |
| 262 base::Bind(&WorkerProcessLauncherTest::ConnectClient, | 246 base::Bind(&WorkerProcessLauncherTest::ConnectClient, |
| 263 base::Unretained(this))); | 247 base::Unretained(this))); |
| 264 return true; | |
| 265 } | 248 } |
| 266 | 249 |
| 267 bool WorkerProcessLauncherTest::FailLaunchAndStopWorker( | 250 void WorkerProcessLauncherTest::FailLaunchAndStopWorker( |
| 268 IPC::Listener* delegate, | 251 WorkerProcessLauncher* event_handler) { |
| 269 ScopedHandle* process_exit_event_out) { | 252 EXPECT_FALSE(event_handler_); |
| 253 | |
| 254 event_handler->OnFatalError(); | |
| 255 | |
| 270 task_runner_->PostTask( | 256 task_runner_->PostTask( |
| 271 FROM_HERE, | 257 FROM_HERE, |
| 272 base::Bind(&WorkerProcessLauncherTest::StopWorker, | 258 base::Bind(&WorkerProcessLauncherTest::StopWorker, |
| 273 base::Unretained(this))); | 259 base::Unretained(this))); |
| 274 return false; | 260 } |
| 261 | |
| 262 void WorkerProcessLauncherTest::KillProcess() { | |
| 263 event_handler_ = NULL; | |
| 264 | |
| 265 if (worker_process_.IsValid()) { | |
| 266 TerminateProcess(worker_process_, CONTROL_C_EXIT); | |
| 267 worker_process_.Close(); | |
| 268 } | |
| 269 } | |
| 270 | |
| 271 void WorkerProcessLauncherTest::TerminateWorker(DWORD exit_code) { | |
| 272 if (worker_process_.IsValid()) | |
| 273 TerminateProcess(worker_process_, exit_code); | |
| 275 } | 274 } |
| 276 | 275 |
| 277 void WorkerProcessLauncherTest::ConnectClient() { | 276 void WorkerProcessLauncherTest::ConnectClient() { |
| 278 channel_client_.reset(new IPC::ChannelProxy( | 277 channel_client_.reset(new IPC::ChannelProxy( |
| 279 IPC::ChannelHandle(channel_name_), | 278 IPC::ChannelHandle(channel_name_), |
| 280 IPC::Channel::MODE_CLIENT, | 279 IPC::Channel::MODE_CLIENT, |
| 281 &client_listener_, | 280 &client_listener_, |
| 282 task_runner_)); | 281 task_runner_)); |
| 283 | 282 |
| 284 // Pretend that |kLaunchSuccessTimeoutSeconds| passed since launching | 283 // Pretend that |kLaunchSuccessTimeoutSeconds| passed since launching |
| 285 // the worker process. This will make the backoff algorithm think that this | 284 // the worker process. This will make the backoff algorithm think that this |
| 286 // launch attempt was successful and it will not delay the next launch. | 285 // launch attempt was successful and it will not delay the next launch. |
| 287 launcher_->ResetLaunchSuccessTimeoutForTest(); | 286 launcher_->RecordSuccessfulLaunchForTest(); |
| 288 } | 287 } |
| 289 | 288 |
| 290 void WorkerProcessLauncherTest::DisconnectClient() { | 289 void WorkerProcessLauncherTest::DisconnectClient() { |
| 291 channel_client_.reset(); | 290 channel_client_.reset(); |
| 292 } | 291 } |
| 293 | 292 |
| 294 void WorkerProcessLauncherTest::DisconnectServer() { | 293 void WorkerProcessLauncherTest::DisconnectServer() { |
| 295 channel_server_.reset(); | 294 channel_server_.reset(); |
| 296 } | 295 } |
| 297 | 296 |
| 298 bool WorkerProcessLauncherTest::SendToProcess(IPC::Message* message) { | 297 void WorkerProcessLauncherTest::SendToProcess(IPC::Message* message) { |
| 299 if (channel_server_) | 298 if (channel_server_) { |
| 300 return channel_server_->Send(message); | 299 channel_server_->Send(message); |
| 300 return; | |
| 301 } | |
| 301 | 302 |
| 302 delete message; | 303 delete message; |
| 303 return false; | |
| 304 } | 304 } |
| 305 | 305 |
| 306 void WorkerProcessLauncherTest::SendFakeMessageToLauncher() { | 306 void WorkerProcessLauncherTest::SendFakeMessageToLauncher() { |
| 307 if (channel_client_) | 307 if (channel_client_) |
| 308 channel_client_->Send(new ChromotingDesktopNetworkMsg_DisconnectSession()); | 308 channel_client_->Send(new ChromotingDesktopNetworkMsg_DisconnectSession()); |
| 309 } | 309 } |
| 310 | 310 |
| 311 void WorkerProcessLauncherTest::CrashWorker() { | 311 void WorkerProcessLauncherTest::CrashWorker() { |
| 312 launcher_->Crash(FROM_HERE); | 312 launcher_->Crash(FROM_HERE); |
| 313 } | 313 } |
| 314 | 314 |
| 315 void WorkerProcessLauncherTest::StartWorker() { | 315 void WorkerProcessLauncherTest::StartWorker() { |
| 316 launcher_.reset(new WorkerProcessLauncher( | 316 launcher_.reset(new WorkerProcessLauncher(launcher_delegate_.Pass(), |
| 317 task_runner_, launcher_delegate_.Pass(), &server_listener_)); | 317 &server_listener_)); |
| 318 | 318 |
| 319 launcher_->SetKillProcessTimeoutForTest(base::TimeDelta::FromMilliseconds(0)); | 319 launcher_->SetKillProcessTimeoutForTest(base::TimeDelta::FromMilliseconds(0)); |
| 320 } | 320 } |
| 321 | 321 |
| 322 void WorkerProcessLauncherTest::StopWorker() { | 322 void WorkerProcessLauncherTest::StopWorker() { |
| 323 launcher_.reset(); | 323 launcher_.reset(); |
| 324 DisconnectClient(); | 324 DisconnectClient(); |
| 325 channel_name_.clear(); | 325 channel_name_.clear(); |
| 326 channel_server_.reset(); | 326 channel_server_.reset(); |
| 327 task_runner_ = NULL; | 327 task_runner_ = NULL; |
| 328 } | 328 } |
| 329 | 329 |
| 330 void WorkerProcessLauncherTest::QuitMainMessageLoop() { | 330 void WorkerProcessLauncherTest::QuitMainMessageLoop() { |
| 331 message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); | 331 message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); |
| 332 } | 332 } |
| 333 | 333 |
| 334 void WorkerProcessLauncherTest::DoLaunchProcess() { | |
|
garykac
2013/05/15 23:24:30
Is is reasonable to Mockout the Windows version ch
alexeypa (please no reviews)
2013/05/16 17:50:04
That should be possible. I'd postpone it until we
| |
| 335 EXPECT_TRUE(event_handler_); | |
| 336 EXPECT_FALSE(worker_process_.IsValid()); | |
| 337 | |
| 338 WCHAR notepad[MAX_PATH + 1]; | |
| 339 ASSERT_GT(ExpandEnvironmentStrings( | |
| 340 L"\045SystemRoot\045\\system32\\notepad.exe", notepad, MAX_PATH), 0u); | |
| 341 | |
| 342 STARTUPINFOW startup_info = { 0 }; | |
| 343 startup_info.cb = sizeof(startup_info); | |
| 344 | |
| 345 base::win::ScopedProcessInformation process_information; | |
| 346 ASSERT_TRUE(CreateProcess(NULL, | |
| 347 notepad, | |
| 348 NULL, // default process attibutes | |
| 349 NULL, // default thread attibutes | |
| 350 FALSE, // do not inherit handles | |
| 351 CREATE_SUSPENDED, | |
| 352 NULL, // no environment | |
| 353 NULL, // default current directory | |
| 354 &startup_info, | |
| 355 process_information.Receive())); | |
| 356 worker_process_.Set(process_information.TakeProcessHandle()); | |
| 357 ASSERT_TRUE(worker_process_.IsValid()); | |
| 358 | |
| 359 channel_name_ = IPC::Channel::GenerateUniqueRandomChannelID(); | |
| 360 ScopedHandle pipe; | |
| 361 ASSERT_TRUE(CreateIpcChannel(channel_name_, kIpcSecurityDescriptor, &pipe)); | |
| 362 | |
| 363 // Wrap the pipe into an IPC channel. | |
| 364 channel_server_.reset(new IPC::ChannelProxy( | |
| 365 IPC::ChannelHandle(pipe), | |
| 366 IPC::Channel::MODE_SERVER, | |
| 367 this, | |
| 368 task_runner_)); | |
| 369 | |
| 370 ScopedHandle copy; | |
| 371 ASSERT_TRUE(DuplicateHandle(GetCurrentProcess(), | |
| 372 worker_process_, | |
| 373 GetCurrentProcess(), | |
| 374 copy.Receive(), | |
| 375 0, | |
| 376 FALSE, | |
| 377 DUPLICATE_SAME_ACCESS)); | |
| 378 | |
| 379 event_handler_->OnProcessLaunched(copy.Pass()); | |
| 380 } | |
| 381 | |
| 334 TEST_F(WorkerProcessLauncherTest, Start) { | 382 TEST_F(WorkerProcessLauncherTest, Start) { |
| 335 EXPECT_CALL(*launcher_delegate_, LaunchProcess(_, _)) | 383 EXPECT_CALL(*launcher_delegate_, LaunchProcess(_)) |
| 336 .Times(1) | 384 .Times(1) |
| 337 .WillRepeatedly(Invoke(this, &WorkerProcessLauncherTest::LaunchProcess)); | 385 .WillRepeatedly(Invoke(this, &WorkerProcessLauncherTest::LaunchProcess)); |
| 338 | 386 |
| 339 EXPECT_CALL(server_listener_, OnChannelConnected(_)) | 387 EXPECT_CALL(server_listener_, OnChannelConnected(_)) |
| 340 .Times(0); | 388 .Times(0); |
| 341 EXPECT_CALL(server_listener_, OnPermanentError()) | 389 EXPECT_CALL(server_listener_, OnPermanentError()) |
| 342 .Times(0); | 390 .Times(0); |
| 343 | 391 |
| 344 StartWorker(); | 392 StartWorker(); |
| 345 StopWorker(); | 393 StopWorker(); |
| 346 message_loop_.Run(); | 394 message_loop_.Run(); |
| 347 } | 395 } |
| 348 | 396 |
| 349 // Starts and connects to the worker process. Expect OnChannelConnected to be | 397 // Starts and connects to the worker process. Expect OnChannelConnected to be |
| 350 // called. | 398 // called. |
| 351 TEST_F(WorkerProcessLauncherTest, StartAndConnect) { | 399 TEST_F(WorkerProcessLauncherTest, StartAndConnect) { |
| 352 EXPECT_CALL(*launcher_delegate_, LaunchProcess(_, _)) | 400 EXPECT_CALL(*launcher_delegate_, LaunchProcess(_)) |
| 353 .Times(1) | 401 .Times(1) |
| 354 .WillRepeatedly(Invoke( | 402 .WillRepeatedly(Invoke( |
| 355 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect)); | 403 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect)); |
| 356 | 404 |
| 357 EXPECT_CALL(server_listener_, OnChannelConnected(_)) | 405 EXPECT_CALL(server_listener_, OnChannelConnected(_)) |
| 358 .Times(1) | 406 .Times(1) |
| 359 .WillOnce(InvokeWithoutArgs(this, | 407 .WillOnce(InvokeWithoutArgs(this, |
| 360 &WorkerProcessLauncherTest::StopWorker)); | 408 &WorkerProcessLauncherTest::StopWorker)); |
| 361 EXPECT_CALL(server_listener_, OnPermanentError()) | 409 EXPECT_CALL(server_listener_, OnPermanentError()) |
| 362 .Times(0); | 410 .Times(0); |
| 363 | 411 |
| 364 StartWorker(); | 412 StartWorker(); |
| 365 message_loop_.Run(); | 413 message_loop_.Run(); |
| 366 } | 414 } |
| 367 | 415 |
| 368 // Kills the worker process after the 1st connect and expects it to be | 416 // Kills the worker process after the 1st connect and expects it to be |
| 369 // restarted. | 417 // restarted. |
| 370 TEST_F(WorkerProcessLauncherTest, Restart) { | 418 TEST_F(WorkerProcessLauncherTest, Restart) { |
| 371 EXPECT_CALL(*launcher_delegate_, LaunchProcess(_, _)) | 419 EXPECT_CALL(*launcher_delegate_, LaunchProcess(_)) |
| 372 .Times(2) | 420 .Times(2) |
| 373 .WillRepeatedly(Invoke( | 421 .WillRepeatedly(Invoke( |
| 374 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect)); | 422 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect)); |
| 375 Expectation first_connect = | 423 Expectation first_connect = |
| 376 EXPECT_CALL(server_listener_, OnChannelConnected(_)) | 424 EXPECT_CALL(server_listener_, OnChannelConnected(_)) |
| 377 .Times(2) | 425 .Times(2) |
| 378 .WillOnce(InvokeWithoutArgs(CreateFunctor( | 426 .WillOnce(InvokeWithoutArgs(CreateFunctor( |
| 379 this, &WorkerProcessLauncherTest::KillProcess, CONTROL_C_EXIT))) | 427 this, &WorkerProcessLauncherTest::TerminateWorker, |
| 428 CONTROL_C_EXIT))) | |
| 380 .WillOnce(InvokeWithoutArgs(this, | 429 .WillOnce(InvokeWithoutArgs(this, |
| 381 &WorkerProcessLauncherTest::StopWorker)); | 430 &WorkerProcessLauncherTest::StopWorker)); |
| 382 | 431 |
| 383 EXPECT_CALL(server_listener_, OnPermanentError()) | 432 EXPECT_CALL(server_listener_, OnPermanentError()) |
| 384 .Times(0); | 433 .Times(0); |
| 385 | 434 |
| 386 StartWorker(); | 435 StartWorker(); |
| 387 message_loop_.Run(); | 436 message_loop_.Run(); |
| 388 } | 437 } |
| 389 | 438 |
| 390 // Drops the IPC channel to the worker process after the 1st connect and expects | 439 // Drops the IPC channel to the worker process after the 1st connect and expects |
| 391 // the worker process to be restarted. | 440 // the worker process to be restarted. |
| 392 TEST_F(WorkerProcessLauncherTest, DropIpcChannel) { | 441 TEST_F(WorkerProcessLauncherTest, DropIpcChannel) { |
| 393 EXPECT_CALL(*launcher_delegate_, LaunchProcess(_, _)) | 442 EXPECT_CALL(*launcher_delegate_, LaunchProcess(_)) |
| 394 .Times(2) | 443 .Times(2) |
| 395 .WillRepeatedly(Invoke( | 444 .WillRepeatedly(Invoke( |
| 396 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect)); | 445 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect)); |
| 397 | 446 |
| 398 Expectation first_connect = | 447 Expectation first_connect = |
| 399 EXPECT_CALL(server_listener_, OnChannelConnected(_)) | 448 EXPECT_CALL(server_listener_, OnChannelConnected(_)) |
| 400 .Times(2) | 449 .Times(2) |
| 401 .WillOnce(InvokeWithoutArgs( | 450 .WillOnce(InvokeWithoutArgs( |
| 402 this, &WorkerProcessLauncherTest::DisconnectClient)) | 451 this, &WorkerProcessLauncherTest::DisconnectClient)) |
| 403 .WillOnce(InvokeWithoutArgs( | 452 .WillOnce(InvokeWithoutArgs( |
| 404 this, &WorkerProcessLauncherTest::StopWorker)); | 453 this, &WorkerProcessLauncherTest::StopWorker)); |
| 405 | 454 |
| 406 EXPECT_CALL(server_listener_, OnPermanentError()) | 455 EXPECT_CALL(server_listener_, OnPermanentError()) |
| 407 .Times(0); | 456 .Times(0); |
| 408 | 457 |
| 409 StartWorker(); | 458 StartWorker(); |
| 410 message_loop_.Run(); | 459 message_loop_.Run(); |
| 411 } | 460 } |
| 412 | 461 |
| 413 // Returns a permanent error exit code and expects OnPermanentError() to be | 462 // Returns a permanent error exit code and expects OnPermanentError() to be |
| 414 // invoked. | 463 // invoked. |
| 415 TEST_F(WorkerProcessLauncherTest, PermanentError) { | 464 TEST_F(WorkerProcessLauncherTest, PermanentError) { |
| 416 EXPECT_CALL(*launcher_delegate_, LaunchProcess(_, _)) | 465 EXPECT_CALL(*launcher_delegate_, LaunchProcess(_)) |
| 417 .Times(1) | 466 .Times(1) |
| 418 .WillRepeatedly(Invoke( | 467 .WillRepeatedly(Invoke( |
| 419 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect)); | 468 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect)); |
| 420 | 469 |
| 421 EXPECT_CALL(server_listener_, OnChannelConnected(_)) | 470 EXPECT_CALL(server_listener_, OnChannelConnected(_)) |
| 422 .Times(1) | 471 .Times(1) |
| 423 .WillOnce(InvokeWithoutArgs(CreateFunctor( | 472 .WillOnce(InvokeWithoutArgs(CreateFunctor( |
| 424 this, &WorkerProcessLauncherTest::KillProcess, CONTROL_C_EXIT))); | 473 this, &WorkerProcessLauncherTest::TerminateWorker, |
| 474 kMinPermanentErrorExitCode))); | |
| 425 EXPECT_CALL(server_listener_, OnPermanentError()) | 475 EXPECT_CALL(server_listener_, OnPermanentError()) |
| 426 .Times(1) | 476 .Times(1) |
| 427 .WillOnce(InvokeWithoutArgs(this, | 477 .WillOnce(InvokeWithoutArgs(this, |
| 428 &WorkerProcessLauncherTest::StopWorker)); | 478 &WorkerProcessLauncherTest::StopWorker)); |
| 429 | 479 |
| 430 permanent_error_ = true; | |
| 431 StartWorker(); | |
| 432 message_loop_.Run(); | |
| 433 } | |
| 434 | |
| 435 // Returns invalid client PID and expects the connection to be rejected. | |
| 436 TEST_F(WorkerProcessLauncherTest, InvalidClientPid) { | |
| 437 EXPECT_CALL(*launcher_delegate_, LaunchProcess(_, _)) | |
| 438 .Times(2) | |
| 439 .WillOnce(Invoke( | |
| 440 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect)) | |
| 441 .WillOnce(Invoke( | |
| 442 this, &WorkerProcessLauncherTest::FailLaunchAndStopWorker)); | |
| 443 | |
| 444 EXPECT_CALL(server_listener_, OnChannelConnected(_)) | |
| 445 .Times(0); | |
| 446 EXPECT_CALL(server_listener_, OnPermanentError()) | |
| 447 .Times(0); | |
| 448 | |
| 449 client_pid_ = GetCurrentProcessId() + 4; | |
| 450 StartWorker(); | 480 StartWorker(); |
| 451 message_loop_.Run(); | 481 message_loop_.Run(); |
| 452 } | 482 } |
| 453 | 483 |
| 454 // Requests the worker to crash and expects it to honor the request. | 484 // Requests the worker to crash and expects it to honor the request. |
| 455 TEST_F(WorkerProcessLauncherTest, Crash) { | 485 TEST_F(WorkerProcessLauncherTest, Crash) { |
| 456 EXPECT_CALL(*launcher_delegate_, LaunchProcess(_, _)) | 486 EXPECT_CALL(*launcher_delegate_, LaunchProcess(_)) |
| 457 .Times(2) | 487 .Times(2) |
| 458 .WillRepeatedly(Invoke( | 488 .WillRepeatedly(Invoke( |
| 459 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect)); | 489 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect)); |
| 460 | 490 |
| 461 EXPECT_CALL(server_listener_, OnChannelConnected(_)) | 491 EXPECT_CALL(server_listener_, OnChannelConnected(_)) |
| 462 .Times(2) | 492 .Times(2) |
| 463 .WillOnce(InvokeWithoutArgs(this, | 493 .WillOnce(InvokeWithoutArgs(this, |
| 464 &WorkerProcessLauncherTest::CrashWorker)) | 494 &WorkerProcessLauncherTest::CrashWorker)) |
| 465 .WillOnce(InvokeWithoutArgs(this, | 495 .WillOnce(InvokeWithoutArgs(this, |
| 466 &WorkerProcessLauncherTest::StopWorker)); | 496 &WorkerProcessLauncherTest::StopWorker)); |
| 467 | 497 |
| 468 EXPECT_CALL(client_listener_, OnCrash(_, _, _)) | 498 EXPECT_CALL(client_listener_, OnCrash(_, _, _)) |
| 469 .Times(1) | 499 .Times(1) |
| 470 .WillOnce(InvokeWithoutArgs(CreateFunctor( | 500 .WillOnce(InvokeWithoutArgs(CreateFunctor( |
| 471 this, &WorkerProcessLauncherTest::KillProcess, | 501 this, &WorkerProcessLauncherTest::TerminateWorker, |
| 472 EXCEPTION_BREAKPOINT))); | 502 EXCEPTION_BREAKPOINT))); |
| 473 | 503 |
| 474 StartWorker(); | 504 StartWorker(); |
| 475 message_loop_.Run(); | 505 message_loop_.Run(); |
| 476 } | 506 } |
| 477 | 507 |
| 478 // Requests the worker to crash and terminates the worker even if it does not | 508 // Requests the worker to crash and terminates the worker even if it does not |
| 479 // comply. | 509 // comply. |
| 480 TEST_F(WorkerProcessLauncherTest, CrashAnyway) { | 510 TEST_F(WorkerProcessLauncherTest, CrashAnyway) { |
| 481 EXPECT_CALL(*launcher_delegate_, LaunchProcess(_, _)) | 511 EXPECT_CALL(*launcher_delegate_, LaunchProcess(_)) |
| 482 .Times(2) | 512 .Times(2) |
| 483 .WillRepeatedly(Invoke( | 513 .WillRepeatedly(Invoke( |
| 484 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect)); | 514 this, &WorkerProcessLauncherTest::LaunchProcessAndConnect)); |
| 485 | 515 |
| 486 EXPECT_CALL(server_listener_, OnChannelConnected(_)) | 516 EXPECT_CALL(server_listener_, OnChannelConnected(_)) |
| 487 .Times(2) | 517 .Times(2) |
| 488 .WillOnce(InvokeWithoutArgs(this, | 518 .WillOnce(InvokeWithoutArgs(this, |
| 489 &WorkerProcessLauncherTest::CrashWorker)) | 519 &WorkerProcessLauncherTest::CrashWorker)) |
| 490 .WillOnce(InvokeWithoutArgs(this, | 520 .WillOnce(InvokeWithoutArgs(this, |
| 491 &WorkerProcessLauncherTest::StopWorker)); | 521 &WorkerProcessLauncherTest::StopWorker)); |
| 492 | 522 |
| 493 // Ignore the crash request and try send another message to the launcher. | 523 // Ignore the crash request and try send another message to the launcher. |
| 494 EXPECT_CALL(client_listener_, OnCrash(_, _, _)) | 524 EXPECT_CALL(client_listener_, OnCrash(_, _, _)) |
| 495 .Times(1) | 525 .Times(1) |
| 496 .WillOnce(InvokeWithoutArgs( | 526 .WillOnce(InvokeWithoutArgs( |
| 497 this, &WorkerProcessLauncherTest::SendFakeMessageToLauncher)); | 527 this, &WorkerProcessLauncherTest::SendFakeMessageToLauncher)); |
| 498 | 528 |
| 499 StartWorker(); | 529 StartWorker(); |
| 500 message_loop_.Run(); | 530 message_loop_.Run(); |
| 501 } | 531 } |
| 502 | 532 |
| 503 } // namespace remoting | 533 } // namespace remoting |
| OLD | NEW |