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" |
13 #include "mojo/services/test_service/test_service.mojom.h" | 15 #include "mojo/services/test_service/test_service.mojom.h" |
16 #include "mojo/services/test_service/toy_monitoring_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; | |
viettrungluu
2014/06/30 17:08:25
I wonder how specific to shell_tests we should mak
tim (not reviewing)
2014/06/30 22:20:54
Good question. I set out wanting to keep things re
| |
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::ToyMonitoringService; | |
27 using mojo::test::ToyMonitoringServicePtr; | |
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 | |
56 static GURL test_app_url() { | |
57 return GURL("mojo:mojo_test_app"); | |
58 } | |
59 | |
60 void GetReport(std::vector<ServiceReport>* report) { | |
61 monitoring_.Bind(ConnectToService(GURL("mojo:mojo_test_monitoring_app"), | |
62 ToyMonitoringService::Name_).Pass()); | |
63 monitoring_->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 ToyMonitoringServicePtr monitoring_; | |
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 service2->Ping(SetAndQuit<bool>(&was_run2, true)); | |
147 message_loop()->Run(); | |
148 EXPECT_TRUE(was_run1); | |
149 EXPECT_TRUE(was_run2); | |
150 EXPECT_FALSE(service1.encountered_error()); | |
151 EXPECT_FALSE(service2.encountered_error()); | |
152 } | |
153 message_loop()->Run(); | |
154 } | |
155 | |
156 // Tests that service A and service B, both in App 1, can talk to each other | |
157 // and parameters are passed around properly. | |
158 TEST_F(ShellTestBaseTest, ConnectDifferentServicesInSingleApp) { | |
159 // Have a TestService GetPartyTime on a TestTimeService in the same app. | |
160 std::string welcome; | |
161 TestServicePtr service; | |
162 service.Bind(ConnectToService(test_app_url(), TestService::Name_).Pass()); | |
163 service->GetFriendlyWelcomeMessage(test_app_url().spec(), | |
164 SetAndQuit<std::string>(&welcome)); | |
165 message_loop()->Run(); | |
166 | |
167 // Verify by hitting the TimeService directly. | |
168 TestTimeServicePtr time_service; | |
169 time_service.Bind( | |
170 ConnectToService(test_app_url(), TestTimeService::Name_).Pass()); | |
171 int64 party_time; | |
172 time_service->GetPartyTime(SetAndQuit<int64>(&party_time)); | |
173 message_loop()->Run(); | |
174 | |
175 std::string expected_welcome( | |
176 TestService::kWelcomeMessagePrefix + | |
177 UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime( | |
178 base::Time::FromInternalValue(party_time)))); | |
179 EXPECT_EQ(welcome, expected_welcome); | |
180 } | |
181 | |
182 // Tests that a service A in App 1 can talk to service B in App 2 and | |
183 // parameters are passed around properly. | |
184 TEST_F(ShellTestBaseTest, ConnectDifferentServicesInDifferentApps) { | |
185 std::string welcome; | |
186 TestServicePtr service; | |
187 service.Bind(ConnectToService(test_app_url(), TestService::Name_).Pass()); | |
188 service->GetFriendlyWelcomeMessage("mojo:mojo_test_monitoring_app", | |
189 SetAndQuit<std::string>(&welcome)); | |
190 message_loop()->Run(); | |
191 | |
192 // Verify by hitting the TimeService in the monitoring app directly. | |
193 TestTimeServicePtr time_service; | |
194 time_service.Bind(ConnectToService(GURL("mojo:mojo_test_monitoring_app"), | |
195 TestTimeService::Name_).Pass()); | |
196 int64 party_time; | |
197 time_service->GetPartyTime(SetAndQuit<int64>(&party_time)); | |
198 message_loop()->Run(); | |
199 | |
200 std::string expected_welcome( | |
201 TestService::kWelcomeMessagePrefix + | |
202 UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime( | |
203 base::Time::FromInternalValue(party_time)))); | |
204 EXPECT_EQ(welcome, expected_welcome); | |
205 } | |
206 | |
207 // Tests that service A in App 1 can be a client of service B in App 2. | |
208 TEST_F(ShellTestBaseTest, ConnectServiceAsClientOfSeparateApp) { | |
209 TestServicePtr service; | |
210 service.Bind(ConnectToService(test_app_url(), TestService::Name_).Pass()); | |
211 service->StartMonitoring(message_loop()->QuitWhenIdleClosure()); | |
212 service->Ping(mojo::Callback<void()>()); | |
213 message_loop()->Run(); | |
214 | |
215 for (int i = 0; i < 9; i++) | |
216 service->Ping(mojo::Callback<void()>()); | |
217 | |
218 // If everything worked properly, the monitoring service should report | |
219 // 10 pings to TestService. | |
220 std::vector<ServiceReport> reports; | |
221 GetReport(&reports); | |
222 ASSERT_EQ(1U, reports.size()); | |
223 EXPECT_EQ("mojo::test::TestService", reports[0].service_name); | |
viettrungluu
2014/06/30 17:08:25
Probably you should use the "Name_" member, rather
tim (not reviewing)
2014/06/30 22:20:54
Done.
| |
224 EXPECT_EQ(10U, reports[0].total_requests); | |
225 } | |
226 | |
227 // Connect several services together and use the monitoring service to verify | |
228 // communication. | |
229 TEST_F(ShellTestBaseTest, ConnectManyClientsAndServices) { | |
230 TestServicePtr service; | |
231 TestTimeServicePtr time_service; | |
232 | |
233 // Make a request to the TestService and have it contact TimeService in the | |
234 // monitoring app. Do all this with monitoring enabled, meaning both services | |
235 // are connected as clients of the MonitoringService. | |
236 service.Bind(ConnectToService(test_app_url(), TestService::Name_).Pass()); | |
237 service->StartMonitoring(message_loop()->QuitWhenIdleClosure()); | |
238 message_loop()->Run(); | |
239 for (int i = 0; i < 5; i++) | |
240 service->Ping(mojo::Callback<void()>()); | |
241 std::string welcome; | |
242 service->GetFriendlyWelcomeMessage("mojo:mojo_test_monitoring_app", | |
243 SetAndQuit<std::string>(&welcome)); | |
244 message_loop()->Run(); | |
245 | |
246 // Also make a few requests to the TimeService in the test_app. | |
247 time_service.Bind( | |
248 ConnectToService(test_app_url(), TestTimeService::Name_).Pass()); | |
249 time_service->StartMonitoring(message_loop()->QuitWhenIdleClosure()); | |
250 time_service->GetPartyTime(mojo::Callback<void(uint64_t)>()); | |
251 message_loop()->Run(); | |
252 for (int i = 0; i < 19; i++) | |
253 time_service->GetPartyTime(mojo::Callback<void(uint64_t)>()); | |
254 | |
255 std::vector<ServiceReport> reports; | |
256 GetReport(&reports); | |
257 ASSERT_EQ(3U, reports.size()); | |
258 EXPECT_EQ("mojo::test::TestService", reports[0].service_name); | |
viettrungluu
2014/06/30 17:08:24
"
tim (not reviewing)
2014/06/30 22:20:54
Done.
| |
259 EXPECT_EQ(6U, reports[0].total_requests); | |
260 EXPECT_EQ("mojo::test::TestTimeService", reports[1].service_name); | |
261 EXPECT_EQ(1U, reports[1].total_requests); | |
262 EXPECT_EQ("mojo::test::TestTimeService", reports[2].service_name); | |
263 EXPECT_EQ(20U, reports[2].total_requests); | |
264 } | |
265 | |
101 } // namespace | 266 } // namespace |
102 } // namespace test | 267 } // namespace test |
103 } // namespace shell | 268 } // namespace shell |
104 } // namespace mojo | 269 } // namespace mojo |
OLD | NEW |