Chromium Code Reviews| 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 |