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/environment/environment.h"
8 #include "mojo/public/cpp/shell/application.h"
9 #include "mojo/public/interfaces/shell/shell.mojom.h"
10 #include "mojo/service_manager/service_loader.h"
11 #include "mojo/service_manager/service_manager.h"
12 #include "mojo/service_manager/test.mojom.h"
13 #include "testing/gtest/include/gtest/gtest.h"
18 const char kTestURLString[] = "test:testService";
21 TestContext() : num_impls(0), num_loader_deletes(0) {}
22 std::string last_test_string;
24 int num_loader_deletes;
27 class TestServiceImpl :
28 public ServiceConnection<TestService, TestServiceImpl, TestContext> {
30 TestServiceImpl() : client_(NULL) {}
32 virtual ~TestServiceImpl() {
34 --context()->num_impls;
39 ++context()->num_impls;
42 // TestService implementation:
43 virtual void SetClient(TestClient* client) OVERRIDE {
46 virtual void Test(const mojo::String& test_string) OVERRIDE {
47 context()->last_test_string = test_string.To<std::string>();
55 class TestClientImpl : public TestClient {
57 explicit TestClientImpl(TestServicePtr service)
58 : service_(service.Pass()),
59 quit_after_ack_(false) {
60 service_->SetClient(this);
63 virtual ~TestClientImpl() {}
65 virtual void AckTest() OVERRIDE {
67 base::MessageLoop::current()->Quit();
70 void Test(std::string test_string) {
71 AllocationScope scope;
72 quit_after_ack_ = true;
73 service_->Test(test_string);
77 TestServicePtr service_;
79 DISALLOW_COPY_AND_ASSIGN(TestClientImpl);
82 class TestServiceLoader : public ServiceLoader {
87 quit_after_error_(false) {
90 virtual ~TestServiceLoader() {
92 ++context_->num_loader_deletes;
93 test_app_.reset(NULL);
96 void set_context(TestContext* context) { context_ = context; }
97 void set_quit_after_error(bool quit_after_error) {
98 quit_after_error_ = quit_after_error;
101 int num_loads() const { return num_loads_; }
104 virtual void LoadService(ServiceManager* manager,
106 ScopedMessagePipeHandle shell_handle) OVERRIDE {
108 test_app_.reset(new Application(shell_handle.Pass()));
109 test_app_->AddServiceConnector(
110 new ServiceConnector<TestServiceImpl, TestContext>(context_));
113 virtual void OnServiceError(ServiceManager* manager,
114 const GURL& url) OVERRIDE {
115 if (quit_after_error_) {
116 base::MessageLoop::current()->PostTask(FROM_HERE,
117 base::MessageLoop::QuitClosure());
122 scoped_ptr<Application> test_app_;
123 TestContext* context_;
125 bool quit_after_error_;
126 DISALLOW_COPY_AND_ASSIGN(TestServiceLoader);
129 class TestServiceInterceptor : public ServiceManager::Interceptor {
131 TestServiceInterceptor() : call_count_(0) {}
133 virtual ScopedMessagePipeHandle OnConnectToClient(
134 const GURL& url, ScopedMessagePipeHandle handle) OVERRIDE {
137 return handle.Pass();
140 std::string url_spec() const {
141 if (!url_.is_valid())
142 return "invalid url";
146 int call_count() const {
153 DISALLOW_COPY_AND_ASSIGN(TestServiceInterceptor);
158 class ServiceManagerTest : public testing::Test {
160 ServiceManagerTest() {}
162 virtual ~ServiceManagerTest() {}
164 virtual void SetUp() OVERRIDE {
165 GURL test_url(kTestURLString);
166 service_manager_.reset(new ServiceManager);
169 TestServicePtr service_proxy = MakeProxy<TestService>(pipe.handle0.Pass());
170 test_client_.reset(new TestClientImpl(service_proxy.Pass()));
172 TestServiceLoader* default_loader = new TestServiceLoader;
173 default_loader->set_context(&context_);
174 default_loader->set_quit_after_error(true);
175 service_manager_->set_default_loader(
176 scoped_ptr<ServiceLoader>(default_loader));
178 service_manager_->Connect(test_url, pipe.handle1.Pass());
181 virtual void TearDown() OVERRIDE {
182 test_client_.reset(NULL);
183 service_manager_.reset(NULL);
186 bool HasFactoryForTestURL() {
187 ServiceManager::TestAPI manager_test_api(service_manager_.get());
188 return manager_test_api.HasFactoryForURL(GURL(kTestURLString));
192 mojo::Environment env_;
193 base::MessageLoop loop_;
194 TestContext context_;
195 scoped_ptr<TestClientImpl> test_client_;
196 scoped_ptr<ServiceManager> service_manager_;
197 DISALLOW_COPY_AND_ASSIGN(ServiceManagerTest);
200 TEST_F(ServiceManagerTest, Basic) {
201 test_client_->Test("test");
203 EXPECT_EQ(std::string("test"), context_.last_test_string);
206 TEST_F(ServiceManagerTest, ClientError) {
207 test_client_->Test("test");
208 EXPECT_TRUE(HasFactoryForTestURL());
210 EXPECT_EQ(1, context_.num_impls);
211 test_client_.reset(NULL);
213 EXPECT_EQ(0, context_.num_impls);
214 EXPECT_FALSE(HasFactoryForTestURL());
217 TEST_F(ServiceManagerTest, Deletes) {
220 TestServiceLoader* default_loader = new TestServiceLoader;
221 default_loader->set_context(&context_);
222 TestServiceLoader* url_loader1 = new TestServiceLoader;
223 TestServiceLoader* url_loader2 = new TestServiceLoader;
224 url_loader1->set_context(&context_);
225 url_loader2->set_context(&context_);
226 TestServiceLoader* scheme_loader1 = new TestServiceLoader;
227 TestServiceLoader* scheme_loader2 = new TestServiceLoader;
228 scheme_loader1->set_context(&context_);
229 scheme_loader2->set_context(&context_);
230 sm.set_default_loader(scoped_ptr<ServiceLoader>(default_loader));
231 sm.SetLoaderForURL(scoped_ptr<ServiceLoader>(url_loader1),
233 sm.SetLoaderForURL(scoped_ptr<ServiceLoader>(url_loader2),
235 sm.SetLoaderForScheme(scoped_ptr<ServiceLoader>(scheme_loader1), "test");
236 sm.SetLoaderForScheme(scoped_ptr<ServiceLoader>(scheme_loader2), "test");
238 EXPECT_EQ(5, context_.num_loader_deletes);
241 // Confirm that both urls and schemes can have their loaders explicitly set.
242 TEST_F(ServiceManagerTest, SetLoaders) {
244 TestServiceLoader* default_loader = new TestServiceLoader;
245 TestServiceLoader* url_loader = new TestServiceLoader;
246 TestServiceLoader* scheme_loader = new TestServiceLoader;
247 sm.set_default_loader(scoped_ptr<ServiceLoader>(default_loader));
248 sm.SetLoaderForURL(scoped_ptr<ServiceLoader>(url_loader), GURL("test:test1"));
249 sm.SetLoaderForScheme(scoped_ptr<ServiceLoader>(scheme_loader), "test");
251 // test::test1 should go to url_loader.
253 sm.Connect(GURL("test:test1"), pipe1.handle0.Pass());
254 EXPECT_EQ(1, url_loader->num_loads());
255 EXPECT_EQ(0, scheme_loader->num_loads());
256 EXPECT_EQ(0, default_loader->num_loads());
258 // test::test2 should go to scheme loader.
260 sm.Connect(GURL("test:test2"), pipe2.handle0.Pass());
261 EXPECT_EQ(1, url_loader->num_loads());
262 EXPECT_EQ(1, scheme_loader->num_loads());
263 EXPECT_EQ(0, default_loader->num_loads());
265 // http::test1 should go to default loader.
267 sm.Connect(GURL("http:test1"), pipe3.handle0.Pass());
268 EXPECT_EQ(1, url_loader->num_loads());
269 EXPECT_EQ(1, scheme_loader->num_loads());
270 EXPECT_EQ(1, default_loader->num_loads());
273 TEST_F(ServiceManagerTest, Interceptor) {
275 TestServiceInterceptor interceptor;
276 TestServiceLoader* default_loader = new TestServiceLoader;
277 sm.set_default_loader(scoped_ptr<ServiceLoader>(default_loader));
278 sm.SetInterceptor(&interceptor);
280 std::string url("test:test3");
282 sm.Connect(GURL(url), pipe1.handle0.Pass());
283 EXPECT_EQ(1, interceptor.call_count());
284 EXPECT_EQ(url, interceptor.url_spec());
285 EXPECT_EQ(1, default_loader->num_loads());