910e62b5创建于 1月15日历史提交
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Browser tests for the RendererSideContentDecoding feature, specifically
// testing scenarios involving successful decoding and simulated failures during
// data pipe creation.

#include <string_view>

#include "base/test/scoped_feature_list.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
#include "services/network/public/cpp/features.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace content {

// Test fixture for RendererSideContentDecoding browser tests.
// Parameterized to run tests in two modes:
// - ExpectSuccess (true): Normal operation, Mojo data pipe creation succeeds.
// - ExpectFail (false): Simulates Mojo data pipe creation failure using the
//   `RendererSideContentDecodingForceMojoFailureForTesting` feature parameter.
class RendererSideContentDecodingBrowserTest
    : public ContentBrowserTest,
      public ::testing::WithParamInterface<bool> {
 public:
  RendererSideContentDecodingBrowserTest() {
    // Enable the main feature and optionally the failure simulation parameter
    // based on the test parameter (`GetParam()`).
    features_.InitWithFeaturesAndParameters(
        {{network::features::kRendererSideContentDecoding,
          {{"RendererSideContentDecodingForceMojoFailureForTesting",
            ShouldSucceed() ? "false" : "true"}}}},
        {});
  }
  ~RendererSideContentDecodingBrowserTest() override = default;

  // Provides human-readable names for the test parameter values.
  static std::string DescribeParams(
      const testing::TestParamInfo<ParamType>& info) {
    return info.param ? "ExpectSuccess" : "ExpectFail";
  }

 protected:
  // Starts the embedded test server and navigates the shell to a simple page.
  void StartServerAndNavigateToTestPage() {
    ASSERT_TRUE(embedded_test_server()->Start());
    EXPECT_TRUE(
        NavigateToURL(shell(), embedded_test_server()->GetURL("/hello.html")));
  }

  // Returns true if the current test parameter expects success (no simulated
  // failure), false otherwise.
  bool ShouldSucceed() const { return GetParam(); }

 private:
  base::test::ScopedFeatureList features_;
};

INSTANTIATE_TEST_SUITE_P(
    /* No prefix */,
    RendererSideContentDecodingBrowserTest,
    // Run with both true (ExpectSuccess) and false (ExpectFail).
    ::testing::Bool(),
    &RendererSideContentDecodingBrowserTest::DescribeParams);

// Tests loading a compressed Javascript file (.js.gz).
// In ExpectSuccess mode, the script should execute.
// In ExpectFail mode, the script load should fail, triggering the 'error'
// event, and a specific error message should be logged to the console.
IN_PROC_BROWSER_TEST_P(RendererSideContentDecodingBrowserTest,
                       CompressedScriptLoad) {
  StartServerAndNavigateToTestPage();
  // Watch for console errors related to resource loading.
  DevToolsInspectorLogWatcher log_watcher(shell()->web_contents());
  const std::string_view script = R"(
    new Promise(resolve => {
        window.resolveTest = resolve;
        const script = document.createElement('script');
        script.src = './loader/compressed.js.gz';
        script.addEventListener('error', () => {resolve('load error')});
        document.body.appendChild(script);
      });
  )";
  // compressed.js.gz contains: window.resolveTest('script executed');
  EXPECT_EQ(ShouldSucceed() ? "script executed" : "load error",
            EvalJs(shell(), script));

  log_watcher.FlushAndStopWatching();
  // Verify the console message in case of failure.
  EXPECT_EQ(log_watcher.last_message(),
            ShouldSucceed()
                ? ""
                : "Failed to load resource: net::ERR_INSUFFICIENT_RESOURCES");
}

// Tests navigating to a compressed HTML file (.html.gz).
// In ExpectSuccess mode, the navigation should complete, and the page title
// should be set correctly.
// In ExpectFail mode, the navigation should fail, and a specific error message
// ("Failed to decode content") should be logged to the console by
// RenderFrameImpl.
IN_PROC_BROWSER_TEST_P(RendererSideContentDecodingBrowserTest,
                       CompressedPageNavigation) {
  StartServerAndNavigateToTestPage();
  // compressed.html.gz contains: <title>page loaded</title>
  std::u16string expected_title(u"page loaded");
  TitleWatcher title_watcher(shell()->web_contents(), expected_title);

  // Watch for the specific console error message logged on navigation failure.
  WebContentsConsoleObserver console_observer(shell()->web_contents());
  console_observer.SetPattern("Failed to decode content");

  // Initiate navigation to the compressed HTML file.
  EXPECT_TRUE(ExecJs(shell(), JsReplace("window.location.href = $1",
                                        "./loader/compressed.html.gz")));

  if (ShouldSucceed()) {
    // Wait for the title change to confirm successful navigation and decoding.
    EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
  } else {
    // Wait for the expected console error message.
    ASSERT_TRUE(console_observer.Wait());
  }
}

}  // namespace content