chromium/chrome/browser/chromeos/extensions/telemetry/api/common/telemetry_extension_capabilities_browser_test.cc

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

#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/functional/callback_helpers.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/chromeos/extensions/telemetry/api/common/base_telemetry_extension_browser_test.h"
#include "chrome/common/chromeos/extensions/chromeos_system_extension_info.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/common/isolated_world_ids.h"
#include "content/public/test/browser_test.h"
#include "extensions/common/manifest_handlers/options_page_info.h"
#include "extensions/test/extension_test_message_listener.h"
#include "extensions/test/test_extension_dir.h"
#include "net/dns/mock_host_resolver.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"

namespace extensions {
class Extension;
}  // namespace extensions

namespace chromeos {

class TelemetryExtensionCapabilitiesBrowserTest
    : public BaseTelemetryExtensionBrowserTest {
 public:
  TelemetryExtensionCapabilitiesBrowserTest() = default;
  TelemetryExtensionCapabilitiesBrowserTest(
      const TelemetryExtensionCapabilitiesBrowserTest&) = delete;
  TelemetryExtensionCapabilitiesBrowserTest& operator=(
      const TelemetryExtensionCapabilitiesBrowserTest&) = delete;
  ~TelemetryExtensionCapabilitiesBrowserTest() override = default;

  GURL GetPwaGURL() const {
    return embedded_test_server()->GetURL("/simple.html");
  }

  // BaseTelemetryExtensionBrowserTest overrides:
  std::string pwa_page_url() const override { return GetPwaGURL().spec(); }
  std::string matches_origin() const override { return GetPwaGURL().spec(); }

  // BaseTelemetryExtensionBrowserTest override:
  void SetUp() override {
    // setup the test server
    embedded_test_server()->ServeFilesFromDirectory(GetChromeTestDataDir());
    ASSERT_TRUE(embedded_test_server()->InitializeAndListen());

    BaseTelemetryExtensionBrowserTest::SetUp();
  }

  // BaseTelemetryExtensionBrowserTest override:
  void SetUpCommandLine(base::CommandLine* command_line) override {
    BaseTelemetryExtensionBrowserTest::SetUpCommandLine(command_line);

    // Make sure the PWA origin is allowed.
    command_line->AppendSwitchASCII(
        chromeos::switches::kTelemetryExtensionPwaOriginOverrideForTesting,
        pwa_page_url());
  }

  // BaseTelemetryExtensionBrowserTest override:
  void SetUpOnMainThread() override {
    BaseTelemetryExtensionBrowserTest::SetUpOnMainThread();

    // This is needed when navigating to a network URL (e.g.
    // ui_test_utils::NavigateToURL). Rules can only be added before
    // BrowserTestBase::InitializeNetworkProcess() is called because host
    // changes will be disabled afterwards.
    host_resolver()->AddRule("*", "127.0.0.1");

    embedded_test_server()->StartAcceptingConnections();
  }
};

// Tests that chromeos_system_extension is able to define externally_connectable
// manifest key and receive messages from another extension.
IN_PROC_BROWSER_TEST_F(TelemetryExtensionCapabilitiesBrowserTest,
                       CanReceiveMessageExternal) {
  // Start listening on the extension.
  ExtensionTestMessageListener listener;

  // Must outlive the extension.
  extensions::TestExtensionDir test_dir_receiver;
  test_dir_receiver.WriteManifest(
      GetManifestFile(public_key(), matches_origin()));
  test_dir_receiver.WriteFile(FILE_PATH_LITERAL("options.html"), "");
  test_dir_receiver.WriteFile("sw.js",
                              base::StringPrintf(R"(
        chrome.test.runTests([
          function runtimeOnMessageExternal() {
            chrome.runtime.onMessageExternal.addListener(
              (message, sender, sendResponse) => {
                chrome.test.assertEq("%s", sender.url);
                chrome.test.assertEq("ping", message);
                chrome.test.sendMessage('success');
            });
            chrome.test.sendMessage('ready');
          }
        ]);
      )",
                                                 pwa_page_url().c_str()));

  // Load and run the extenion (chromeos_system_extension).
  const extensions::Extension* receiver =
      LoadExtension(test_dir_receiver.UnpackedPath());
  ASSERT_TRUE(receiver);

  // Make sure the extension is ready.
  ASSERT_TRUE(listener.WaitUntilSatisfied());
  EXPECT_EQ("ready", listener.message());

  listener.Reset();

  // From the |kPwaPageUrlString| page, send a message to
  // |kChromeOSSystemExtensionId|.
  // Note: |pwa_page_rfh_| is the RenderFrameHost for |kPwaPageUrlString| page.
  const auto script = base::StringPrintf(
      "window.chrome.runtime.sendMessage('%s', 'ping', (result) => {});",
      extension_id().c_str());

  auto* pwa_page_rfh = ui_test_utils::NavigateToURL(browser(), GetPwaGURL());
  ASSERT_TRUE(pwa_page_rfh);
  pwa_page_rfh->ExecuteJavaScriptForTests(base::ASCIIToUTF16(script),
                                          base::NullCallback(),
                                          content::ISOLATED_WORLD_ID_GLOBAL);

  // Wait until the extension receives the message.
  ASSERT_TRUE(listener.WaitUntilSatisfied());
  EXPECT_EQ("success", listener.message());
}

// Tests that chromeos_system_extension is able to define options_page manifest
// key and user can navigate to the options page.
IN_PROC_BROWSER_TEST_F(TelemetryExtensionCapabilitiesBrowserTest,
                       CanNavigateToOptionsPage) {
  // Start listening on the extension.
  ExtensionTestMessageListener listener;

  // Must outlive the extension.
  extensions::TestExtensionDir test_dir;
  test_dir.WriteManifest(GetManifestFile(public_key(), matches_origin()));
  test_dir.WriteFile(FILE_PATH_LITERAL("options.html"),
                     "<script>chrome.test.sendMessage('done')</script>");
  test_dir.WriteFile("sw.js", "chrome.test.sendMessage('ready');");

  // Load and run the extenion (chromeos_system_extension).
  const extensions::Extension* extension =
      LoadExtension(test_dir.UnpackedPath());
  ASSERT_TRUE(extension);

  // Make sure the extension is ready.
  ASSERT_TRUE(listener.WaitUntilSatisfied());
  EXPECT_EQ("ready", listener.message());

  listener.Reset();

  // Navigate to the extension's options page.
  ASSERT_TRUE(extensions::OptionsPageInfo::HasOptionsPage(extension));
  ASSERT_TRUE(ui_test_utils::NavigateToURL(
      browser(), extensions::OptionsPageInfo::GetOptionsPage(extension)));

  // Wait until the extension's options page is loaded.
  ASSERT_TRUE(listener.WaitUntilSatisfied());
  EXPECT_EQ("done", listener.message());
}

}  // namespace chromeos