1 // Copyright 2014 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 "base/message_loop/message_loop.h"
6 #include "mojo/public/cpp/bindings/allocation_scope.h"
7 #include "mojo/public/cpp/bindings/remote_ptr.h"
8 #include "mojo/public/cpp/environment/environment.h"
9 #include "mojo/public/cpp/shell/application.h"
10 #include "mojo/public/interfaces/shell/shell.mojom.h"
11 #include "mojo/service_manager/service_loader.h"
12 #include "mojo/service_manager/service_manager.h"
13 #include "mojo/service_manager/test.mojom.h"
14 #include "testing/gtest/include/gtest/gtest.h"
19 const char kTestURLString
[] = "test:testService";
22 TestContext() : num_impls(0), num_loader_deletes(0) {}
23 std::string last_test_string
;
25 int num_loader_deletes
;
28 class TestServiceImpl
:
29 public ServiceConnection
<TestService
, TestServiceImpl
, TestContext
> {
33 virtual ~TestServiceImpl() {
35 --context()->num_impls
;
38 virtual void Test(const mojo::String
& test_string
) OVERRIDE
{
39 context()->last_test_string
= test_string
.To
<std::string
>();
44 ServiceConnector
<TestServiceImpl
, TestContext
>* service_factory
,
45 ScopedMessagePipeHandle client_handle
) {
46 ServiceConnection
<TestService
, TestServiceImpl
, TestContext
>::Initialize(
47 service_factory
, client_handle
.Pass());
49 ++context()->num_impls
;
53 class TestClientImpl
: public TestClient
{
55 explicit TestClientImpl(ScopedTestServiceHandle service_handle
)
56 : service_(service_handle
.Pass(), this),
57 quit_after_ack_(false) {
60 virtual ~TestClientImpl() {}
62 virtual void AckTest() OVERRIDE
{
64 base::MessageLoop::current()->Quit();
67 void Test(std::string test_string
) {
68 AllocationScope scope
;
69 quit_after_ack_
= true;
70 service_
->Test(mojo::String(test_string
));
74 RemotePtr
<TestService
> service_
;
76 DISALLOW_COPY_AND_ASSIGN(TestClientImpl
);
79 class TestServiceLoader
: public ServiceLoader
{
84 quit_after_error_(false) {
87 virtual ~TestServiceLoader() {
89 ++context_
->num_loader_deletes
;
90 test_app_
.reset(NULL
);
93 void set_context(TestContext
* context
) { context_
= context
; }
94 void set_quit_after_error(bool quit_after_error
) {
95 quit_after_error_
= quit_after_error
;
98 int num_loads() const { return num_loads_
; }
101 virtual void LoadService(ServiceManager
* manager
,
103 ScopedShellHandle shell_handle
) OVERRIDE
{
105 test_app_
.reset(new Application(shell_handle
.Pass()));
106 test_app_
->AddServiceConnector(
107 new ServiceConnector
<TestServiceImpl
, TestContext
>(context_
));
110 virtual void OnServiceError(ServiceManager
* manager
,
111 const GURL
& url
) OVERRIDE
{
112 if (quit_after_error_
) {
113 base::MessageLoop::current()->PostTask(FROM_HERE
,
114 base::MessageLoop::QuitClosure());
119 scoped_ptr
<Application
> test_app_
;
120 TestContext
* context_
;
122 bool quit_after_error_
;
123 DISALLOW_COPY_AND_ASSIGN(TestServiceLoader
);
126 class TestServiceInterceptor
: public ServiceManager::Interceptor
{
128 TestServiceInterceptor() : call_count_(0) {}
130 virtual ScopedMessagePipeHandle
OnConnectToClient(
131 const GURL
& url
, ScopedMessagePipeHandle handle
) OVERRIDE
{
134 return handle
.Pass();
137 std::string
url_spec() const {
138 if (!url_
.is_valid())
139 return "invalid url";
143 int call_count() const {
150 DISALLOW_COPY_AND_ASSIGN(TestServiceInterceptor
);
155 class ServiceManagerTest
: public testing::Test
{
157 ServiceManagerTest() {}
159 virtual ~ServiceManagerTest() {}
161 virtual void SetUp() OVERRIDE
{
162 GURL
test_url(kTestURLString
);
163 service_manager_
.reset(new ServiceManager
);
165 InterfacePipe
<TestService
, AnyInterface
> pipe
;
166 test_client_
.reset(new TestClientImpl(pipe
.handle_to_self
.Pass()));
167 TestServiceLoader
* default_loader
= new TestServiceLoader
;
168 default_loader
->set_context(&context_
);
169 default_loader
->set_quit_after_error(true);
170 service_manager_
->set_default_loader(
171 scoped_ptr
<ServiceLoader
>(default_loader
));
172 service_manager_
->Connect(test_url
, pipe
.handle_to_peer
.Pass());
175 virtual void TearDown() OVERRIDE
{
176 test_client_
.reset(NULL
);
177 service_manager_
.reset(NULL
);
180 bool HasFactoryForTestURL() {
181 ServiceManager::TestAPI
manager_test_api(service_manager_
.get());
182 return manager_test_api
.HasFactoryForURL(GURL(kTestURLString
));
186 mojo::Environment env_
;
187 base::MessageLoop loop_
;
188 TestContext context_
;
189 scoped_ptr
<TestClientImpl
> test_client_
;
190 scoped_ptr
<ServiceManager
> service_manager_
;
191 DISALLOW_COPY_AND_ASSIGN(ServiceManagerTest
);
194 TEST_F(ServiceManagerTest
, Basic
) {
195 test_client_
->Test("test");
197 EXPECT_EQ(std::string("test"), context_
.last_test_string
);
200 TEST_F(ServiceManagerTest
, ClientError
) {
201 test_client_
->Test("test");
202 EXPECT_TRUE(HasFactoryForTestURL());
204 EXPECT_EQ(1, context_
.num_impls
);
205 test_client_
.reset(NULL
);
207 EXPECT_EQ(0, context_
.num_impls
);
208 EXPECT_FALSE(HasFactoryForTestURL());
211 TEST_F(ServiceManagerTest
, Deletes
) {
214 TestServiceLoader
* default_loader
= new TestServiceLoader
;
215 default_loader
->set_context(&context_
);
216 TestServiceLoader
* url_loader1
= new TestServiceLoader
;
217 TestServiceLoader
* url_loader2
= new TestServiceLoader
;
218 url_loader1
->set_context(&context_
);
219 url_loader2
->set_context(&context_
);
220 TestServiceLoader
* scheme_loader1
= new TestServiceLoader
;
221 TestServiceLoader
* scheme_loader2
= new TestServiceLoader
;
222 scheme_loader1
->set_context(&context_
);
223 scheme_loader2
->set_context(&context_
);
224 sm
.set_default_loader(scoped_ptr
<ServiceLoader
>(default_loader
));
225 sm
.SetLoaderForURL(scoped_ptr
<ServiceLoader
>(url_loader1
),
227 sm
.SetLoaderForURL(scoped_ptr
<ServiceLoader
>(url_loader2
),
229 sm
.SetLoaderForScheme(scoped_ptr
<ServiceLoader
>(scheme_loader1
), "test");
230 sm
.SetLoaderForScheme(scoped_ptr
<ServiceLoader
>(scheme_loader2
), "test");
232 EXPECT_EQ(5, context_
.num_loader_deletes
);
235 // Confirm that both urls and schemes can have their loaders explicitly set.
236 TEST_F(ServiceManagerTest
, SetLoaders
) {
238 TestServiceLoader
* default_loader
= new TestServiceLoader
;
239 TestServiceLoader
* url_loader
= new TestServiceLoader
;
240 TestServiceLoader
* scheme_loader
= new TestServiceLoader
;
241 sm
.set_default_loader(scoped_ptr
<ServiceLoader
>(default_loader
));
242 sm
.SetLoaderForURL(scoped_ptr
<ServiceLoader
>(url_loader
), GURL("test:test1"));
243 sm
.SetLoaderForScheme(scoped_ptr
<ServiceLoader
>(scheme_loader
), "test");
245 // test::test1 should go to url_loader.
246 InterfacePipe
<TestService
, AnyInterface
> pipe1
;
247 sm
.Connect(GURL("test:test1"), pipe1
.handle_to_peer
.Pass());
248 EXPECT_EQ(1, url_loader
->num_loads());
249 EXPECT_EQ(0, scheme_loader
->num_loads());
250 EXPECT_EQ(0, default_loader
->num_loads());
252 // test::test2 should go to scheme loader.
253 InterfacePipe
<TestService
, AnyInterface
> pipe2
;
254 sm
.Connect(GURL("test:test2"), pipe2
.handle_to_peer
.Pass());
255 EXPECT_EQ(1, url_loader
->num_loads());
256 EXPECT_EQ(1, scheme_loader
->num_loads());
257 EXPECT_EQ(0, default_loader
->num_loads());
259 // http::test1 should go to default loader.
260 InterfacePipe
<TestService
, AnyInterface
> pipe3
;
261 sm
.Connect(GURL("http:test1"), pipe3
.handle_to_peer
.Pass());
262 EXPECT_EQ(1, url_loader
->num_loads());
263 EXPECT_EQ(1, scheme_loader
->num_loads());
264 EXPECT_EQ(1, default_loader
->num_loads());
267 TEST_F(ServiceManagerTest
, Interceptor
) {
269 TestServiceInterceptor interceptor
;
270 TestServiceLoader
* default_loader
= new TestServiceLoader
;
271 sm
.set_default_loader(scoped_ptr
<ServiceLoader
>(default_loader
));
272 sm
.SetInterceptor(&interceptor
);
274 std::string
url("test:test3");
275 InterfacePipe
<TestService
, AnyInterface
> pipe1
;
276 sm
.Connect(GURL(url
), pipe1
.handle_to_peer
.Pass());
277 EXPECT_EQ(1, interceptor
.call_count());
278 EXPECT_EQ(url
, interceptor
.url_spec());
279 EXPECT_EQ(1, default_loader
->num_loads());