Commit 3c70fb4e authored by nancy's avatar nancy Committed by Commit Bot

Move AppModelBuilder related unit tests to AppService folder.

Move below unit tests to AppService folder, because they use
AppServiceAppModelBuilder for test:
CrostiniAppModelBuilderTest
ExtensionAppModelBuilderTest
InternalAppModelBuilderTest

BUG=1016159

Change-Id: I2aef91d4bb3b847a8861dca6b692bd0d92f0c4de
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1942897Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Commit-Queue: Nancy Wang <nancylingwang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#720731}
parent ba2855b1
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Copyright 2019 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 <stddef.h>
#include "chrome/browser/ui/app_list/app_service/app_service_app_model_builder.h"
#include <memory>
#include <set>
#include <string>
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/values.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/apps/app_service/app_service_test.h"
#include "chrome/browser/chromeos/crostini/crostini_registry_service.h"
#include "chrome/browser/chromeos/crostini/crostini_registry_service_factory.h"
#include "chrome/browser/chromeos/crostini/crostini_test_helper.h"
#include "chrome/browser/chromeos/crostini/crostini_util.h"
#include "chrome/browser/extensions/extension_function_test_utils.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/install_tracker.h"
#include "chrome/browser/extensions/install_tracker_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/app_list/app_list_test_util.h"
#include "chrome/browser/ui/app_list/app_service/app_service_app_model_builder.h"
#include "chrome/browser/ui/app_list/chrome_app_list_item.h"
#include "chrome/browser/ui/app_list/internal_app/internal_app_metadata.h"
#include "chrome/browser/ui/app_list/test/fake_app_list_model_updater.h"
#include "chrome/browser/ui/app_list/test/test_app_list_controller_delegate.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/services/app_service/public/mojom/types.mojom-shared.h"
#include "chrome/services/app_service/public/mojom/types.mojom.h"
#include "chrome/test/base/testing_profile.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_profile.h"
#include "components/prefs/pref_service.h"
#include "extensions/browser/app_sorting.h"
#include "extensions/browser/disable_reason.h"
......@@ -36,18 +50,44 @@
#include "extensions/browser/uninstall_reason.h"
#include "extensions/common/extension_set.h"
#include "extensions/common/manifest.h"
#include "testing/gtest/include/gtest/gtest.h"
using crostini::CrostiniTestHelper;
using extensions::AppSorting;
using extensions::ExtensionSystem;
using ::testing::_;
using ::testing::Matcher;
namespace {
const size_t kDefaultAppCount = 3u;
constexpr char kRootFolderName[] = "Linux apps";
constexpr char kDummyApp1Name[] = "dummy1";
constexpr char kDummyApp2Id[] = "dummy2";
constexpr char kDummyApp2Name[] = "dummy2";
constexpr char kAppNewName[] = "new name";
constexpr char kBananaAppId[] = "banana";
constexpr char kBananaAppName[] = "banana app name";
// Convenience matcher for some important fields of the chrome app.
MATCHER_P3(IsChromeApp, id, name, folder_id, "") {
Matcher<std::string> id_m(id);
Matcher<std::string> name_m(name);
Matcher<std::string> folder_id_m(folder_id);
return id_m.Matches(arg->id()) && name_m.Matches(arg->name()) &&
folder_id_m.Matches(arg->folder_id());
}
// Matches a chrome app item if its persistence field is set to true.
MATCHER(IsPersistentApp, "") {
return arg->is_persistent();
}
// Get a set of all apps in |model|.
std::set<std::string> GetModelContent(AppListModelUpdater* model_updater) {
std::set<std::string> content;
std::vector<std::string> GetModelContent(AppListModelUpdater* model_updater) {
std::vector<std::string> content;
for (size_t i = 0; i < model_updater->ItemCount(); ++i)
content.insert(model_updater->ItemAtForTest(i)->name());
content.push_back(model_updater->ItemAtForTest(i)->name());
return content;
}
......@@ -60,50 +100,40 @@ scoped_refptr<extensions::Extension> MakeApp(const std::string& name,
value.SetString("name", name);
value.SetString("version", version);
value.SetString("app.launch.web_url", url);
scoped_refptr<extensions::Extension> app =
extensions::Extension::Create(
base::FilePath(),
extensions::Manifest::INTERNAL,
value,
extensions::Extension::WAS_INSTALLED_BY_DEFAULT,
id,
&err);
scoped_refptr<extensions::Extension> app = extensions::Extension::Create(
base::FilePath(), extensions::Manifest::INTERNAL, value,
extensions::Extension::WAS_INSTALLED_BY_DEFAULT, id, &err);
EXPECT_EQ(err, "");
return app;
}
// For testing purposes, we want to pretend there are only Extension apps on the
// system. This method removes the others.
void RemoveNonExtensionApps(Profile* profile,
// For testing purposes, we want to pretend there are only |app_type| apps on
// the system. This method removes the others.
void RemoveApps(apps::mojom::AppType app_type,
Profile* profile,
FakeAppListModelUpdater* model_updater) {
apps::AppServiceProxy* proxy =
apps::AppServiceProxyFactory::GetForProfile(profile);
DCHECK(proxy);
proxy->FlushMojoCallsForTesting();
proxy->AppRegistryCache().ForEachApp(
[&model_updater](const apps::AppUpdate& update) {
if (update.AppType() != apps::mojom::AppType::kExtension &&
update.AppType() != apps::mojom::AppType::kWeb) {
[&model_updater, &app_type](const apps::AppUpdate& update) {
if (update.AppType() != app_type) {
model_updater->RemoveItem(update.AppId());
}
});
}
const size_t kDefaultAppCount = 3u;
} // namespace
class ExtensionAppModelBuilderTest : public AppListTestBase {
class AppServiceAppModelBuilderTest : public AppListTestBase {
public:
ExtensionAppModelBuilderTest() {}
~ExtensionAppModelBuilderTest() override {}
void SetUp() override {
AppListTestBase::SetUp();
AppServiceAppModelBuilderTest() {}
~AppServiceAppModelBuilderTest() override {}
default_apps_ = {"Packaged App 1", "Packaged App 2", "Hosted App"};
CreateBuilder();
}
AppServiceAppModelBuilderTest(const AppServiceAppModelBuilderTest&) = delete;
AppServiceAppModelBuilderTest& operator=(
const AppServiceAppModelBuilderTest&) = delete;
void TearDown() override {
ResetBuilder();
......@@ -111,76 +141,105 @@ class ExtensionAppModelBuilderTest : public AppListTestBase {
}
protected:
void ResetBuilder() {
builder_.reset();
controller_.reset();
model_updater_.reset();
}
// Creates a new builder, destroying any existing one.
void CreateBuilder() {
void CreateBuilder(bool guest_mode) {
ResetBuilder(); // Destroy any existing builder in the correct order.
app_service_test_.UninstallAllApps(profile());
testing_profile()->SetGuestSession(guest_mode);
app_service_test_.SetUp(testing_profile());
model_updater_ = std::make_unique<FakeAppListModelUpdater>();
controller_ = std::make_unique<test::TestAppListControllerDelegate>();
builder_ = std::make_unique<AppServiceAppModelBuilder>(controller_.get());
builder_->Initialize(nullptr, profile_.get(), model_updater_.get());
RemoveNonExtensionApps(profile_.get(), model_updater_.get());
builder_->Initialize(nullptr, testing_profile(), model_updater_.get());
}
void ResetBuilder() {
builder_.reset();
controller_.reset();
model_updater_.reset();
apps::AppServiceTest app_service_test_;
std::unique_ptr<AppServiceAppModelBuilder> builder_;
std::unique_ptr<FakeAppListModelUpdater> model_updater_;
std::unique_ptr<test::TestAppListControllerDelegate> controller_;
};
class BuiltInAppTest : public AppServiceAppModelBuilderTest {
protected:
// Creates a new builder, destroying any existing one.
void CreateBuilder(bool guest_mode) {
AppServiceAppModelBuilderTest::CreateBuilder(guest_mode);
RemoveApps(apps::mojom::AppType::kBuiltIn, testing_profile(),
model_updater_.get());
}
};
// Flush mojo calls to allow AppService async callbacks to run.
void FlushMojoCallsForAppService() {
apps::AppServiceProxy* app_service_proxy_ =
apps::AppServiceProxyFactory::GetForProfile(profile_.get());
DCHECK(app_service_proxy_);
app_service_proxy_->FlushMojoCallsForTesting();
class ExtensionAppTest : public AppServiceAppModelBuilderTest {
public:
void SetUp() override {
AppListTestBase::SetUp();
default_apps_ = {"Hosted App", "Packaged App 1", "Packaged App 2"};
CreateBuilder();
}
// Reinitialize proxy so that ExtensionApps can reinitialize to add the "web
// store" app and "enterprise web store" app.
void AppServiceProxyReInitializeForTesting() {
apps::AppServiceProxy* proxy =
apps::AppServiceProxyFactory::GetForProfile(profile_.get());
DCHECK(proxy);
proxy->ReInitializeForTesting(profile_.get());
FlushMojoCallsForAppService();
protected:
// Creates a new builder, destroying any existing one.
void CreateBuilder() {
AppServiceAppModelBuilderTest::CreateBuilder(false /*guest_mode*/);
RemoveApps(apps::mojom::AppType::kExtension, testing_profile(),
model_updater_.get());
}
std::unique_ptr<FakeAppListModelUpdater> model_updater_;
std::unique_ptr<test::TestAppListControllerDelegate> controller_;
std::unique_ptr<AppServiceAppModelBuilder> builder_;
std::set<std::string> default_apps_;
std::vector<std::string> default_apps_;
};
base::ScopedTempDir second_profile_temp_dir_;
TEST_F(BuiltInAppTest, Build) {
// The internal apps list is provided by GetInternalAppList() in
// internal_app_metadata.cc. Only count the apps can display in launcher.
std::string built_in_apps_name;
CreateBuilder(false);
EXPECT_EQ(app_list::GetNumberOfInternalAppsShowInLauncherForTest(
&built_in_apps_name, profile()),
model_updater_->ItemCount());
EXPECT_EQ(built_in_apps_name,
base::JoinString(GetModelContent(model_updater_.get()), ","));
}
private:
DISALLOW_COPY_AND_ASSIGN(ExtensionAppModelBuilderTest);
};
TEST_F(BuiltInAppTest, BuildGuestMode) {
// The internal apps list is provided by GetInternalAppList() in
// internal_app_metadata.cc. Only count the apps can display in launcher.
std::string built_in_apps_name;
CreateBuilder(true);
EXPECT_EQ(app_list::GetNumberOfInternalAppsShowInLauncherForTest(
&built_in_apps_name, profile()),
model_updater_->ItemCount());
EXPECT_EQ(built_in_apps_name,
base::JoinString(GetModelContent(model_updater_.get()), ","));
}
TEST_F(ExtensionAppModelBuilderTest, Build) {
TEST_F(ExtensionAppTest, Build) {
// The apps list would have 3 extension apps in the profile.
EXPECT_EQ(kDefaultAppCount, model_updater_->ItemCount());
EXPECT_EQ(default_apps_, GetModelContent(model_updater_.get()));
}
TEST_F(ExtensionAppModelBuilderTest, HideWebStore) {
TEST_F(ExtensionAppTest, HideWebStore) {
// Install a "web store" app.
scoped_refptr<extensions::Extension> store =
MakeApp("webstore",
"0.0",
"http://google.com",
MakeApp("webstore", "0.0", "http://google.com",
std::string(extensions::kWebStoreAppId));
service_->AddExtension(store.get());
// Install an "enterprise web store" app.
scoped_refptr<extensions::Extension> enterprise_store =
MakeApp("enterprise_webstore",
"0.0",
"http://google.com",
MakeApp("enterprise_webstore", "0.0", "http://google.com",
std::string(extension_misc::kEnterpriseWebStoreAppId));
service_->AddExtension(enterprise_store.get());
AppServiceProxyReInitializeForTesting();
app_service_test_.SetUp(profile_.get());
// Web stores should be present in the model.
FakeAppListModelUpdater model_updater1;
......@@ -191,7 +250,7 @@ TEST_F(ExtensionAppModelBuilderTest, HideWebStore) {
// Activate the HideWebStoreIcon policy.
profile_->GetPrefs()->SetBoolean(prefs::kHideWebStoreIcon, true);
FlushMojoCallsForAppService();
app_service_test_.FlushMojoCalls();
// Now the web stores should not be present anymore.
EXPECT_FALSE(model_updater1.FindItem(store->id()));
EXPECT_FALSE(model_updater1.FindItem(enterprise_store->id()));
......@@ -200,57 +259,55 @@ TEST_F(ExtensionAppModelBuilderTest, HideWebStore) {
FakeAppListModelUpdater model_updater2;
AppServiceAppModelBuilder builder2(controller_.get());
builder2.Initialize(nullptr, profile_.get(), &model_updater2);
FlushMojoCallsForAppService();
app_service_test_.FlushMojoCalls();
EXPECT_FALSE(model_updater2.FindItem(store->id()));
EXPECT_FALSE(model_updater2.FindItem(enterprise_store->id()));
// Deactivate the HideWebStoreIcon policy again.
profile_->GetPrefs()->SetBoolean(prefs::kHideWebStoreIcon, false);
FlushMojoCallsForAppService();
app_service_test_.FlushMojoCalls();
// Now the web stores should have appeared.
EXPECT_TRUE(model_updater2.FindItem(store->id()));
EXPECT_TRUE(model_updater2.FindItem(enterprise_store->id()));
}
TEST_F(ExtensionAppModelBuilderTest, DisableAndEnable) {
TEST_F(ExtensionAppTest, DisableAndEnable) {
service_->DisableExtension(kHostedAppId,
extensions::disable_reason::DISABLE_USER_ACTION);
FlushMojoCallsForAppService();
app_service_test_.FlushMojoCalls();
EXPECT_EQ(default_apps_, GetModelContent(model_updater_.get()));
service_->EnableExtension(kHostedAppId);
FlushMojoCallsForAppService();
app_service_test_.FlushMojoCalls();
EXPECT_EQ(default_apps_, GetModelContent(model_updater_.get()));
}
TEST_F(ExtensionAppModelBuilderTest, Uninstall) {
service_->UninstallExtension(kPackagedApp2Id,
extensions::UNINSTALL_REASON_FOR_TESTING,
NULL);
FlushMojoCallsForAppService();
EXPECT_EQ(std::set<std::string>({"Packaged App 1", "Hosted App"}),
TEST_F(ExtensionAppTest, Uninstall) {
service_->UninstallExtension(
kPackagedApp2Id, extensions::UNINSTALL_REASON_FOR_TESTING, nullptr);
app_service_test_.FlushMojoCalls();
EXPECT_EQ((std::vector<std::string>{"Hosted App", "Packaged App 1"}),
GetModelContent(model_updater_.get()));
base::RunLoop().RunUntilIdle();
}
TEST_F(ExtensionAppModelBuilderTest, UninstallTerminatedApp) {
TEST_F(ExtensionAppTest, UninstallTerminatedApp) {
ASSERT_NE(nullptr, registry()->GetInstalledExtension(kPackagedApp2Id));
// Simulate an app termination.
service_->TerminateExtension(kPackagedApp2Id);
service_->UninstallExtension(kPackagedApp2Id,
extensions::UNINSTALL_REASON_FOR_TESTING,
NULL);
FlushMojoCallsForAppService();
EXPECT_EQ(std::set<std::string>({"Packaged App 1", "Hosted App"}),
service_->UninstallExtension(
kPackagedApp2Id, extensions::UNINSTALL_REASON_FOR_TESTING, nullptr);
app_service_test_.FlushMojoCalls();
EXPECT_EQ((std::vector<std::string>{"Hosted App", "Packaged App 1"}),
GetModelContent(model_updater_.get()));
base::RunLoop().RunUntilIdle();
}
TEST_F(ExtensionAppModelBuilderTest, Reinstall) {
TEST_F(ExtensionAppTest, Reinstall) {
EXPECT_EQ(default_apps_, GetModelContent(model_updater_.get()));
// Install kPackagedApp1Id again should not create a new entry.
......@@ -259,18 +316,18 @@ TEST_F(ExtensionAppModelBuilderTest, Reinstall) {
extensions::InstallObserver::ExtensionInstallParams params(
kPackagedApp1Id, "", gfx::ImageSkia(), true, true);
tracker->OnBeginExtensionInstall(params);
FlushMojoCallsForAppService();
app_service_test_.FlushMojoCalls();
EXPECT_EQ(default_apps_, GetModelContent(model_updater_.get()));
}
TEST_F(ExtensionAppModelBuilderTest, OrdinalPrefsChange) {
TEST_F(ExtensionAppTest, OrdinalPrefsChange) {
AppSorting* sorting = ExtensionSystem::Get(profile_.get())->app_sorting();
syncer::StringOrdinal package_app_page =
sorting->GetPageOrdinal(kPackagedApp1Id);
sorting->SetPageOrdinal(kHostedAppId, package_app_page.CreateBefore());
FlushMojoCallsForAppService();
app_service_test_.FlushMojoCalls();
// Old behavior: This would be "Hosted App,Packaged App 1,Packaged App 2"
// New behavior: Sorting order doesn't change.
EXPECT_EQ(default_apps_, GetModelContent(model_updater_.get()));
......@@ -282,37 +339,37 @@ TEST_F(ExtensionAppModelBuilderTest, OrdinalPrefsChange) {
sorting->SetPageOrdinal(kHostedAppId, package_app_page);
sorting->SetAppLaunchOrdinal(kHostedAppId,
app1_ordinal.CreateBetween(app2_ordinal));
FlushMojoCallsForAppService();
app_service_test_.FlushMojoCalls();
// Old behavior: This would be "Packaged App 1,Hosted App,Packaged App 2"
// New behavior: Sorting order doesn't change.
EXPECT_EQ(default_apps_, GetModelContent(model_updater_.get()));
}
TEST_F(ExtensionAppModelBuilderTest, OnExtensionMoved) {
TEST_F(ExtensionAppTest, OnExtensionMoved) {
AppSorting* sorting = ExtensionSystem::Get(profile_.get())->app_sorting();
sorting->SetPageOrdinal(kHostedAppId,
sorting->GetPageOrdinal(kPackagedApp1Id));
sorting->OnExtensionMoved(kHostedAppId, kPackagedApp1Id, kPackagedApp2Id);
FlushMojoCallsForAppService();
app_service_test_.FlushMojoCalls();
// Old behavior: This would be "Packaged App 1,Hosted App,Packaged App 2"
// New behavior: Sorting order doesn't change.
EXPECT_EQ(default_apps_, GetModelContent(model_updater_.get()));
sorting->OnExtensionMoved(kHostedAppId, kPackagedApp2Id, std::string());
FlushMojoCallsForAppService();
app_service_test_.FlushMojoCalls();
// Old behavior: This would be restored to the default order.
// New behavior: Sorting order still doesn't change.
EXPECT_EQ(default_apps_, GetModelContent(model_updater_.get()));
sorting->OnExtensionMoved(kHostedAppId, std::string(), kPackagedApp1Id);
FlushMojoCallsForAppService();
app_service_test_.FlushMojoCalls();
// Old behavior: This would be "Hosted App,Packaged App 1,Packaged App 2"
// New behavior: Sorting order doesn't change.
EXPECT_EQ(default_apps_, GetModelContent(model_updater_.get()));
}
TEST_F(ExtensionAppModelBuilderTest, InvalidOrdinal) {
TEST_F(ExtensionAppTest, InvalidOrdinal) {
// Creates a no-ordinal case.
AppSorting* sorting = ExtensionSystem::Get(profile_.get())->app_sorting();
sorting->ClearOrdinals(kPackagedApp1Id);
......@@ -329,7 +386,7 @@ TEST_F(ExtensionAppModelBuilderTest, InvalidOrdinal) {
}
// This test adds a bookmark app to the app list.
TEST_F(ExtensionAppModelBuilderTest, BookmarkApp) {
TEST_F(ExtensionAppTest, BookmarkApp) {
const std::string kAppName = "Bookmark App";
const std::string kAppVersion = "2014.1.24.19748";
const std::string kAppUrl = "http://google.com";
......@@ -341,20 +398,243 @@ TEST_F(ExtensionAppModelBuilderTest, BookmarkApp) {
value.SetString("app.launch.web_url", kAppUrl);
scoped_refptr<extensions::Extension> bookmark_app =
extensions::Extension::Create(
base::FilePath(),
extensions::Manifest::INTERNAL,
value,
base::FilePath(), extensions::Manifest::INTERNAL, value,
extensions::Extension::WAS_INSTALLED_BY_DEFAULT |
extensions::Extension::FROM_BOOKMARK,
kAppId,
&err);
kAppId, &err);
EXPECT_TRUE(err.empty());
service_->AddExtension(bookmark_app.get());
AppServiceProxyReInitializeForTesting();
RemoveNonExtensionApps(profile_.get(), model_updater_.get());
EXPECT_EQ(kDefaultAppCount + 1, model_updater_->ItemCount());
const std::set<std::string> result_set =
GetModelContent(model_updater_.get());
EXPECT_NE(result_set.end(), result_set.find(kAppName));
app_service_test_.SetUp(profile_.get());
RemoveApps(apps::mojom::AppType::kWeb, profile_.get(), model_updater_.get());
EXPECT_EQ(1u, model_updater_->ItemCount());
EXPECT_EQ((std::vector<std::string>{kAppName}),
GetModelContent(model_updater_.get()));
}
class CrostiniAppTest : public AppListTestBase {
public:
CrostiniAppTest() {}
~CrostiniAppTest() override {}
CrostiniAppTest(const CrostiniAppTest&) = delete;
CrostiniAppTest& operator=(const CrostiniAppTest&) = delete;
void SetUp() override {
AppListTestBase::SetUp();
test_helper_ = std::make_unique<CrostiniTestHelper>(testing_profile());
test_helper_->ReInitializeAppServiceIntegration();
CreateBuilder();
}
void TearDown() override {
ResetBuilder();
test_helper_.reset();
AppListTestBase::TearDown();
}
protected:
AppListModelUpdater* GetModelUpdater() const {
return sync_service_->GetModelUpdater();
}
size_t GetModelItemCount() const {
// Pump the Mojo IPCs.
base::RunLoop().RunUntilIdle();
return sync_service_->GetModelUpdater()->ItemCount();
}
std::vector<ChromeAppListItem*> GetAllApps() const {
std::vector<ChromeAppListItem*> result;
for (size_t i = 0; i < GetModelItemCount(); ++i) {
result.emplace_back(GetModelUpdater()->ItemAtForTest(i));
}
return result;
}
// For testing purposes, we want to pretend there are only crostini apps on
// the system. This method removes the others.
void RemoveNonCrostiniApps() {
std::vector<std::string> existing_item_ids;
for (const auto& pair : sync_service_->sync_items()) {
existing_item_ids.emplace_back(pair.first);
}
for (const std::string& id : existing_item_ids) {
if (id == crostini::kCrostiniFolderId ||
id == crostini::kCrostiniTerminalId) {
continue;
}
sync_service_->RemoveItem(id);
}
}
void CreateBuilder() {
model_updater_factory_scope_ = std::make_unique<
app_list::AppListSyncableService::ScopedModelUpdaterFactoryForTest>(
base::BindRepeating(
[](Profile* profile) -> std::unique_ptr<AppListModelUpdater> {
return std::make_unique<FakeAppListModelUpdater>(profile);
},
profile()));
// The AppListSyncableService creates the CrostiniAppModelBuilder.
sync_service_ =
std::make_unique<app_list::AppListSyncableService>(profile_.get());
RemoveNonCrostiniApps();
}
void ResetBuilder() {
sync_service_.reset();
model_updater_factory_scope_.reset();
}
crostini::CrostiniRegistryService* RegistryService() {
return crostini::CrostiniRegistryServiceFactory::GetForProfile(profile());
}
std::string TerminalAppName() {
return l10n_util::GetStringUTF8(IDS_CROSTINI_TERMINAL_APP_NAME);
}
std::unique_ptr<app_list::AppListSyncableService> sync_service_;
std::unique_ptr<CrostiniTestHelper> test_helper_;
private:
std::unique_ptr<
app_list::AppListSyncableService::ScopedModelUpdaterFactoryForTest>
model_updater_factory_scope_;
};
// Test that the Terminal app is only shown when Crostini is enabled
TEST_F(CrostiniAppTest, EnableAndDisableCrostini) {
// Reset things so we start with Crostini not enabled.
ResetBuilder();
test_helper_.reset();
test_helper_ = std::make_unique<CrostiniTestHelper>(
testing_profile(), /*enable_crostini=*/false);
CreateBuilder();
EXPECT_EQ(0u, GetModelItemCount());
CrostiniTestHelper::EnableCrostini(testing_profile());
EXPECT_THAT(GetAllApps(),
testing::UnorderedElementsAre(
IsChromeApp(crostini::kCrostiniTerminalId, TerminalAppName(),
crostini::kCrostiniFolderId)));
CrostiniTestHelper::DisableCrostini(testing_profile());
EXPECT_THAT(GetAllApps(), testing::IsEmpty());
}
TEST_F(CrostiniAppTest, AppInstallation) {
// Terminal app.
EXPECT_EQ(1u, GetModelItemCount());
test_helper_->SetupDummyApps();
EXPECT_THAT(GetAllApps(),
testing::UnorderedElementsAre(
IsChromeApp(crostini::kCrostiniTerminalId, TerminalAppName(),
crostini::kCrostiniFolderId),
IsChromeApp(_, kDummyApp1Name, crostini::kCrostiniFolderId),
IsChromeApp(_, kDummyApp2Name, crostini::kCrostiniFolderId)));
test_helper_->AddApp(
CrostiniTestHelper::BasicApp(kBananaAppId, kBananaAppName));
EXPECT_THAT(GetAllApps(),
testing::UnorderedElementsAre(
IsChromeApp(crostini::kCrostiniTerminalId, TerminalAppName(),
crostini::kCrostiniFolderId),
IsChromeApp(_, kDummyApp1Name, crostini::kCrostiniFolderId),
IsChromeApp(_, kDummyApp2Name, crostini::kCrostiniFolderId),
IsChromeApp(_, kBananaAppName, crostini::kCrostiniFolderId)));
}
// Test that the app model builder correctly picks up changes to existing apps.
TEST_F(CrostiniAppTest, UpdateApps) {
test_helper_->SetupDummyApps();
// 3 apps.
EXPECT_EQ(3u, GetModelItemCount());
// Setting NoDisplay to true should hide an app.
vm_tools::apps::App dummy1 = test_helper_->GetApp(0);
dummy1.set_no_display(true);
test_helper_->AddApp(dummy1);
EXPECT_THAT(GetAllApps(),
testing::UnorderedElementsAre(
IsChromeApp(crostini::kCrostiniTerminalId, _, _),
IsChromeApp(CrostiniTestHelper::GenerateAppId(kDummyApp2Name),
_, _)));
// Setting NoDisplay to false should unhide an app.
dummy1.set_no_display(false);
test_helper_->AddApp(dummy1);
EXPECT_THAT(
GetAllApps(),
testing::UnorderedElementsAre(
IsChromeApp(crostini::kCrostiniTerminalId, _, _),
IsChromeApp(CrostiniTestHelper::GenerateAppId(kDummyApp1Name), _, _),
IsChromeApp(CrostiniTestHelper::GenerateAppId(kDummyApp2Name), _,
_)));
// Changes to app names should be detected.
vm_tools::apps::App dummy2 =
CrostiniTestHelper::BasicApp(kDummyApp2Id, kAppNewName);
test_helper_->AddApp(dummy2);
EXPECT_THAT(GetAllApps(),
testing::UnorderedElementsAre(
IsChromeApp(crostini::kCrostiniTerminalId, _, _),
IsChromeApp(CrostiniTestHelper::GenerateAppId(kDummyApp1Name),
kDummyApp1Name, _),
IsChromeApp(CrostiniTestHelper::GenerateAppId(kDummyApp2Name),
kAppNewName, _)));
}
// Test that the app model builder handles removed apps
TEST_F(CrostiniAppTest, RemoveApps) {
test_helper_->SetupDummyApps();
// 3 apps.
EXPECT_EQ(3u, GetModelItemCount());
// Remove dummy1
test_helper_->RemoveApp(0);
EXPECT_EQ(2u, GetModelItemCount());
// Remove dummy2
test_helper_->RemoveApp(0);
EXPECT_EQ(1u, GetModelItemCount());
}
// Tests that the crostini folder is (re)created with the correct parameters.
TEST_F(CrostiniAppTest, CreatesFolder) {
EXPECT_THAT(GetAllApps(),
testing::UnorderedElementsAre(
IsChromeApp(crostini::kCrostiniTerminalId, TerminalAppName(),
crostini::kCrostiniFolderId)));
// We simulate ash creating the crostini folder and calling back into chrome
// (rather than use a full browser test).
auto metadata = std::make_unique<ash::AppListItemMetadata>();
metadata->id = crostini::kCrostiniFolderId;
GetModelUpdater()->OnFolderCreated(std::move(metadata));
EXPECT_THAT(GetAllApps(),
testing::UnorderedElementsAre(
IsChromeApp(crostini::kCrostiniTerminalId, TerminalAppName(),
crostini::kCrostiniFolderId),
testing::AllOf(IsChromeApp(crostini::kCrostiniFolderId,
kRootFolderName, ""),
IsPersistentApp())));
}
// Test that the Terminal app is removed when Crostini is disabled.
TEST_F(CrostiniAppTest, DisableCrostini) {
test_helper_->SetupDummyApps();
// 3 apps.
EXPECT_EQ(3u, GetModelItemCount());
// The uninstall flow removes all apps before setting the CrostiniEnabled pref
// to false, so we need to do that explicitly too.
RegistryService()->ClearApplicationList(crostini::kCrostiniDefaultVmName, "");
CrostiniTestHelper::DisableCrostini(testing_profile());
EXPECT_EQ(0u, GetModelItemCount());
}
// 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 <utility>
#include <vector>
#include "base/run_loop.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/chromeos/crostini/crostini_registry_service.h"
#include "chrome/browser/chromeos/crostini/crostini_registry_service_factory.h"
#include "chrome/browser/chromeos/crostini/crostini_test_helper.h"
#include "chrome/browser/chromeos/crostini/crostini_util.h"
#include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
#include "chrome/browser/ui/app_list/app_list_test_util.h"
#include "chrome/browser/ui/app_list/chrome_app_list_item.h"
#include "chrome/browser/ui/app_list/test/fake_app_list_model_updater.h"
#include "chrome/common/chrome_features.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/test/base/testing_profile.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "ui/base/l10n/l10n_util.h"
using crostini::CrostiniTestHelper;
using ::testing::_;
using ::testing::Matcher;
namespace {
constexpr char kRootFolderName[] = "Linux apps";
constexpr char kDummyApp1Name[] = "dummy1";
constexpr char kDummyApp2Id[] = "dummy2";
constexpr char kDummyApp2Name[] = "dummy2";
constexpr char kAppNewName[] = "new name";
constexpr char kBananaAppId[] = "banana";
constexpr char kBananaAppName[] = "banana app name";
// Convenience matcher for some important fields of the chrome app.
MATCHER_P3(IsChromeApp, id, name, folder_id, "") {
Matcher<std::string> id_m(id);
Matcher<std::string> name_m(name);
Matcher<std::string> folder_id_m(folder_id);
return id_m.Matches(arg->id()) && name_m.Matches(arg->name()) &&
folder_id_m.Matches(arg->folder_id());
}
// Matches a chrome app item if its persistence field is set to true.
MATCHER(IsPersistentApp, "") {
return arg->is_persistent();
}
// For testing purposes, we want to pretend there are only crostini apps on the
// system. This method removes the others.
void RemoveNonCrostiniApps(app_list::AppListSyncableService* sync_service) {
std::vector<std::string> existing_item_ids;
for (const auto& pair : sync_service->sync_items()) {
existing_item_ids.emplace_back(pair.first);
}
for (const std::string& id : existing_item_ids) {
if (id == crostini::kCrostiniFolderId ||
id == crostini::kCrostiniTerminalId) {
continue;
}
sync_service->RemoveItem(id);
}
}
} // namespace
class CrostiniAppModelBuilderTest : public AppListTestBase {
public:
CrostiniAppModelBuilderTest() {}
~CrostiniAppModelBuilderTest() override {}
void SetUp() override {
AppListTestBase::SetUp();
test_helper_ = std::make_unique<CrostiniTestHelper>(testing_profile());
test_helper_->ReInitializeAppServiceIntegration();
CreateBuilder();
}
void TearDown() override {
ResetBuilder();
test_helper_.reset();
AppListTestBase::TearDown();
}
protected:
AppListModelUpdater* GetModelUpdater() const {
return sync_service_->GetModelUpdater();
}
size_t GetModelItemCount() const {
// Pump the Mojo IPCs.
base::RunLoop().RunUntilIdle();
return sync_service_->GetModelUpdater()->ItemCount();
}
std::vector<ChromeAppListItem*> GetAllApps() const {
std::vector<ChromeAppListItem*> result;
for (size_t i = 0; i < GetModelItemCount(); ++i) {
result.emplace_back(GetModelUpdater()->ItemAtForTest(i));
}
return result;
}
void CreateBuilder() {
model_updater_factory_scope_ = std::make_unique<
app_list::AppListSyncableService::ScopedModelUpdaterFactoryForTest>(
base::BindRepeating(
[](Profile* profile) -> std::unique_ptr<AppListModelUpdater> {
return std::make_unique<FakeAppListModelUpdater>(profile);
},
profile()));
// The AppListSyncableService creates the CrostiniAppModelBuilder.
sync_service_ =
std::make_unique<app_list::AppListSyncableService>(profile_.get());
RemoveNonCrostiniApps(sync_service_.get());
}
void ResetBuilder() {
sync_service_.reset();
model_updater_factory_scope_.reset();
}
crostini::CrostiniRegistryService* RegistryService() {
return crostini::CrostiniRegistryServiceFactory::GetForProfile(profile());
}
std::string TerminalAppName() {
return l10n_util::GetStringUTF8(IDS_CROSTINI_TERMINAL_APP_NAME);
}
std::unique_ptr<app_list::AppListSyncableService> sync_service_;
std::unique_ptr<CrostiniTestHelper> test_helper_;
private:
std::unique_ptr<
app_list::AppListSyncableService::ScopedModelUpdaterFactoryForTest>
model_updater_factory_scope_;
DISALLOW_COPY_AND_ASSIGN(CrostiniAppModelBuilderTest);
};
// Test that the Terminal app is only shown when Crostini is enabled
TEST_F(CrostiniAppModelBuilderTest, EnableAndDisableCrostini) {
// Reset things so we start with Crostini not enabled.
ResetBuilder();
test_helper_.reset();
test_helper_ = std::make_unique<CrostiniTestHelper>(
testing_profile(), /*enable_crostini=*/false);
CreateBuilder();
EXPECT_EQ(0u, GetModelItemCount());
CrostiniTestHelper::EnableCrostini(testing_profile());
EXPECT_THAT(GetAllApps(),
testing::UnorderedElementsAre(
IsChromeApp(crostini::kCrostiniTerminalId, TerminalAppName(),
crostini::kCrostiniFolderId)));
CrostiniTestHelper::DisableCrostini(testing_profile());
EXPECT_THAT(GetAllApps(), testing::IsEmpty());
}
TEST_F(CrostiniAppModelBuilderTest, AppInstallation) {
// Terminal app.
EXPECT_EQ(1u, GetModelItemCount());
test_helper_->SetupDummyApps();
EXPECT_THAT(
GetAllApps(),
testing::UnorderedElementsAre(
IsChromeApp(crostini::kCrostiniTerminalId, TerminalAppName(),
crostini::kCrostiniFolderId),
IsChromeApp(_, kDummyApp1Name, crostini::kCrostiniFolderId),
IsChromeApp(_, kDummyApp2Name, crostini::kCrostiniFolderId)));
test_helper_->AddApp(
CrostiniTestHelper::BasicApp(kBananaAppId, kBananaAppName));
EXPECT_THAT(GetAllApps(),
testing::UnorderedElementsAre(
IsChromeApp(crostini::kCrostiniTerminalId, TerminalAppName(),
crostini::kCrostiniFolderId),
IsChromeApp(_, kDummyApp1Name, crostini::kCrostiniFolderId),
IsChromeApp(_, kDummyApp2Name, crostini::kCrostiniFolderId),
IsChromeApp(_, kBananaAppName, crostini::kCrostiniFolderId)));
}
// Test that the app model builder correctly picks up changes to existing apps.
TEST_F(CrostiniAppModelBuilderTest, UpdateApps) {
test_helper_->SetupDummyApps();
// 3 apps.
EXPECT_EQ(3u, GetModelItemCount());
// Setting NoDisplay to true should hide an app.
vm_tools::apps::App dummy1 = test_helper_->GetApp(0);
dummy1.set_no_display(true);
test_helper_->AddApp(dummy1);
EXPECT_THAT(
GetAllApps(),
testing::UnorderedElementsAre(
IsChromeApp(crostini::kCrostiniTerminalId, _, _),
IsChromeApp(CrostiniTestHelper::GenerateAppId(kDummyApp2Name), _,
_)));
// Setting NoDisplay to false should unhide an app.
dummy1.set_no_display(false);
test_helper_->AddApp(dummy1);
EXPECT_THAT(
GetAllApps(),
testing::UnorderedElementsAre(
IsChromeApp(crostini::kCrostiniTerminalId, _, _),
IsChromeApp(CrostiniTestHelper::GenerateAppId(kDummyApp1Name), _, _),
IsChromeApp(CrostiniTestHelper::GenerateAppId(kDummyApp2Name), _,
_)));
// Changes to app names should be detected.
vm_tools::apps::App dummy2 =
CrostiniTestHelper::BasicApp(kDummyApp2Id, kAppNewName);
test_helper_->AddApp(dummy2);
EXPECT_THAT(
GetAllApps(),
testing::UnorderedElementsAre(
IsChromeApp(crostini::kCrostiniTerminalId, _, _),
IsChromeApp(CrostiniTestHelper::GenerateAppId(kDummyApp1Name),
kDummyApp1Name, _),
IsChromeApp(CrostiniTestHelper::GenerateAppId(kDummyApp2Name),
kAppNewName, _)));
}
// Test that the app model builder handles removed apps
TEST_F(CrostiniAppModelBuilderTest, RemoveApps) {
test_helper_->SetupDummyApps();
// 3 apps.
EXPECT_EQ(3u, GetModelItemCount());
// Remove dummy1
test_helper_->RemoveApp(0);
EXPECT_EQ(2u, GetModelItemCount());
// Remove dummy2
test_helper_->RemoveApp(0);
EXPECT_EQ(1u, GetModelItemCount());
}
// Tests that the crostini folder is (re)created with the correct parameters.
TEST_F(CrostiniAppModelBuilderTest, CreatesFolder) {
EXPECT_THAT(GetAllApps(),
testing::UnorderedElementsAre(
IsChromeApp(crostini::kCrostiniTerminalId, TerminalAppName(),
crostini::kCrostiniFolderId)));
// We simulate ash creating the crostini folder and calling back into chrome
// (rather than use a full browser test).
auto metadata = std::make_unique<ash::AppListItemMetadata>();
metadata->id = crostini::kCrostiniFolderId;
GetModelUpdater()->OnFolderCreated(std::move(metadata));
EXPECT_THAT(GetAllApps(),
testing::UnorderedElementsAre(
IsChromeApp(crostini::kCrostiniTerminalId, TerminalAppName(),
crostini::kCrostiniFolderId),
testing::AllOf(IsChromeApp(crostini::kCrostiniFolderId,
kRootFolderName, ""),
IsPersistentApp())));
}
// Test that the Terminal app is removed when Crostini is disabled.
TEST_F(CrostiniAppModelBuilderTest, DisableCrostini) {
test_helper_->SetupDummyApps();
// 3 apps.
EXPECT_EQ(3u, GetModelItemCount());
// The uninstall flow removes all apps before setting the CrostiniEnabled pref
// to false, so we need to do that explicitly too.
RegistryService()->ClearApplicationList(crostini::kCrostiniDefaultVmName, "");
CrostiniTestHelper::DisableCrostini(testing_profile());
EXPECT_EQ(0u, GetModelItemCount());
}
// 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 "base/macros.h"
#include "base/strings/string_util.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/apps/app_service/app_service_test.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/app_list/app_list_test_util.h"
#include "chrome/browser/ui/app_list/app_service/app_service_app_model_builder.h"
#include "chrome/browser/ui/app_list/chrome_app_list_item.h"
#include "chrome/browser/ui/app_list/internal_app/internal_app_metadata.h"
#include "chrome/browser/ui/app_list/test/fake_app_list_model_updater.h"
#include "chrome/browser/ui/app_list/test/test_app_list_controller_delegate.h"
#include "chrome/test/base/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
// Get a set of all apps in |model|.
std::string GetModelContent(AppListModelUpdater* model_updater) {
std::vector<std::string> app_names;
for (size_t i = 0; i < model_updater->ItemCount(); ++i)
app_names.emplace_back(model_updater->ItemAtForTest(i)->name());
return base::JoinString(app_names, ",");
}
// For testing purposes, we want to pretend there are only BuiltIn apps on the
// system. This method removes the others.
void RemoveNonBuiltInApps(Profile* profile,
FakeAppListModelUpdater* model_updater) {
apps::AppServiceProxy* proxy =
apps::AppServiceProxyFactory::GetForProfile(profile);
DCHECK(proxy);
proxy->FlushMojoCallsForTesting();
proxy->AppRegistryCache().ForEachApp(
[&model_updater](const apps::AppUpdate& update) {
if (update.AppType() != apps::mojom::AppType::kBuiltIn) {
model_updater->RemoveItem(update.AppId());
}
});
}
} // namespace
class InternalAppModelBuilderTest : public AppListTestBase {
public:
InternalAppModelBuilderTest() {}
~InternalAppModelBuilderTest() override {}
// AppListTestBase:
void SetUp() override {
AppListTestBase::SetUp();
}
void TearDown() override {
ResetBuilder();
AppListTestBase::TearDown();
}
protected:
// Creates a new builder, destroying any existing one.
void CreateBuilder(bool guest_mode) {
ResetBuilder(); // Destroy any existing builder in the correct order.
app_service_test_.UninstallAllApps(profile());
testing_profile()->SetGuestSession(guest_mode);
app_service_test_.SetUp(testing_profile());
model_updater_ = std::make_unique<FakeAppListModelUpdater>();
controller_ = std::make_unique<test::TestAppListControllerDelegate>();
builder_ = std::make_unique<AppServiceAppModelBuilder>(controller_.get());
builder_->Initialize(nullptr, testing_profile(), model_updater_.get());
RemoveNonBuiltInApps(testing_profile(), model_updater_.get());
}
std::unique_ptr<FakeAppListModelUpdater> model_updater_;
private:
void ResetBuilder() {
builder_.reset();
controller_.reset();
model_updater_.reset();
}
apps::AppServiceTest app_service_test_;
std::unique_ptr<test::TestAppListControllerDelegate> controller_;
std::unique_ptr<AppServiceAppModelBuilder> builder_;
DISALLOW_COPY_AND_ASSIGN(InternalAppModelBuilderTest);
};
TEST_F(InternalAppModelBuilderTest, Build) {
// The internal apps list is provided by GetInternalAppList() in
// internal_app_metadata.cc. Only count the apps can display in launcher.
std::string internal_apps_name;
CreateBuilder(false);
EXPECT_EQ(app_list::GetNumberOfInternalAppsShowInLauncherForTest(
&internal_apps_name, profile()),
model_updater_->ItemCount());
EXPECT_EQ(internal_apps_name, GetModelContent(model_updater_.get()));
}
TEST_F(InternalAppModelBuilderTest, BuildGuestMode) {
// The internal apps list is provided by GetInternalAppList() in
// internal_app_metadata.cc. Only count the apps can display in launcher.
std::string internal_apps_name;
CreateBuilder(true);
EXPECT_EQ(app_list::GetNumberOfInternalAppsShowInLauncherForTest(
&internal_apps_name, profile()),
model_updater_->ItemCount());
EXPECT_EQ(internal_apps_name, GetModelContent(model_updater_.get()));
}
......@@ -4156,6 +4156,7 @@ test("unit_tests") {
"../browser/ui/app_list/app_list_syncable_service_unittest.cc",
"../browser/ui/app_list/app_list_test_util.cc",
"../browser/ui/app_list/app_list_test_util.h",
"../browser/ui/app_list/app_service/app_service_app_model_builder_unittest.cc",
"../browser/ui/app_list/arc/arc_app_test.cc",
"../browser/ui/app_list/arc/arc_app_test.h",
"../browser/ui/app_list/arc/arc_app_unittest.cc",
......@@ -4163,9 +4164,6 @@ test("unit_tests") {
"../browser/ui/app_list/arc/arc_vpn_provider_unittest.cc",
"../browser/ui/app_list/arc/mock_arc_app_list_prefs_observer.cc",
"../browser/ui/app_list/arc/mock_arc_app_list_prefs_observer.h",
"../browser/ui/app_list/crostini/crostini_app_model_builder_unittest.cc",
"../browser/ui/app_list/extension_app_model_builder_unittest.cc",
"../browser/ui/app_list/internal_app/internal_app_model_builder_unittest.cc",
"../browser/ui/app_list/md_icon_normalizer_unittest.cc",
"../browser/ui/app_list/search/answer_card/answer_card_result_unittest.cc",
"../browser/ui/app_list/search/answer_card/answer_card_search_provider_unittest.cc",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment