• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "base/message_loop/message_loop.h"
6 #include "remoting/base/auto_thread_task_runner.h"
7 #include "remoting/base/constants.h"
8 #include "remoting/host/audio_capturer.h"
9 #include "remoting/host/client_session.h"
10 #include "remoting/host/desktop_environment.h"
11 #include "remoting/host/host_mock_objects.h"
12 #include "remoting/host/screen_capturer_fake.h"
13 #include "remoting/protocol/protocol_mock_objects.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
16 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h"
17 #include "third_party/webrtc/modules/desktop_capture/screen_capturer_mock_objects.h"
18 
19 namespace remoting {
20 
21 using protocol::MockConnectionToClient;
22 using protocol::MockClientStub;
23 using protocol::MockHostStub;
24 using protocol::MockInputStub;
25 using protocol::MockSession;
26 using protocol::MockVideoStub;
27 using protocol::SessionConfig;
28 
29 using testing::_;
30 using testing::AnyNumber;
31 using testing::AtMost;
32 using testing::DeleteArg;
33 using testing::DoAll;
34 using testing::Expectation;
35 using testing::Return;
36 using testing::ReturnRef;
37 using testing::Sequence;
38 
39 namespace {
40 
ACTION_P2(InjectClipboardEvent,connection,event)41 ACTION_P2(InjectClipboardEvent, connection, event) {
42   connection->clipboard_stub()->InjectClipboardEvent(event);
43 }
44 
ACTION_P2(InjectKeyEvent,connection,event)45 ACTION_P2(InjectKeyEvent, connection, event) {
46   connection->input_stub()->InjectKeyEvent(event);
47 }
48 
ACTION_P2(InjectMouseEvent,connection,event)49 ACTION_P2(InjectMouseEvent, connection, event) {
50   connection->input_stub()->InjectMouseEvent(event);
51 }
52 
ACTION_P2(LocalMouseMoved,client_session,event)53 ACTION_P2(LocalMouseMoved, client_session, event) {
54   client_session->OnLocalMouseMoved(
55       webrtc::DesktopVector(event.x(), event.y()));
56 }
57 
58 }  // namespace
59 
60 class ClientSessionTest : public testing::Test {
61  public:
ClientSessionTest()62   ClientSessionTest() : client_jid_("user@domain/rest-of-jid") {}
63 
64   virtual void SetUp() OVERRIDE;
65   virtual void TearDown() OVERRIDE;
66 
67   // Disconnects the client session.
68   void DisconnectClientSession();
69 
70   // Stops and releases the ClientSession, allowing the MessageLoop to quit.
71   void StopClientSession();
72 
73  protected:
74   // Creates a DesktopEnvironment with a fake webrtc::ScreenCapturer, to mock
75   // DesktopEnvironmentFactory::Create().
76   DesktopEnvironment* CreateDesktopEnvironment();
77 
78   // Returns |input_injector_| created and initialized by SetUp(), to mock
79   // DesktopEnvironment::CreateInputInjector().
80   InputInjector* CreateInputInjector();
81 
82   // Creates a fake webrtc::ScreenCapturer, to mock
83   // DesktopEnvironment::CreateVideoCapturer().
84   webrtc::ScreenCapturer* CreateVideoCapturer();
85 
86   // Notifies the client session that the client connection has been
87   // authenticated and channels have been connected. This effectively enables
88   // the input pipe line and starts video capturing.
89   void ConnectClientSession();
90 
91   // Invoked when the last reference to the AutoThreadTaskRunner has been
92   // released and quits the message loop to finish the test.
93   void QuitMainMessageLoop();
94 
95   // Message loop passed to |client_session_| to perform all functions on.
96   base::MessageLoop message_loop_;
97 
98   // ClientSession instance under test.
99   scoped_ptr<ClientSession> client_session_;
100 
101   // ClientSession::EventHandler mock for use in tests.
102   MockClientSessionEventHandler session_event_handler_;
103 
104   // Storage for values to be returned by the protocol::Session mock.
105   SessionConfig session_config_;
106   const std::string client_jid_;
107 
108   // Stubs returned to |client_session_| components by |connection_|.
109   MockClientStub client_stub_;
110   MockVideoStub video_stub_;
111 
112   // DesktopEnvironment owns |input_injector_|, but input injection tests need
113   // to express expectations on it.
114   scoped_ptr<MockInputInjector> input_injector_;
115 
116   // ClientSession owns |connection_| but tests need it to inject fake events.
117   MockConnectionToClient* connection_;
118 
119   scoped_ptr<MockDesktopEnvironmentFactory> desktop_environment_factory_;
120 };
121 
SetUp()122 void ClientSessionTest::SetUp() {
123   // Arrange to run |message_loop_| until no components depend on it.
124   scoped_refptr<AutoThreadTaskRunner> ui_task_runner = new AutoThreadTaskRunner(
125       message_loop_.message_loop_proxy(),
126       base::Bind(&ClientSessionTest::QuitMainMessageLoop,
127                  base::Unretained(this)));
128 
129   desktop_environment_factory_.reset(new MockDesktopEnvironmentFactory());
130   EXPECT_CALL(*desktop_environment_factory_, CreatePtr())
131       .Times(AnyNumber())
132       .WillRepeatedly(Invoke(this,
133                              &ClientSessionTest::CreateDesktopEnvironment));
134   EXPECT_CALL(*desktop_environment_factory_, SupportsAudioCapture())
135       .Times(AnyNumber())
136       .WillRepeatedly(Return(false));
137 
138   input_injector_.reset(new MockInputInjector());
139 
140   session_config_ = SessionConfig::ForTest();
141 
142   // Mock protocol::Session APIs called directly by ClientSession.
143   protocol::MockSession* session = new MockSession();
144   EXPECT_CALL(*session, config()).WillRepeatedly(ReturnRef(session_config_));
145   EXPECT_CALL(*session, jid()).WillRepeatedly(ReturnRef(client_jid_));
146   EXPECT_CALL(*session, SetEventHandler(_));
147 
148   // Mock protocol::ConnectionToClient APIs called directly by ClientSession.
149   // HostStub is not touched by ClientSession, so we can safely pass NULL.
150   scoped_ptr<MockConnectionToClient> connection(
151       new MockConnectionToClient(session, NULL));
152   EXPECT_CALL(*connection, session()).WillRepeatedly(Return(session));
153   EXPECT_CALL(*connection, client_stub())
154       .WillRepeatedly(Return(&client_stub_));
155   EXPECT_CALL(*connection, video_stub()).WillRepeatedly(Return(&video_stub_));
156   EXPECT_CALL(*connection, Disconnect());
157   connection_ = connection.get();
158 
159   client_session_.reset(new ClientSession(
160       &session_event_handler_,
161       ui_task_runner, // Audio thread.
162       ui_task_runner, // Input thread.
163       ui_task_runner, // Capture thread.
164       ui_task_runner, // Encode thread.
165       ui_task_runner, // Network thread.
166       ui_task_runner, // UI thread.
167       connection.PassAs<protocol::ConnectionToClient>(),
168       desktop_environment_factory_.get(),
169       base::TimeDelta(),
170       NULL));
171 }
172 
TearDown()173 void ClientSessionTest::TearDown() {
174   // Verify that the client session has been stopped.
175   EXPECT_TRUE(!client_session_);
176 }
177 
DisconnectClientSession()178 void ClientSessionTest::DisconnectClientSession() {
179   client_session_->DisconnectSession();
180   // MockSession won't trigger OnConnectionClosed, so fake it.
181   client_session_->OnConnectionClosed(client_session_->connection(),
182                                       protocol::OK);
183 }
184 
StopClientSession()185 void ClientSessionTest::StopClientSession() {
186   client_session_.reset();
187 
188   desktop_environment_factory_.reset();
189 }
190 
CreateDesktopEnvironment()191 DesktopEnvironment* ClientSessionTest::CreateDesktopEnvironment() {
192   MockDesktopEnvironment* desktop_environment = new MockDesktopEnvironment();
193   EXPECT_CALL(*desktop_environment, CreateAudioCapturerPtr())
194       .Times(0);
195   EXPECT_CALL(*desktop_environment, CreateInputInjectorPtr())
196       .WillOnce(Invoke(this, &ClientSessionTest::CreateInputInjector));
197   EXPECT_CALL(*desktop_environment, CreateScreenControlsPtr())
198       .Times(AtMost(1));
199   EXPECT_CALL(*desktop_environment, CreateVideoCapturerPtr())
200       .WillOnce(Invoke(this, &ClientSessionTest::CreateVideoCapturer));
201   EXPECT_CALL(*desktop_environment, GetCapabilities())
202       .Times(AtMost(1));
203   EXPECT_CALL(*desktop_environment, SetCapabilities(_))
204       .Times(AtMost(1));
205 
206   return desktop_environment;
207 }
208 
CreateInputInjector()209 InputInjector* ClientSessionTest::CreateInputInjector() {
210   EXPECT_TRUE(input_injector_);
211   return input_injector_.release();
212 }
213 
CreateVideoCapturer()214 webrtc::ScreenCapturer* ClientSessionTest::CreateVideoCapturer() {
215   return new ScreenCapturerFake();
216 }
217 
ConnectClientSession()218 void ClientSessionTest::ConnectClientSession() {
219   client_session_->OnConnectionAuthenticated(client_session_->connection());
220   client_session_->OnConnectionChannelsConnected(client_session_->connection());
221 }
222 
QuitMainMessageLoop()223 void ClientSessionTest::QuitMainMessageLoop() {
224   message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
225 }
226 
227 MATCHER_P2(EqualsClipboardEvent, m, d, "") {
228   return (strcmp(arg.mime_type().c_str(), m) == 0 &&
229       memcmp(arg.data().data(), d, arg.data().size()) == 0);
230 }
231 
TEST_F(ClientSessionTest,ClipboardStubFilter)232 TEST_F(ClientSessionTest, ClipboardStubFilter) {
233   protocol::ClipboardEvent clipboard_event1;
234   clipboard_event1.set_mime_type(kMimeTypeTextUtf8);
235   clipboard_event1.set_data("a");
236 
237   protocol::ClipboardEvent clipboard_event2;
238   clipboard_event2.set_mime_type(kMimeTypeTextUtf8);
239   clipboard_event2.set_data("b");
240 
241   protocol::ClipboardEvent clipboard_event3;
242   clipboard_event3.set_mime_type(kMimeTypeTextUtf8);
243   clipboard_event3.set_data("c");
244 
245   Expectation authenticated =
246       EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_))
247           .WillOnce(Return(true));
248   EXPECT_CALL(*input_injector_, StartPtr(_))
249       .After(authenticated);
250   EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_))
251       .After(authenticated);
252 
253   // Wait for the first video packet to be captured to make sure that
254   // the injected input will go though. Otherwise mouse events will be blocked
255   // by the mouse clamping filter.
256   Sequence s;
257   EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
258       .InSequence(s)
259       .After(authenticated)
260       .WillOnce(DoAll(
261           // This event should get through to the clipboard stub.
262           InjectClipboardEvent(connection_, clipboard_event2),
263           InvokeWithoutArgs(this, &ClientSessionTest::DisconnectClientSession),
264           // This event should not get through to the clipboard stub,
265           // because the client has disconnected.
266           InjectClipboardEvent(connection_, clipboard_event3),
267           InvokeWithoutArgs(this, &ClientSessionTest::StopClientSession)));
268   EXPECT_CALL(*input_injector_, InjectClipboardEvent(EqualsClipboardEvent(
269       kMimeTypeTextUtf8, "b")))
270       .InSequence(s);
271   EXPECT_CALL(session_event_handler_, OnSessionClosed(_))
272       .InSequence(s);
273 
274   // This event should not get through to the clipboard stub,
275   // because the client isn't authenticated yet.
276   connection_->clipboard_stub()->InjectClipboardEvent(clipboard_event1);
277 
278   ConnectClientSession();
279   message_loop_.Run();
280 }
281 
282 namespace {
283 
284 MATCHER_P2(EqualsUsbEvent, usb_keycode, pressed, "") {
285   return arg.usb_keycode() == (unsigned int)usb_keycode &&
286          arg.pressed() == pressed;
287 }
288 
289 MATCHER_P2(EqualsMouseEvent, x, y, "") {
290   return arg.x() == x && arg.y() == y;
291 }
292 
293 MATCHER_P2(EqualsMouseButtonEvent, button, down, "") {
294   return arg.button() == button && arg.button_down() == down;
295 }
296 
297 }
298 
TEST_F(ClientSessionTest,InputStubFilter)299 TEST_F(ClientSessionTest, InputStubFilter) {
300   protocol::KeyEvent key_event1;
301   key_event1.set_pressed(true);
302   key_event1.set_usb_keycode(1);
303 
304   protocol::KeyEvent key_event2_down;
305   key_event2_down.set_pressed(true);
306   key_event2_down.set_usb_keycode(2);
307 
308   protocol::KeyEvent key_event2_up;
309   key_event2_up.set_pressed(false);
310   key_event2_up.set_usb_keycode(2);
311 
312   protocol::KeyEvent key_event3;
313   key_event3.set_pressed(true);
314   key_event3.set_usb_keycode(3);
315 
316   protocol::MouseEvent mouse_event1;
317   mouse_event1.set_x(100);
318   mouse_event1.set_y(101);
319 
320   protocol::MouseEvent mouse_event2;
321   mouse_event2.set_x(200);
322   mouse_event2.set_y(201);
323 
324   protocol::MouseEvent mouse_event3;
325   mouse_event3.set_x(300);
326   mouse_event3.set_y(301);
327 
328   Expectation authenticated =
329       EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_))
330           .WillOnce(Return(true));
331   EXPECT_CALL(*input_injector_, StartPtr(_))
332       .After(authenticated);
333   EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_))
334       .After(authenticated);
335 
336   // Wait for the first video packet to be captured to make sure that
337   // the injected input will go though. Otherwise mouse events will be blocked
338   // by the mouse clamping filter.
339   Sequence s;
340   EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
341       .InSequence(s)
342       .After(authenticated)
343       .WillOnce(DoAll(
344           // These events should get through to the input stub.
345           InjectKeyEvent(connection_, key_event2_down),
346           InjectKeyEvent(connection_, key_event2_up),
347           InjectMouseEvent(connection_, mouse_event2),
348           InvokeWithoutArgs(this, &ClientSessionTest::DisconnectClientSession),
349           // These events should not get through to the input stub,
350           // because the client has disconnected.
351           InjectKeyEvent(connection_, key_event3),
352           InjectMouseEvent(connection_, mouse_event3),
353           InvokeWithoutArgs(this, &ClientSessionTest::StopClientSession)));
354   EXPECT_CALL(*input_injector_, InjectKeyEvent(EqualsUsbEvent(2, true)))
355       .InSequence(s);
356   EXPECT_CALL(*input_injector_, InjectKeyEvent(EqualsUsbEvent(2, false)))
357       .InSequence(s);
358   EXPECT_CALL(*input_injector_, InjectMouseEvent(EqualsMouseEvent(200, 201)))
359       .InSequence(s);
360   EXPECT_CALL(session_event_handler_, OnSessionClosed(_))
361       .InSequence(s);
362 
363   // These events should not get through to the input stub,
364   // because the client isn't authenticated yet.
365   connection_->input_stub()->InjectKeyEvent(key_event1);
366   connection_->input_stub()->InjectMouseEvent(mouse_event1);
367 
368   ConnectClientSession();
369   message_loop_.Run();
370 }
371 
TEST_F(ClientSessionTest,LocalInputTest)372 TEST_F(ClientSessionTest, LocalInputTest) {
373   protocol::MouseEvent mouse_event1;
374   mouse_event1.set_x(100);
375   mouse_event1.set_y(101);
376   protocol::MouseEvent mouse_event2;
377   mouse_event2.set_x(200);
378   mouse_event2.set_y(201);
379   protocol::MouseEvent mouse_event3;
380   mouse_event3.set_x(300);
381   mouse_event3.set_y(301);
382 
383   Expectation authenticated =
384       EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_))
385           .WillOnce(Return(true));
386   EXPECT_CALL(*input_injector_, StartPtr(_))
387       .After(authenticated);
388   EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_))
389       .After(authenticated);
390 
391   // Wait for the first video packet to be captured to make sure that
392   // the injected input will go though. Otherwise mouse events will be blocked
393   // by the mouse clamping filter.
394   Sequence s;
395   EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
396       .InSequence(s)
397       .After(authenticated)
398       .WillOnce(DoAll(
399           // This event should get through to the input stub.
400           InjectMouseEvent(connection_, mouse_event1),
401 #if !defined(OS_WIN)
402           // The OS echoes the injected event back.
403           LocalMouseMoved(client_session_.get(), mouse_event1),
404 #endif  // !defined(OS_WIN)
405           // This one should get throught as well.
406           InjectMouseEvent(connection_, mouse_event2),
407           // Now this is a genuine local event.
408           LocalMouseMoved(client_session_.get(), mouse_event1),
409           // This one should be blocked because of the previous  local input
410           // event.
411           InjectMouseEvent(connection_, mouse_event3),
412           // TODO(jamiewalch): Verify that remote inputs are re-enabled
413           // eventually (via dependency injection, not sleep!)
414           InvokeWithoutArgs(this, &ClientSessionTest::DisconnectClientSession),
415           InvokeWithoutArgs(this, &ClientSessionTest::StopClientSession)));
416   EXPECT_CALL(*input_injector_, InjectMouseEvent(EqualsMouseEvent(100, 101)))
417       .InSequence(s);
418   EXPECT_CALL(*input_injector_, InjectMouseEvent(EqualsMouseEvent(200, 201)))
419       .InSequence(s);
420   EXPECT_CALL(session_event_handler_, OnSessionClosed(_))
421       .InSequence(s);
422 
423   ConnectClientSession();
424   message_loop_.Run();
425 }
426 
TEST_F(ClientSessionTest,RestoreEventState)427 TEST_F(ClientSessionTest, RestoreEventState) {
428   protocol::KeyEvent key1;
429   key1.set_pressed(true);
430   key1.set_usb_keycode(1);
431 
432   protocol::KeyEvent key2;
433   key2.set_pressed(true);
434   key2.set_usb_keycode(2);
435 
436   protocol::MouseEvent mousedown;
437   mousedown.set_button(protocol::MouseEvent::BUTTON_LEFT);
438   mousedown.set_button_down(true);
439 
440   Expectation authenticated =
441       EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_))
442           .WillOnce(Return(true));
443   EXPECT_CALL(*input_injector_, StartPtr(_))
444       .After(authenticated);
445   EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_))
446       .After(authenticated);
447 
448   // Wait for the first video packet to be captured to make sure that
449   // the injected input will go though. Otherwise mouse events will be blocked
450   // by the mouse clamping filter.
451   Sequence s;
452   EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
453       .InSequence(s)
454       .After(authenticated)
455       .WillOnce(DoAll(
456           InjectKeyEvent(connection_, key1),
457           InjectKeyEvent(connection_, key2),
458           InjectMouseEvent(connection_, mousedown),
459           InvokeWithoutArgs(this, &ClientSessionTest::DisconnectClientSession),
460           InvokeWithoutArgs(this, &ClientSessionTest::StopClientSession)));
461   EXPECT_CALL(*input_injector_, InjectKeyEvent(EqualsUsbEvent(1, true)))
462       .InSequence(s);
463   EXPECT_CALL(*input_injector_, InjectKeyEvent(EqualsUsbEvent(2, true)))
464       .InSequence(s);
465   EXPECT_CALL(*input_injector_, InjectMouseEvent(EqualsMouseButtonEvent(
466       protocol::MouseEvent::BUTTON_LEFT, true)))
467       .InSequence(s);
468   EXPECT_CALL(*input_injector_, InjectKeyEvent(EqualsUsbEvent(1, false)))
469       .InSequence(s);
470   EXPECT_CALL(*input_injector_, InjectKeyEvent(EqualsUsbEvent(2, false)))
471       .InSequence(s);
472   EXPECT_CALL(*input_injector_, InjectMouseEvent(EqualsMouseButtonEvent(
473       protocol::MouseEvent::BUTTON_LEFT, false)))
474       .InSequence(s);
475   EXPECT_CALL(session_event_handler_, OnSessionClosed(_))
476       .InSequence(s);
477 
478   ConnectClientSession();
479   message_loop_.Run();
480 }
481 
TEST_F(ClientSessionTest,ClampMouseEvents)482 TEST_F(ClientSessionTest, ClampMouseEvents) {
483   Expectation authenticated =
484       EXPECT_CALL(session_event_handler_, OnSessionAuthenticated(_))
485           .WillOnce(Return(true));
486   EXPECT_CALL(*input_injector_, StartPtr(_))
487       .After(authenticated);
488   EXPECT_CALL(session_event_handler_, OnSessionChannelsConnected(_))
489       .After(authenticated);
490   EXPECT_CALL(session_event_handler_, OnSessionClosed(_))
491       .After(authenticated);
492 
493   Expectation connected = authenticated;
494 
495   int input_x[3] = { -999, 100, 999 };
496   int expected_x[3] = { 0, 100, ScreenCapturerFake::kWidth - 1 };
497   int input_y[3] = { -999, 50, 999 };
498   int expected_y[3] = { 0, 50, ScreenCapturerFake::kHeight - 1 };
499 
500   protocol::MouseEvent expected_event;
501   for (int j = 0; j < 3; j++) {
502     for (int i = 0; i < 3; i++) {
503       protocol::MouseEvent injected_event;
504       injected_event.set_x(input_x[i]);
505       injected_event.set_y(input_y[j]);
506 
507       if (i == 0 && j == 0) {
508         // Inject the 1st event once a video packet has been received.
509         connected =
510             EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
511                 .After(connected)
512                 .WillOnce(InjectMouseEvent(connection_, injected_event));
513       } else {
514         // Every next event is injected once the previous event has been
515         // received.
516         connected =
517             EXPECT_CALL(*input_injector_,
518                         InjectMouseEvent(EqualsMouseEvent(expected_event.x(),
519                                                           expected_event.y())))
520                 .After(connected)
521                 .WillOnce(InjectMouseEvent(connection_, injected_event));
522       }
523 
524       expected_event.set_x(expected_x[i]);
525       expected_event.set_y(expected_y[j]);
526     }
527   }
528 
529   // Shutdown the connection once the last event has been received.
530   EXPECT_CALL(*input_injector_,
531               InjectMouseEvent(EqualsMouseEvent(expected_event.x(),
532                                                 expected_event.y())))
533       .After(connected)
534       .WillOnce(DoAll(
535           InvokeWithoutArgs(this, &ClientSessionTest::DisconnectClientSession),
536           InvokeWithoutArgs(this, &ClientSessionTest::StopClientSession)));
537 
538   ConnectClientSession();
539   message_loop_.Run();
540 }
541 
542 }  // namespace remoting
543