1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/extensions/requirements_checker.h"
6
7#include <vector>
8
9#include "base/bind.h"
10#include "base/files/file_path.h"
11#include "base/memory/ref_counted.h"
12#include "base/message_loop/message_loop.h"
13#include "base/path_service.h"
14#include "base/strings/string_util.h"
15#include "chrome/browser/extensions/extension_browsertest.h"
16#include "chrome/common/chrome_paths.h"
17#include "chrome/grit/generated_resources.h"
18#include "content/public/browser/browser_thread.h"
19#include "content/public/browser/gpu_data_manager.h"
20#include "content/public/test/test_utils.h"
21#include "extensions/common/extension.h"
22#include "extensions/common/file_util.h"
23#include "gpu/config/gpu_info.h"
24#include "ui/base/l10n/l10n_util.h"
25
26namespace extensions {
27
28class RequirementsCheckerBrowserTest : public ExtensionBrowserTest {
29 public:
30  scoped_refptr<const Extension> LoadExtensionFromDirName(
31      const std::string& extension_dir_name) {
32    base::FilePath extension_path;
33    std::string load_error;
34    PathService::Get(chrome::DIR_TEST_DATA, &extension_path);
35    extension_path = extension_path.AppendASCII("requirements_checker")
36                                   .AppendASCII(extension_dir_name);
37    scoped_refptr<const Extension> extension = file_util::LoadExtension(
38        extension_path, Manifest::UNPACKED, 0, &load_error);
39    CHECK_EQ(0U, load_error.length());
40    return extension;
41  }
42
43  void ValidateRequirementErrors(std::vector<std::string> expected_errors,
44                                 std::vector<std::string> actual_errors) {
45    ASSERT_EQ(expected_errors, actual_errors);
46    requirement_errors_.swap(actual_errors);
47  }
48
49  // This should only be called once per test instance. Calling more than once
50  // will result in stale information in the GPUDataManager which will throw off
51  // the RequirementsChecker.
52  void BlackListGPUFeatures(const std::vector<std::string>& features) {
53#if !defined(NDEBUG)
54    static bool called = false;
55    DCHECK(!called);
56    called = true;
57#endif
58
59    static const std::string json_blacklist =
60      "{\n"
61      "  \"name\": \"gpu blacklist\",\n"
62      "  \"version\": \"1.0\",\n"
63      "  \"entries\": [\n"
64      "    {\n"
65      "      \"id\": 1,\n"
66      "      \"features\": [\"" + JoinString(features, "\", \"") + "\"]\n"
67      "    }\n"
68      "  ]\n"
69      "}";
70    gpu::GPUInfo gpu_info;
71    content::GpuDataManager::GetInstance()->InitializeForTesting(
72        json_blacklist, gpu_info);
73  }
74
75 protected:
76  std::vector<std::string> requirement_errors_;
77  RequirementsChecker checker_;
78};
79
80IN_PROC_BROWSER_TEST_F(RequirementsCheckerBrowserTest, CheckEmptyExtension) {
81  scoped_refptr<const Extension> extension(
82      LoadExtensionFromDirName("no_requirements"));
83  ASSERT_TRUE(extension.get());
84  checker_.Check(extension, base::Bind(
85      &RequirementsCheckerBrowserTest::ValidateRequirementErrors,
86      base::Unretained(this), std::vector<std::string>()));
87  content::RunAllBlockingPoolTasksUntilIdle();
88}
89
90IN_PROC_BROWSER_TEST_F(RequirementsCheckerBrowserTest, CheckNpapiExtension) {
91  scoped_refptr<const Extension> extension(
92      LoadExtensionFromDirName("require_npapi"));
93  ASSERT_TRUE(extension.get());
94
95  std::vector<std::string> expected_errors;
96#if defined(OS_POSIX) && !defined(OS_MACOSX)
97  expected_errors.push_back(l10n_util::GetStringUTF8(
98      IDS_EXTENSION_NPAPI_NOT_SUPPORTED));
99#endif
100
101  checker_.Check(extension, base::Bind(
102      &RequirementsCheckerBrowserTest::ValidateRequirementErrors,
103      base::Unretained(this), expected_errors));
104  content::RunAllBlockingPoolTasksUntilIdle();
105}
106
107IN_PROC_BROWSER_TEST_F(RequirementsCheckerBrowserTest,
108                       CheckWindowShapeExtension) {
109  scoped_refptr<const Extension> extension(
110      LoadExtensionFromDirName("require_window_shape"));
111  ASSERT_TRUE(extension.get());
112
113  std::vector<std::string> expected_errors;
114#if !defined(USE_AURA)
115  expected_errors.push_back(l10n_util::GetStringUTF8(
116      IDS_EXTENSION_WINDOW_SHAPE_NOT_SUPPORTED));
117#endif  // !defined(USE_AURA)
118
119  checker_.Check(extension, base::Bind(
120      &RequirementsCheckerBrowserTest::ValidateRequirementErrors,
121      base::Unretained(this), expected_errors));
122  content::RunAllBlockingPoolTasksUntilIdle();
123}
124
125IN_PROC_BROWSER_TEST_F(RequirementsCheckerBrowserTest, DisallowWebGL) {
126  scoped_refptr<const Extension> extension(
127      LoadExtensionFromDirName("require_3d"));
128  ASSERT_TRUE(extension.get());
129
130  // Backlist webgl
131  std::vector<std::string> blacklisted_features;
132  blacklisted_features.push_back("webgl");
133  BlackListGPUFeatures(blacklisted_features);
134  content::RunAllBlockingPoolTasksUntilIdle();
135
136  std::vector<std::string> expected_errors;
137  expected_errors.push_back(l10n_util::GetStringUTF8(
138      IDS_EXTENSION_WEBGL_NOT_SUPPORTED));
139
140  checker_.Check(extension, base::Bind(
141      &RequirementsCheckerBrowserTest::ValidateRequirementErrors,
142      base::Unretained(this), expected_errors));
143  content::RunAllBlockingPoolTasksUntilIdle();
144}
145
146IN_PROC_BROWSER_TEST_F(RequirementsCheckerBrowserTest, Check3DExtension) {
147  scoped_refptr<const Extension> extension(
148      LoadExtensionFromDirName("require_3d"));
149  ASSERT_TRUE(extension.get());
150
151  std::vector<std::string> expected_errors;
152
153  if (!content::GpuDataManager::GetInstance()->GpuAccessAllowed(NULL)) {
154    expected_errors.push_back(l10n_util::GetStringUTF8(
155        IDS_EXTENSION_WEBGL_NOT_SUPPORTED));
156  }
157
158  checker_.Check(extension, base::Bind(
159      &RequirementsCheckerBrowserTest::ValidateRequirementErrors,
160      base::Unretained(this), expected_errors));
161  content::RunAllBlockingPoolTasksUntilIdle();
162}
163
164}  // namespace extensions
165