blob: ed7fb8bfa67a0f68f16a70b4c533282a77c77240 [file] [log] [blame]
// Copyright 2018 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 <set>
#include <sstream>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/callback.h"
#include "base/files/scoped_temp_dir.h"
#include "base/optional.h"
#include "base/run_loop.h"
#include "components/services/app_service/app_service_impl.h"
#include "components/services/app_service/public/cpp/app_capability_access_cache.h"
#include "components/services/app_service/public/cpp/intent_filter_util.h"
#include "components/services/app_service/public/cpp/intent_util.h"
#include "components/services/app_service/public/cpp/preferred_apps_list.h"
#include "components/services/app_service/public/cpp/publisher_base.h"
#include "components/services/app_service/public/mojom/types.mojom.h"
#include "content/public/test/browser_task_environment.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/remote_set.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace apps {
class FakePublisher : public apps::PublisherBase {
public:
FakePublisher(AppServiceImpl* impl,
apps::mojom::AppType app_type,
std::vector<std::string> initial_app_ids)
: app_type_(app_type), known_app_ids_(std::move(initial_app_ids)) {
mojo::PendingRemote<apps::mojom::Publisher> remote;
receivers_.Add(this, remote.InitWithNewPipeAndPassReceiver());
impl->RegisterPublisher(std::move(remote), app_type_);
}
void PublishMoreApps(std::vector<std::string> app_ids) {
for (auto& subscriber : subscribers_) {
CallOnApps(subscriber.get(), app_ids, /*uninstall=*/false);
}
for (const auto& app_id : app_ids) {
known_app_ids_.push_back(app_id);
}
}
void ModifyCapabilityAccess(const std::string& app_id,
base::Optional<bool> accessing_camera,
base::Optional<bool> accessing_microphone) {
if (accessing_camera.has_value()) {
if (accessing_camera.value()) {
apps_accessing_camera_.insert(app_id);
} else {
apps_accessing_camera_.erase(app_id);
}
}
if (accessing_microphone.has_value()) {
if (accessing_microphone.value()) {
apps_accessing_microphone_.insert(app_id);
} else {
apps_accessing_microphone_.erase(app_id);
}
}
PublisherBase::ModifyCapabilityAccess(
subscribers_, app_id, accessing_camera, accessing_microphone);
}
void UninstallApps(std::vector<std::string> app_ids, AppServiceImpl* impl) {
for (auto& subscriber : subscribers_) {
CallOnApps(subscriber.get(), app_ids, /*uninstall=*/true);
}
for (const auto& app_id : app_ids) {
known_app_ids_.push_back(app_id);
impl->RemovePreferredApp(app_type_, app_id);
}
}
std::string load_icon_app_id;
private:
void Connect(mojo::PendingRemote<apps::mojom::Subscriber> subscriber_remote,
apps::mojom::ConnectOptionsPtr opts) override {
mojo::Remote<apps::mojom::Subscriber> subscriber(
std::move(subscriber_remote));
CallOnApps(subscriber.get(), known_app_ids_, /*uninstall=*/false);
CallOnCapabilityAccesses(subscriber.get(), known_app_ids_);
subscribers_.Add(std::move(subscriber));
}
void LoadIcon(const std::string& app_id,
apps::mojom::IconKeyPtr icon_key,
apps::mojom::IconType icon_type,
int32_t size_hint_in_dip,
bool allow_placeholder_icon,
LoadIconCallback callback) override {
load_icon_app_id = app_id;
std::move(callback).Run(apps::mojom::IconValue::New());
}
void Launch(const std::string& app_id,
int32_t event_flags,
apps::mojom::LaunchSource launch_source,
apps::mojom::WindowInfoPtr window_info) override {}
void CallOnApps(apps::mojom::Subscriber* subscriber,
std::vector<std::string>& app_ids,
bool uninstall) {
std::vector<apps::mojom::AppPtr> apps;
for (const auto& app_id : app_ids) {
auto app = apps::mojom::App::New();
app->app_type = app_type_;
app->app_id = app_id;
if (uninstall) {
app->readiness = apps::mojom::Readiness::kUninstalledByUser;
}
apps.push_back(std::move(app));
}
subscriber->OnApps(std::move(apps), app_type_,
false /* should_notify_initialized */);
}
void CallOnCapabilityAccesses(apps::mojom::Subscriber* subscriber,
std::vector<std::string>& app_ids) {
std::vector<apps::mojom::CapabilityAccessPtr> capability_accesses;
for (const auto& app_id : app_ids) {
auto capability_access = apps::mojom::CapabilityAccess::New();
capability_access->app_id = app_id;
if (apps_accessing_camera_.find(app_id) != apps_accessing_camera_.end()) {
capability_access->camera = apps::mojom::OptionalBool::kTrue;
}
if (apps_accessing_microphone_.find(app_id) !=
apps_accessing_microphone_.end()) {
capability_access->microphone = apps::mojom::OptionalBool::kTrue;
}
capability_accesses.push_back(std::move(capability_access));
}
subscriber->OnCapabilityAccesses(std::move(capability_accesses));
}
apps::mojom::AppType app_type_;
std::vector<std::string> known_app_ids_;
std::set<std::string> apps_accessing_camera_;
std::set<std::string> apps_accessing_microphone_;
mojo::ReceiverSet<apps::mojom::Publisher> receivers_;
mojo::RemoteSet<apps::mojom::Subscriber> subscribers_;
};
class FakeSubscriber : public apps::mojom::Subscriber {
public:
explicit FakeSubscriber(AppServiceImpl* impl) {
mojo::PendingRemote<apps::mojom::Subscriber> remote;
receivers_.Add(this, remote.InitWithNewPipeAndPassReceiver());
impl->RegisterSubscriber(std::move(remote), nullptr);
}
std::string AppIdsSeen() {
std::stringstream ss;
for (const auto& app_id : app_ids_seen_) {
ss << app_id;
}
return ss.str();
}
std::string AppIdsAccessingCamera() {
std::stringstream ss;
for (const auto& app_id : cache_.GetAppsAccessingCamera()) {
ss << app_id;
}
return ss.str();
}
std::string AppIdsAccessingMicrophone() {
std::stringstream ss;
for (const auto& app_id : cache_.GetAppsAccessingMicrophone()) {
ss << app_id;
}
return ss.str();
}
PreferredAppsList& PreferredApps() { return preferred_apps_; }
private:
void OnApps(std::vector<apps::mojom::AppPtr> deltas,
apps::mojom::AppType app_type,
bool should_notify_initialized) override {
for (const auto& delta : deltas) {
app_ids_seen_.insert(delta->app_id);
if (delta->readiness == apps::mojom::Readiness::kUninstalledByUser) {
preferred_apps_.DeleteAppId(delta->app_id);
}
}
}
void OnCapabilityAccesses(
std::vector<apps::mojom::CapabilityAccessPtr> deltas) override {
cache_.OnCapabilityAccesses(std::move(deltas));
}
void Clone(mojo::PendingReceiver<apps::mojom::Subscriber> receiver) override {
receivers_.Add(this, std::move(receiver));
}
void OnPreferredAppSet(const std::string& app_id,
apps::mojom::IntentFilterPtr intent_filter) override {
preferred_apps_.AddPreferredApp(app_id, intent_filter);
}
void OnPreferredAppRemoved(
const std::string& app_id,
apps::mojom::IntentFilterPtr intent_filter) override {
preferred_apps_.DeletePreferredApp(app_id, intent_filter);
}
void InitializePreferredApps(
PreferredAppsList::PreferredApps preferred_apps) override {
preferred_apps_.Init(preferred_apps);
}
mojo::ReceiverSet<apps::mojom::Subscriber> receivers_;
std::set<std::string> app_ids_seen_;
AppCapabilityAccessCache cache_;
apps::PreferredAppsList preferred_apps_;
};
class AppServiceImplTest : public testing::Test {
protected:
// base::test::TaskEnvironment task_environment_;
content::BrowserTaskEnvironment task_environment_;
base::ScopedTempDir temp_dir_;
};
TEST_F(AppServiceImplTest, PubSub) {
const int size_hint_in_dip = 64;
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
AppServiceImpl impl(temp_dir_.GetPath(),
/*is_share_intents_supported=*/false);
// Start with one subscriber.
FakeSubscriber sub0(&impl);
impl.FlushMojoCallsForTesting();
EXPECT_EQ("", sub0.AppIdsSeen());
EXPECT_EQ("", sub0.AppIdsAccessingCamera());
EXPECT_EQ("", sub0.AppIdsAccessingMicrophone());
// Add one publisher.
FakePublisher pub0(&impl, apps::mojom::AppType::kArc,
std::vector<std::string>{"A", "B"});
impl.FlushMojoCallsForTesting();
EXPECT_EQ("AB", sub0.AppIdsSeen());
EXPECT_EQ("", sub0.AppIdsAccessingCamera());
EXPECT_EQ("", sub0.AppIdsAccessingMicrophone());
pub0.ModifyCapabilityAccess("B", base::nullopt, base::nullopt);
impl.FlushMojoCallsForTesting();
EXPECT_EQ("", sub0.AppIdsAccessingCamera());
EXPECT_EQ("", sub0.AppIdsAccessingMicrophone());
pub0.ModifyCapabilityAccess("B", true, base::nullopt);
impl.FlushMojoCallsForTesting();
EXPECT_EQ("B", sub0.AppIdsAccessingCamera());
EXPECT_EQ("", sub0.AppIdsAccessingMicrophone());
// Have that publisher publish more apps.
pub0.PublishMoreApps(std::vector<std::string>{"C", "D", "E"});
impl.FlushMojoCallsForTesting();
EXPECT_EQ("ABCDE", sub0.AppIdsSeen());
pub0.ModifyCapabilityAccess("D", true, true);
impl.FlushMojoCallsForTesting();
EXPECT_EQ("BD", sub0.AppIdsAccessingCamera());
EXPECT_EQ("D", sub0.AppIdsAccessingMicrophone());
// Add a second publisher.
FakePublisher pub1(&impl, apps::mojom::AppType::kBuiltIn,
std::vector<std::string>{"m"});
impl.FlushMojoCallsForTesting();
EXPECT_EQ("ABCDEm", sub0.AppIdsSeen());
// Have both publishers publish more apps.
pub0.PublishMoreApps(std::vector<std::string>{"F"});
pub1.PublishMoreApps(std::vector<std::string>{"n"});
pub0.ModifyCapabilityAccess("B", false, base::nullopt);
pub1.ModifyCapabilityAccess("n", base::nullopt, true);
impl.FlushMojoCallsForTesting();
EXPECT_EQ("ABCDEFmn", sub0.AppIdsSeen());
EXPECT_EQ("D", sub0.AppIdsAccessingCamera());
EXPECT_EQ("Dn", sub0.AppIdsAccessingMicrophone());
// Add a second subscriber.
FakeSubscriber sub1(&impl);
impl.FlushMojoCallsForTesting();
EXPECT_EQ("ABCDEFmn", sub0.AppIdsSeen());
EXPECT_EQ("ABCDEFmn", sub1.AppIdsSeen());
EXPECT_EQ("D", sub0.AppIdsAccessingCamera());
EXPECT_EQ("Dn", sub0.AppIdsAccessingMicrophone());
EXPECT_EQ("D", sub1.AppIdsAccessingCamera());
EXPECT_EQ("Dn", sub1.AppIdsAccessingMicrophone());
// Publish more apps.
pub0.ModifyCapabilityAccess("D", false, false);
pub1.PublishMoreApps(std::vector<std::string>{"o", "p", "q"});
pub1.ModifyCapabilityAccess("n", true, base::nullopt);
impl.FlushMojoCallsForTesting();
EXPECT_EQ("ABCDEFmnopq", sub0.AppIdsSeen());
EXPECT_EQ("ABCDEFmnopq", sub1.AppIdsSeen());
EXPECT_EQ("n", sub0.AppIdsAccessingCamera());
EXPECT_EQ("n", sub0.AppIdsAccessingMicrophone());
EXPECT_EQ("n", sub1.AppIdsAccessingCamera());
EXPECT_EQ("n", sub1.AppIdsAccessingMicrophone());
// Add a third publisher.
FakePublisher pub2(&impl, apps::mojom::AppType::kCrostini,
std::vector<std::string>{"$"});
impl.FlushMojoCallsForTesting();
EXPECT_EQ("$ABCDEFmnopq", sub0.AppIdsSeen());
EXPECT_EQ("$ABCDEFmnopq", sub1.AppIdsSeen());
// Publish more apps.
pub2.PublishMoreApps(std::vector<std::string>{"&"});
pub1.PublishMoreApps(std::vector<std::string>{"r"});
pub0.PublishMoreApps(std::vector<std::string>{"G"});
pub1.ModifyCapabilityAccess("n", false, false);
pub2.ModifyCapabilityAccess("&", true, false);
impl.FlushMojoCallsForTesting();
EXPECT_EQ("$&ABCDEFGmnopqr", sub0.AppIdsSeen());
EXPECT_EQ("$&ABCDEFGmnopqr", sub1.AppIdsSeen());
EXPECT_EQ("&", sub0.AppIdsAccessingCamera());
EXPECT_EQ("", sub0.AppIdsAccessingMicrophone());
EXPECT_EQ("&", sub1.AppIdsAccessingCamera());
EXPECT_EQ("", sub1.AppIdsAccessingMicrophone());
// Call LoadIcon on the impl twice.
//
// The first time (i == 0), it should be forwarded onto the AppType::kBuiltIn
// publisher (which is pub1) and no other publisher.
//
// The second time (i == 1), passing AppType::kUnknown, none of the
// publishers' LoadIcon's should fire, but the callback should still be run.
for (int i = 0; i < 2; i++) {
auto app_type = i == 0 ? apps::mojom::AppType::kBuiltIn
: apps::mojom::AppType::kUnknown;
bool callback_ran = false;
pub0.load_icon_app_id = "-";
pub1.load_icon_app_id = "-";
pub2.load_icon_app_id = "-";
auto icon_key = apps::mojom::IconKey::New(0, 0, 0);
constexpr bool allow_placeholder_icon = false;
impl.LoadIcon(
app_type, "o", std::move(icon_key),
apps::mojom::IconType::kUncompressed, size_hint_in_dip,
allow_placeholder_icon,
base::BindOnce(
[](bool* ran, apps::mojom::IconValuePtr iv) { *ran = true; },
&callback_ran));
impl.FlushMojoCallsForTesting();
EXPECT_TRUE(callback_ran);
EXPECT_EQ("-", pub0.load_icon_app_id);
EXPECT_EQ(i == 0 ? "o" : "-", pub1.load_icon_app_id);
EXPECT_EQ("-", pub2.load_icon_app_id);
}
}
// TODO(https://crbug.com/1074596) Test to see if the flakiness is fixed. If it
// is not fixed, please update to the same bug.
TEST_F(AppServiceImplTest, PreferredApps) {
// Test Initialize.
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
AppServiceImpl impl(temp_dir_.GetPath(),
/*is_share_intents_supported=*/false);
impl.GetPreferredAppsForTesting().Init();
const char kAppId1[] = "abcdefg";
const char kAppId2[] = "aaaaaaa";
GURL filter_url = GURL("https://www.google.com/abc");
auto intent_filter = apps_util::CreateIntentFilterForUrlScope(filter_url);
impl.GetPreferredAppsForTesting().AddPreferredApp(kAppId1, intent_filter);
// Add one subscriber.
FakeSubscriber sub0(&impl);
task_environment_.RunUntilIdle();
EXPECT_EQ(sub0.PreferredApps().GetValue(),
impl.GetPreferredAppsForTesting().GetValue());
// Add another subscriber.
FakeSubscriber sub1(&impl);
task_environment_.RunUntilIdle();
EXPECT_EQ(sub1.PreferredApps().GetValue(),
impl.GetPreferredAppsForTesting().GetValue());
FakePublisher pub0(&impl, apps::mojom::AppType::kArc,
std::vector<std::string>{kAppId1, kAppId2});
task_environment_.RunUntilIdle();
// Test sync preferred app to all subscribers.
filter_url = GURL("https://www.abc.com/");
GURL another_filter_url = GURL("https://www.test.com/");
intent_filter = apps_util::CreateIntentFilterForUrlScope(filter_url);
auto another_intent_filter =
apps_util::CreateIntentFilterForUrlScope(another_filter_url);
task_environment_.RunUntilIdle();
EXPECT_EQ(base::nullopt,
sub0.PreferredApps().FindPreferredAppForUrl(filter_url));
EXPECT_EQ(base::nullopt,
sub1.PreferredApps().FindPreferredAppForUrl(filter_url));
EXPECT_EQ(base::nullopt,
sub0.PreferredApps().FindPreferredAppForUrl(another_filter_url));
EXPECT_EQ(base::nullopt,
sub1.PreferredApps().FindPreferredAppForUrl(another_filter_url));
impl.AddPreferredApp(
apps::mojom::AppType::kUnknown, kAppId2, intent_filter->Clone(),
apps_util::CreateIntentFromUrl(filter_url), /*from_publisher=*/true);
impl.AddPreferredApp(apps::mojom::AppType::kUnknown, kAppId2,
another_intent_filter->Clone(),
apps_util::CreateIntentFromUrl(another_filter_url),
/*from_publisher=*/true);
task_environment_.RunUntilIdle();
EXPECT_EQ(kAppId2, sub0.PreferredApps().FindPreferredAppForUrl(filter_url));
EXPECT_EQ(kAppId2, sub1.PreferredApps().FindPreferredAppForUrl(filter_url));
EXPECT_EQ(kAppId2,
sub0.PreferredApps().FindPreferredAppForUrl(another_filter_url));
EXPECT_EQ(kAppId2,
sub1.PreferredApps().FindPreferredAppForUrl(another_filter_url));
// Test that uninstall removes all the settings for the app.
pub0.UninstallApps(std::vector<std::string>{kAppId2}, &impl);
task_environment_.RunUntilIdle();
EXPECT_EQ(base::nullopt,
sub0.PreferredApps().FindPreferredAppForUrl(filter_url));
EXPECT_EQ(base::nullopt,
sub1.PreferredApps().FindPreferredAppForUrl(filter_url));
EXPECT_EQ(base::nullopt,
sub0.PreferredApps().FindPreferredAppForUrl(another_filter_url));
EXPECT_EQ(base::nullopt,
sub1.PreferredApps().FindPreferredAppForUrl(another_filter_url));
impl.AddPreferredApp(
apps::mojom::AppType::kUnknown, kAppId2, intent_filter->Clone(),
apps_util::CreateIntentFromUrl(filter_url), /*from_publisher=*/true);
impl.AddPreferredApp(apps::mojom::AppType::kUnknown, kAppId2,
another_intent_filter->Clone(),
apps_util::CreateIntentFromUrl(another_filter_url),
/*from_publisher=*/true);
task_environment_.RunUntilIdle();
EXPECT_EQ(kAppId2, sub0.PreferredApps().FindPreferredAppForUrl(filter_url));
EXPECT_EQ(kAppId2, sub1.PreferredApps().FindPreferredAppForUrl(filter_url));
EXPECT_EQ(kAppId2,
sub0.PreferredApps().FindPreferredAppForUrl(another_filter_url));
EXPECT_EQ(kAppId2,
sub1.PreferredApps().FindPreferredAppForUrl(another_filter_url));
// Test that remove setting for one filter.
impl.RemovePreferredAppForFilter(apps::mojom::AppType::kUnknown, kAppId2,
intent_filter->Clone());
task_environment_.RunUntilIdle();
EXPECT_EQ(base::nullopt,
sub0.PreferredApps().FindPreferredAppForUrl(filter_url));
EXPECT_EQ(base::nullopt,
sub1.PreferredApps().FindPreferredAppForUrl(filter_url));
EXPECT_EQ(kAppId2,
sub0.PreferredApps().FindPreferredAppForUrl(another_filter_url));
EXPECT_EQ(kAppId2,
sub1.PreferredApps().FindPreferredAppForUrl(another_filter_url));
}
TEST_F(AppServiceImplTest, PreferredAppsPersistency) {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
const char kAppId1[] = "abcdefg";
GURL filter_url = GURL("https://www.google.com/abc");
auto intent_filter = apps_util::CreateIntentFilterForUrlScope(filter_url);
{
base::RunLoop run_loop_read;
base::RunLoop run_loop_write;
AppServiceImpl impl(temp_dir_.GetPath(),
/*is_share_intents_supported=*/false,
run_loop_read.QuitClosure(),
run_loop_write.QuitClosure());
impl.FlushMojoCallsForTesting();
run_loop_read.Run();
impl.AddPreferredApp(apps::mojom::AppType::kUnknown, kAppId1,
intent_filter->Clone(),
apps_util::CreateIntentFromUrl(filter_url),
/*from_publisher=*/false);
run_loop_write.Run();
impl.FlushMojoCallsForTesting();
}
// Create a new impl to initialize preferred apps from the disk.
{
base::RunLoop run_loop_read;
AppServiceImpl impl(temp_dir_.GetPath(),
/*is_share_intents_supported=*/false,
run_loop_read.QuitClosure());
impl.FlushMojoCallsForTesting();
run_loop_read.Run();
EXPECT_EQ(kAppId1, impl.GetPreferredAppsForTesting().FindPreferredAppForUrl(
filter_url));
}
}
TEST_F(AppServiceImplTest, PreferredAppsUpgrade) {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
const char kAppId1[] = "abcdefg";
const char kAppId2[] = "gfedcba";
GURL filter_url1 = GURL("https://www.google.com/abc");
GURL filter_url2 = GURL("https://www.abc.com");
auto intent_filter1 = apps_util::CreateIntentFilterForUrlScope(filter_url1);
auto intent_filter1_with_action = apps_util::CreateIntentFilterForUrlScope(
filter_url1, /*with_action_view=*/true);
auto intent_filter2_with_action = apps_util::CreateIntentFilterForUrlScope(
filter_url2, /*with_action_view=*/true);
{
base::RunLoop run_loop_read;
base::RunLoop run_loop_write;
AppServiceImpl impl(temp_dir_.GetPath(),
/*is_share_intents_supported=*/false,
run_loop_read.QuitClosure(),
run_loop_write.QuitClosure());
impl.FlushMojoCallsForTesting();
run_loop_read.Run();
impl.AddPreferredApp(apps::mojom::AppType::kUnknown, kAppId1,
intent_filter1->Clone(),
apps_util::CreateIntentFromUrl(filter_url1),
/*from_publisher=*/false);
impl.AddPreferredApp(apps::mojom::AppType::kUnknown, kAppId2,
intent_filter2_with_action->Clone(),
apps_util::CreateIntentFromUrl(filter_url2),
/*from_publisher=*/false);
run_loop_write.Run();
impl.FlushMojoCallsForTesting();
// If try to remove old intent filter with filter with action, it wouldn't
// work.
impl.RemovePreferredAppForFilter(apps::mojom::AppType::kUnknown, kAppId1,
intent_filter1_with_action->Clone());
task_environment_.RunUntilIdle();
EXPECT_EQ(kAppId1, impl.GetPreferredAppsForTesting().FindPreferredAppForUrl(
filter_url1));
EXPECT_EQ(kAppId2, impl.GetPreferredAppsForTesting().FindPreferredAppForUrl(
filter_url2));
}
// Create a new impl with sharing flag on to initialize preferred apps from
// the disk.
{
base::RunLoop run_loop_read;
base::RunLoop run_loop_write;
AppServiceImpl impl(temp_dir_.GetPath(),
/*is_share_intents_supported=*/true,
run_loop_read.QuitClosure(),
run_loop_write.QuitClosure());
impl.FlushMojoCallsForTesting();
run_loop_read.Run();
EXPECT_EQ(kAppId1, impl.GetPreferredAppsForTesting().FindPreferredAppForUrl(
filter_url1));
EXPECT_EQ(kAppId2, impl.GetPreferredAppsForTesting().FindPreferredAppForUrl(
filter_url2));
run_loop_write.Run();
impl.FlushMojoCallsForTesting();
}
// Create another new impl to read from disk and see if the filter is upgraded
// by trying to delete the entry using new filter.
{
base::RunLoop run_loop_read;
AppServiceImpl impl(temp_dir_.GetPath(),
/*is_share_intents_supported=*/false,
run_loop_read.QuitClosure());
impl.FlushMojoCallsForTesting();
run_loop_read.Run();
impl.RemovePreferredAppForFilter(apps::mojom::AppType::kUnknown, kAppId1,
intent_filter1_with_action->Clone());
impl.RemovePreferredAppForFilter(apps::mojom::AppType::kUnknown, kAppId2,
intent_filter2_with_action->Clone());
task_environment_.RunUntilIdle();
EXPECT_EQ(
base::nullopt,
impl.GetPreferredAppsForTesting().FindPreferredAppForUrl(filter_url1));
EXPECT_EQ(
base::nullopt,
impl.GetPreferredAppsForTesting().FindPreferredAppForUrl(filter_url2));
}
}
} // namespace apps