
When loading an extension through disable-extensions-except, the extension id is added to disable_flag_exempted_extensions_ after its extension is loaded. However, when loading the extension, it is necessary to check whether the extension id is in disable_flag_exempted_extensions_. To avoid this problem, the callback in RequirementsChecker is executed asynchronously. When asynchronously loading an extension with declarativeNetRequest permission, WebRequestAPI::UpdateMayHaveProxies() will clean up all CrosUrlFactory mojo bindings in NetworkService, causing the existing ServiceWorker to be destroyed due to mojo disconnection. Bug: 353034823 Change-Id: I338d7ea9700519eed490c27fc860ba288865289c Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5719840 Commit-Queue: Devlin Cronin <rdevlin.cronin@chromium.org> Reviewed-by: Kelvin Jiang <kelvinjiang@chromium.org> Reviewed-by: Devlin Cronin <rdevlin.cronin@chromium.org> Cr-Commit-Position: refs/heads/main@{#1342319}
149 lines
4.4 KiB
C++
149 lines
4.4 KiB
C++
// Copyright 2017 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "extensions/browser/preload_check_group.h"
|
|
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
#include "content/public/test/browser_task_environment.h"
|
|
#include "extensions/browser/preload_check_test_util.h"
|
|
#include "testing/gmock/include/gmock/gmock.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
namespace extensions {
|
|
|
|
namespace {
|
|
PreloadCheck::Error kDummyError1 = PreloadCheck::Error::kDisallowedByPolicy;
|
|
PreloadCheck::Error kDummyError2 = PreloadCheck::Error::kBlocklistedId;
|
|
PreloadCheck::Error kDummyError3 = PreloadCheck::Error::kBlocklistedUnknown;
|
|
}
|
|
|
|
class PreloadCheckGroupTest : public testing::Test {
|
|
public:
|
|
PreloadCheckGroupTest()
|
|
: check_group_(std::make_unique<PreloadCheckGroup>()) {}
|
|
~PreloadCheckGroupTest() override {}
|
|
|
|
protected:
|
|
// Adds a check to |check_group_|, storing its unique_ptr in |checks_|.
|
|
void AddCheck(PreloadCheck::Errors errors, bool is_async = false) {
|
|
auto check_stub = std::make_unique<PreloadCheckStub>(errors);
|
|
check_stub->set_is_async(is_async);
|
|
check_group_->AddCheck(check_stub.get());
|
|
checks_.push_back(std::move(check_stub));
|
|
}
|
|
|
|
// Convenience method for add an async check.
|
|
void AddAsyncCheck(PreloadCheck::Errors errors) {
|
|
AddCheck(errors, /*is_async=*/true);
|
|
}
|
|
|
|
// Verifies that all checks have started.
|
|
void ExpectStarted() {
|
|
for (const auto& check : checks_)
|
|
EXPECT_TRUE(check->started());
|
|
}
|
|
|
|
PreloadCheckRunner runner_;
|
|
std::vector<std::unique_ptr<PreloadCheckStub>> checks_;
|
|
std::unique_ptr<PreloadCheckGroup> check_group_;
|
|
|
|
private:
|
|
// Required for the asynchronous tests.
|
|
content::BrowserTaskEnvironment task_environment_;
|
|
};
|
|
|
|
// Tests multiple succeeding checks.
|
|
TEST_F(PreloadCheckGroupTest, Succeed) {
|
|
for (int i = 0; i < 3; i++)
|
|
AddCheck(PreloadCheck::Errors());
|
|
runner_.Run(check_group_.get());
|
|
|
|
ExpectStarted();
|
|
EXPECT_EQ(0u, runner_.errors().size());
|
|
}
|
|
|
|
// Tests multiple succeeding sync and async checks.
|
|
TEST_F(PreloadCheckGroupTest, SucceedAsync) {
|
|
for (int i = 0; i < 2; i++) {
|
|
AddCheck(PreloadCheck::Errors());
|
|
AddAsyncCheck(PreloadCheck::Errors());
|
|
}
|
|
|
|
runner_.RunUntilComplete(check_group_.get());
|
|
ExpectStarted();
|
|
EXPECT_EQ(0u, runner_.errors().size());
|
|
}
|
|
|
|
// Tests failing checks.
|
|
TEST_F(PreloadCheckGroupTest, Fail) {
|
|
AddCheck(PreloadCheck::Errors());
|
|
AddAsyncCheck({kDummyError1, kDummyError2});
|
|
AddCheck({kDummyError3});
|
|
runner_.Run(check_group_.get());
|
|
|
|
ExpectStarted();
|
|
EXPECT_FALSE(runner_.called());
|
|
|
|
// The runner is called with all errors.
|
|
runner_.WaitForComplete();
|
|
EXPECT_EQ(3u, runner_.errors().size());
|
|
}
|
|
|
|
// Tests failing synchronous checks with stop_on_first_error.
|
|
TEST_F(PreloadCheckGroupTest, FailFast) {
|
|
check_group_->set_stop_on_first_error(true);
|
|
|
|
AddCheck({kDummyError1, kDummyError2});
|
|
AddCheck({kDummyError3});
|
|
runner_.Run(check_group_.get());
|
|
|
|
// After the first check fails, the remaining checks should not be started.
|
|
EXPECT_TRUE(checks_[0]->started());
|
|
EXPECT_FALSE(checks_[1]->started());
|
|
|
|
// The callback of PreloadCheckGroup is called aynchronously.
|
|
runner_.WaitForComplete();
|
|
EXPECT_TRUE(runner_.called());
|
|
EXPECT_THAT(runner_.errors(),
|
|
testing::UnorderedElementsAre(kDummyError1, kDummyError2));
|
|
}
|
|
|
|
// Tests failing asynchronous checks with stop_on_first_error.
|
|
TEST_F(PreloadCheckGroupTest, FailFastAsync) {
|
|
check_group_->set_stop_on_first_error(true);
|
|
|
|
AddCheck(PreloadCheck::Errors());
|
|
AddAsyncCheck(PreloadCheck::Errors());
|
|
AddAsyncCheck({kDummyError1});
|
|
AddAsyncCheck({kDummyError2});
|
|
runner_.Run(check_group_.get());
|
|
|
|
// All checks were started, because the sync check passes.
|
|
ExpectStarted();
|
|
EXPECT_FALSE(runner_.called());
|
|
runner_.WaitForComplete();
|
|
|
|
// The first async check should have failed, triggering fail fast. The
|
|
// second async check's failure should be ignored.
|
|
EXPECT_THAT(runner_.errors(), testing::UnorderedElementsAre(kDummyError1));
|
|
}
|
|
|
|
// Tests we don't crash when the PreloadCheckGroup is destroyed prematurely.
|
|
TEST_F(PreloadCheckGroupTest, DestroyPreloadCheckGroup) {
|
|
AddAsyncCheck({kDummyError1});
|
|
AddAsyncCheck({kDummyError2});
|
|
runner_.Run(check_group_.get());
|
|
|
|
check_group_.reset();
|
|
|
|
// Checks should have been started, but the runner is never called.
|
|
ExpectStarted();
|
|
runner_.WaitForIdle();
|
|
EXPECT_FALSE(runner_.called());
|
|
}
|
|
|
|
} // namespace extensions
|