blob: d88f8ea17ab02132ae30b8822f601698bb757383 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "extensions/browser/requirements_checker.h"
#include <memory>
#include <vector>
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "content/public/browser/gpu_data_manager.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "extensions/browser/extension_system.h"
#include "extensions/browser/extensions_test.h"
#include "extensions/browser/preload_check.h"
#include "extensions/browser/preload_check_test_util.h"
#include "extensions/common/extension.h"
#include "extensions/common/manifest.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
namespace extensions {
namespace {
// Whether this build supports the window.shape requirement.
const bool kSupportsWindowShape =
#if defined(USE_AURA)
true;
#else
false;
#endif
// Whether this build supports the plugins.npapi requirement.
const bool kSupportsNPAPI =
#if defined(OS_POSIX) && !defined(OS_MACOSX)
false;
#else
true;
#endif
// Returns true if a WebGL check might not fail immediately.
bool MightSupportWebGL() {
return content::GpuDataManager::GetInstance()->GpuAccessAllowed(nullptr);
}
const char kFeaturesKey[] = "requirements.3D.features";
const char kFeatureWebGL[] = "webgl";
const char kFeatureCSS3d[] = "css3d";
} // namespace
class RequirementsCheckerTest : public ExtensionsTest {
public:
RequirementsCheckerTest()
: ExtensionsTest(base::MakeUnique<content::TestBrowserThreadBundle>()) {
manifest_dict_ = base::MakeUnique<base::DictionaryValue>();
}
~RequirementsCheckerTest() override {}
void CreateExtension() {
manifest_dict_->SetString("name", "dummy name");
manifest_dict_->SetString("version", "1");
std::string error;
extension_ =
Extension::Create(base::FilePath(), Manifest::UNPACKED, *manifest_dict_,
Extension::NO_FLAGS, &error);
ASSERT_TRUE(extension_.get()) << error;
}
protected:
void StartChecker() {
checker_ = base::MakeUnique<RequirementsChecker>(extension_);
// TODO(michaelpg): This should normally not have to be async. Use Run()
// instead of RunUntilComplete() after crbug.com/708354 is addressed.
runner_.RunUntilComplete(checker_.get());
}
void RequireWindowShape() {
manifest_dict_->SetBoolean("requirements.window.shape", true);
}
void RequireNPAPI() {
manifest_dict_->SetBoolean("requirements.plugins.npapi", true);
}
void RequireFeature(const char feature[]) {
if (!manifest_dict_->HasKey(kFeaturesKey))
manifest_dict_->Set(kFeaturesKey, base::MakeUnique<base::ListValue>());
base::ListValue* features_list = nullptr;
ASSERT_TRUE(manifest_dict_->GetList(kFeaturesKey, &features_list));
features_list->AppendString(feature);
}
std::unique_ptr<RequirementsChecker> checker_;
PreloadCheckRunner runner_;
private:
scoped_refptr<Extension> extension_;
std::unique_ptr<base::DictionaryValue> manifest_dict_;
};
// Tests no requirements.
TEST_F(RequirementsCheckerTest, RequirementsEmpty) {
CreateExtension();
StartChecker();
EXPECT_TRUE(runner_.called());
EXPECT_EQ(0u, runner_.errors().size());
EXPECT_TRUE(checker_->GetErrorMessage().empty());
}
// Tests fulfilled requirements.
TEST_F(RequirementsCheckerTest, RequirementsSuccess) {
if (kSupportsWindowShape)
RequireWindowShape();
if (kSupportsNPAPI)
RequireNPAPI();
RequireFeature(kFeatureCSS3d);
CreateExtension();
StartChecker();
EXPECT_TRUE(runner_.called());
EXPECT_EQ(0u, runner_.errors().size());
EXPECT_TRUE(checker_->GetErrorMessage().empty());
}
// Tests multiple requirements failing (on some builds).
TEST_F(RequirementsCheckerTest, RequirementsFailMultiple) {
size_t expected_errors = 0u;
if (!kSupportsWindowShape) {
RequireWindowShape();
expected_errors++;
}
if (!kSupportsNPAPI) {
RequireNPAPI();
expected_errors++;
}
if (!MightSupportWebGL()) {
RequireFeature(kFeatureWebGL);
expected_errors++;
}
// css3d should always succeed.
RequireFeature(kFeatureCSS3d);
CreateExtension();
StartChecker();
EXPECT_TRUE(runner_.called());
EXPECT_EQ(expected_errors, runner_.errors().size());
EXPECT_EQ(expected_errors == 0, checker_->GetErrorMessage().empty());
}
// Tests a requirement that might fail asynchronously.
TEST_F(RequirementsCheckerTest, RequirementsFailWebGL) {
content::GpuDataManager::GetInstance()->BlacklistWebGLForTesting();
RequireFeature(kFeatureWebGL);
CreateExtension();
StartChecker();
// TODO(michaelpg): Check that the runner actually finishes, which requires
// waiting for the GPU check to succeed: crbug.com/706204.
if (runner_.errors().size()) {
EXPECT_THAT(runner_.errors(), testing::UnorderedElementsAre(
PreloadCheck::WEBGL_NOT_SUPPORTED));
EXPECT_FALSE(checker_->GetErrorMessage().empty());
}
}
} // namespace extensions