1 // Copyright 2014 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/supervised_user/supervised_user_service.h"
6 
7 #include <stddef.h>
8 
9 #include <memory>
10 #include <utility>
11 
12 #include "base/bind.h"
13 #include "base/macros.h"
14 #include "base/memory/ptr_util.h"
15 #include "base/path_service.h"
16 #include "base/run_loop.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/test/scoped_feature_list.h"
19 #include "base/threading/thread_task_runner_handle.h"
20 #include "base/values.h"
21 #include "build/build_config.h"
22 #include "chrome/browser/chrome_notification_types.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
25 #include "chrome/browser/supervised_user/permission_request_creator.h"
26 #include "chrome/browser/supervised_user/supervised_user_allowlist_service.h"
27 #include "chrome/browser/supervised_user/supervised_user_features.h"
28 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
29 #include "chrome/common/chrome_paths.h"
30 #include "chrome/common/pref_names.h"
31 #include "chrome/test/base/testing_profile.h"
32 #include "components/prefs/pref_service.h"
33 #include "components/prefs/scoped_user_pref_update.h"
34 #include "components/version_info/version_info.h"
35 #include "content/public/test/browser_task_environment.h"
36 #include "content/public/test/test_utils.h"
37 #include "extensions/buildflags/buildflags.h"
38 #include "testing/gtest/include/gtest/gtest.h"
39 
40 #if BUILDFLAG(ENABLE_EXTENSIONS)
41 #include "chrome/browser/extensions/extension_service.h"
42 #include "chrome/browser/extensions/extension_service_test_base.h"
43 #include "chrome/browser/extensions/extension_util.h"
44 #include "chrome/browser/extensions/unpacked_installer.h"
45 #include "extensions/common/extension.h"
46 #include "extensions/common/extension_builder.h"
47 #include "extensions/common/features/feature_channel.h"
48 #include "extensions/common/manifest_constants.h"
49 
50 using extensions::Extension;
51 #endif
52 
53 using content::MessageLoopRunner;
54 
55 namespace {
56 
57 // Base class for helper objects that wait for certain events to happen.
58 // This class will ensure that calls to QuitRunLoop() (triggered by a subclass)
59 // are balanced with Wait() calls.
60 class AsyncTestHelper {
61  public:
Wait()62   void Wait() {
63     run_loop_->Run();
64     Reset();
65   }
66 
67  protected:
AsyncTestHelper()68   AsyncTestHelper() {
69     // |quit_called_| will be initialized in Reset().
70     Reset();
71   }
72 
~AsyncTestHelper()73   ~AsyncTestHelper() {
74     EXPECT_FALSE(quit_called_);
75   }
76 
QuitRunLoop()77   void QuitRunLoop() {
78     // QuitRunLoop() can not be called more than once between calls to Wait().
79     ASSERT_FALSE(quit_called_);
80     quit_called_ = true;
81     run_loop_->Quit();
82   }
83 
84  private:
Reset()85   void Reset() {
86     quit_called_ = false;
87     run_loop_.reset(new base::RunLoop);
88   }
89 
90   std::unique_ptr<base::RunLoop> run_loop_;
91   bool quit_called_;
92 
93   DISALLOW_COPY_AND_ASSIGN(AsyncTestHelper);
94 };
95 
96 class SupervisedUserURLFilterObserver
97     : public AsyncTestHelper,
98       public SupervisedUserURLFilter::Observer {
99  public:
SupervisedUserURLFilterObserver()100   SupervisedUserURLFilterObserver() : scoped_observer_(this) {}
~SupervisedUserURLFilterObserver()101   ~SupervisedUserURLFilterObserver() {}
102 
Init(SupervisedUserURLFilter * url_filter)103   void Init(SupervisedUserURLFilter* url_filter) {
104     scoped_observer_.Add(url_filter);
105   }
106 
107   // SupervisedUserURLFilter::Observer
OnSiteListUpdated()108   void OnSiteListUpdated() override {
109     QuitRunLoop();
110   }
111 
112  private:
113   ScopedObserver<SupervisedUserURLFilter, SupervisedUserURLFilter::Observer>
114       scoped_observer_;
115 
116   DISALLOW_COPY_AND_ASSIGN(SupervisedUserURLFilterObserver);
117 };
118 
119 class SiteListObserver : public AsyncTestHelper {
120  public:
SiteListObserver()121   SiteListObserver() {}
~SiteListObserver()122   ~SiteListObserver() {}
123 
Init(SupervisedUserAllowlistService * service)124   void Init(SupervisedUserAllowlistService* service) {
125     service->AddSiteListsChangedCallback(base::Bind(
126         &SiteListObserver::OnSiteListsChanged, base::Unretained(this)));
127 
128     // The initial call to AddSiteListsChangedCallback will call
129     // OnSiteListsChanged(), so we balance it out by calling Wait().
130     Wait();
131   }
132 
site_lists()133   const std::vector<scoped_refptr<SupervisedUserSiteList>>& site_lists() {
134     return site_lists_;
135   }
136 
137  private:
OnSiteListsChanged(const std::vector<scoped_refptr<SupervisedUserSiteList>> & site_lists)138   void OnSiteListsChanged(
139       const std::vector<scoped_refptr<SupervisedUserSiteList>>& site_lists) {
140     site_lists_ = site_lists;
141 
142     QuitRunLoop();
143   }
144 
145   std::vector<scoped_refptr<SupervisedUserSiteList>> site_lists_;
146 
147   DISALLOW_COPY_AND_ASSIGN(SiteListObserver);
148 };
149 
150 class AsyncResultHolder {
151  public:
AsyncResultHolder()152   AsyncResultHolder() : result_(false) {}
~AsyncResultHolder()153   ~AsyncResultHolder() {}
154 
SetResult(bool result)155   void SetResult(bool result) {
156     result_ = result;
157     run_loop_.Quit();
158   }
159 
GetResult()160   bool GetResult() {
161     run_loop_.Run();
162     return result_;
163   }
164 
165  private:
166   base::RunLoop run_loop_;
167   bool result_;
168 
169   DISALLOW_COPY_AND_ASSIGN(AsyncResultHolder);
170 };
171 
172 class SupervisedUserServiceTest : public ::testing::Test {
173  public:
SupervisedUserServiceTest()174   SupervisedUserServiceTest() {}
175 
SetUp()176   void SetUp() override {
177     profile_ = IdentityTestEnvironmentProfileAdaptor::
178         CreateProfileForIdentityTestEnvironment({});
179     identity_test_environment_adaptor_ =
180         std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile_.get());
181     supervised_user_service_ =
182         SupervisedUserServiceFactory::GetForProfile(profile_.get());
183   }
184 
TearDown()185   void TearDown() override {
186     identity_test_environment_adaptor_.reset();
187     profile_.reset();
188   }
189 
~SupervisedUserServiceTest()190   ~SupervisedUserServiceTest() override {}
191 
192  protected:
AddURLAccessRequest(const GURL & url,AsyncResultHolder * result_holder)193   void AddURLAccessRequest(const GURL& url, AsyncResultHolder* result_holder) {
194     supervised_user_service_->AddURLAccessRequest(
195         url, base::BindOnce(&AsyncResultHolder::SetResult,
196                             base::Unretained(result_holder)));
197   }
198 
199   std::unique_ptr<IdentityTestEnvironmentProfileAdaptor>
200       identity_test_environment_adaptor_;
201   content::BrowserTaskEnvironment task_environment_;
202   std::unique_ptr<TestingProfile> profile_;
203   SupervisedUserService* supervised_user_service_;
204 };
205 
206 }  // namespace
207 
208 namespace {
209 
210 class MockPermissionRequestCreator : public PermissionRequestCreator {
211  public:
MockPermissionRequestCreator()212   MockPermissionRequestCreator() : enabled_(false) {}
~MockPermissionRequestCreator()213   ~MockPermissionRequestCreator() override {}
214 
set_enabled(bool enabled)215   void set_enabled(bool enabled) {
216     enabled_ = enabled;
217   }
218 
requested_urls() const219   const std::vector<GURL>& requested_urls() const {
220     return requested_urls_;
221   }
222 
AnswerRequest(size_t index,bool result)223   void AnswerRequest(size_t index, bool result) {
224     ASSERT_LT(index, requested_urls_.size());
225     std::move(callbacks_[index]).Run(result);
226     callbacks_.erase(callbacks_.begin() + index);
227     requested_urls_.erase(requested_urls_.begin() + index);
228   }
229 
230  private:
231   // PermissionRequestCreator:
IsEnabled() const232   bool IsEnabled() const override { return enabled_; }
233 
CreateURLAccessRequest(const GURL & url_requested,SuccessCallback callback)234   void CreateURLAccessRequest(const GURL& url_requested,
235                               SuccessCallback callback) override {
236     ASSERT_TRUE(enabled_);
237     requested_urls_.push_back(url_requested);
238     callbacks_.push_back(std::move(callback));
239   }
240 
241   bool enabled_;
242   std::vector<GURL> requested_urls_;
243   std::vector<SuccessCallback> callbacks_;
244 
245   DISALLOW_COPY_AND_ASSIGN(MockPermissionRequestCreator);
246 };
247 
248 }  // namespace
249 
TEST_F(SupervisedUserServiceTest,CreatePermissionRequest)250 TEST_F(SupervisedUserServiceTest, CreatePermissionRequest) {
251   GURL url("http://www.example.com");
252 
253   // Without any permission request creators, it should be disabled, and any
254   // AddURLAccessRequest() calls should fail.
255   EXPECT_FALSE(supervised_user_service_->AccessRequestsEnabled());
256   {
257     AsyncResultHolder result_holder;
258     AddURLAccessRequest(url, &result_holder);
259     EXPECT_FALSE(result_holder.GetResult());
260   }
261 
262   // Add a disabled permission request creator. This should not change anything.
263   MockPermissionRequestCreator* creator = new MockPermissionRequestCreator;
264   supervised_user_service_->AddPermissionRequestCreator(
265       base::WrapUnique(creator));
266 
267   EXPECT_FALSE(supervised_user_service_->AccessRequestsEnabled());
268   {
269     AsyncResultHolder result_holder;
270     AddURLAccessRequest(url, &result_holder);
271     EXPECT_FALSE(result_holder.GetResult());
272   }
273 
274   // Enable the permission request creator. This should enable permission
275   // requests and queue them up.
276   creator->set_enabled(true);
277   EXPECT_TRUE(supervised_user_service_->AccessRequestsEnabled());
278   {
279     AsyncResultHolder result_holder;
280     AddURLAccessRequest(url, &result_holder);
281     ASSERT_EQ(1u, creator->requested_urls().size());
282     EXPECT_EQ(url.spec(), creator->requested_urls()[0].spec());
283 
284     creator->AnswerRequest(0, true);
285     EXPECT_TRUE(result_holder.GetResult());
286   }
287 
288   {
289     AsyncResultHolder result_holder;
290     AddURLAccessRequest(url, &result_holder);
291     ASSERT_EQ(1u, creator->requested_urls().size());
292     EXPECT_EQ(url.spec(), creator->requested_urls()[0].spec());
293 
294     creator->AnswerRequest(0, false);
295     EXPECT_FALSE(result_holder.GetResult());
296   }
297 
298   // Add a second permission request creator.
299   MockPermissionRequestCreator* creator_2 = new MockPermissionRequestCreator;
300   creator_2->set_enabled(true);
301   supervised_user_service_->AddPermissionRequestCreator(
302       base::WrapUnique(creator_2));
303 
304   {
305     AsyncResultHolder result_holder;
306     AddURLAccessRequest(url, &result_holder);
307     ASSERT_EQ(1u, creator->requested_urls().size());
308     EXPECT_EQ(url.spec(), creator->requested_urls()[0].spec());
309 
310     // Make the first creator succeed. This should make the whole thing succeed.
311     creator->AnswerRequest(0, true);
312     EXPECT_TRUE(result_holder.GetResult());
313   }
314 
315   {
316     AsyncResultHolder result_holder;
317     AddURLAccessRequest(url, &result_holder);
318     ASSERT_EQ(1u, creator->requested_urls().size());
319     EXPECT_EQ(url.spec(), creator->requested_urls()[0].spec());
320 
321     // Make the first creator fail. This should fall back to the second one.
322     creator->AnswerRequest(0, false);
323     ASSERT_EQ(1u, creator_2->requested_urls().size());
324     EXPECT_EQ(url.spec(), creator_2->requested_urls()[0].spec());
325 
326     // Make the second creator succeed, which will make the whole thing succeed.
327     creator_2->AnswerRequest(0, true);
328     EXPECT_TRUE(result_holder.GetResult());
329   }
330 }
331 
332 #if BUILDFLAG(ENABLE_EXTENSIONS)
333 class SupervisedUserServiceExtensionTestBase
334     : public extensions::ExtensionServiceTestBase {
335  public:
SupervisedUserServiceExtensionTestBase(bool is_supervised)336   explicit SupervisedUserServiceExtensionTestBase(bool is_supervised)
337       : is_supervised_(is_supervised),
338         channel_(version_info::Channel::DEV) {}
~SupervisedUserServiceExtensionTestBase()339   ~SupervisedUserServiceExtensionTestBase() override {}
340 
SetUp()341   void SetUp() override {
342     ExtensionServiceTestBase::SetUp();
343     ExtensionServiceTestBase::ExtensionServiceInitParams params =
344         CreateDefaultInitParams();
345     params.profile_is_supervised = is_supervised_;
346     InitializeExtensionService(params);
347     // Flush the message loop, to ensure that credentials have been loaded in
348     // Identity Manager.
349     base::RunLoop().RunUntilIdle();
350 
351     SupervisedUserService* service =
352         SupervisedUserServiceFactory::GetForProfile(profile_.get());
353     service->Init();
354     site_list_observer_.Init(service->GetAllowlistService());
355 
356     SupervisedUserURLFilter* url_filter = service->GetURLFilter();
357     url_filter->SetBlockingTaskRunnerForTesting(
358         base::ThreadTaskRunnerHandle::Get());
359     url_filter_observer_.Init(url_filter);
360 
361     // Wait for the initial update to finish.
362     url_filter_observer_.Wait();
363   }
364 
TearDown()365   void TearDown() override {
366     // Flush the message loop, to ensure all posted tasks run.
367     base::RunLoop().RunUntilIdle();
368   }
369 
370  protected:
MakeThemeExtension()371   scoped_refptr<const extensions::Extension> MakeThemeExtension() {
372     std::unique_ptr<base::DictionaryValue> source(new base::DictionaryValue());
373     source->SetString(extensions::manifest_keys::kName, "Theme");
374     source->Set(extensions::manifest_keys::kTheme,
375                 std::make_unique<base::DictionaryValue>());
376     source->SetString(extensions::manifest_keys::kVersion, "1.0");
377     extensions::ExtensionBuilder builder;
378     scoped_refptr<const extensions::Extension> extension =
379         builder.SetManifest(std::move(source)).Build();
380     return extension;
381   }
382 
MakeExtension()383   scoped_refptr<const extensions::Extension> MakeExtension() {
384     scoped_refptr<const extensions::Extension> extension =
385         extensions::ExtensionBuilder("Extension").Build();
386     return extension;
387   }
388 
InitSupervisedUserInitiatedExtensionInstallFeature(bool enabled)389   void InitSupervisedUserInitiatedExtensionInstallFeature(bool enabled) {
390     if (enabled) {
391       scoped_feature_list_.InitAndEnableFeature(
392           supervised_users::kSupervisedUserInitiatedExtensionInstall);
393     }
394   }
395 
396   bool is_supervised_;
397   extensions::ScopedCurrentChannel channel_;
398   SiteListObserver site_list_observer_;
399   SupervisedUserURLFilterObserver url_filter_observer_;
400   base::test::ScopedFeatureList scoped_feature_list_;
401 };
402 
403 class SupervisedUserServiceExtensionTestUnsupervised
404     : public SupervisedUserServiceExtensionTestBase {
405  public:
SupervisedUserServiceExtensionTestUnsupervised()406   SupervisedUserServiceExtensionTestUnsupervised()
407       : SupervisedUserServiceExtensionTestBase(false) {}
408 };
409 
410 class SupervisedUserServiceExtensionTest
411     : public SupervisedUserServiceExtensionTestBase {
412  public:
SupervisedUserServiceExtensionTest()413   SupervisedUserServiceExtensionTest()
414       : SupervisedUserServiceExtensionTestBase(true) {}
415 };
416 
TEST_F(SupervisedUserServiceExtensionTest,ExtensionManagementPolicyProviderWithoutSUInitiatedInstalls)417 TEST_F(SupervisedUserServiceExtensionTest,
418        ExtensionManagementPolicyProviderWithoutSUInitiatedInstalls) {
419   InitSupervisedUserInitiatedExtensionInstallFeature(true);
420 
421   SupervisedUserService* supervised_user_service =
422       SupervisedUserServiceFactory::GetForProfile(profile_.get());
423   supervised_user_service
424       ->SetSupervisedUserExtensionsMayRequestPermissionsPrefForTesting(false);
425   EXPECT_FALSE(supervised_user_service
426                    ->GetSupervisedUserExtensionsMayRequestPermissionsPref());
427   EXPECT_TRUE(profile_->IsSupervised());
428 
429   // Check that a supervised user can install and uninstall a theme even if
430   // they are not allowed to install extensions.
431   {
432     scoped_refptr<const extensions::Extension> theme = MakeThemeExtension();
433 
434     base::string16 error_1;
435     EXPECT_TRUE(supervised_user_service->UserMayLoad(theme.get(), &error_1));
436     EXPECT_TRUE(error_1.empty());
437 
438     base::string16 error_2;
439     EXPECT_FALSE(
440         supervised_user_service->MustRemainInstalled(theme.get(), &error_2));
441     EXPECT_TRUE(error_2.empty());
442   }
443 
444   // Now check a different kind of extension; the supervised user should not be
445   // able to load it. It should also not need to remain installed.
446   {
447     scoped_refptr<const extensions::Extension> extension = MakeExtension();
448 
449     base::string16 error_1;
450     EXPECT_FALSE(
451         supervised_user_service->UserMayLoad(extension.get(), &error_1));
452     EXPECT_FALSE(error_1.empty());
453 
454     base::string16 error_2;
455     EXPECT_FALSE(
456         supervised_user_service->UserMayInstall(extension.get(), &error_2));
457     EXPECT_FALSE(error_2.empty());
458 
459     base::string16 error_3;
460     EXPECT_FALSE(supervised_user_service->MustRemainInstalled(extension.get(),
461                                                               &error_3));
462     EXPECT_TRUE(error_3.empty());
463   }
464 
465 #if DCHECK_IS_ON()
466   EXPECT_FALSE(supervised_user_service->GetDebugPolicyProviderName().empty());
467 #endif
468 }
469 
TEST_F(SupervisedUserServiceExtensionTest,ExtensionManagementPolicyProviderWithSUInitiatedInstalls)470 TEST_F(SupervisedUserServiceExtensionTest,
471        ExtensionManagementPolicyProviderWithSUInitiatedInstalls) {
472   // Enable child users to initiate extension installs by simulating the
473   // toggling of "Permissions for sites and apps" to enabled.
474   InitSupervisedUserInitiatedExtensionInstallFeature(true);
475 
476   SupervisedUserService* supervised_user_service =
477       SupervisedUserServiceFactory::GetForProfile(profile_.get());
478   supervised_user_service
479       ->SetSupervisedUserExtensionsMayRequestPermissionsPrefForTesting(true);
480   EXPECT_TRUE(supervised_user_service
481                   ->GetSupervisedUserExtensionsMayRequestPermissionsPref());
482   EXPECT_TRUE(profile_->IsSupervised());
483 
484   // The supervised user should be able to load and uninstall the extensions
485   // they install.
486   {
487     scoped_refptr<const extensions::Extension> extension = MakeExtension();
488 
489     base::string16 error;
490     EXPECT_TRUE(supervised_user_service->UserMayLoad(extension.get(), &error));
491     EXPECT_TRUE(error.empty());
492 
493     base::string16 error_2;
494     EXPECT_FALSE(supervised_user_service->MustRemainInstalled(extension.get(),
495                                                               &error_2));
496     EXPECT_TRUE(error_2.empty());
497 
498     base::string16 error_3;
499     extensions::disable_reason::DisableReason reason =
500         extensions::disable_reason::DISABLE_NONE;
501     EXPECT_TRUE(supervised_user_service->MustRemainDisabled(extension.get(),
502                                                             &reason,
503                                                             &error_3));
504     EXPECT_EQ(extensions::disable_reason::DISABLE_CUSTODIAN_APPROVAL_REQUIRED,
505               reason);
506     EXPECT_FALSE(error_3.empty());
507 
508     base::string16 error_4;
509     EXPECT_TRUE(supervised_user_service->UserMayModifySettings(extension.get(),
510                                                                &error_4));
511     EXPECT_TRUE(error_4.empty());
512 
513     base::string16 error_5;
514     EXPECT_TRUE(
515         supervised_user_service->UserMayInstall(extension.get(), &error_5));
516     EXPECT_TRUE(error_5.empty());
517   }
518 
519 #if DCHECK_IS_ON()
520   EXPECT_FALSE(supervised_user_service->GetDebugPolicyProviderName().empty());
521 #endif
522 }
523 
TEST_F(SupervisedUserServiceExtensionTest,NoContentPacks)524 TEST_F(SupervisedUserServiceExtensionTest, NoContentPacks) {
525   InitSupervisedUserInitiatedExtensionInstallFeature(true);
526 
527   SupervisedUserService* supervised_user_service =
528       SupervisedUserServiceFactory::GetForProfile(profile_.get());
529   SupervisedUserURLFilter* url_filter = supervised_user_service->GetURLFilter();
530 
531   // ASSERT_EQ instead of ASSERT_TRUE([...].empty()) so that the error
532   // message contains the size in case of failure.
533   ASSERT_EQ(0u, site_list_observer_.site_lists().size());
534 
535   GURL url("http://youtube.com");
536   EXPECT_EQ(SupervisedUserURLFilter::ALLOW,
537             url_filter->GetFilteringBehaviorForURL(url));
538 }
539 
TEST_F(SupervisedUserServiceExtensionTest,InstallContentPacks)540 TEST_F(SupervisedUserServiceExtensionTest, InstallContentPacks) {
541   InitSupervisedUserInitiatedExtensionInstallFeature(true);
542 
543   SupervisedUserService* supervised_user_service =
544       SupervisedUserServiceFactory::GetForProfile(profile_.get());
545   SupervisedUserURLFilter* url_filter = supervised_user_service->GetURLFilter();
546 
547   const std::string id1 = "ID 1";
548   const base::string16 title1 = base::ASCIIToUTF16("Title 1");
549   const std::string id2 = "ID 2";
550   const base::string16 title2 = base::ASCIIToUTF16("Title 2");
551 
552   GURL youtube_url("http://www.youtube.com");
553   GURL moose_url("http://moose.org");
554   EXPECT_EQ(SupervisedUserURLFilter::ALLOW,
555             url_filter->GetFilteringBehaviorForURL(youtube_url));
556 
557   profile_->GetPrefs()->SetInteger(
558       prefs::kDefaultSupervisedUserFilteringBehavior,
559       SupervisedUserURLFilter::BLOCK);
560   EXPECT_EQ(SupervisedUserURLFilter::BLOCK,
561             url_filter->GetFilteringBehaviorForURL(youtube_url));
562 
563   profile_->GetPrefs()->SetInteger(
564       prefs::kDefaultSupervisedUserFilteringBehavior,
565       SupervisedUserURLFilter::WARN);
566   EXPECT_EQ(SupervisedUserURLFilter::WARN,
567             url_filter->GetFilteringBehaviorForURL(youtube_url));
568 
569   // Load a allowlist.
570   base::FilePath test_data_dir;
571   ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir));
572   SupervisedUserAllowlistService* allowlist_service =
573       supervised_user_service->GetAllowlistService();
574   base::FilePath allowlist_path =
575       test_data_dir.AppendASCII("whitelists/content_pack/site_list.json");
576   allowlist_service->LoadAllowlistForTesting(id1, title1, allowlist_path);
577   site_list_observer_.Wait();
578 
579   ASSERT_EQ(1u, site_list_observer_.site_lists().size());
580   EXPECT_EQ(id1, site_list_observer_.site_lists()[0]->id());
581   EXPECT_EQ(title1, site_list_observer_.site_lists()[0]->title());
582   EXPECT_EQ(youtube_url, site_list_observer_.site_lists()[0]->entry_point());
583 
584   url_filter_observer_.Wait();
585   EXPECT_EQ(SupervisedUserURLFilter::ALLOW,
586             url_filter->GetFilteringBehaviorForURL(youtube_url));
587   EXPECT_EQ(SupervisedUserURLFilter::WARN,
588             url_filter->GetFilteringBehaviorForURL(moose_url));
589 
590   // Load a second allowlist.
591   allowlist_path =
592       test_data_dir.AppendASCII("whitelists/content_pack_2/site_list.json");
593   allowlist_service->LoadAllowlistForTesting(id2, title2, allowlist_path);
594   site_list_observer_.Wait();
595 
596   ASSERT_EQ(2u, site_list_observer_.site_lists().size());
597   EXPECT_EQ(id1, site_list_observer_.site_lists()[0]->id());
598   EXPECT_EQ(title1, site_list_observer_.site_lists()[0]->title());
599   EXPECT_EQ(youtube_url, site_list_observer_.site_lists()[0]->entry_point());
600   EXPECT_EQ(id2, site_list_observer_.site_lists()[1]->id());
601   EXPECT_EQ(title2, site_list_observer_.site_lists()[1]->title());
602   EXPECT_TRUE(site_list_observer_.site_lists()[1]->entry_point().is_empty());
603 
604   url_filter_observer_.Wait();
605   EXPECT_EQ(SupervisedUserURLFilter::ALLOW,
606             url_filter->GetFilteringBehaviorForURL(youtube_url));
607   EXPECT_EQ(SupervisedUserURLFilter::ALLOW,
608             url_filter->GetFilteringBehaviorForURL(moose_url));
609 
610   // Unload the first allowlist.
611   allowlist_service->UnloadAllowlist(id1);
612   site_list_observer_.Wait();
613 
614   ASSERT_EQ(1u, site_list_observer_.site_lists().size());
615   EXPECT_EQ(id2, site_list_observer_.site_lists()[0]->id());
616   EXPECT_EQ(title2, site_list_observer_.site_lists()[0]->title());
617   EXPECT_TRUE(site_list_observer_.site_lists()[0]->entry_point().is_empty());
618 
619   url_filter_observer_.Wait();
620   EXPECT_EQ(SupervisedUserURLFilter::WARN,
621             url_filter->GetFilteringBehaviorForURL(youtube_url));
622   EXPECT_EQ(SupervisedUserURLFilter::ALLOW,
623             url_filter->GetFilteringBehaviorForURL(moose_url));
624 }
625 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
626