chromium/chrome/browser/chromeos/app_mode/kiosk_session_plugin_handler_unittest.cc

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/app_mode/kiosk_session_plugin_handler.h"

#include "chrome/browser/chromeos/app_mode/kiosk_session_plugin_handler_delegate.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"

using content::WebContents;
using content::WebContentsObserver;

namespace chromeos {

namespace {

constexpr char kValidPluginPath[] = "/path/to/valid_plugin";
constexpr char kInvalidPluginPath[] = "/path/to/invalid_plugin";
constexpr char kProcessId = 2;
constexpr int kPluginChildId = 2;

}  // namespace

class TestKioskSessionPluginHandlerDelegate
    : public KioskSessionPluginHandlerDelegate {
 public:
  TestKioskSessionPluginHandlerDelegate() = default;
  ~TestKioskSessionPluginHandlerDelegate() override = default;

  bool ShouldHandlePlugin(const base::FilePath& plugin_path) const override {
    return plugin_path.AsUTF8Unsafe() == kValidPluginPath;
  }

  void OnPluginCrashed(const base::FilePath& plugin_path) override {
    has_crashed_ = true;
  }

  void OnPluginHung(const std::set<int>& hung_plugins) override {}

  bool has_crashed() const { return has_crashed_; }

 private:
  bool has_crashed_ = false;
};

class KioskSessionPluginHandlerTest : public testing::Test {
 public:
  KioskSessionPluginHandlerTest() = default;
  ~KioskSessionPluginHandlerTest() override = default;

  void SetUp() override {
    delegate_ = std::make_unique<TestKioskSessionPluginHandlerDelegate>();
    handler_ = std::make_unique<KioskSessionPluginHandler>(delegate_.get());
  }

  TestKioskSessionPluginHandlerDelegate* delegate() const {
    return delegate_.get();
  }

  KioskSessionPluginHandler* handler() const { return handler_.get(); }

 private:
  content::BrowserTaskEnvironment task_environment_;
  std::unique_ptr<TestKioskSessionPluginHandlerDelegate> delegate_;
  std::unique_ptr<KioskSessionPluginHandler> handler_;
};

TEST_F(KioskSessionPluginHandlerTest, ObserveAndDestroyWebContents) {
  // At the beginning, there is no watcher.
  EXPECT_EQ(handler()->GetWatchersForTesting().size(), 0U);

  // The number of watchers increases after a new WebContents instance is
  // observed.
  TestingProfile profile1;
  std::unique_ptr<WebContents> contents1 =
      WebContents::Create(WebContents::CreateParams(&profile1));
  handler()->Observe(contents1.get());
  EXPECT_EQ(handler()->GetWatchersForTesting().size(), 1U);

  // The number of watchers increases again after another new WebContents
  // instance is observed.
  TestingProfile profile2;
  std::unique_ptr<WebContents> contents2 =
      WebContents::Create(WebContents::CreateParams(&profile2));
  handler()->Observe(contents2.get());

  std::vector<KioskSessionPluginHandler::Observer*> watchers =
      handler()->GetWatchersForTesting();
  EXPECT_EQ(watchers.size(), 2U);

  // The number of watchers returns to zero after each WebContents instance is
  // destroyed.
  for (WebContentsObserver* observer : watchers) {
    observer->WebContentsDestroyed();
  }
  EXPECT_EQ(handler()->GetWatchersForTesting().size(), 0U);
}

TEST_F(KioskSessionPluginHandlerTest, PluginCrashed) {
  TestingProfile profile;
  std::unique_ptr<WebContents> contents =
      WebContents::Create(WebContents::CreateParams(&profile));
  handler()->Observe(contents.get());
  WebContentsObserver* watcher = handler()->GetWatchersForTesting().front();

  // At the beginning, no crash is notified to the delegate.
  EXPECT_FALSE(delegate()->has_crashed());

  // No crash is notified if the `plugin_path` is invalid.
  watcher->PluginCrashed(base::FilePath(kInvalidPluginPath),
                         base::ProcessId(kProcessId));
  EXPECT_FALSE(delegate()->has_crashed());

  // Crash is notified if the `plugin_path` is valid.
  watcher->PluginCrashed(base::FilePath(kValidPluginPath),
                         base::ProcessId(kProcessId));
  EXPECT_TRUE(delegate()->has_crashed());
}

TEST_F(KioskSessionPluginHandlerTest, PluginHungStatusChanged) {
  TestingProfile profile;
  std::unique_ptr<WebContents> contents =
      WebContents::Create(WebContents::CreateParams(&profile));
  handler()->Observe(contents.get());

  KioskSessionPluginHandler::Observer* observer =
      handler()->GetWatchersForTesting().front();
  WebContentsObserver* watcher = observer;

  // At the beginning, there is no hung plugin.
  EXPECT_EQ(observer->GetHungPluginsForTesting().size(), 0U);

  // The hung plugin is not stored if the `plugin_path` is invalid.
  watcher->PluginHungStatusChanged(kPluginChildId,
                                   base::FilePath(kInvalidPluginPath), true);
  EXPECT_EQ(observer->GetHungPluginsForTesting().size(), 0U);

  // The hung plugin is not stored if the `is_hung` is false.
  watcher->PluginHungStatusChanged(kPluginChildId,
                                   base::FilePath(kValidPluginPath), false);
  EXPECT_EQ(observer->GetHungPluginsForTesting().size(), 0U);

  // The hung plugin is store.
  watcher->PluginHungStatusChanged(kPluginChildId,
                                   base::FilePath(kValidPluginPath), true);
  EXPECT_EQ(observer->GetHungPluginsForTesting().size(), 1U);
}

}  // namespace chromeos