OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "mojo/shell/shell_test_base.h" | 5 #include "mojo/shell/shell_test_base.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/i18n/time_formatting.h" |
8 #include "base/macros.h" | 9 #include "base/macros.h" |
9 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
| 11 #include "base/strings/utf_string_conversions.h" |
10 #include "mojo/public/cpp/bindings/error_handler.h" | 12 #include "mojo/public/cpp/bindings/error_handler.h" |
11 #include "mojo/public/cpp/bindings/interface_ptr.h" | 13 #include "mojo/public/cpp/bindings/interface_ptr.h" |
12 #include "mojo/public/cpp/system/core.h" | 14 #include "mojo/public/cpp/system/core.h" |
| 15 #include "mojo/services/test_service/test_request_tracker.mojom.h" |
13 #include "mojo/services/test_service/test_service.mojom.h" | 16 #include "mojo/services/test_service/test_service.mojom.h" |
14 #include "testing/gtest/include/gtest/gtest.h" | 17 #include "testing/gtest/include/gtest/gtest.h" |
15 #include "url/gurl.h" | 18 #include "url/gurl.h" |
16 | 19 |
| 20 using mojo::test::ServiceReport; |
| 21 using mojo::test::ServiceReportPtr; |
| 22 using mojo::test::TestService; |
| 23 using mojo::test::TestTimeService; |
| 24 using mojo::test::TestServicePtr; |
| 25 using mojo::test::TestTimeServicePtr; |
| 26 using mojo::test::TestTrackedRequestService; |
| 27 using mojo::test::TestTrackedRequestServicePtr; |
| 28 |
17 namespace mojo { | 29 namespace mojo { |
18 namespace shell { | 30 namespace shell { |
19 namespace test { | 31 namespace test { |
20 namespace { | 32 namespace { |
21 | 33 |
22 typedef ShellTestBase ShellTestBaseTest; | 34 void GetReportCallback(base::MessageLoop* loop, |
| 35 std::vector<ServiceReport>* reports_out, |
| 36 mojo::Array<ServiceReportPtr> report) { |
| 37 for (size_t i = 0; i < report.size(); i++) |
| 38 reports_out->push_back(*report[i]); |
| 39 loop->QuitWhenIdle(); |
| 40 } |
| 41 |
| 42 class ShellTestBaseTest : public ShellTestBase { |
| 43 public: |
| 44 // Convenience helpers for use as callbacks in tests. |
| 45 template <typename T> |
| 46 base::Callback<void()> SetAndQuit(T* val, T result) { |
| 47 return base::Bind(&ShellTestBaseTest::SetAndQuitImpl<T>, |
| 48 base::Unretained(this), val, result); |
| 49 } |
| 50 template <typename T> |
| 51 base::Callback<void(T result)> SetAndQuit(T* val) { |
| 52 return base::Bind(&ShellTestBaseTest::SetAndQuitImpl<T>, |
| 53 base::Unretained(this), val); |
| 54 } |
| 55 static GURL test_app_url() { |
| 56 return GURL("mojo:mojo_test_app"); |
| 57 } |
| 58 |
| 59 void GetReport(std::vector<ServiceReport>* report) { |
| 60 request_tracking_.Bind( |
| 61 ConnectToService(GURL("mojo:mojo_test_request_tracker_app"), |
| 62 TestTrackedRequestService::Name_).Pass()); |
| 63 request_tracking_->GetReport(base::Bind(&GetReportCallback, |
| 64 base::Unretained(message_loop()), |
| 65 base::Unretained(report))); |
| 66 message_loop()->Run(); |
| 67 } |
| 68 |
| 69 private: |
| 70 template<typename T> |
| 71 void SetAndQuitImpl(T* val, T result) { |
| 72 *val = result; |
| 73 message_loop()->QuitWhenIdle(); |
| 74 } |
| 75 TestTrackedRequestServicePtr request_tracking_; |
| 76 }; |
23 | 77 |
24 class QuitMessageLoopErrorHandler : public ErrorHandler { | 78 class QuitMessageLoopErrorHandler : public ErrorHandler { |
25 public: | 79 public: |
26 QuitMessageLoopErrorHandler() {} | 80 QuitMessageLoopErrorHandler() {} |
27 virtual ~QuitMessageLoopErrorHandler() {} | 81 virtual ~QuitMessageLoopErrorHandler() {} |
28 | 82 |
29 // |ErrorHandler| implementation: | 83 // |ErrorHandler| implementation: |
30 virtual void OnConnectionError() OVERRIDE { | 84 virtual void OnConnectionError() OVERRIDE { |
31 base::MessageLoop::current()->QuitWhenIdle(); | 85 base::MessageLoop::current()->QuitWhenIdle(); |
32 } | 86 } |
33 | 87 |
34 private: | 88 private: |
35 DISALLOW_COPY_AND_ASSIGN(QuitMessageLoopErrorHandler); | 89 DISALLOW_COPY_AND_ASSIGN(QuitMessageLoopErrorHandler); |
36 }; | 90 }; |
37 | 91 |
38 void PingCallback(base::MessageLoop* message_loop, bool* was_run) { | 92 // Tests that we can connect to a single service within a single app. |
39 *was_run = true; | 93 TEST_F(ShellTestBaseTest, ConnectBasic) { |
40 VLOG(2) << "Ping callback"; | 94 InterfacePtr<TestService> service; |
41 message_loop->QuitWhenIdle(); | 95 service.Bind(ConnectToService(test_app_url(), TestService::Name_).Pass()); |
42 } | |
43 | |
44 TEST_F(ShellTestBaseTest, LaunchServiceInProcess) { | |
45 InterfacePtr<mojo::test::ITestService> test_service; | |
46 | |
47 { | |
48 ScopedMessagePipeHandle service_handle = | |
49 LaunchServiceInProcess(GURL("mojo:mojo_test_service"), | |
50 mojo::test::ITestService::Name_); | |
51 test_service.Bind(service_handle.Pass()); | |
52 } | |
53 | 96 |
54 bool was_run = false; | 97 bool was_run = false; |
55 test_service->Ping(base::Bind(&PingCallback, | 98 service->Ping(SetAndQuit<bool>(&was_run, true)); |
56 base::Unretained(message_loop()), | |
57 base::Unretained(&was_run))); | |
58 message_loop()->Run(); | 99 message_loop()->Run(); |
59 EXPECT_TRUE(was_run); | 100 EXPECT_TRUE(was_run); |
60 EXPECT_FALSE(test_service.encountered_error()); | 101 EXPECT_FALSE(service.encountered_error()); |
61 | 102 |
62 test_service.reset(); | 103 service.reset(); |
63 | 104 |
64 // This will run until the test service has actually quit (which it will, | 105 // This will run until the test app has actually quit (which it will, |
65 // since we killed the only connection to it). | 106 // since we killed the only connection to it). |
66 message_loop()->Run(); | 107 message_loop()->Run(); |
67 } | 108 } |
68 | 109 |
69 // Tests that launching a service in process fails properly if the service | 110 // Tests that trying to connect to a service fails properly if the service |
70 // doesn't exist. | 111 // doesn't exist. |
71 TEST_F(ShellTestBaseTest, LaunchServiceInProcessInvalidService) { | 112 TEST_F(ShellTestBaseTest, ConnectInvalidService) { |
72 InterfacePtr<mojo::test::ITestService> test_service; | 113 InterfacePtr<TestService> test_service; |
73 | 114 test_service.Bind(ConnectToService(GURL("mojo:non_existent_service"), |
74 { | 115 TestService::Name_).Pass()); |
75 ScopedMessagePipeHandle service_handle = | |
76 LaunchServiceInProcess(GURL("mojo:non_existent_service"), | |
77 mojo::test::ITestService::Name_); | |
78 test_service.Bind(service_handle.Pass()); | |
79 } | |
80 | 116 |
81 bool was_run = false; | 117 bool was_run = false; |
82 test_service->Ping(base::Bind(&PingCallback, | 118 test_service->Ping(SetAndQuit<bool>(&was_run, true)); |
83 base::Unretained(message_loop()), | |
84 base::Unretained(&was_run))); | |
85 | 119 |
86 // This will quit because there's nothing running. | 120 // This will quit because there's nothing running. |
87 message_loop()->Run(); | 121 message_loop()->Run(); |
88 EXPECT_FALSE(was_run); | 122 EXPECT_FALSE(was_run); |
89 | 123 |
90 // It may have quit before an error was processed. | 124 // It may have quit before an error was processed. |
91 if (!test_service.encountered_error()) { | 125 if (!test_service.encountered_error()) { |
92 QuitMessageLoopErrorHandler quitter; | 126 QuitMessageLoopErrorHandler quitter; |
93 test_service.set_error_handler(&quitter); | 127 test_service.set_error_handler(&quitter); |
94 message_loop()->Run(); | 128 message_loop()->Run(); |
95 EXPECT_TRUE(test_service.encountered_error()); | 129 EXPECT_TRUE(test_service.encountered_error()); |
96 } | 130 } |
97 | 131 |
98 test_service.reset(); | 132 test_service.reset(); |
99 } | 133 } |
100 | 134 |
| 135 // Similar to ConnectBasic, but causes the app to instantiate multiple |
| 136 // service implementation objects and verifies the shell can reach both. |
| 137 TEST_F(ShellTestBaseTest, ConnectMultipleInstancesPerApp) { |
| 138 { |
| 139 TestServicePtr service1, service2; |
| 140 service1.Bind(ConnectToService(test_app_url(), TestService::Name_).Pass()); |
| 141 service2.Bind(ConnectToService(test_app_url(), TestService::Name_).Pass()); |
| 142 |
| 143 bool was_run1 = false; |
| 144 bool was_run2 = false; |
| 145 service1->Ping(SetAndQuit<bool>(&was_run1, true)); |
| 146 message_loop()->Run(); |
| 147 service2->Ping(SetAndQuit<bool>(&was_run2, true)); |
| 148 message_loop()->Run(); |
| 149 EXPECT_TRUE(was_run1); |
| 150 EXPECT_TRUE(was_run2); |
| 151 EXPECT_FALSE(service1.encountered_error()); |
| 152 EXPECT_FALSE(service2.encountered_error()); |
| 153 } |
| 154 message_loop()->Run(); |
| 155 } |
| 156 |
| 157 // Tests that service A and service B, both in App 1, can talk to each other |
| 158 // and parameters are passed around properly. |
| 159 TEST_F(ShellTestBaseTest, ConnectDifferentServicesInSingleApp) { |
| 160 // Have a TestService GetPartyTime on a TestTimeService in the same app. |
| 161 int64 time_message; |
| 162 TestServicePtr service; |
| 163 service.Bind(ConnectToService(test_app_url(), TestService::Name_).Pass()); |
| 164 service->ConnectToAppAndGetTime(test_app_url().spec(), |
| 165 SetAndQuit<int64>(&time_message)); |
| 166 message_loop()->Run(); |
| 167 |
| 168 // Verify by hitting the TimeService directly. |
| 169 TestTimeServicePtr time_service; |
| 170 time_service.Bind( |
| 171 ConnectToService(test_app_url(), TestTimeService::Name_).Pass()); |
| 172 int64 party_time; |
| 173 time_service->GetPartyTime(SetAndQuit<int64>(&party_time)); |
| 174 message_loop()->Run(); |
| 175 |
| 176 EXPECT_EQ(time_message, party_time); |
| 177 } |
| 178 |
| 179 // Tests that a service A in App 1 can talk to service B in App 2 and |
| 180 // parameters are passed around properly. |
| 181 TEST_F(ShellTestBaseTest, ConnectDifferentServicesInDifferentApps) { |
| 182 int64 time_message; |
| 183 TestServicePtr service; |
| 184 service.Bind(ConnectToService(test_app_url(), TestService::Name_).Pass()); |
| 185 service->ConnectToAppAndGetTime("mojo:mojo_test_request_tracker_app", |
| 186 SetAndQuit<int64>(&time_message)); |
| 187 message_loop()->Run(); |
| 188 |
| 189 // Verify by hitting the TimeService in the request tracker app directly. |
| 190 TestTimeServicePtr time_service; |
| 191 time_service.Bind(ConnectToService(GURL("mojo:mojo_test_request_tracker_app"), |
| 192 TestTimeService::Name_).Pass()); |
| 193 int64 party_time; |
| 194 time_service->GetPartyTime(SetAndQuit<int64>(&party_time)); |
| 195 message_loop()->Run(); |
| 196 |
| 197 EXPECT_EQ(time_message, party_time); |
| 198 } |
| 199 |
| 200 // Tests that service A in App 1 can be a client of service B in App 2. |
| 201 TEST_F(ShellTestBaseTest, ConnectServiceAsClientOfSeparateApp) { |
| 202 TestServicePtr service; |
| 203 service.Bind(ConnectToService(test_app_url(), TestService::Name_).Pass()); |
| 204 service->StartTrackingRequests(message_loop()->QuitWhenIdleClosure()); |
| 205 service->Ping(mojo::Callback<void()>()); |
| 206 message_loop()->Run(); |
| 207 |
| 208 for (int i = 0; i < 8; i++) |
| 209 service->Ping(mojo::Callback<void()>()); |
| 210 service->Ping(message_loop()->QuitWhenIdleClosure()); |
| 211 message_loop()->Run(); |
| 212 |
| 213 // If everything worked properly, the tracking service should report |
| 214 // 10 pings to TestService. |
| 215 std::vector<ServiceReport> reports; |
| 216 GetReport(&reports); |
| 217 ASSERT_EQ(1U, reports.size()); |
| 218 EXPECT_EQ(TestService::Name_, reports[0].service_name); |
| 219 EXPECT_EQ(10U, reports[0].total_requests); |
| 220 } |
| 221 |
| 222 // Connect several services together and use the tracking service to verify |
| 223 // communication. |
| 224 TEST_F(ShellTestBaseTest, ConnectManyClientsAndServices) { |
| 225 TestServicePtr service; |
| 226 TestTimeServicePtr time_service; |
| 227 |
| 228 // Make a request to the TestService and have it contact TimeService in the |
| 229 // tracking app. Do all this with tracking enabled, meaning both services |
| 230 // are connected as clients of the TrackedRequestService. |
| 231 service.Bind(ConnectToService(test_app_url(), TestService::Name_).Pass()); |
| 232 service->StartTrackingRequests(message_loop()->QuitWhenIdleClosure()); |
| 233 message_loop()->Run(); |
| 234 for (int i = 0; i < 5; i++) |
| 235 service->Ping(mojo::Callback<void()>()); |
| 236 int64 time_result; |
| 237 service->ConnectToAppAndGetTime("mojo:mojo_test_request_tracker_app", |
| 238 SetAndQuit<int64>(&time_result)); |
| 239 message_loop()->Run(); |
| 240 |
| 241 // Also make a few requests to the TimeService in the test_app. |
| 242 time_service.Bind( |
| 243 ConnectToService(test_app_url(), TestTimeService::Name_).Pass()); |
| 244 time_service->StartTrackingRequests(message_loop()->QuitWhenIdleClosure()); |
| 245 time_service->GetPartyTime(mojo::Callback<void(uint64_t)>()); |
| 246 message_loop()->Run(); |
| 247 for (int i = 0; i < 18; i++) |
| 248 time_service->GetPartyTime(mojo::Callback<void(uint64_t)>()); |
| 249 // Flush the tasks with one more to quit. |
| 250 int64 party_time = 0; |
| 251 time_service->GetPartyTime(SetAndQuit<int64>(&party_time)); |
| 252 message_loop()->Run(); |
| 253 |
| 254 std::vector<ServiceReport> reports; |
| 255 GetReport(&reports); |
| 256 ASSERT_EQ(3U, reports.size()); |
| 257 EXPECT_EQ(TestService::Name_, reports[0].service_name); |
| 258 EXPECT_EQ(6U, reports[0].total_requests); |
| 259 EXPECT_EQ(TestTimeService::Name_, reports[1].service_name); |
| 260 EXPECT_EQ(1U, reports[1].total_requests); |
| 261 EXPECT_EQ(TestTimeService::Name_, reports[2].service_name); |
| 262 EXPECT_EQ(20U, reports[2].total_requests); |
| 263 } |
| 264 |
101 } // namespace | 265 } // namespace |
102 } // namespace test | 266 } // namespace test |
103 } // namespace shell | 267 } // namespace shell |
104 } // namespace mojo | 268 } // namespace mojo |
OLD | NEW |