// Copyright 2019 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/optional.h" #include "base/run_loop.h" #include "base/test/bind_test_util.h" #include "base/time/time.h" #include "base/timer/elapsed_timer.h" #include "content/public/browser/service_process_host.h" #include "content/public/test/content_browser_test.h" #include "services/test/echo/public/mojom/echo.mojom.h" #include "testing/gtest/include/gtest/gtest.h" namespace content { using ServiceProcessHostBrowserTest = ContentBrowserTest; class EchoServiceProcessObserver : public ServiceProcessHost::Observer { public: EchoServiceProcessObserver() { ServiceProcessHost::AddObserver(this); } ~EchoServiceProcessObserver() override { ServiceProcessHost::RemoveObserver(this); } void WaitForLaunch() { launch_loop_.Run(); } void WaitForDeath() { death_loop_.Run(); } void WaitForCrash() { crash_loop_.Run(); } private: // ServiceProcessHost::Observer: void OnServiceProcessLaunched(const ServiceProcessInfo& info) override { if (info.IsService<echo::mojom::EchoService>()) launch_loop_.Quit(); } void OnServiceProcessTerminatedNormally( const ServiceProcessInfo& info) override { if (info.IsService<echo::mojom::EchoService>()) death_loop_.Quit(); } void OnServiceProcessCrashed(const ServiceProcessInfo& info) override { if (info.IsService<echo::mojom::EchoService>()) crash_loop_.Quit(); } base::RunLoop launch_loop_; base::RunLoop death_loop_; base::RunLoop crash_loop_; DISALLOW_COPY_AND_ASSIGN(EchoServiceProcessObserver); }; IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, Launch) { EchoServiceProcessObserver observer; auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>(); observer.WaitForLaunch(); const std::string kTestString = "Aurora borealis! At this time of year? At this time of day? " "In this part of the country? Localized entirely within your kitchen?"; base::RunLoop loop; echo_service->EchoString( kTestString, base::BindLambdaForTesting([&](const std::string& echoed_input) { EXPECT_EQ(kTestString, echoed_input); loop.Quit(); })); loop.Run(); } IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, LocalDisconnectQuits) { EchoServiceProcessObserver observer; auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>(); observer.WaitForLaunch(); echo_service.reset(); observer.WaitForDeath(); } IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, RemoteDisconnectQuits) { EchoServiceProcessObserver observer; auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>(); observer.WaitForLaunch(); echo_service->Quit(); observer.WaitForDeath(); } IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, ObserveCrash) { EchoServiceProcessObserver observer; auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>(); observer.WaitForLaunch(); echo_service->Crash(); observer.WaitForCrash(); } IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, IdleTimeout) { EchoServiceProcessObserver observer; auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>(); base::RunLoop wait_for_idle_loop; constexpr auto kTimeout = base::TimeDelta::FromSeconds(1); echo_service.set_idle_handler(kTimeout, base::BindLambdaForTesting([&] { wait_for_idle_loop.Quit(); echo_service.reset(); })); // Send a message and wait for the reply. Once the message is sent we should // observe at least |kTimeout| time elapsing before the RunLoop quits, because // the service process must wait at least that long to report itself as idle. base::ElapsedTimer timer; const std::string kTestString = "Yes, and you call them steamed hams despite the fact that they are " "obviously grilled."; echo_service->EchoString( kTestString, base::BindLambdaForTesting([&](const std::string& echoed_input) { EXPECT_EQ(kTestString, echoed_input); })); wait_for_idle_loop.Run(); EXPECT_GE(timer.Elapsed(), kTimeout); // And since the idle handler resets |echo_service|, we should imminently see // normal service process termination. observer.WaitForDeath(); } } // namespace content