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.
5 #include "remoting/host/desktop_process.h"
8 #include "base/bind_helpers.h"
9 #include "base/location.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "base/single_thread_task_runner.h"
14 #include "ipc/ipc_channel.h"
15 #include "ipc/ipc_channel_proxy.h"
16 #include "ipc/ipc_listener.h"
17 #include "ipc/ipc_message.h"
18 #include "remoting/base/auto_thread.h"
19 #include "remoting/base/auto_thread_task_runner.h"
20 #include "remoting/host/chromoting_messages.h"
21 #include "remoting/host/desktop_process.h"
22 #include "remoting/host/fake_desktop_capturer.h"
23 #include "remoting/host/host_exit_codes.h"
24 #include "remoting/host/host_mock_objects.h"
25 #include "remoting/host/screen_resolution.h"
26 #include "remoting/protocol/protocol_mock_objects.h"
27 #include "testing/gmock/include/gmock/gmock.h"
28 #include "testing/gmock_mutant.h"
29 #include "testing/gtest/include/gtest/gtest.h"
32 using testing::AnyNumber
;
33 using testing::AtMost
;
34 using testing::InSequence
;
35 using testing::Return
;
41 class MockDaemonListener
: public IPC::Listener
{
43 MockDaemonListener() {}
44 ~MockDaemonListener() override
{}
46 bool OnMessageReceived(const IPC::Message
& message
) override
;
48 MOCK_METHOD1(OnDesktopAttached
, void(IPC::PlatformFileForTransit
));
49 MOCK_METHOD1(OnChannelConnected
, void(int32
));
50 MOCK_METHOD0(OnChannelError
, void());
53 DISALLOW_COPY_AND_ASSIGN(MockDaemonListener
);
56 class MockNetworkListener
: public IPC::Listener
{
58 MockNetworkListener() {}
59 ~MockNetworkListener() override
{}
61 bool OnMessageReceived(const IPC::Message
& message
) override
;
63 MOCK_METHOD1(OnChannelConnected
, void(int32
));
64 MOCK_METHOD0(OnChannelError
, void());
66 MOCK_METHOD0(OnDesktopEnvironmentCreated
, void());
69 DISALLOW_COPY_AND_ASSIGN(MockNetworkListener
);
72 bool MockDaemonListener::OnMessageReceived(const IPC::Message
& message
) {
74 IPC_BEGIN_MESSAGE_MAP(MockDaemonListener
, message
)
75 IPC_MESSAGE_HANDLER(ChromotingDesktopDaemonMsg_DesktopAttached
,
77 IPC_MESSAGE_UNHANDLED(handled
= false)
84 bool MockNetworkListener::OnMessageReceived(const IPC::Message
& message
) {
87 // TODO(alexeypa): handle received messages here.
95 class DesktopProcessTest
: public testing::Test
{
98 ~DesktopProcessTest() override
;
100 // testing::Test overrides
101 void SetUp() override
;
102 void TearDown() override
;
104 // MockDaemonListener mocks
105 void ConnectNetworkChannel(IPC::PlatformFileForTransit desktop_process
);
106 void OnDesktopAttached(IPC::PlatformFileForTransit desktop_process
);
108 // Creates a DesktopEnvironment with a fake webrtc::DesktopCapturer, to mock
109 // DesktopEnvironmentFactory::Create().
110 DesktopEnvironment
* CreateDesktopEnvironment();
112 // Creates a dummy InputInjector, to mock
113 // DesktopEnvironment::CreateInputInjector().
114 InputInjector
* CreateInputInjector();
116 // Creates a fake webrtc::DesktopCapturer, to mock
117 // DesktopEnvironment::CreateVideoCapturer().
118 webrtc::DesktopCapturer
* CreateVideoCapturer();
120 // Disconnects the daemon-to-desktop channel causing the desktop process to
122 void DisconnectChannels();
124 // Posts DisconnectChannels() to |message_loop_|.
125 void PostDisconnectChannels();
127 // Runs the desktop process code in a separate thread.
128 void RunDesktopProcess();
130 // Creates the desktop process and sends a crash request to it.
133 // Sends a crash request to the desktop process.
134 void SendCrashRequest();
136 // Requests the desktop process to start the desktop session agent.
137 void SendStartSessionAgent();
140 // The daemon's end of the daemon-to-desktop channel.
141 scoped_ptr
<IPC::ChannelProxy
> daemon_channel_
;
143 // Delegate that is passed to |daemon_channel_|.
144 MockDaemonListener daemon_listener_
;
146 // Runs the daemon's end of the channel.
147 base::MessageLoopForUI message_loop_
;
149 scoped_refptr
<AutoThreadTaskRunner
> io_task_runner_
;
151 // The network's end of the network-to-desktop channel.
152 scoped_ptr
<IPC::ChannelProxy
> network_channel_
;
154 // Delegate that is passed to |network_channel_|.
155 MockNetworkListener network_listener_
;
158 DesktopProcessTest::DesktopProcessTest() {}
160 DesktopProcessTest::~DesktopProcessTest() {
163 void DesktopProcessTest::SetUp() {
166 void DesktopProcessTest::TearDown() {
169 void DesktopProcessTest::ConnectNetworkChannel(
170 IPC::PlatformFileForTransit desktop_process
) {
172 #if defined(OS_POSIX)
173 IPC::ChannelHandle
channel_handle(std::string(), desktop_process
);
174 #elif defined(OS_WIN)
175 IPC::ChannelHandle
channel_handle(desktop_process
);
176 #endif // defined(OS_WIN)
178 network_channel_
= IPC::ChannelProxy::Create(channel_handle
,
179 IPC::Channel::MODE_CLIENT
,
181 io_task_runner_
.get(),
185 void DesktopProcessTest::OnDesktopAttached(
186 IPC::PlatformFileForTransit desktop_process
) {
187 #if defined(OS_POSIX)
188 DCHECK(desktop_process
.auto_close
);
190 base::File
closer(IPC::PlatformFileForTransitToFile(desktop_process
));
191 #endif // defined(OS_POSIX)
194 DesktopEnvironment
* DesktopProcessTest::CreateDesktopEnvironment() {
195 MockDesktopEnvironment
* desktop_environment
= new MockDesktopEnvironment();
196 EXPECT_CALL(*desktop_environment
, CreateAudioCapturerPtr())
198 EXPECT_CALL(*desktop_environment
, CreateInputInjectorPtr())
200 .WillOnce(Invoke(this, &DesktopProcessTest::CreateInputInjector
));
201 EXPECT_CALL(*desktop_environment
, CreateScreenControlsPtr())
203 EXPECT_CALL(*desktop_environment
, CreateVideoCapturerPtr())
205 .WillOnce(Invoke(this, &DesktopProcessTest::CreateVideoCapturer
));
206 EXPECT_CALL(*desktop_environment
, GetCapabilities())
208 EXPECT_CALL(*desktop_environment
, SetCapabilities(_
))
211 // Notify the test that the desktop environment has been created.
212 network_listener_
.OnDesktopEnvironmentCreated();
213 return desktop_environment
;
216 InputInjector
* DesktopProcessTest::CreateInputInjector() {
217 MockInputInjector
* input_injector
= new MockInputInjector();
218 EXPECT_CALL(*input_injector
, StartPtr(_
));
219 return input_injector
;
222 webrtc::DesktopCapturer
* DesktopProcessTest::CreateVideoCapturer() {
223 return new FakeDesktopCapturer();
226 void DesktopProcessTest::DisconnectChannels() {
227 daemon_channel_
.reset();
228 network_channel_
.reset();
229 io_task_runner_
= nullptr;
232 void DesktopProcessTest::PostDisconnectChannels() {
233 message_loop_
.PostTask(FROM_HERE
, base::Bind(
234 &DesktopProcessTest::DisconnectChannels
, base::Unretained(this)));
237 void DesktopProcessTest::RunDesktopProcess() {
238 base::RunLoop run_loop
;
239 base::Closure quit_ui_task_runner
= base::Bind(
240 base::IgnoreResult(&base::SingleThreadTaskRunner::PostTask
),
241 message_loop_
.task_runner(),
242 FROM_HERE
, run_loop
.QuitClosure());
243 scoped_refptr
<AutoThreadTaskRunner
> ui_task_runner
= new AutoThreadTaskRunner(
244 message_loop_
.task_runner(), quit_ui_task_runner
);
246 io_task_runner_
= AutoThread::CreateWithType(
247 "IPC thread", ui_task_runner
, base::MessageLoop::TYPE_IO
);
249 std::string channel_name
= IPC::Channel::GenerateUniqueRandomChannelID();
250 daemon_channel_
= IPC::ChannelProxy::Create(IPC::ChannelHandle(channel_name
),
251 IPC::Channel::MODE_SERVER
,
253 io_task_runner_
.get(),
256 scoped_ptr
<MockDesktopEnvironmentFactory
> desktop_environment_factory(
257 new MockDesktopEnvironmentFactory());
258 EXPECT_CALL(*desktop_environment_factory
, CreatePtr())
260 .WillRepeatedly(Invoke(this,
261 &DesktopProcessTest::CreateDesktopEnvironment
));
262 EXPECT_CALL(*desktop_environment_factory
, SupportsAudioCapture())
264 .WillRepeatedly(Return(false));
266 DesktopProcess
desktop_process(ui_task_runner
, io_task_runner_
, channel_name
);
267 EXPECT_TRUE(desktop_process
.Start(desktop_environment_factory
.Pass()));
269 ui_task_runner
= nullptr;
273 void DesktopProcessTest::RunDeathTest() {
275 EXPECT_CALL(daemon_listener_
, OnChannelConnected(_
));
276 EXPECT_CALL(daemon_listener_
, OnDesktopAttached(_
))
278 Invoke(this, &DesktopProcessTest::OnDesktopAttached
),
279 InvokeWithoutArgs(this, &DesktopProcessTest::SendCrashRequest
)));
284 void DesktopProcessTest::SendCrashRequest() {
285 tracked_objects::Location location
= FROM_HERE
;
286 daemon_channel_
->Send(new ChromotingDaemonMsg_Crash(
287 location
.function_name(), location
.file_name(), location
.line_number()));
290 void DesktopProcessTest::SendStartSessionAgent() {
291 network_channel_
->Send(new ChromotingNetworkDesktopMsg_StartSessionAgent(
292 "user@domain/rest-of-jid", ScreenResolution(), false));
295 // Launches the desktop process and waits when it connects back.
296 TEST_F(DesktopProcessTest
, Basic
) {
298 EXPECT_CALL(daemon_listener_
, OnChannelConnected(_
));
299 EXPECT_CALL(daemon_listener_
, OnDesktopAttached(_
))
301 Invoke(this, &DesktopProcessTest::OnDesktopAttached
),
302 InvokeWithoutArgs(this, &DesktopProcessTest::DisconnectChannels
)));
307 // Launches the desktop process and waits when it connects back.
308 TEST_F(DesktopProcessTest
, ConnectNetworkChannel
) {
310 EXPECT_CALL(daemon_listener_
, OnChannelConnected(_
));
311 EXPECT_CALL(daemon_listener_
, OnDesktopAttached(_
))
312 .WillOnce(Invoke(this, &DesktopProcessTest::ConnectNetworkChannel
));
313 EXPECT_CALL(network_listener_
, OnChannelConnected(_
))
314 .WillOnce(InvokeWithoutArgs(
315 this, &DesktopProcessTest::DisconnectChannels
));
320 // Launches the desktop process, waits when it connects back and starts
321 // the desktop session agent.
322 TEST_F(DesktopProcessTest
, StartSessionAgent
) {
325 EXPECT_CALL(daemon_listener_
, OnChannelConnected(_
));
326 EXPECT_CALL(daemon_listener_
, OnDesktopAttached(_
))
327 .WillOnce(Invoke(this, &DesktopProcessTest::ConnectNetworkChannel
));
328 EXPECT_CALL(network_listener_
, OnChannelConnected(_
))
329 .WillOnce(InvokeWithoutArgs(
330 this, &DesktopProcessTest::SendStartSessionAgent
));
333 EXPECT_CALL(network_listener_
, OnDesktopEnvironmentCreated())
334 .WillOnce(InvokeWithoutArgs(
335 this, &DesktopProcessTest::PostDisconnectChannels
));
340 // Run the desktop process and ask it to crash.
341 TEST_F(DesktopProcessTest
, DeathTest
) {
342 testing::GTEST_FLAG(death_test_style
) = "threadsafe";
344 EXPECT_DEATH(RunDeathTest(), "");
347 } // namespace remoting