OLD | NEW |
(Empty) | |
| 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 "remoting/host/desktop_process.h" |
| 6 |
| 7 #include "base/location.h" |
| 8 #include "base/memory/ref_counted.h" |
| 9 #include "base/message_loop.h" |
| 10 #include "base/single_thread_task_runner.h" |
| 11 #include "ipc/ipc_channel.h" |
| 12 #include "ipc/ipc_channel_proxy.h" |
| 13 #include "ipc/ipc_listener.h" |
| 14 #include "ipc/ipc_message.h" |
| 15 #include "remoting/base/auto_thread.h" |
| 16 #include "remoting/base/auto_thread_task_runner.h" |
| 17 #include "remoting/host/chromoting_messages.h" |
| 18 #include "remoting/host/desktop_process.h" |
| 19 #include "remoting/host/host_exit_codes.h" |
| 20 #include "testing/gmock_mutant.h" |
| 21 #include "testing/gmock/include/gmock/gmock.h" |
| 22 #include "testing/gtest/include/gtest/gtest.h" |
| 23 |
| 24 using testing::_; |
| 25 using testing::AnyNumber; |
| 26 using testing::InSequence; |
| 27 |
| 28 namespace remoting { |
| 29 |
| 30 namespace { |
| 31 |
| 32 class MockDaemonListener : public IPC::Listener { |
| 33 public: |
| 34 MockDaemonListener() {} |
| 35 virtual ~MockDaemonListener() {} |
| 36 |
| 37 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; |
| 38 |
| 39 MOCK_METHOD1(OnDesktopAttached, void(IPC::PlatformFileForTransit)); |
| 40 MOCK_METHOD1(OnChannelConnected, void(int32)); |
| 41 MOCK_METHOD0(OnChannelError, void()); |
| 42 |
| 43 private: |
| 44 DISALLOW_COPY_AND_ASSIGN(MockDaemonListener); |
| 45 }; |
| 46 |
| 47 bool MockDaemonListener::OnMessageReceived(const IPC::Message& message) { |
| 48 bool handled = true; |
| 49 IPC_BEGIN_MESSAGE_MAP(MockDaemonListener, message) |
| 50 IPC_MESSAGE_HANDLER(ChromotingDesktopDaemonMsg_DesktopAttached, |
| 51 OnDesktopAttached) |
| 52 IPC_MESSAGE_UNHANDLED(handled = false) |
| 53 IPC_END_MESSAGE_MAP() |
| 54 |
| 55 EXPECT_TRUE(handled); |
| 56 return handled; |
| 57 } |
| 58 |
| 59 } // namespace |
| 60 |
| 61 class DesktopProcessTest : public testing::Test { |
| 62 public: |
| 63 DesktopProcessTest(); |
| 64 virtual ~DesktopProcessTest(); |
| 65 |
| 66 // testing::Test overrides |
| 67 virtual void SetUp() OVERRIDE; |
| 68 virtual void TearDown() OVERRIDE; |
| 69 |
| 70 // MockDaemonListener mocks |
| 71 void ConnectNetworkChannel(IPC::PlatformFileForTransit desktop_process); |
| 72 void OnDesktopAttached(IPC::PlatformFileForTransit desktop_process); |
| 73 |
| 74 // Disconnects the daemon-to-desktop channel causing the desktop process to |
| 75 // exit. |
| 76 void DisconnectChannels(); |
| 77 |
| 78 void QuitMessageLoop(); |
| 79 |
| 80 // Runs the desktop process code in a separate thread. |
| 81 void RunDesktopProcess(); |
| 82 |
| 83 // Creates the desktop process and sends a crash request to it. |
| 84 void RunDeathTest(); |
| 85 |
| 86 // Sends a crash request to the desktop process. |
| 87 void SendCrashRequest(); |
| 88 |
| 89 protected: |
| 90 // Name of the daemon-to_desktop channel. |
| 91 std::string channel_name_; |
| 92 |
| 93 // The daemon's end of the daemon-to-desktop channel. |
| 94 scoped_ptr<IPC::ChannelProxy> daemon_channel_; |
| 95 |
| 96 // Delegate that is passed to |daemon_channel_|. |
| 97 MockDaemonListener daemon_listener_; |
| 98 |
| 99 // Runs the daemon's end of the channel. |
| 100 MessageLoop message_loop_; |
| 101 |
| 102 scoped_refptr<AutoThreadTaskRunner> io_task_runner_; |
| 103 |
| 104 // The network's end of the network-to-desktop channel. |
| 105 scoped_ptr<IPC::ChannelProxy> network_channel_; |
| 106 |
| 107 // Delegate that is passed to |network_channel_|. |
| 108 MockDaemonListener network_listener_; |
| 109 }; |
| 110 |
| 111 |
| 112 DesktopProcessTest::DesktopProcessTest() |
| 113 : message_loop_(MessageLoop::TYPE_UI) { |
| 114 } |
| 115 |
| 116 DesktopProcessTest::~DesktopProcessTest() { |
| 117 } |
| 118 |
| 119 void DesktopProcessTest::SetUp() { |
| 120 scoped_refptr<AutoThreadTaskRunner> ui_task_runner = new AutoThreadTaskRunner( |
| 121 message_loop_.message_loop_proxy(), |
| 122 base::Bind(&DesktopProcessTest::QuitMessageLoop, |
| 123 base::Unretained(this))); |
| 124 |
| 125 io_task_runner_ = AutoThread::CreateWithType("IPC thread", ui_task_runner, |
| 126 MessageLoop::TYPE_IO); |
| 127 |
| 128 // Create the daemon-to-desktop process channel. |
| 129 channel_name_ = IPC::Channel::GenerateUniqueRandomChannelID(); |
| 130 daemon_channel_.reset(new IPC::ChannelProxy( |
| 131 IPC::ChannelHandle(channel_name_), |
| 132 IPC::Channel::MODE_SERVER, |
| 133 &daemon_listener_, |
| 134 io_task_runner_)); |
| 135 } |
| 136 |
| 137 void DesktopProcessTest::TearDown() { |
| 138 } |
| 139 |
| 140 void DesktopProcessTest::ConnectNetworkChannel( |
| 141 IPC::PlatformFileForTransit desktop_process) { |
| 142 |
| 143 #if defined(OS_POSIX) |
| 144 IPC::ChannelHandle channel_handle("", desktop_process); |
| 145 #elif defined(OS_WIN) |
| 146 IPC::ChannelHandle channel_handle(desktop_process); |
| 147 #endif // defined(OS_WIN) |
| 148 |
| 149 daemon_channel_.reset(new IPC::ChannelProxy( |
| 150 channel_handle, |
| 151 IPC::Channel::MODE_CLIENT, |
| 152 &network_listener_, |
| 153 io_task_runner_)); |
| 154 } |
| 155 |
| 156 void DesktopProcessTest::OnDesktopAttached( |
| 157 IPC::PlatformFileForTransit desktop_process) { |
| 158 #if defined(OS_POSIX) |
| 159 DCHECK(desktop_process.auto_close); |
| 160 |
| 161 base::ClosePlatformFile(desktop_process.fd); |
| 162 #endif // defined(OS_POSIX) |
| 163 } |
| 164 |
| 165 void DesktopProcessTest::DisconnectChannels() { |
| 166 daemon_channel_.reset(); |
| 167 network_channel_.reset(); |
| 168 io_task_runner_ = NULL; |
| 169 } |
| 170 |
| 171 void DesktopProcessTest::QuitMessageLoop() { |
| 172 message_loop_.PostTask(FROM_HERE, MessageLoop::QuitClosure()); |
| 173 } |
| 174 |
| 175 void DesktopProcessTest::RunDesktopProcess() { |
| 176 DesktopProcess desktop_process(channel_name_); |
| 177 EXPECT_EQ(desktop_process.Run(), kSuccessExitCode); |
| 178 } |
| 179 |
| 180 void DesktopProcessTest::RunDeathTest() { |
| 181 InSequence s; |
| 182 EXPECT_CALL(daemon_listener_, OnChannelConnected(_)); |
| 183 EXPECT_CALL(daemon_listener_, OnDesktopAttached(_)) |
| 184 .WillOnce(DoAll( |
| 185 Invoke(this, &DesktopProcessTest::OnDesktopAttached), |
| 186 InvokeWithoutArgs(this, &DesktopProcessTest::SendCrashRequest))); |
| 187 |
| 188 RunDesktopProcess(); |
| 189 } |
| 190 |
| 191 void DesktopProcessTest::SendCrashRequest() { |
| 192 tracked_objects::Location location = FROM_HERE; |
| 193 daemon_channel_->Send(new ChromotingDaemonDesktopMsg_Crash( |
| 194 location.function_name(), location.file_name(), location.line_number())); |
| 195 } |
| 196 |
| 197 // Launches the desktop process and waits when it connects back. |
| 198 TEST_F(DesktopProcessTest, Basic) { |
| 199 InSequence s; |
| 200 EXPECT_CALL(daemon_listener_, OnChannelConnected(_)); |
| 201 EXPECT_CALL(daemon_listener_, OnDesktopAttached(_)) |
| 202 .WillOnce(DoAll( |
| 203 Invoke(this, &DesktopProcessTest::OnDesktopAttached), |
| 204 InvokeWithoutArgs(this, &DesktopProcessTest::DisconnectChannels))); |
| 205 |
| 206 RunDesktopProcess(); |
| 207 } |
| 208 |
| 209 // Launches the desktop process and waits when it connects back. |
| 210 TEST_F(DesktopProcessTest, ConnectNetworkChannel) { |
| 211 InSequence s; |
| 212 EXPECT_CALL(daemon_listener_, OnChannelConnected(_)); |
| 213 EXPECT_CALL(daemon_listener_, OnDesktopAttached(_)) |
| 214 .WillOnce(Invoke(this, &DesktopProcessTest::ConnectNetworkChannel)); |
| 215 EXPECT_CALL(network_listener_, OnChannelConnected(_)) |
| 216 .WillOnce(InvokeWithoutArgs( |
| 217 this, &DesktopProcessTest::DisconnectChannels)); |
| 218 |
| 219 RunDesktopProcess(); |
| 220 } |
| 221 |
| 222 // Run the desktop process and ask it to crash. |
| 223 TEST_F(DesktopProcessTest, DeathTest) { |
| 224 testing::GTEST_FLAG(death_test_style) = "threadsafe"; |
| 225 |
| 226 EXPECT_DEATH(RunDeathTest(), ""); |
| 227 |
| 228 DisconnectChannels(); |
| 229 } |
| 230 |
| 231 } // namespace remoting |
OLD | NEW |