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.
6 #include "base/bind_helpers.h"
7 #include "base/location.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/process.h"
10 #include "ipc/ipc_message.h"
11 #include "ipc/ipc_message_macros.h"
12 #include "ipc/ipc_platform_file.h"
13 #include "remoting/base/auto_thread_task_runner.h"
14 #include "remoting/host/chromoting_messages.h"
15 #include "remoting/host/daemon_process.h"
16 #include "remoting/host/desktop_session.h"
17 #include "testing/gmock_mutant.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
22 using testing::AnyNumber
;
23 using testing::InSequence
;
30 kMessageCrash
= ChromotingDaemonMsg_Crash::ID
,
31 kMessageConfiguration
= ChromotingDaemonNetworkMsg_Configuration::ID
,
32 kMessageConnectTerminal
= ChromotingNetworkHostMsg_ConnectTerminal::ID
,
33 kMessageDisconnectTerminal
= ChromotingNetworkHostMsg_DisconnectTerminal::ID
,
34 kMessageTerminalDisconnected
=
35 ChromotingDaemonNetworkMsg_TerminalDisconnected::ID
38 // Provides a public constructor allowing the test to create instances of
39 // DesktopSession directly.
40 class FakeDesktopSession
: public DesktopSession
{
42 FakeDesktopSession(DaemonProcess
* daemon_process
, int id
);
43 virtual ~FakeDesktopSession();
45 virtual void SetScreenResolution(
46 const ScreenResolution
& resolution
) OVERRIDE
{}
49 DISALLOW_COPY_AND_ASSIGN(FakeDesktopSession
);
52 class MockDaemonProcess
: public DaemonProcess
{
55 scoped_refptr
<AutoThreadTaskRunner
> caller_task_runner
,
56 scoped_refptr
<AutoThreadTaskRunner
> io_task_runner
,
57 const base::Closure
& stopped_callback
);
58 virtual ~MockDaemonProcess();
60 virtual scoped_ptr
<DesktopSession
> DoCreateDesktopSession(
62 const ScreenResolution
& resolution
,
63 bool virtual_terminal
) OVERRIDE
;
65 virtual bool OnMessageReceived(const IPC::Message
& message
) OVERRIDE
;
66 virtual void SendToNetwork(IPC::Message
* message
) OVERRIDE
;
68 MOCK_METHOD1(Received
, void(const IPC::Message
&));
69 MOCK_METHOD1(Sent
, void(const IPC::Message
&));
71 MOCK_METHOD3(OnDesktopSessionAgentAttached
,
72 bool(int, base::ProcessHandle
, IPC::PlatformFileForTransit
));
74 MOCK_METHOD1(DoCreateDesktopSessionPtr
, DesktopSession
*(int));
75 MOCK_METHOD1(DoCrashNetworkProcess
, void(const tracked_objects::Location
&));
76 MOCK_METHOD0(LaunchNetworkProcess
, void());
79 DISALLOW_COPY_AND_ASSIGN(MockDaemonProcess
);
82 FakeDesktopSession::FakeDesktopSession(DaemonProcess
* daemon_process
, int id
)
83 : DesktopSession(daemon_process
, id
) {
86 FakeDesktopSession::~FakeDesktopSession() {
89 MockDaemonProcess::MockDaemonProcess(
90 scoped_refptr
<AutoThreadTaskRunner
> caller_task_runner
,
91 scoped_refptr
<AutoThreadTaskRunner
> io_task_runner
,
92 const base::Closure
& stopped_callback
)
93 : DaemonProcess(caller_task_runner
, io_task_runner
, stopped_callback
) {
96 MockDaemonProcess::~MockDaemonProcess() {
99 scoped_ptr
<DesktopSession
> MockDaemonProcess::DoCreateDesktopSession(
101 const ScreenResolution
& resolution
,
102 bool virtual_terminal
) {
103 return scoped_ptr
<DesktopSession
>(DoCreateDesktopSessionPtr(terminal_id
));
106 bool MockDaemonProcess::OnMessageReceived(const IPC::Message
& message
) {
107 // Notify the mock method.
110 // Call the actual handler.
111 return DaemonProcess::OnMessageReceived(message
);
114 void MockDaemonProcess::SendToNetwork(IPC::Message
* message
) {
115 // Notify the mock method.
122 class DaemonProcessTest
: public testing::Test
{
125 virtual ~DaemonProcessTest();
127 virtual void SetUp() OVERRIDE
;
128 virtual void TearDown() OVERRIDE
;
130 // DaemonProcess mocks
131 DesktopSession
* DoCreateDesktopSession(int terminal_id
);
132 void DoCrashNetworkProcess(const tracked_objects::Location
& location
);
133 void LaunchNetworkProcess();
135 // Deletes |daemon_process_|.
136 void DeleteDaemonProcess();
138 // Quits |message_loop_|.
139 void QuitMessageLoop();
141 void StartDaemonProcess();
143 const DaemonProcess::DesktopSessionList
& desktop_sessions() const {
144 return daemon_process_
->desktop_sessions();
148 base::MessageLoop message_loop_
;
150 scoped_ptr
<MockDaemonProcess
> daemon_process_
;
154 DaemonProcessTest::DaemonProcessTest()
155 : message_loop_(base::MessageLoop::TYPE_IO
), terminal_id_(0) {
158 DaemonProcessTest::~DaemonProcessTest() {
161 void DaemonProcessTest::SetUp() {
162 scoped_refptr
<AutoThreadTaskRunner
> task_runner
= new AutoThreadTaskRunner(
163 message_loop_
.message_loop_proxy(),
164 base::Bind(&DaemonProcessTest::QuitMessageLoop
,
165 base::Unretained(this)));
166 daemon_process_
.reset(
167 new MockDaemonProcess(task_runner
, task_runner
,
168 base::Bind(&DaemonProcessTest::DeleteDaemonProcess
,
169 base::Unretained(this))));
171 // Set up daemon process mocks.
172 EXPECT_CALL(*daemon_process_
, DoCreateDesktopSessionPtr(_
))
174 .WillRepeatedly(Invoke(this, &DaemonProcessTest::DoCreateDesktopSession
));
175 EXPECT_CALL(*daemon_process_
, DoCrashNetworkProcess(_
))
177 .WillRepeatedly(Invoke(this, &DaemonProcessTest::DoCrashNetworkProcess
));
178 EXPECT_CALL(*daemon_process_
, LaunchNetworkProcess())
180 .WillRepeatedly(Invoke(this, &DaemonProcessTest::LaunchNetworkProcess
));
183 void DaemonProcessTest::TearDown() {
184 daemon_process_
->Stop();
188 DesktopSession
* DaemonProcessTest::DoCreateDesktopSession(int terminal_id
) {
189 return new FakeDesktopSession(daemon_process_
.get(), terminal_id
);
192 void DaemonProcessTest::DoCrashNetworkProcess(
193 const tracked_objects::Location
& location
) {
194 daemon_process_
->SendToNetwork(
195 new ChromotingDaemonMsg_Crash(location
.function_name(),
196 location
.file_name(),
197 location
.line_number()));
200 void DaemonProcessTest::LaunchNetworkProcess() {
202 daemon_process_
->OnChannelConnected(0);
205 void DaemonProcessTest::DeleteDaemonProcess() {
206 daemon_process_
.reset();
209 void DaemonProcessTest::QuitMessageLoop() {
210 message_loop_
.PostTask(FROM_HERE
, base::MessageLoop::QuitClosure());
213 void DaemonProcessTest::StartDaemonProcess() {
214 // DaemonProcess::Initialize() sets up the config watcher that this test does
215 // not support. Launch the process directly.
216 daemon_process_
->LaunchNetworkProcess();
219 MATCHER_P(Message
, type
, "") {
220 return arg
.type() == static_cast<uint32
>(type
);
223 TEST_F(DaemonProcessTest
, OpenClose
) {
225 EXPECT_CALL(*daemon_process_
, Sent(Message(kMessageConfiguration
)));
226 EXPECT_CALL(*daemon_process_
, Received(Message(kMessageConnectTerminal
)));
227 EXPECT_CALL(*daemon_process_
, Received(Message(kMessageDisconnectTerminal
)));
228 EXPECT_CALL(*daemon_process_
, Sent(Message(kMessageTerminalDisconnected
)));
230 StartDaemonProcess();
232 int id
= terminal_id_
++;
233 ScreenResolution resolution
;
235 EXPECT_TRUE(daemon_process_
->OnMessageReceived(
236 ChromotingNetworkHostMsg_ConnectTerminal(id
, resolution
, false)));
237 EXPECT_EQ(1u, desktop_sessions().size());
238 EXPECT_EQ(id
, desktop_sessions().front()->id());
240 EXPECT_TRUE(daemon_process_
->OnMessageReceived(
241 ChromotingNetworkHostMsg_DisconnectTerminal(id
)));
242 EXPECT_TRUE(desktop_sessions().empty());
245 TEST_F(DaemonProcessTest
, CallCloseDesktopSession
) {
247 EXPECT_CALL(*daemon_process_
, Sent(Message(kMessageConfiguration
)));
248 EXPECT_CALL(*daemon_process_
, Received(Message(kMessageConnectTerminal
)));
249 EXPECT_CALL(*daemon_process_
, Sent(Message(kMessageTerminalDisconnected
)));
251 StartDaemonProcess();
253 int id
= terminal_id_
++;
254 ScreenResolution resolution
;
256 EXPECT_TRUE(daemon_process_
->OnMessageReceived(
257 ChromotingNetworkHostMsg_ConnectTerminal(id
, resolution
, false)));
258 EXPECT_EQ(1u, desktop_sessions().size());
259 EXPECT_EQ(id
, desktop_sessions().front()->id());
261 daemon_process_
->CloseDesktopSession(id
);
262 EXPECT_TRUE(desktop_sessions().empty());
265 // Sends two CloseDesktopSession messages and expects the second one to be
267 TEST_F(DaemonProcessTest
, DoubleDisconnectTerminal
) {
269 EXPECT_CALL(*daemon_process_
, Sent(Message(kMessageConfiguration
)));
270 EXPECT_CALL(*daemon_process_
, Received(Message(kMessageConnectTerminal
)));
271 EXPECT_CALL(*daemon_process_
, Received(Message(kMessageDisconnectTerminal
)));
272 EXPECT_CALL(*daemon_process_
, Sent(Message(kMessageTerminalDisconnected
)));
273 EXPECT_CALL(*daemon_process_
, Received(Message(kMessageDisconnectTerminal
)));
275 StartDaemonProcess();
277 int id
= terminal_id_
++;
278 ScreenResolution resolution
;
280 EXPECT_TRUE(daemon_process_
->OnMessageReceived(
281 ChromotingNetworkHostMsg_ConnectTerminal(id
, resolution
, false)));
282 EXPECT_EQ(1u, desktop_sessions().size());
283 EXPECT_EQ(id
, desktop_sessions().front()->id());
285 EXPECT_TRUE(daemon_process_
->OnMessageReceived(
286 ChromotingNetworkHostMsg_DisconnectTerminal(id
)));
287 EXPECT_TRUE(desktop_sessions().empty());
289 EXPECT_TRUE(daemon_process_
->OnMessageReceived(
290 ChromotingNetworkHostMsg_DisconnectTerminal(id
)));
291 EXPECT_TRUE(desktop_sessions().empty());
294 // Tries to close an invalid terminal ID and expects the network process to be
296 TEST_F(DaemonProcessTest
, InvalidDisconnectTerminal
) {
298 EXPECT_CALL(*daemon_process_
, Sent(Message(kMessageConfiguration
)));
299 EXPECT_CALL(*daemon_process_
, Received(Message(kMessageDisconnectTerminal
)));
300 EXPECT_CALL(*daemon_process_
, Sent(Message(kMessageCrash
)))
301 .WillOnce(InvokeWithoutArgs(this,
302 &DaemonProcessTest::LaunchNetworkProcess
));
303 EXPECT_CALL(*daemon_process_
, Sent(Message(kMessageConfiguration
)));
305 StartDaemonProcess();
307 int id
= terminal_id_
++;
309 EXPECT_TRUE(daemon_process_
->OnMessageReceived(
310 ChromotingNetworkHostMsg_DisconnectTerminal(id
)));
311 EXPECT_TRUE(desktop_sessions().empty());
312 EXPECT_EQ(0, terminal_id_
);
315 // Tries to open an invalid terminal ID and expects the network process to be
317 TEST_F(DaemonProcessTest
, InvalidConnectTerminal
) {
319 EXPECT_CALL(*daemon_process_
, Sent(Message(kMessageConfiguration
)));
320 EXPECT_CALL(*daemon_process_
, Received(Message(kMessageConnectTerminal
)));
321 EXPECT_CALL(*daemon_process_
, Received(Message(kMessageConnectTerminal
)));
322 EXPECT_CALL(*daemon_process_
, Sent(Message(kMessageCrash
)))
323 .WillOnce(InvokeWithoutArgs(this,
324 &DaemonProcessTest::LaunchNetworkProcess
));
325 EXPECT_CALL(*daemon_process_
, Sent(Message(kMessageConfiguration
)));
327 StartDaemonProcess();
329 int id
= terminal_id_
++;
330 ScreenResolution resolution
;
332 EXPECT_TRUE(daemon_process_
->OnMessageReceived(
333 ChromotingNetworkHostMsg_ConnectTerminal(id
, resolution
, false)));
334 EXPECT_EQ(1u, desktop_sessions().size());
335 EXPECT_EQ(id
, desktop_sessions().front()->id());
337 EXPECT_TRUE(daemon_process_
->OnMessageReceived(
338 ChromotingNetworkHostMsg_ConnectTerminal(id
, resolution
, false)));
339 EXPECT_TRUE(desktop_sessions().empty());
340 EXPECT_EQ(0, terminal_id_
);
343 } // namespace remoting