Chromium Code Reviews| Index: mojo/shell/shell_test_base_unittest.cc |
| diff --git a/mojo/shell/shell_test_base_unittest.cc b/mojo/shell/shell_test_base_unittest.cc |
| index 4b861f90ff97bde7c699c56312ab51f178ddd968..8c84ed40fad92652083ca834bec60952e6428eba 100644 |
| --- a/mojo/shell/shell_test_base_unittest.cc |
| +++ b/mojo/shell/shell_test_base_unittest.cc |
| @@ -5,21 +5,75 @@ |
| #include "mojo/shell/shell_test_base.h" |
| #include "base/bind.h" |
| +#include "base/i18n/time_formatting.h" |
| #include "base/macros.h" |
| #include "base/message_loop/message_loop.h" |
| +#include "base/strings/utf_string_conversions.h" |
| #include "mojo/public/cpp/bindings/error_handler.h" |
| #include "mojo/public/cpp/bindings/interface_ptr.h" |
| #include "mojo/public/cpp/system/core.h" |
| #include "mojo/services/test_service/test_service.mojom.h" |
| +#include "mojo/services/test_service/toy_monitoring_service.mojom.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "url/gurl.h" |
| +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
|
| +using mojo::test::ServiceReportPtr; |
| +using mojo::test::TestService; |
| +using mojo::test::TestTimeService; |
| +using mojo::test::TestServicePtr; |
| +using mojo::test::TestTimeServicePtr; |
| +using mojo::test::ToyMonitoringService; |
| +using mojo::test::ToyMonitoringServicePtr; |
| + |
| namespace mojo { |
| namespace shell { |
| namespace test { |
| namespace { |
| -typedef ShellTestBase ShellTestBaseTest; |
| +void GetReportCallback(base::MessageLoop* loop, |
| + std::vector<ServiceReport>* reports_out, |
| + mojo::Array<ServiceReportPtr> report) { |
| + for (size_t i = 0; i < report.size(); i++) |
| + reports_out->push_back(*report[i]); |
| + loop->QuitWhenIdle(); |
| +} |
| + |
| +class ShellTestBaseTest : public ShellTestBase { |
| + public: |
| + // Convenience helpers for use as callbacks in tests. |
| + template <typename T> |
| + base::Callback<void()> SetAndQuit(T* val, T result) { |
| + return base::Bind(&ShellTestBaseTest::SetAndQuitImpl<T>, |
| + base::Unretained(this), val, result); |
| + } |
| + template <typename T> |
| + base::Callback<void(T result)> SetAndQuit(T* val) { |
| + return base::Bind(&ShellTestBaseTest::SetAndQuitImpl<T>, |
| + base::Unretained(this), val); |
| + } |
| + |
| + static GURL test_app_url() { |
| + return GURL("mojo:mojo_test_app"); |
| + } |
| + |
| + void GetReport(std::vector<ServiceReport>* report) { |
| + monitoring_.Bind(ConnectToService(GURL("mojo:mojo_test_monitoring_app"), |
| + ToyMonitoringService::Name_).Pass()); |
| + monitoring_->GetReport(base::Bind(&GetReportCallback, |
| + base::Unretained(message_loop()), |
| + base::Unretained(report))); |
| + message_loop()->Run(); |
| + } |
| + |
| + private: |
| + template<typename T> |
| + void SetAndQuitImpl(T* val, T result) { |
| + *val = result; |
| + message_loop()->QuitWhenIdle(); |
| + } |
| + ToyMonitoringServicePtr monitoring_; |
| +}; |
| class QuitMessageLoopErrorHandler : public ErrorHandler { |
| public: |
| @@ -35,53 +89,33 @@ class QuitMessageLoopErrorHandler : public ErrorHandler { |
| DISALLOW_COPY_AND_ASSIGN(QuitMessageLoopErrorHandler); |
| }; |
| -void PingCallback(base::MessageLoop* message_loop, bool* was_run) { |
| - *was_run = true; |
| - VLOG(2) << "Ping callback"; |
| - message_loop->QuitWhenIdle(); |
| -} |
| - |
| -TEST_F(ShellTestBaseTest, LaunchServiceInProcess) { |
| - InterfacePtr<mojo::test::ITestService> test_service; |
| - |
| - { |
| - ScopedMessagePipeHandle service_handle = |
| - LaunchServiceInProcess(GURL("mojo:mojo_test_service"), |
| - mojo::test::ITestService::Name_); |
| - test_service.Bind(service_handle.Pass()); |
| - } |
| +// Tests that we can connect to a single service within a single app. |
| +TEST_F(ShellTestBaseTest, ConnectBasic) { |
| + InterfacePtr<TestService> service; |
| + service.Bind(ConnectToService(test_app_url(), TestService::Name_).Pass()); |
| bool was_run = false; |
| - test_service->Ping(base::Bind(&PingCallback, |
| - base::Unretained(message_loop()), |
| - base::Unretained(&was_run))); |
| + service->Ping(SetAndQuit<bool>(&was_run, true)); |
| message_loop()->Run(); |
| EXPECT_TRUE(was_run); |
| - EXPECT_FALSE(test_service.encountered_error()); |
| + EXPECT_FALSE(service.encountered_error()); |
| - test_service.reset(); |
| + service.reset(); |
| - // This will run until the test service has actually quit (which it will, |
| + // This will run until the test app has actually quit (which it will, |
| // since we killed the only connection to it). |
| message_loop()->Run(); |
| } |
| -// Tests that launching a service in process fails properly if the service |
| +// Tests that trying to connect to a service fails properly if the service |
| // doesn't exist. |
| -TEST_F(ShellTestBaseTest, LaunchServiceInProcessInvalidService) { |
| - InterfacePtr<mojo::test::ITestService> test_service; |
| - |
| - { |
| - ScopedMessagePipeHandle service_handle = |
| - LaunchServiceInProcess(GURL("mojo:non_existent_service"), |
| - mojo::test::ITestService::Name_); |
| - test_service.Bind(service_handle.Pass()); |
| - } |
| +TEST_F(ShellTestBaseTest, ConnectInvalidService) { |
| + InterfacePtr<TestService> test_service; |
| + test_service.Bind(ConnectToService(GURL("mojo:non_existent_service"), |
| + TestService::Name_).Pass()); |
| bool was_run = false; |
| - test_service->Ping(base::Bind(&PingCallback, |
| - base::Unretained(message_loop()), |
| - base::Unretained(&was_run))); |
| + test_service->Ping(SetAndQuit<bool>(&was_run, true)); |
| // This will quit because there's nothing running. |
| message_loop()->Run(); |
| @@ -98,6 +132,137 @@ TEST_F(ShellTestBaseTest, LaunchServiceInProcessInvalidService) { |
| test_service.reset(); |
| } |
| +// Similar to ConnectBasic, but causes the app to instantiate multiple |
| +// service implementation objects and verifies the shell can reach both. |
| +TEST_F(ShellTestBaseTest, ConnectMultipleInstancesPerApp) { |
| + { |
| + TestServicePtr service1, service2; |
| + service1.Bind(ConnectToService(test_app_url(), TestService::Name_).Pass()); |
| + service2.Bind(ConnectToService(test_app_url(), TestService::Name_).Pass()); |
| + |
| + bool was_run1 = false; |
| + bool was_run2 = false; |
| + service1->Ping(SetAndQuit<bool>(&was_run1, true)); |
| + service2->Ping(SetAndQuit<bool>(&was_run2, true)); |
| + message_loop()->Run(); |
| + EXPECT_TRUE(was_run1); |
| + EXPECT_TRUE(was_run2); |
| + EXPECT_FALSE(service1.encountered_error()); |
| + EXPECT_FALSE(service2.encountered_error()); |
| + } |
| + message_loop()->Run(); |
| +} |
| + |
| +// Tests that service A and service B, both in App 1, can talk to each other |
| +// and parameters are passed around properly. |
| +TEST_F(ShellTestBaseTest, ConnectDifferentServicesInSingleApp) { |
| + // Have a TestService GetPartyTime on a TestTimeService in the same app. |
| + std::string welcome; |
| + TestServicePtr service; |
| + service.Bind(ConnectToService(test_app_url(), TestService::Name_).Pass()); |
| + service->GetFriendlyWelcomeMessage(test_app_url().spec(), |
| + SetAndQuit<std::string>(&welcome)); |
| + message_loop()->Run(); |
| + |
| + // Verify by hitting the TimeService directly. |
| + TestTimeServicePtr time_service; |
| + time_service.Bind( |
| + ConnectToService(test_app_url(), TestTimeService::Name_).Pass()); |
| + int64 party_time; |
| + time_service->GetPartyTime(SetAndQuit<int64>(&party_time)); |
| + message_loop()->Run(); |
| + |
| + std::string expected_welcome( |
| + TestService::kWelcomeMessagePrefix + |
| + UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime( |
| + base::Time::FromInternalValue(party_time)))); |
| + EXPECT_EQ(welcome, expected_welcome); |
| +} |
| + |
| +// Tests that a service A in App 1 can talk to service B in App 2 and |
| +// parameters are passed around properly. |
| +TEST_F(ShellTestBaseTest, ConnectDifferentServicesInDifferentApps) { |
| + std::string welcome; |
| + TestServicePtr service; |
| + service.Bind(ConnectToService(test_app_url(), TestService::Name_).Pass()); |
| + service->GetFriendlyWelcomeMessage("mojo:mojo_test_monitoring_app", |
| + SetAndQuit<std::string>(&welcome)); |
| + message_loop()->Run(); |
| + |
| + // Verify by hitting the TimeService in the monitoring app directly. |
| + TestTimeServicePtr time_service; |
| + time_service.Bind(ConnectToService(GURL("mojo:mojo_test_monitoring_app"), |
| + TestTimeService::Name_).Pass()); |
| + int64 party_time; |
| + time_service->GetPartyTime(SetAndQuit<int64>(&party_time)); |
| + message_loop()->Run(); |
| + |
| + std::string expected_welcome( |
| + TestService::kWelcomeMessagePrefix + |
| + UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime( |
| + base::Time::FromInternalValue(party_time)))); |
| + EXPECT_EQ(welcome, expected_welcome); |
| +} |
| + |
| +// Tests that service A in App 1 can be a client of service B in App 2. |
| +TEST_F(ShellTestBaseTest, ConnectServiceAsClientOfSeparateApp) { |
| + TestServicePtr service; |
| + service.Bind(ConnectToService(test_app_url(), TestService::Name_).Pass()); |
| + service->StartMonitoring(message_loop()->QuitWhenIdleClosure()); |
| + service->Ping(mojo::Callback<void()>()); |
| + message_loop()->Run(); |
| + |
| + for (int i = 0; i < 9; i++) |
| + service->Ping(mojo::Callback<void()>()); |
| + |
| + // If everything worked properly, the monitoring service should report |
| + // 10 pings to TestService. |
| + std::vector<ServiceReport> reports; |
| + GetReport(&reports); |
| + ASSERT_EQ(1U, reports.size()); |
| + 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.
|
| + EXPECT_EQ(10U, reports[0].total_requests); |
| +} |
| + |
| +// Connect several services together and use the monitoring service to verify |
| +// communication. |
| +TEST_F(ShellTestBaseTest, ConnectManyClientsAndServices) { |
| + TestServicePtr service; |
| + TestTimeServicePtr time_service; |
| + |
| + // Make a request to the TestService and have it contact TimeService in the |
| + // monitoring app. Do all this with monitoring enabled, meaning both services |
| + // are connected as clients of the MonitoringService. |
| + service.Bind(ConnectToService(test_app_url(), TestService::Name_).Pass()); |
| + service->StartMonitoring(message_loop()->QuitWhenIdleClosure()); |
| + message_loop()->Run(); |
| + for (int i = 0; i < 5; i++) |
| + service->Ping(mojo::Callback<void()>()); |
| + std::string welcome; |
| + service->GetFriendlyWelcomeMessage("mojo:mojo_test_monitoring_app", |
| + SetAndQuit<std::string>(&welcome)); |
| + message_loop()->Run(); |
| + |
| + // Also make a few requests to the TimeService in the test_app. |
| + time_service.Bind( |
| + ConnectToService(test_app_url(), TestTimeService::Name_).Pass()); |
| + time_service->StartMonitoring(message_loop()->QuitWhenIdleClosure()); |
| + time_service->GetPartyTime(mojo::Callback<void(uint64_t)>()); |
| + message_loop()->Run(); |
| + for (int i = 0; i < 19; i++) |
| + time_service->GetPartyTime(mojo::Callback<void(uint64_t)>()); |
| + |
| + std::vector<ServiceReport> reports; |
| + GetReport(&reports); |
| + ASSERT_EQ(3U, reports.size()); |
| + 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.
|
| + EXPECT_EQ(6U, reports[0].total_requests); |
| + EXPECT_EQ("mojo::test::TestTimeService", reports[1].service_name); |
| + EXPECT_EQ(1U, reports[1].total_requests); |
| + EXPECT_EQ("mojo::test::TestTimeService", reports[2].service_name); |
| + EXPECT_EQ(20U, reports[2].total_requests); |
| +} |
| + |
| } // namespace |
| } // namespace test |
| } // namespace shell |