blob: 5727b72737046ab54d5971714cd6ce86e91ffca9 [file] [log] [blame]
// 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.
#include "base/strings/stringprintf.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/test/browser_test.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/test/extension_test_message_listener.h"
#include "extensions/test/result_catcher.h"
#include "extensions/test/test_extension_dir.h"
namespace extensions {
using ComponentExtensionBrowserTest = ExtensionBrowserTest;
#if BUILDFLAG(IS_CHROMEOS)
// Tests that MojoJS is enabled for component extensions that need it.
// Note the test currently only runs for ChromeOS because the test extension
// uses `mojoPrivate` to test and `mojoPrivate` is ChromeOS only.
IN_PROC_BROWSER_TEST_F(ComponentExtensionBrowserTest, MojoJS) {
ResultCatcher result_catcher;
auto* extension =
LoadExtension(test_data_dir_.AppendASCII("service_worker/mojo"),
{.load_as_component = true});
ASSERT_TRUE(extension);
ASSERT_TRUE(result_catcher.GetNextResult());
}
#endif // BUILDFLAG(IS_CHROMEOS)
const ExtensionId kExtensionId = "iegclhlplifhodhkoafiokenjoapiobj";
constexpr char kExtensionKey[] =
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjzv7dI7Ygyh67VHE1DdidudpYf8P"
"Ffv8iucWvzO+3xpF/Dm5xNo7aQhPNiEaNfHwJQ7lsp4gc+C+4bbaVewBFspTruoSJhZc5uEf"
"qxwovJwN+v1/SUFXTXQmQBv6gs0qZB4gBbl4caNQBlqrFwAMNisnu1V6UROna8rOJQ90D7Nv"
"7TCwoVPKBfVshpFjdDOTeBg4iLctO3S/06QYqaTDrwVceSyHkVkvzBY6tc6mnYX0RZu78J9i"
"L8bdqwfllOhs69cqoHHgrLdI6JdOyiuh6pBP6vxMlzSKWJ3YTNjaQTPwfOYaLMuzdl0v+Ydz"
"afIzV9zwe4Xiskk+5JNGt8b2rQIDAQAB";
// Tests updating a Service Worker-based component extension across a restart.
// This simulates a browser update where a component extension might change.
class ComponentExtensionServiceWorkerUpdateBrowserTest
: public ComponentExtensionBrowserTest {
public:
void WriteExtension(TestExtensionDir* dir, int version) {
constexpr char kManifestTemplate[] =
R"({
"name": "Component SW Update Test",
"manifest_version": 3,
"version": "%d",
"background": {"service_worker": "sw.js"},
"key": "%s"
})";
dir->WriteManifest(
base::StringPrintf(kManifestTemplate, version, kExtensionKey));
constexpr char kBackgroundScriptTemplate[] =
R"(self.version = %d;
chrome.test.sendMessage(`v${self.version} ready`);)";
dir->WriteFile(FILE_PATH_LITERAL("sw.js"),
base::StringPrintf(kBackgroundScriptTemplate, version));
}
int GetWorkerVersion(const ExtensionId& id) {
constexpr char kGetVersionScript[] =
"chrome.test.sendScriptResult(self.version);";
base::Value version = ExecuteScriptInBackgroundPage(id, kGetVersionScript);
if (!version.is_int()) {
ADD_FAILURE() << "Script did not return an integer. Value: " << version;
return -1;
}
return version.GetInt();
}
TestExtensionDir test_dir_v1_;
TestExtensionDir test_dir_v2_;
};
// PRE_ test: Installs V1 of the component extension. Verifies it runs.
IN_PROC_BROWSER_TEST_F(ComponentExtensionServiceWorkerUpdateBrowserTest,
PRE_Update) {
WriteExtension(&test_dir_v1_, 1);
// Load V1 of the component extension.
ExtensionTestMessageListener v1_ready("v1 ready");
const Extension* extension_v1 =
LoadExtension(test_dir_v1_.UnpackedPath(), {.load_as_component = true});
ASSERT_TRUE(extension_v1);
// Ensure it has the correct ID and wait for it to start.
const ExtensionId id = extension_v1->id();
ASSERT_EQ(kExtensionId, id);
ASSERT_TRUE(v1_ready.WaitUntilSatisfied());
// Check service worker version.
EXPECT_EQ("1", extension_v1->version().GetString());
EXPECT_EQ(1, GetWorkerVersion(id));
}
// Main test: Installs V2 of the component extension. Verifies V2 runs.
IN_PROC_BROWSER_TEST_F(ComponentExtensionServiceWorkerUpdateBrowserTest,
Update) {
ASSERT_FALSE(
extension_registry()->enabled_extensions().GetByID(kExtensionId));
WriteExtension(&test_dir_v2_, 2);
// Load V2 of the component extension.
ExtensionTestMessageListener v2_ready("v2 ready");
const Extension* extension_v2 =
LoadExtension(test_dir_v2_.UnpackedPath(), {.load_as_component = true});
ASSERT_TRUE(extension_v2);
// Ensure it has the correct ID (same as V1) and wait for it to start.
const ExtensionId id = extension_v2->id();
EXPECT_EQ(kExtensionId, id);
ASSERT_TRUE(v2_ready.WaitUntilSatisfied());
// Check service worker version.
EXPECT_EQ("2", extension_v2->version().GetString());
EXPECT_EQ(2, GetWorkerVersion(id));
}
} // namespace extensions