Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(547)

Side by Side Diff: services/shell/tests/loader_unittest.cc

Issue 1898433002: Remove shell::Loader (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix windows gyp linkage Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « services/shell/tests/BUILD.gn ('k') | services/shell/tests/placeholder_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include <memory>
6 #include <utility>
7
8 #include "base/at_exit.h"
9 #include "base/bind.h"
10 #include "base/macros.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/memory/scoped_vector.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/run_loop.h"
15 #include "mojo/public/cpp/bindings/strong_binding.h"
16 #include "services/catalog/catalog.h"
17 #include "services/catalog/store.h"
18 #include "services/shell/connect_util.h"
19 #include "services/shell/loader.h"
20 #include "services/shell/public/cpp/connector.h"
21 #include "services/shell/public/cpp/interface_factory.h"
22 #include "services/shell/public/cpp/shell_client.h"
23 #include "services/shell/public/cpp/shell_connection.h"
24 #include "services/shell/public/interfaces/interface_provider.mojom.h"
25 #include "services/shell/shell.h"
26 #include "services/shell/tests/test.mojom.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28
29 namespace shell {
30 namespace test {
31
32 const char kTestURLString[] = "test:testService";
33 const char kTestAURLString[] = "test:TestA";
34 const char kTestBURLString[] = "test:TestB";
35
36 struct TestContext {
37 TestContext() : num_impls(0), num_loader_deletes(0) {}
38 std::string last_test_string;
39 int num_impls;
40 int num_loader_deletes;
41 };
42
43 void QuitClosure(const Identity& expected,
44 bool* value,
45 const Identity& actual) {
46 if (expected == actual) {
47 *value = true;
48 base::MessageLoop::current()->QuitWhenIdle();
49 }
50 }
51
52 class TestServiceImpl : public TestService {
53 public:
54 TestServiceImpl(TestContext* context, TestServiceRequest request)
55 : context_(context), binding_(this, std::move(request)) {
56 ++context_->num_impls;
57 }
58
59 ~TestServiceImpl() override {
60 --context_->num_impls;
61 if (!base::MessageLoop::current()->is_running())
62 return;
63 base::MessageLoop::current()->QuitWhenIdle();
64 }
65
66 // TestService implementation:
67 void Test(const mojo::String& test_string,
68 const mojo::Closure& callback) override {
69 context_->last_test_string = test_string;
70 callback.Run();
71 }
72
73 private:
74 TestContext* context_;
75 mojo::StrongBinding<TestService> binding_;
76 };
77
78 class TestClient {
79 public:
80 explicit TestClient(TestServicePtr service)
81 : service_(std::move(service)), quit_after_ack_(false) {}
82
83 void AckTest() {
84 if (quit_after_ack_)
85 base::MessageLoop::current()->QuitWhenIdle();
86 }
87
88 void Test(const std::string& test_string) {
89 quit_after_ack_ = true;
90 service_->Test(test_string,
91 base::Bind(&TestClient::AckTest, base::Unretained(this)));
92 }
93
94 private:
95 TestServicePtr service_;
96 bool quit_after_ack_;
97 DISALLOW_COPY_AND_ASSIGN(TestClient);
98 };
99
100 class TestLoader : public Loader,
101 public ShellClient,
102 public InterfaceFactory<TestService> {
103 public:
104 explicit TestLoader(TestContext* context)
105 : context_(context), num_loads_(0) {}
106
107 ~TestLoader() override {
108 ++context_->num_loader_deletes;
109 shell_connection_.reset();
110 }
111
112 int num_loads() const { return num_loads_; }
113 const std::string& last_requestor_name() const {
114 return last_requestor_name_;
115 }
116
117 private:
118 // Loader implementation.
119 void Load(const std::string& name,
120 mojom::ShellClientRequest request) override {
121 ++num_loads_;
122 shell_connection_.reset(new ShellConnection(this, std::move(request)));
123 }
124
125 // ShellClient implementation.
126 bool AcceptConnection(Connection* connection) override {
127 connection->AddInterface<TestService>(this);
128 last_requestor_name_ = connection->GetRemoteIdentity().name();
129 return true;
130 }
131
132 // InterfaceFactory<TestService> implementation.
133 void Create(Connection* connection, TestServiceRequest request) override {
134 new TestServiceImpl(context_, std::move(request));
135 }
136
137 std::unique_ptr<ShellConnection> shell_connection_;
138 TestContext* context_;
139 int num_loads_;
140 std::string last_requestor_name_;
141
142 DISALLOW_COPY_AND_ASSIGN(TestLoader);
143 };
144
145 class ClosingLoader : public Loader {
146 private:
147 // Loader implementation.
148 void Load(const std::string& name,
149 mojom::ShellClientRequest request) override {
150 }
151 };
152
153 class TesterContext {
154 public:
155 explicit TesterContext(base::MessageLoop* loop)
156 : num_b_calls_(0),
157 num_c_calls_(0),
158 num_a_deletes_(0),
159 num_b_deletes_(0),
160 num_c_deletes_(0),
161 tester_called_quit_(false),
162 a_called_quit_(false),
163 loop_(loop) {}
164
165 void IncrementNumBCalls() {
166 base::AutoLock lock(lock_);
167 num_b_calls_++;
168 }
169
170 void IncrementNumCCalls() {
171 base::AutoLock lock(lock_);
172 num_c_calls_++;
173 }
174
175 void IncrementNumADeletes() {
176 base::AutoLock lock(lock_);
177 num_a_deletes_++;
178 }
179
180 void IncrementNumBDeletes() {
181 base::AutoLock lock(lock_);
182 num_b_deletes_++;
183 }
184
185 void IncrementNumCDeletes() {
186 base::AutoLock lock(lock_);
187 num_c_deletes_++;
188 }
189
190 void set_tester_called_quit() {
191 base::AutoLock lock(lock_);
192 tester_called_quit_ = true;
193 }
194
195 void set_a_called_quit() {
196 base::AutoLock lock(lock_);
197 a_called_quit_ = true;
198 }
199
200 int num_b_calls() {
201 base::AutoLock lock(lock_);
202 return num_b_calls_;
203 }
204 int num_c_calls() {
205 base::AutoLock lock(lock_);
206 return num_c_calls_;
207 }
208 int num_a_deletes() {
209 base::AutoLock lock(lock_);
210 return num_a_deletes_;
211 }
212 int num_b_deletes() {
213 base::AutoLock lock(lock_);
214 return num_b_deletes_;
215 }
216 int num_c_deletes() {
217 base::AutoLock lock(lock_);
218 return num_c_deletes_;
219 }
220 bool tester_called_quit() {
221 base::AutoLock lock(lock_);
222 return tester_called_quit_;
223 }
224 bool a_called_quit() {
225 base::AutoLock lock(lock_);
226 return a_called_quit_;
227 }
228
229 void QuitSoon() {
230 loop_->PostTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
231 }
232
233 private:
234 // lock_ protects all members except for loop_ which must be unchanged for the
235 // lifetime of this class.
236 base::Lock lock_;
237 int num_b_calls_;
238 int num_c_calls_;
239 int num_a_deletes_;
240 int num_b_deletes_;
241 int num_c_deletes_;
242 bool tester_called_quit_;
243 bool a_called_quit_;
244
245 base::MessageLoop* loop_;
246 };
247
248 // Used to test that the requestor name will be correctly passed.
249 class TestAImpl : public TestA {
250 public:
251 TestAImpl(Connector* connector,
252 TesterContext* test_context,
253 TestARequest request,
254 InterfaceFactory<TestC>* factory)
255 : test_context_(test_context), binding_(this, std::move(request)) {
256 connection_ = connector->Connect(kTestBURLString);
257 connection_->AddInterface<TestC>(factory);
258 connection_->GetInterface(&b_);
259 }
260
261 ~TestAImpl() override {
262 test_context_->IncrementNumADeletes();
263 if (base::MessageLoop::current()->is_running())
264 Quit();
265 }
266
267 private:
268 void CallB() override {
269 b_->B(base::Bind(&TestAImpl::Quit, base::Unretained(this)));
270 }
271
272 void CallCFromB() override {
273 b_->CallC(base::Bind(&TestAImpl::Quit, base::Unretained(this)));
274 }
275
276 void Quit() {
277 base::MessageLoop::current()->QuitWhenIdle();
278 test_context_->set_a_called_quit();
279 test_context_->QuitSoon();
280 }
281
282 std::unique_ptr<Connection> connection_;
283 TesterContext* test_context_;
284 TestBPtr b_;
285 mojo::StrongBinding<TestA> binding_;
286 };
287
288 class TestBImpl : public TestB {
289 public:
290 TestBImpl(Connection* connection,
291 TesterContext* test_context,
292 TestBRequest request)
293 : test_context_(test_context), binding_(this, std::move(request)) {
294 connection->GetInterface(&c_);
295 }
296
297 ~TestBImpl() override {
298 test_context_->IncrementNumBDeletes();
299 if (base::MessageLoop::current()->is_running())
300 base::MessageLoop::current()->QuitWhenIdle();
301 test_context_->QuitSoon();
302 }
303
304 private:
305 void B(const mojo::Closure& callback) override {
306 test_context_->IncrementNumBCalls();
307 callback.Run();
308 }
309
310 void CallC(const mojo::Closure& callback) override {
311 test_context_->IncrementNumBCalls();
312 c_->C(callback);
313 }
314
315 TesterContext* test_context_;
316 TestCPtr c_;
317 mojo::StrongBinding<TestB> binding_;
318 };
319
320 class TestCImpl : public TestC {
321 public:
322 TestCImpl(Connection* connection,
323 TesterContext* test_context,
324 TestCRequest request)
325 : test_context_(test_context), binding_(this, std::move(request)) {}
326
327 ~TestCImpl() override { test_context_->IncrementNumCDeletes(); }
328
329 private:
330 void C(const mojo::Closure& callback) override {
331 test_context_->IncrementNumCCalls();
332 callback.Run();
333 }
334
335 TesterContext* test_context_;
336 mojo::StrongBinding<TestC> binding_;
337 };
338
339 class Tester : public ShellClient,
340 public Loader,
341 public InterfaceFactory<TestA>,
342 public InterfaceFactory<TestB>,
343 public InterfaceFactory<TestC> {
344 public:
345 Tester(TesterContext* context, const std::string& requestor_name)
346 : context_(context), requestor_name_(requestor_name) {}
347 ~Tester() override {}
348
349 private:
350 void Load(const std::string& name,
351 mojom::ShellClientRequest request) override {
352 app_.reset(new ShellConnection(this, std::move(request)));
353 }
354
355 bool AcceptConnection(Connection* connection) override {
356 if (!requestor_name_.empty() &&
357 requestor_name_ != connection->GetRemoteIdentity().name()) {
358 context_->set_tester_called_quit();
359 context_->QuitSoon();
360 base::MessageLoop::current()->QuitWhenIdle();
361 return false;
362 }
363 // If we're coming from A, then add B, otherwise A.
364 if (connection->GetRemoteIdentity().name() == kTestAURLString)
365 connection->AddInterface<TestB>(this);
366 else
367 connection->AddInterface<TestA>(this);
368 return true;
369 }
370
371 void Create(Connection* connection, TestARequest request) override {
372 a_bindings_.push_back(
373 new TestAImpl(app_->connector(), context_, std::move(request), this));
374 }
375
376 void Create(Connection* connection, TestBRequest request) override {
377 new TestBImpl(connection, context_, std::move(request));
378 }
379
380 void Create(Connection* connection, TestCRequest request) override {
381 new TestCImpl(connection, context_, std::move(request));
382 }
383
384 TesterContext* context_;
385 std::unique_ptr<ShellConnection> app_;
386 std::string requestor_name_;
387 ScopedVector<TestAImpl> a_bindings_;
388 };
389
390 void OnConnect(base::RunLoop* loop,
391 mojom::ConnectResult result,
392 const mojo::String& user_id,
393 uint32_t instance_id) {
394 loop->Quit();
395 }
396
397 class LoaderTest : public testing::Test {
398 public:
399 LoaderTest() : tester_context_(&loop_) {}
400 ~LoaderTest() override {}
401
402 void SetUp() override {
403 blocking_pool_ = new base::SequencedWorkerPool(3, "blocking_pool");
404 catalog_.reset(
405 new catalog::Catalog(blocking_pool_.get(), nullptr, nullptr));
406 shell_.reset(new Shell(nullptr, catalog_->TakeShellClient()));
407 test_loader_ = new TestLoader(&context_);
408 shell_->set_default_loader(std::unique_ptr<Loader>(test_loader_));
409
410 TestServicePtr service_proxy;
411 ConnectToInterface(kTestURLString, &service_proxy);
412 test_client_.reset(new TestClient(std::move(service_proxy)));
413 }
414
415 void TearDown() override {
416 test_client_.reset();
417 shell_.reset();
418 blocking_pool_->Shutdown();
419 }
420
421 void AddLoaderForName(const std::string& name,
422 const std::string& requestor_name) {
423 shell_->SetLoaderForName(
424 base::WrapUnique(new Tester(&tester_context_, requestor_name)), name);
425 }
426
427 bool HasRunningInstanceForName(const std::string& name) {
428 Shell::TestAPI test_api(shell_.get());
429 return test_api.HasRunningInstanceForName(name);
430 }
431
432 protected:
433 template <typename Interface>
434 void ConnectToInterface(const std::string& name,
435 mojo::InterfacePtr<Interface>* ptr) {
436 base::RunLoop loop;
437 mojom::InterfaceProviderPtr remote_interfaces;
438 std::unique_ptr<ConnectParams> params(new ConnectParams);
439 params->set_source(CreateShellIdentity());
440 params->set_target(Identity(name, mojom::kRootUserID));
441 params->set_remote_interfaces(mojo::GetProxy(&remote_interfaces));
442 params->set_connect_callback(
443 base::Bind(&OnConnect, base::Unretained(&loop)));
444 shell_->Connect(std::move(params));
445 loop.Run();
446
447 GetInterface(remote_interfaces.get(), ptr);
448 }
449
450 base::ShadowingAtExitManager at_exit_;
451 TestLoader* test_loader_;
452 TesterContext tester_context_;
453 TestContext context_;
454 base::MessageLoop loop_;
455 std::unique_ptr<TestClient> test_client_;
456 std::unique_ptr<catalog::Catalog> catalog_;
457 scoped_refptr<base::SequencedWorkerPool> blocking_pool_;
458 std::unique_ptr<Shell> shell_;
459
460 DISALLOW_COPY_AND_ASSIGN(LoaderTest);
461 };
462
463 TEST_F(LoaderTest, Basic) {
464 test_client_->Test("test");
465 loop_.Run();
466 EXPECT_EQ(std::string("test"), context_.last_test_string);
467 }
468
469 TEST_F(LoaderTest, ClientError) {
470 test_client_->Test("test");
471 EXPECT_TRUE(HasRunningInstanceForName(kTestURLString));
472 loop_.Run();
473 EXPECT_EQ(1, context_.num_impls);
474 test_client_.reset();
475 loop_.Run();
476 EXPECT_EQ(0, context_.num_impls);
477 EXPECT_TRUE(HasRunningInstanceForName(kTestURLString));
478 }
479
480 TEST_F(LoaderTest, Deletes) {
481 {
482 catalog::Catalog catalog(blocking_pool_.get(), nullptr, nullptr);
483 Shell shell(nullptr, catalog.TakeShellClient());
484 TestLoader* default_loader = new TestLoader(&context_);
485 TestLoader* name_loader1 = new TestLoader(&context_);
486 TestLoader* name_loader2 = new TestLoader(&context_);
487 shell.set_default_loader(std::unique_ptr<Loader>(default_loader));
488 shell.SetLoaderForName(std::unique_ptr<Loader>(name_loader1), "test:test1");
489 shell.SetLoaderForName(std::unique_ptr<Loader>(name_loader2), "test:test1");
490 }
491 EXPECT_EQ(3, context_.num_loader_deletes);
492 }
493
494 // Test for SetLoaderForName() & set_default_loader().
495 TEST_F(LoaderTest, SetLoaders) {
496 TestLoader* default_loader = new TestLoader(&context_);
497 TestLoader* name_loader = new TestLoader(&context_);
498 shell_->set_default_loader(std::unique_ptr<Loader>(default_loader));
499 shell_->SetLoaderForName(std::unique_ptr<Loader>(name_loader), "test:test1");
500
501 // test::test1 should go to name_loader.
502 TestServicePtr test_service;
503 ConnectToInterface("test:test1", &test_service);
504 EXPECT_EQ(1, name_loader->num_loads());
505 EXPECT_EQ(0, default_loader->num_loads());
506
507 // http::test1 should go to default loader.
508 ConnectToInterface("http:test1", &test_service);
509 EXPECT_EQ(1, name_loader->num_loads());
510 EXPECT_EQ(1, default_loader->num_loads());
511 }
512
513 TEST_F(LoaderTest, NoServiceNoLoad) {
514 AddLoaderForName(kTestAURLString, std::string());
515
516 // There is no TestC service implementation registered with the Shell, so this
517 // cannot succeed (but also shouldn't crash).
518 TestCPtr c;
519 ConnectToInterface(kTestAURLString, &c);
520 c.set_connection_error_handler(
521 []() { base::MessageLoop::current()->QuitWhenIdle(); });
522
523 loop_.Run();
524 EXPECT_TRUE(c.encountered_error());
525 }
526
527 TEST_F(LoaderTest, TestEndApplicationClosure) {
528 ClosingLoader* loader = new ClosingLoader();
529 shell_->SetLoaderForName(std::unique_ptr<Loader>(loader), "test:test");
530
531 bool called = false;
532 std::unique_ptr<ConnectParams> params(new ConnectParams);
533 params->set_source(CreateShellIdentity());
534 params->set_target(Identity("test:test", mojom::kRootUserID));
535 shell_->SetInstanceQuitCallback(
536 base::Bind(&QuitClosure, params->target(), &called));
537 shell_->Connect(std::move(params));
538 loop_.Run();
539 EXPECT_TRUE(called);
540 }
541
542 TEST_F(LoaderTest, SameIdentityShouldNotCauseDuplicateLoad) {
543 // 1 because LoaderTest connects once at startup.
544 EXPECT_EQ(1, test_loader_->num_loads());
545
546 TestServicePtr test_service;
547 ConnectToInterface("test:foo", &test_service);
548 EXPECT_EQ(2, test_loader_->num_loads());
549
550 // Exactly the same name as above.
551 ConnectToInterface("test:foo", &test_service);
552 EXPECT_EQ(2, test_loader_->num_loads());
553
554 // A different identity because the domain is different.
555 ConnectToInterface("test:bar", &test_service);
556 EXPECT_EQ(3, test_loader_->num_loads());
557 }
558
559 } // namespace test
560 } // namespace shell
OLDNEW
« no previous file with comments | « services/shell/tests/BUILD.gn ('k') | services/shell/tests/placeholder_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698