1 // Copyright 2015 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 "chrome/service/service_ipc_server.h"
8 #include "base/bind_helpers.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "base/threading/thread.h"
14 #include "chrome/common/service_messages.h"
15 #include "ipc/ipc_channel.h"
16 #include "ipc/ipc_channel_handle.h"
17 #include "testing/gtest/include/gtest/gtest.h"
21 void PumpCurrentLoop() {
22 base::MessageLoop::ScopedNestableTaskAllower
nestable_task_allower(
23 base::MessageLoop::current());
24 base::RunLoop().RunUntilIdle();
27 class FakeServiceIPCServerClient
: public ServiceIPCServer::Client
{
29 FakeServiceIPCServerClient() {}
30 ~FakeServiceIPCServerClient() override
{}
31 void OnShutdown() override
;
32 void OnUpdateAvailable() override
;
33 bool OnIPCClientDisconnect() override
;
35 int shutdown_calls
= 0;
36 int update_available_calls
= 0;
37 int ipc_client_disconnect_calls
= 0;
40 void FakeServiceIPCServerClient::OnShutdown() {
44 void FakeServiceIPCServerClient::OnUpdateAvailable() {
45 update_available_calls
++;
48 bool FakeServiceIPCServerClient::OnIPCClientDisconnect() {
49 ipc_client_disconnect_calls
++;
51 // Always return true to indicate the server must continue listening for new
56 class FakeChannelListener
: public IPC::Listener
{
58 FakeChannelListener() {}
59 ~FakeChannelListener() override
{}
60 bool OnMessageReceived(const IPC::Message
& message
) override
{ return true; }
63 class FakeMessageHandler
: public ServiceIPCServer::MessageHandler
{
65 explicit FakeMessageHandler(bool should_handle
);
66 bool HandleMessage(const IPC::Message
& message
) override
;
68 int handle_message_calls_
;
71 FakeMessageHandler::FakeMessageHandler(bool should_handle
)
72 : should_handle_(should_handle
), handle_message_calls_(0) {
75 bool FakeMessageHandler::HandleMessage(const IPC::Message
& message
) {
76 handle_message_calls_
++;
77 return should_handle_
;
82 class ServiceIPCServerTest
: public ::testing::Test
{
84 ServiceIPCServerTest();
85 ~ServiceIPCServerTest() override
{}
86 void SetUp() override
;
87 void TearDown() override
;
90 // Simulates the browser process connecting to the service process.
91 void ConnectClientChannel();
93 // Simulates the browser process shutting down.
94 void DestroyClientChannel();
96 // Sends |message| to the ServiceIPCServer.
97 void SendToServiceProcess(IPC::Message
* message
);
99 IPC::SyncChannel
* GetServerChannel() {
100 return server_
->channel_
.get();
104 FakeServiceIPCServerClient service_process_client_
;
105 IPC::ChannelHandle channel_handle_
;
106 base::MessageLoopForUI main_message_loop_
;
107 base::Thread io_thread_
;
108 base::WaitableEvent shutdown_event_
;
109 scoped_ptr
<ServiceIPCServer
> server_
;
110 FakeChannelListener client_process_channel_listener_
;
111 scoped_ptr
<IPC::SyncChannel
> client_process_channel_
;
114 ServiceIPCServerTest::ServiceIPCServerTest()
115 : channel_handle_(IPC::Channel::GenerateUniqueRandomChannelID()),
116 io_thread_("ServiceIPCServerTest IO"),
117 shutdown_event_(true /* manual_reset */, false /* initially_signaled */) {
120 void ServiceIPCServerTest::SetUp() {
121 base::Thread::Options options
;
122 options
.message_loop_type
= base::MessageLoop::TYPE_IO
;
123 ASSERT_TRUE(io_thread_
.StartWithOptions(options
));
125 server_
.reset(new ServiceIPCServer(&service_process_client_
,
126 io_thread_
.task_runner(),
132 void ServiceIPCServerTest::TearDown() {
133 // Close the ipc channels to prevent memory leaks.
134 if (client_process_channel_
) {
135 client_process_channel_
->Close();
138 if (GetServerChannel()) {
139 GetServerChannel()->Close();
145 void ServiceIPCServerTest::PumpLoops() {
146 base::RunLoop run_loop
;
147 io_thread_
.task_runner()->PostTaskAndReply(FROM_HERE
,
148 base::Bind(&PumpCurrentLoop
),
149 run_loop
.QuitClosure());
154 void ServiceIPCServerTest::ConnectClientChannel() {
155 client_process_channel_
= IPC::SyncChannel::Create(
157 IPC::Channel::MODE_NAMED_CLIENT
,
158 &client_process_channel_listener_
,
159 io_thread_
.task_runner(),
160 true /* create_pipe_now */,
165 void ServiceIPCServerTest::DestroyClientChannel() {
166 client_process_channel_
.reset();
170 void ServiceIPCServerTest::SendToServiceProcess(IPC::Message
* message
) {
171 client_process_channel_
->Send(message
);
175 TEST_F(ServiceIPCServerTest
, ConnectDisconnectReconnect
) {
176 // Initially there is no ipc client connected.
177 ASSERT_FALSE(server_
->is_ipc_client_connected());
179 // When a channel is connected the server is notified via OnChannelConnected.
180 ConnectClientChannel();
181 ASSERT_TRUE(server_
->is_ipc_client_connected());
183 // When the channel is destroyed the server is notified via OnChannelError.
184 // In turn, the server notifies its service process client.
185 DestroyClientChannel();
186 ASSERT_FALSE(server_
->is_ipc_client_connected());
187 ASSERT_EQ(1, service_process_client_
.ipc_client_disconnect_calls
);
189 // On Windows only, the server recreates its channel in OnChannelError, if the
190 // service process client tells it to continue listening. On other platforms
191 // the channel is reused for subsequent reconnects by the client process. This
192 // means however that OnChannelConnected is not called again and the server is
193 // only aware of being connected once an IPC message is received.
194 ConnectClientChannel();
196 ASSERT_TRUE(server_
->is_ipc_client_connected());
198 ASSERT_FALSE(server_
->is_ipc_client_connected());
200 SendToServiceProcess(new ServiceMsg_UpdateAvailable());
201 ASSERT_TRUE(server_
->is_ipc_client_connected());
203 // Destroy the client process channel again to verify the
204 // ServiceIPCServer::Client is notified again. This means that unlike
205 // OnChannelConnected, OnChannelError is called more than once.
206 DestroyClientChannel();
207 ASSERT_FALSE(server_
->is_ipc_client_connected());
208 ASSERT_EQ(2, service_process_client_
.ipc_client_disconnect_calls
);
211 TEST_F(ServiceIPCServerTest
, Shutdown
) {
212 ConnectClientChannel();
213 ASSERT_TRUE(server_
->is_ipc_client_connected());
215 // When a shutdown message is received, the ServiceIPCServer::Client is
217 SendToServiceProcess(new ServiceMsg_Shutdown());
218 ASSERT_EQ(1, service_process_client_
.shutdown_calls
);
221 TEST_F(ServiceIPCServerTest
, UpdateAvailable
) {
222 ConnectClientChannel();
223 ASSERT_TRUE(server_
->is_ipc_client_connected());
225 // When a product update message is received, the ServiceIPCServer::Client is
227 SendToServiceProcess(new ServiceMsg_UpdateAvailable());
228 ASSERT_EQ(1, service_process_client_
.update_available_calls
);
231 TEST_F(ServiceIPCServerTest
, SingleMessageHandler
) {
232 ConnectClientChannel();
233 ASSERT_TRUE(server_
->is_ipc_client_connected());
235 // Verify that a message handler is offered messages not handled by the server
237 FakeMessageHandler
* handler
=
238 new FakeMessageHandler(true /* should_handle */);
239 server_
->AddMessageHandler(make_scoped_ptr(handler
));
240 SendToServiceProcess(new ServiceMsg_DisableCloudPrintProxy());
241 ASSERT_EQ(1, handler
->handle_message_calls_
);
244 TEST_F(ServiceIPCServerTest
, MultipleMessageHandlers
) {
245 ConnectClientChannel();
246 ASSERT_TRUE(server_
->is_ipc_client_connected());
248 // If there are multiple handlers they are offered the message in order of
249 // being added until it is handled.
250 FakeMessageHandler
* handler1
=
251 new FakeMessageHandler(false /* should_handle */);
252 server_
->AddMessageHandler(make_scoped_ptr(handler1
));
253 FakeMessageHandler
* handler2
=
254 new FakeMessageHandler(true /* should_handle */);
255 server_
->AddMessageHandler(make_scoped_ptr(handler2
));
256 FakeMessageHandler
* handler3
=
257 new FakeMessageHandler(true /* should_handle */);
258 server_
->AddMessageHandler(make_scoped_ptr(handler3
));
259 SendToServiceProcess(new ServiceMsg_DisableCloudPrintProxy());
260 ASSERT_EQ(1, handler1
->handle_message_calls_
);
261 ASSERT_EQ(1, handler2
->handle_message_calls_
);
262 ASSERT_EQ(0, handler3
->handle_message_calls_
);