1 // Copyright 2020 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 "chrome/browser/chromeos/app_mode/kiosk_session_plugin_handler.h"
6 
7 #include "chrome/browser/chromeos/app_mode/kiosk_session_plugin_handler_delegate.h"
8 #include "chrome/test/base/testing_browser_process.h"
9 #include "chrome/test/base/testing_profile.h"
10 #include "content/public/browser/web_contents.h"
11 #include "content/public/test/browser_task_environment.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 
14 using content::WebContents;
15 using content::WebContentsObserver;
16 
17 namespace chromeos {
18 
19 namespace {
20 
21 constexpr char kValidPluginPath[] = "/path/to/valid_plugin";
22 constexpr char kInvalidPluginPath[] = "/path/to/invalid_plugin";
23 constexpr char kProcessId = 2;
24 constexpr int kPluginChildId = 2;
25 
26 }  // namespace
27 
28 class TestKioskSessionPluginHandlerDelegate
29     : public KioskSessionPluginHandlerDelegate {
30  public:
31   TestKioskSessionPluginHandlerDelegate() = default;
32   ~TestKioskSessionPluginHandlerDelegate() override = default;
33 
ShouldHandlePlugin(const base::FilePath & plugin_path) const34   bool ShouldHandlePlugin(const base::FilePath& plugin_path) const override {
35     return plugin_path.AsUTF8Unsafe() == kValidPluginPath;
36   }
37 
OnPluginCrashed(const base::FilePath & plugin_path)38   void OnPluginCrashed(const base::FilePath& plugin_path) override {
39     has_crashed_ = true;
40   }
41 
OnPluginHung(const std::set<int> & hung_plugins)42   void OnPluginHung(const std::set<int>& hung_plugins) override {}
43 
has_crashed() const44   bool has_crashed() const { return has_crashed_; }
45 
46  private:
47   bool has_crashed_ = false;
48 };
49 
50 class KioskSessionPluginHandlerTest : public testing::Test {
51  public:
52   KioskSessionPluginHandlerTest() = default;
53   ~KioskSessionPluginHandlerTest() override = default;
54 
SetUp()55   void SetUp() override {
56     delegate_ = std::make_unique<TestKioskSessionPluginHandlerDelegate>();
57     handler_ = std::make_unique<KioskSessionPluginHandler>(delegate_.get());
58   }
59 
delegate() const60   TestKioskSessionPluginHandlerDelegate* delegate() const {
61     return delegate_.get();
62   }
63 
handler() const64   KioskSessionPluginHandler* handler() const { return handler_.get(); }
65 
66  private:
67   content::BrowserTaskEnvironment task_environment_;
68   std::unique_ptr<TestKioskSessionPluginHandlerDelegate> delegate_;
69   std::unique_ptr<KioskSessionPluginHandler> handler_;
70 };
71 
TEST_F(KioskSessionPluginHandlerTest,ObserveAndDestroyWebContents)72 TEST_F(KioskSessionPluginHandlerTest, ObserveAndDestroyWebContents) {
73   // At the beginning, there is no watcher.
74   EXPECT_EQ(handler()->GetWatchersForTesting().size(), 0U);
75 
76   // The number of watchers increases after a new WebContents instance is
77   // observed.
78   TestingProfile profile1;
79   std::unique_ptr<WebContents> contents1 =
80       WebContents::Create(WebContents::CreateParams(&profile1));
81   handler()->Observe(contents1.get());
82   EXPECT_EQ(handler()->GetWatchersForTesting().size(), 1U);
83 
84   // The number of watchers increases again after another new WebContents
85   // instance is observed.
86   TestingProfile profile2;
87   std::unique_ptr<WebContents> contents2 =
88       WebContents::Create(WebContents::CreateParams(&profile2));
89   handler()->Observe(contents2.get());
90 
91   std::vector<KioskSessionPluginHandler::Observer*> watchers =
92       handler()->GetWatchersForTesting();
93   EXPECT_EQ(watchers.size(), 2U);
94 
95   // The number of watchers returns to zero after each WebContents instance is
96   // destroyed.
97   for (WebContentsObserver* observer : watchers)
98     observer->WebContentsDestroyed();
99   EXPECT_EQ(handler()->GetWatchersForTesting().size(), 0U);
100 }
101 
TEST_F(KioskSessionPluginHandlerTest,PluginCrashed)102 TEST_F(KioskSessionPluginHandlerTest, PluginCrashed) {
103   TestingProfile profile;
104   std::unique_ptr<WebContents> contents =
105       WebContents::Create(WebContents::CreateParams(&profile));
106   handler()->Observe(contents.get());
107   WebContentsObserver* watcher = handler()->GetWatchersForTesting().front();
108 
109   // At the beginning, no crash is notified to the delegate.
110   EXPECT_FALSE(delegate()->has_crashed());
111 
112   // No crash is notified if the |plugin_path| is invalid.
113   watcher->PluginCrashed(base::FilePath(kInvalidPluginPath),
114                          base::ProcessId(kProcessId));
115   EXPECT_FALSE(delegate()->has_crashed());
116 
117   // Crash is notified if the |plugin_path| is valid.
118   watcher->PluginCrashed(base::FilePath(kValidPluginPath),
119                          base::ProcessId(kProcessId));
120   EXPECT_TRUE(delegate()->has_crashed());
121 }
122 
TEST_F(KioskSessionPluginHandlerTest,PluginHungStatusChanged)123 TEST_F(KioskSessionPluginHandlerTest, PluginHungStatusChanged) {
124   TestingProfile profile;
125   std::unique_ptr<WebContents> contents =
126       WebContents::Create(WebContents::CreateParams(&profile));
127   handler()->Observe(contents.get());
128 
129   KioskSessionPluginHandler::Observer* observer =
130       handler()->GetWatchersForTesting().front();
131   WebContentsObserver* watcher = observer;
132 
133   // At the beginning, there is no hung plugin.
134   EXPECT_EQ(observer->GetHungPluginsForTesting().size(), 0U);
135 
136   // The hung plugin is not stored if the |plugin_path| is invalid.
137   watcher->PluginHungStatusChanged(kPluginChildId,
138                                    base::FilePath(kInvalidPluginPath), true);
139   EXPECT_EQ(observer->GetHungPluginsForTesting().size(), 0U);
140 
141   // The hung plugin is not stored if the |is_hung| is false.
142   watcher->PluginHungStatusChanged(kPluginChildId,
143                                    base::FilePath(kValidPluginPath), false);
144   EXPECT_EQ(observer->GetHungPluginsForTesting().size(), 0U);
145 
146   // The hung plugin is store.
147   watcher->PluginHungStatusChanged(kPluginChildId,
148                                    base::FilePath(kValidPluginPath), true);
149   EXPECT_EQ(observer->GetHungPluginsForTesting().size(), 1U);
150 }
151 
152 }  // namespace chromeos
153