forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathservice_ipc_server_unittest.cc
189 lines (155 loc) · 5.83 KB
/
service_ipc_server_unittest.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/service/service_ipc_server.h"
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "build/build_config.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
void PumpCurrentLoop() {
base::RunLoop(base::RunLoop::Type::kNestableTasksAllowed).RunUntilIdle();
}
class FakeServiceIPCServerClient : public ServiceIPCServer::Client {
public:
FakeServiceIPCServerClient() {}
~FakeServiceIPCServerClient() override {}
void OnShutdown() override;
void OnUpdateAvailable() override;
bool OnIPCClientDisconnect() override;
mojo::ScopedMessagePipeHandle CreateChannelMessagePipe() override;
int shutdown_calls_ = 0;
int update_available_calls_ = 0;
int ipc_client_disconnect_calls_ = 0;
service_manager::mojom::InterfaceProviderPtr interface_provider_;
};
void FakeServiceIPCServerClient::OnShutdown() {
shutdown_calls_++;
}
void FakeServiceIPCServerClient::OnUpdateAvailable() {
update_available_calls_++;
}
bool FakeServiceIPCServerClient::OnIPCClientDisconnect() {
ipc_client_disconnect_calls_++;
// Always return true to indicate the server must continue listening for new
// connections.
return true;
}
mojo::ScopedMessagePipeHandle
FakeServiceIPCServerClient::CreateChannelMessagePipe() {
return mojo::MakeRequest(&interface_provider_).PassMessagePipe();
}
} // namespace
class ServiceIPCServerTest : public ::testing::Test {
public:
ServiceIPCServerTest();
~ServiceIPCServerTest() override {}
void SetUp() override;
void TearDown() override;
void PumpLoops();
// Simulates the browser process connecting to the service process.
void ConnectClientChannel();
// Simulates the browser process shutting down.
void DestroyClientChannel();
protected:
FakeServiceIPCServerClient service_process_client_;
base::MessageLoopForUI main_message_loop_;
base::Thread io_thread_;
base::WaitableEvent shutdown_event_;
std::unique_ptr<ServiceIPCServer> server_;
service_manager::InterfaceProvider remote_interfaces_;
chrome::mojom::ServiceProcessPtr service_process_;
};
ServiceIPCServerTest::ServiceIPCServerTest()
: io_thread_("ServiceIPCServerTest IO"),
shutdown_event_(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED) {}
void ServiceIPCServerTest::SetUp() {
base::Thread::Options options;
mojo::MessagePipe channel;
options.message_loop_type = base::MessageLoop::TYPE_IO;
ASSERT_TRUE(io_thread_.StartWithOptions(options));
server_.reset(new ServiceIPCServer(&service_process_client_,
io_thread_.task_runner(),
&shutdown_event_));
server_->Init();
}
void ServiceIPCServerTest::TearDown() {
// Close the ipc channels to prevent memory leaks.
if (service_process_) {
remote_interfaces_.Close();
service_process_.reset();
PumpLoops();
}
io_thread_.Stop();
}
void ServiceIPCServerTest::PumpLoops() {
base::RunLoop run_loop;
io_thread_.task_runner()->PostTaskAndReply(FROM_HERE,
base::Bind(&PumpCurrentLoop),
run_loop.QuitClosure());
run_loop.Run();
PumpCurrentLoop();
}
void ServiceIPCServerTest::ConnectClientChannel() {
remote_interfaces_.Close();
remote_interfaces_.Bind(
std::move(service_process_client_.interface_provider_));
remote_interfaces_.GetInterface(&service_process_);
service_process_->Hello(base::DoNothing());
PumpLoops();
}
void ServiceIPCServerTest::DestroyClientChannel() {
remote_interfaces_.Close();
service_process_.reset();
PumpLoops();
}
TEST_F(ServiceIPCServerTest, ConnectDisconnectReconnect) {
// Initially there is no ipc client connected.
ASSERT_FALSE(server_->is_ipc_client_connected());
// When a channel is connected the server is notified via OnChannelConnected.
ConnectClientChannel();
ASSERT_TRUE(server_->is_ipc_client_connected());
// When the channel is destroyed the server is notified via OnChannelError.
// In turn, the server notifies its service process client.
DestroyClientChannel();
ASSERT_FALSE(server_->is_ipc_client_connected());
ASSERT_EQ(1, service_process_client_.ipc_client_disconnect_calls_);
ConnectClientChannel();
ASSERT_TRUE(server_->is_ipc_client_connected());
service_process_->UpdateAvailable();
PumpLoops();
ASSERT_TRUE(server_->is_ipc_client_connected());
// Destroy the client process channel again to verify the
// ServiceIPCServer::Client is notified again. This means that unlike
// OnChannelConnected, OnChannelError is called more than once.
DestroyClientChannel();
ASSERT_FALSE(server_->is_ipc_client_connected());
ASSERT_EQ(2, service_process_client_.ipc_client_disconnect_calls_);
}
TEST_F(ServiceIPCServerTest, Shutdown) {
ConnectClientChannel();
ASSERT_TRUE(server_->is_ipc_client_connected());
// When a shutdown message is received, the ServiceIPCServer::Client is
// notified.
service_process_->ShutDown();
PumpLoops();
ASSERT_EQ(1, service_process_client_.shutdown_calls_);
}
TEST_F(ServiceIPCServerTest, UpdateAvailable) {
ConnectClientChannel();
ASSERT_TRUE(server_->is_ipc_client_connected());
// When a product update message is received, the ServiceIPCServer::Client is
// notified.
service_process_->UpdateAvailable();
PumpLoops();
ASSERT_EQ(1, service_process_client_.update_available_calls_);
}