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