1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/optional.h"
6 #include "base/run_loop.h"
7 #include "base/test/bind_test_util.h"
8 #include "base/time/time.h"
9 #include "base/timer/elapsed_timer.h"
10 #include "content/public/browser/service_process_host.h"
11 #include "content/public/test/content_browser_test.h"
12 #include "services/test/echo/public/mojom/echo.mojom.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 
15 namespace content {
16 
17 using ServiceProcessHostBrowserTest = ContentBrowserTest;
18 
19 class EchoServiceProcessObserver : public ServiceProcessHost::Observer {
20  public:
EchoServiceProcessObserver()21   EchoServiceProcessObserver() { ServiceProcessHost::AddObserver(this); }
22 
~EchoServiceProcessObserver()23   ~EchoServiceProcessObserver() override {
24     ServiceProcessHost::RemoveObserver(this);
25   }
26 
WaitForLaunch()27   void WaitForLaunch() { launch_loop_.Run(); }
WaitForDeath()28   void WaitForDeath() { death_loop_.Run(); }
WaitForCrash()29   void WaitForCrash() { crash_loop_.Run(); }
30 
31  private:
32   // ServiceProcessHost::Observer:
OnServiceProcessLaunched(const ServiceProcessInfo & info)33   void OnServiceProcessLaunched(const ServiceProcessInfo& info) override {
34     if (info.IsService<echo::mojom::EchoService>())
35       launch_loop_.Quit();
36   }
37 
OnServiceProcessTerminatedNormally(const ServiceProcessInfo & info)38   void OnServiceProcessTerminatedNormally(
39       const ServiceProcessInfo& info) override {
40     if (info.IsService<echo::mojom::EchoService>())
41       death_loop_.Quit();
42   }
43 
OnServiceProcessCrashed(const ServiceProcessInfo & info)44   void OnServiceProcessCrashed(const ServiceProcessInfo& info) override {
45     if (info.IsService<echo::mojom::EchoService>())
46       crash_loop_.Quit();
47   }
48 
49   base::RunLoop launch_loop_;
50   base::RunLoop death_loop_;
51   base::RunLoop crash_loop_;
52 
53   DISALLOW_COPY_AND_ASSIGN(EchoServiceProcessObserver);
54 };
55 
IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest,Launch)56 IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, Launch) {
57   EchoServiceProcessObserver observer;
58   auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>();
59   observer.WaitForLaunch();
60 
61   const std::string kTestString =
62       "Aurora borealis! At this time of year? At this time of day? "
63       "In this part of the country? Localized entirely within your kitchen?";
64   base::RunLoop loop;
65   echo_service->EchoString(
66       kTestString,
67       base::BindLambdaForTesting([&](const std::string& echoed_input) {
68         EXPECT_EQ(kTestString, echoed_input);
69         loop.Quit();
70       }));
71   loop.Run();
72 }
73 
IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest,LocalDisconnectQuits)74 IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, LocalDisconnectQuits) {
75   EchoServiceProcessObserver observer;
76   auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>();
77   observer.WaitForLaunch();
78   echo_service.reset();
79   observer.WaitForDeath();
80 }
81 
IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest,RemoteDisconnectQuits)82 IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, RemoteDisconnectQuits) {
83   EchoServiceProcessObserver observer;
84   auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>();
85   observer.WaitForLaunch();
86   echo_service->Quit();
87   observer.WaitForDeath();
88 }
89 
IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest,ObserveCrash)90 IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, ObserveCrash) {
91   EchoServiceProcessObserver observer;
92   auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>();
93   observer.WaitForLaunch();
94   echo_service->Crash();
95   observer.WaitForCrash();
96 }
97 
IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest,IdleTimeout)98 IN_PROC_BROWSER_TEST_F(ServiceProcessHostBrowserTest, IdleTimeout) {
99   EchoServiceProcessObserver observer;
100   auto echo_service = ServiceProcessHost::Launch<echo::mojom::EchoService>();
101 
102   base::RunLoop wait_for_idle_loop;
103   constexpr auto kTimeout = base::TimeDelta::FromSeconds(1);
104   echo_service.set_idle_handler(kTimeout, base::BindLambdaForTesting([&] {
105                                   wait_for_idle_loop.Quit();
106                                   echo_service.reset();
107                                 }));
108 
109   // Send a message and wait for the reply. Once the message is sent we should
110   // observe at least |kTimeout| time elapsing before the RunLoop quits, because
111   // the service process must wait at least that long to report itself as idle.
112   base::ElapsedTimer timer;
113   const std::string kTestString =
114       "Yes, and you call them steamed hams despite the fact that they are "
115       "obviously grilled.";
116   echo_service->EchoString(
117       kTestString,
118       base::BindLambdaForTesting([&](const std::string& echoed_input) {
119         EXPECT_EQ(kTestString, echoed_input);
120       }));
121   wait_for_idle_loop.Run();
122   EXPECT_GE(timer.Elapsed(), kTimeout);
123 
124   // And since the idle handler resets |echo_service|, we should imminently see
125   // normal service process termination.
126   observer.WaitForDeath();
127 }
128 
129 }  // namespace content
130