Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(72)

Side by Side Diff: chrome/browser/chromeos/policy/signin_profile_apps_policy_browsertest.cc

Issue 2865063003: Add an end-to-end test for sign-in profile apps installation (Closed)
Patch Set: Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <string>
6
7 #include "base/bind.h"
5 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/files/file_path.h"
10 #include "base/location.h"
11 #include "base/logging.h"
6 #include "base/macros.h" 12 #include "base/macros.h"
13 #include "base/strings/string_util.h"
7 #include "chrome/browser/browser_process.h" 14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
16 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
17 #include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
8 #include "chrome/browser/chromeos/profiles/profile_helper.h" 18 #include "chrome/browser/chromeos/profiles/profile_helper.h"
19 #include "chrome/browser/extensions/crx_installer.h"
9 #include "chrome/browser/extensions/extension_service.h" 20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/net/url_request_mock_util.h"
10 #include "chrome/browser/profiles/profile_manager.h" 22 #include "chrome/browser/profiles/profile_manager.h"
11 #include "chrome/common/chrome_switches.h" 23 #include "chrome/common/chrome_switches.h"
12 #include "chrome/test/base/in_process_browser_test.h" 24 #include "chrome/test/base/in_process_browser_test.h"
25 #include "chromeos/chromeos_switches.h"
26 #include "chromeos/dbus/fake_session_manager_client.h"
27 #include "components/version_info/channel.h"
28 #include "components/version_info/version_info.h"
29 #include "content/public/browser/browser_thread.h"
30 #include "content/public/browser/notification_source.h"
13 #include "content/public/test/browser_test.h" 31 #include "content/public/test/browser_test.h"
32 #include "content/public/test/test_utils.h"
33 #include "extensions/browser/extension_registry.h"
14 #include "extensions/browser/extension_system.h" 34 #include "extensions/browser/extension_system.h"
35 #include "extensions/browser/notification_types.h"
36 #include "extensions/browser/test_extension_registry_observer.h"
37 #include "extensions/common/extension.h"
38 #include "extensions/common/extension_set.h"
39 #include "extensions/common/features/feature_channel.h"
40 #include "net/test/url_request/url_request_mock_http_job.h"
15 #include "testing/gtest/include/gtest/gtest.h" 41 #include "testing/gtest/include/gtest/gtest.h"
42 #include "url/gurl.h"
16 43
17 namespace policy { 44 namespace policy {
18 45
19 namespace { 46 namespace {
20 47
48 // Parameters for the several extensions and apps that are used by the tests in
49 // this file (note that the paths are given relative to the src/chrome/test/data
50 // directory):
51 // * The test app which is whitelisted for running in the sign-in profile:
52 const char kTestAppId[] = "bjaiihebfngildkcjkjckolinodhliff";
53 const char kTestAppUpdateManifestPath[] =
54 "extensions/signin_screen_test_app/update_manifest.xml";
55 // * A trivial test app which is NOT whitelisted for running in the sign-in
56 // profile:
57 const char kTrivialAppId[] = "mockapnacjbcdncmpkjngjalkhphojek";
58 const char kTrivialAppUpdateManifestPath[] =
59 "extensions/trivial_platform_app/update_manifest.xml";
60 // * A trivial test extension (note that extensions cannot be whitelisted for
61 // running in the sign-in profile):
62 const char kTrivialExtensionId[] = "mockepjebcnmhmhcahfddgfcdgkdifnc";
63 const char kTrivialExtensionUpdateManifestPath[] =
64 "extensions/trivial_extension/update_manifest.xml";
65
66 // Observer that allows waiting for an installation failure of a specific
67 // extension.
68 // TODO(emaxx): Extract this into a more generic helper class for using in other
69 // tests.
70 class ExtensionInstallErrorObserver final {
achuithb 2017/05/08 23:49:45 I haven't seen any other examples of final, but I
emaxx 2017/05/09 15:03:35 Yes, the wording is that it's actually "recommende
71 public:
72 ExtensionInstallErrorObserver(const Profile* profile,
73 const std::string& extension_id)
74 : profile_(profile),
75 extension_id_(extension_id),
76 notification_observer_(
77 extensions::NOTIFICATION_EXTENSION_INSTALL_ERROR,
78 base::Bind(&ExtensionInstallErrorObserver::IsNotificationRelevant,
79 base::Unretained(this))) {}
achuithb 2017/05/08 23:49:45 I assume this use of 'this' in the initializer is
emaxx 2017/05/09 15:03:35 Yes, AFAIU it's equivalent to use of "this" in the
80
81 void Wait() { notification_observer_.Wait(); }
82
83 private:
84 bool IsNotificationRelevant(
achuithb 2017/05/08 23:49:45 add comment?
emaxx 2017/05/09 15:03:35 Done.
85 const content::NotificationSource& source,
86 const content::NotificationDetails& details) const {
87 extensions::CrxInstaller* const crx_installer =
88 content::Source<extensions::CrxInstaller>(source).ptr();
89 return crx_installer->profile() == profile_ &&
90 crx_installer->extension()->id() == extension_id_;
91 }
92
93 const Profile* const profile_;
94 const std::string extension_id_;
95 content::WindowedNotificationObserver notification_observer_;
96
97 DISALLOW_COPY_AND_ASSIGN(ExtensionInstallErrorObserver);
98 };
99
100 // Observer that allows waiting until the background page of the specified
101 // extension loads.
102 // TODO(emaxx): Extract this into a more generic helper class for using in other
103 // tests.
104 class ExtensionBackgroundPageReadyObserver final {
105 public:
106 explicit ExtensionBackgroundPageReadyObserver(const std::string& extension_id)
107 : extension_id_(extension_id),
108 notification_observer_(
109 extensions::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY,
110 base::Bind(
111 &ExtensionBackgroundPageReadyObserver::IsNotificationRelevant,
112 base::Unretained(this))) {}
113
114 void Wait() { notification_observer_.Wait(); }
115
116 private:
117 bool IsNotificationRelevant(
118 const content::NotificationSource& source,
119 const content::NotificationDetails& details) const {
120 return content::Source<const extensions::Extension>(source)->id() ==
121 extension_id_;
122 }
123
124 const std::string extension_id_;
125 content::WindowedNotificationObserver notification_observer_;
126
127 DISALLOW_COPY_AND_ASSIGN(ExtensionBackgroundPageReadyObserver);
128 };
129
130 // Returns the initial profile, which is the original profile of the sign-in
131 // profile. The apps specified in the policy will be installed into the initial
132 // profile, and then become available in both.
133 Profile* GetProfile() {
134 // Intentionally not using the |chromeos::ProfileHelper::GetSigninProfile|
135 // method here, as it performs the lazy construction of the profile, while for
136 // the test purposes it's better to assert that it has been created before.
137 Profile* const profile =
138 g_browser_process->profile_manager()->GetProfileByPath(
139 chromeos::ProfileHelper::GetSigninProfileDir());
140 DCHECK(profile);
141 return profile;
142 }
143
21 // Tests for the sign-in profile apps being enabled via the command line flag. 144 // Tests for the sign-in profile apps being enabled via the command line flag.
22 // TODO(emaxx): Remove this smoke test once it's investigated whether just 145 // TODO(emaxx): Remove this smoke test once it's investigated whether just
23 // specifying this command line flag leads to tests being timed out. 146 // specifying this command line flag leads to tests being timed out.
24 class SigninProfileAppsEnabledViaCommandLineTest : public InProcessBrowserTest { 147 class SigninProfileAppsEnabledViaCommandLineTest : public InProcessBrowserTest {
25 protected: 148 protected:
26 SigninProfileAppsEnabledViaCommandLineTest() {} 149 SigninProfileAppsEnabledViaCommandLineTest() {}
27 150
28 void SetUpCommandLine(base::CommandLine* command_line) override { 151 void SetUpCommandLine(base::CommandLine* command_line) override {
29 InProcessBrowserTest::SetUpCommandLine(command_line); 152 InProcessBrowserTest::SetUpCommandLine(command_line);
30 command_line->AppendSwitch(switches::kEnableLoginScreenApps); 153 command_line->AppendSwitch(switches::kEnableLoginScreenApps);
31 } 154 }
32 155
33 private: 156 private:
34 DISALLOW_COPY_AND_ASSIGN(SigninProfileAppsEnabledViaCommandLineTest); 157 DISALLOW_COPY_AND_ASSIGN(SigninProfileAppsEnabledViaCommandLineTest);
35 }; 158 };
36 159
37 } // namespace 160 } // namespace
38 161
39 IN_PROC_BROWSER_TEST_F(SigninProfileAppsEnabledViaCommandLineTest, 162 IN_PROC_BROWSER_TEST_F(SigninProfileAppsEnabledViaCommandLineTest,
40 NoExtensions) { 163 NoExtensions) {
41 Profile* const initial_profile = 164 EXPECT_TRUE(extensions::ExtensionSystem::Get(GetProfile())
42 g_browser_process->profile_manager()->GetProfileByPath(
43 chromeos::ProfileHelper::GetSigninProfileDir());
44 ASSERT_TRUE(initial_profile);
45 EXPECT_TRUE(extensions::ExtensionSystem::Get(initial_profile)
46 ->extension_service() 165 ->extension_service()
47 ->extensions_enabled()); 166 ->extensions_enabled());
48 } 167 }
49 168
169 namespace {
170
171 // Base class for testing sign-in profile apps that are installed via the device
172 // policy.
173 class SigninProfileAppsPolicyTestBase : public DevicePolicyCrosBrowserTest {
174 protected:
175 explicit SigninProfileAppsPolicyTestBase(version_info::Channel channel)
176 : channel_(channel), scoped_current_channel_(channel) {}
177
178 void SetUpCommandLine(base::CommandLine* command_line) override {
179 DevicePolicyCrosBrowserTest::SetUpCommandLine(command_line);
180 command_line->AppendSwitch(chromeos::switches::kLoginManager);
181 command_line->AppendSwitch(chromeos::switches::kForceLoginManagerInTests);
182 command_line->AppendSwitch(switches::kEnableLoginScreenApps);
183 }
184
185 void SetUpInProcessBrowserTestFixture() override {
186 DevicePolicyCrosBrowserTest::SetUpInProcessBrowserTestFixture();
187 InstallOwnerKey();
188 MarkAsEnterpriseOwned();
189 }
190
191 void SetUpOnMainThread() override {
192 EnableUrlRequestMocks();
193 DevicePolicyCrosBrowserTest::SetUpOnMainThread();
194 }
195
196 void AddExtensionForForceInstallation(
197 const std::string& extension_id,
198 const base::FilePath& update_manifest_relative_path) {
199 const GURL update_manifest_url = net::URLRequestMockHTTPJob::GetMockUrl(
200 update_manifest_relative_path.MaybeAsASCII());
201 const std::string policy_item_value = base::ReplaceStringPlaceholders(
202 "$1;$2", {extension_id, update_manifest_url.spec()}, nullptr);
203 device_policy()
204 ->payload()
205 .mutable_device_login_screen_app_install_list()
206 ->add_device_login_screen_app_install_list(policy_item_value);
207 RefreshDevicePolicy();
208 }
209
210 const version_info::Channel channel_;
211
212 private:
213 // Enables URL request mocks for making the test data files (extensions'
214 // update manifests and packages) available under corresponding URLs.
215 static void EnableUrlRequestMocks() {
216 content::BrowserThread::PostTask(
217 content::BrowserThread::IO, FROM_HERE,
218 base::BindOnce(&chrome_browser_net::SetUrlRequestMocksEnabled, true));
219 }
220
221 const extensions::ScopedCurrentChannel scoped_current_channel_;
222
223 DISALLOW_COPY_AND_ASSIGN(SigninProfileAppsPolicyTestBase);
224 };
225
226 // Class for testing sign-in profile apps under different browser channels.
227 class SigninProfileAppsPolicyPerChannelTest
228 : public SigninProfileAppsPolicyTestBase,
229 public testing::WithParamInterface<version_info::Channel> {
230 protected:
231 SigninProfileAppsPolicyPerChannelTest()
232 : SigninProfileAppsPolicyTestBase(GetParam()) {}
233
234 private:
235 DISALLOW_COPY_AND_ASSIGN(SigninProfileAppsPolicyPerChannelTest);
236 };
237
238 } // namespace
239
240 // Tests that a whitelisted app gets installed on any browser channel.
241 IN_PROC_BROWSER_TEST_P(SigninProfileAppsPolicyPerChannelTest,
242 WhitelistedAppInstallation) {
243 extensions::TestExtensionRegistryObserver registry_observer(
244 extensions::ExtensionRegistry::Get(GetProfile()), kTestAppId);
245
246 AddExtensionForForceInstallation(kTestAppId,
247 base::FilePath(kTestAppUpdateManifestPath));
248
249 registry_observer.WaitForExtensionLoaded();
250 EXPECT_TRUE(extensions::ExtensionRegistry::Get(GetProfile())
251 ->enabled_extensions()
252 .Contains(kTestAppId));
253 }
254
255 // Tests that a non-whitelisted app is installed only when on Dev, Canary or
256 // "unknown" (trunk) channels, but not on Beta or Stable channels.
257 IN_PROC_BROWSER_TEST_P(SigninProfileAppsPolicyPerChannelTest,
258 NotWhitelistedAppInstallation) {
259 extensions::TestExtensionRegistryObserver registry_observer(
260 extensions::ExtensionRegistry::Get(GetProfile()), kTrivialAppId);
261 ExtensionInstallErrorObserver install_error_observer(GetProfile(),
262 kTrivialAppId);
263
264 AddExtensionForForceInstallation(
265 kTrivialAppId, base::FilePath(kTrivialAppUpdateManifestPath));
266
267 switch (channel_) {
268 case version_info::Channel::UNKNOWN:
269 case version_info::Channel::CANARY:
270 case version_info::Channel::DEV:
271 registry_observer.WaitForExtensionLoaded();
272 EXPECT_TRUE(extensions::ExtensionRegistry::Get(GetProfile())
273 ->enabled_extensions()
274 .Contains(kTrivialAppId));
275 break;
276 case version_info::Channel::BETA:
277 case version_info::Channel::STABLE:
278 install_error_observer.Wait();
279 EXPECT_FALSE(extensions::ExtensionRegistry::Get(GetProfile())
280 ->GetInstalledExtension(kTrivialAppId));
281 break;
282 }
achuithb 2017/05/08 23:49:45 Should we add an assert for default?
emaxx 2017/05/09 15:03:35 Ack. Note that in the current version, the compile
283 }
284
285 // Tests that an extension is forbidden from installation regardless of the
286 // browser channel.
287 IN_PROC_BROWSER_TEST_P(SigninProfileAppsPolicyPerChannelTest,
288 ExtensionInstallation) {
289 ExtensionInstallErrorObserver install_error_observer(GetProfile(),
290 kTrivialExtensionId);
291
292 AddExtensionForForceInstallation(
293 kTrivialExtensionId, base::FilePath(kTrivialExtensionUpdateManifestPath));
294
295 install_error_observer.Wait();
296 EXPECT_FALSE(extensions::ExtensionRegistry::Get(GetProfile())
297 ->GetInstalledExtension(kTrivialExtensionId));
298 }
299
300 INSTANTIATE_TEST_CASE_P(,
301 SigninProfileAppsPolicyPerChannelTest,
302 testing::Values(version_info::Channel::UNKNOWN,
303 version_info::Channel::CANARY,
304 version_info::Channel::DEV,
305 version_info::Channel::BETA,
306 version_info::Channel::STABLE));
307
308 namespace {
309
310 // Class for testing sign-in profile apps under the "unknown" browser channel,
311 // which allows to bypass the troublesome whitelist checks.
312 class SigninProfileAppsPolicyTest : public SigninProfileAppsPolicyTestBase {
313 protected:
314 SigninProfileAppsPolicyTest()
315 : SigninProfileAppsPolicyTestBase(version_info::Channel::UNKNOWN) {}
316
317 private:
318 DISALLOW_COPY_AND_ASSIGN(SigninProfileAppsPolicyTest);
319 };
320
321 } // namespace
322
323 // Tests that a background page is created for the installed sign-in profile
324 // app.
325 IN_PROC_BROWSER_TEST_F(SigninProfileAppsPolicyTest, BackgroundPage) {
326 ExtensionBackgroundPageReadyObserver page_observer(kTrivialAppId);
327 AddExtensionForForceInstallation(
328 kTrivialAppId, base::FilePath(kTrivialAppUpdateManifestPath));
329 page_observer.Wait();
330 }
331
332 // Tests installation of multiple sign-in profile apps.
333 IN_PROC_BROWSER_TEST_F(SigninProfileAppsPolicyTest, MultipleApps) {
334 extensions::TestExtensionRegistryObserver registry_observer1(
335 extensions::ExtensionRegistry::Get(GetProfile()), kTestAppId);
336 extensions::TestExtensionRegistryObserver registry_observer2(
337 extensions::ExtensionRegistry::Get(GetProfile()), kTrivialAppId);
338
339 AddExtensionForForceInstallation(kTestAppId,
340 base::FilePath(kTestAppUpdateManifestPath));
341 AddExtensionForForceInstallation(
342 kTrivialAppId, base::FilePath(kTrivialAppUpdateManifestPath));
343
344 registry_observer1.WaitForExtensionLoaded();
345 registry_observer2.WaitForExtensionLoaded();
346 }
347
50 } // namespace policy 348 } // namespace policy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698