#include "ash/constants/ash_features.h"
#include "ash/public/cpp/system/toast_data.h"
#include "ash/public/cpp/system/toast_manager.h"
#include "ash/wm/desks/desks_controller.h"
#include "ash/wm/desks/desks_test_api.h"
#include "ash/wm/desks/desks_test_util.h"
#include "base/memory/scoped_refptr.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/spin_wait.h"
#include "base/time/time.h"
#include "base/uuid.h"
#include "build/build_config.h"
#include "chrome/browser/chromeos/extensions/wm/wm_desks_private_api.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "content/public/test/browser_test.h"
#include "extensions/browser/api_test_utils.h"
namespace extensions {
class WmDesksPrivateApiTest : public ExtensionApiTest {
public:
WmDesksPrivateApiTest() {
scoped_feature_list.InitWithFeatures(
{ash::features::kDesksTemplates},
{ash::features::kDeskTemplateSync});
}
~WmDesksPrivateApiTest() override = default;
private:
base::test::ScopedFeatureList scoped_feature_list;
};
IN_PROC_BROWSER_TEST_F(WmDesksPrivateApiTest, WmDesksPrivateApiTest) {
ASSERT_TRUE(RunExtensionTest("wm_desks_private")) << message_;
}
IN_PROC_BROWSER_TEST_F(WmDesksPrivateApiTest, LaunchAndCloseDeskTest) {
auto launch_desk_function =
base::MakeRefCounted<WmDesksPrivateLaunchDeskFunction>();
ash::DeskSwitchAnimationWaiter launch_waiter;
base::HistogramTester histogram_tester;
auto desk_id = api_test_utils::RunFunctionAndReturnSingleResult(
launch_desk_function.get(), R"([{"deskName":"test"}])",
browser()->profile());
EXPECT_TRUE(desk_id->is_string());
EXPECT_TRUE(
base::Uuid::ParseCaseInsensitive(desk_id->GetString()).is_valid());
histogram_tester.ExpectBucketCount("Ash.DeskApi.LaunchDesk.Result", 1, 1);
if (ash::DesksController::Get()->AreDesksBeingModified()) {
launch_waiter.Wait();
}
ash::DeskSwitchAnimationWaiter remove_waiter;
auto remove_desk_function =
base::MakeRefCounted<WmDesksPrivateRemoveDeskFunction>();
api_test_utils::RunFunctionAndReturnSingleResult(
remove_desk_function.get(),
R"([")" + desk_id->GetString() +
R"(", { "combineDesks": false, "allowUndo":false }])",
browser()->profile());
histogram_tester.ExpectBucketCount("Ash.DeskApi.RemoveDesk.Result", 1, 1);
if (ash::DesksController::Get()->AreDesksBeingModified()) {
remove_waiter.Wait();
}
histogram_tester.ExpectUniqueSample("Ash.DeskApi.RemoveDeskType",
ash::DeskCloseType::kCloseAllWindows, 1);
}
IN_PROC_BROWSER_TEST_F(WmDesksPrivateApiTest, LaunchAndAttemptUndo) {
auto launch_desk_function =
base::MakeRefCounted<WmDesksPrivateLaunchDeskFunction>();
ash::DeskSwitchAnimationWaiter launch_waiter;
base::HistogramTester histogram_tester;
auto desk_id = api_test_utils::RunFunctionAndReturnSingleResult(
launch_desk_function.get(), R"([{"deskName":"test"}])",
browser()->profile());
EXPECT_TRUE(desk_id->is_string());
EXPECT_TRUE(
base::Uuid::ParseCaseInsensitive(desk_id->GetString()).is_valid());
histogram_tester.ExpectBucketCount("Ash.DeskApi.LaunchDesk.Result", 1, 1);
if (ash::DesksController::Get()->AreDesksBeingModified()) {
launch_waiter.Wait();
}
ash::DeskSwitchAnimationWaiter remove_waiter;
auto remove_desk_function =
base::MakeRefCounted<WmDesksPrivateRemoveDeskFunction>();
api_test_utils::RunFunctionAndReturnSingleResult(
remove_desk_function.get(),
R"([")" + desk_id->GetString() +
R"(", { "combineDesks": false, "allowUndo": true }])",
browser()->profile());
if (ash::DesksController::Get()->AreDesksBeingModified()) {
remove_waiter.Wait();
}
EXPECT_TRUE(ash::DesksTestApi::DesksControllerCanUndoDeskRemoval());
if (!ash::ToastManager::Get()->IsToastShown("UndoCloseAllToast_1")) {
LOG(INFO) << "Non-undo toast running, must wait for other toasts :(";
SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(
base::Seconds(45),
ash::ToastManager::Get()->IsToastShown("UndoCloseAllToast_1"));
}
ash::WaitForMilliseconds(
ash::ToastData::kDefaultToastDuration.InMilliseconds() +
ash::DesksTestApi::GetCloseAllWindowCloseTimeout().InMilliseconds());
EXPECT_FALSE(ash::DesksTestApi::DesksControllerCanUndoDeskRemoval());
histogram_tester.ExpectBucketCount("Ash.DeskApi.RemoveDesk.Result", 1, 1);
}
#if defined(ADDRESS_SANITIZER) && defined(LEAK_SANITIZER)
#define MAYBE_LaunchAndUndo DISABLED_LaunchAndUndo
#else
#define MAYBE_LaunchAndUndo LaunchAndUndo
#endif
IN_PROC_BROWSER_TEST_F(WmDesksPrivateApiTest, MAYBE_LaunchAndUndo) {
auto launch_desk_function =
base::MakeRefCounted<WmDesksPrivateLaunchDeskFunction>();
ash::DeskSwitchAnimationWaiter launch_waiter;
base::HistogramTester histogram_tester;
auto desk_id = api_test_utils::RunFunctionAndReturnSingleResult(
launch_desk_function.get(), R"([{"deskName":"test"}])",
browser()->profile());
EXPECT_TRUE(desk_id->is_string());
EXPECT_TRUE(
base::Uuid::ParseCaseInsensitive(desk_id->GetString()).is_valid());
histogram_tester.ExpectBucketCount("Ash.DeskApi.LaunchDesk.Result", 1, 1);
if (ash::DesksController::Get()->AreDesksBeingModified()) {
launch_waiter.Wait();
}
ash::DeskSwitchAnimationWaiter remove_waiter;
auto remove_desk_function =
base::MakeRefCounted<WmDesksPrivateRemoveDeskFunction>();
api_test_utils::RunFunctionAndReturnSingleResult(
remove_desk_function.get(),
R"([")" + desk_id->GetString() +
R"(", { "combineDesks": false, "allowUndo": true }])",
browser()->profile());
if (ash::DesksController::Get()->AreDesksBeingModified()) {
remove_waiter.Wait();
}
histogram_tester.ExpectBucketCount("Ash.DeskApi.RemoveDesk.Result", 1, 1);
histogram_tester.ExpectUniqueSample(
"Ash.DeskApi.RemoveDeskType", ash::DeskCloseType::kCloseAllWindowsAndWait,
1);
EXPECT_TRUE(ash::DesksTestApi::DesksControllerCanUndoDeskRemoval());
ash::DesksController::Get()->MaybeCancelDeskRemoval();
histogram_tester.ExpectTotalCount("Ash.DeskApi.CloseAllUndo", 1);
EXPECT_FALSE(ash::DesksTestApi::DesksControllerCanUndoDeskRemoval());
EXPECT_EQ(2, ash::DesksController::Get()->GetNumberOfDesks());
}
IN_PROC_BROWSER_TEST_F(WmDesksPrivateApiTest, LaunchAndCombineUndoTrue) {
auto launch_desk_function =
base::MakeRefCounted<WmDesksPrivateLaunchDeskFunction>();
ash::DeskSwitchAnimationWaiter launch_waiter;
base::HistogramTester histogram_tester;
auto desk_id = api_test_utils::RunFunctionAndReturnSingleResult(
launch_desk_function.get(), R"([{"deskName":"test"}])",
browser()->profile());
EXPECT_TRUE(desk_id->is_string());
EXPECT_TRUE(
base::Uuid::ParseCaseInsensitive(desk_id->GetString()).is_valid());
histogram_tester.ExpectBucketCount("Ash.DeskApi.LaunchDesk.Result", 1, 1);
if (ash::DesksController::Get()->AreDesksBeingModified()) {
launch_waiter.Wait();
}
ash::DeskSwitchAnimationWaiter remove_waiter;
auto remove_desk_function =
base::MakeRefCounted<WmDesksPrivateRemoveDeskFunction>();
api_test_utils::RunFunctionAndReturnSingleResult(
remove_desk_function.get(),
R"([")" + desk_id->GetString() +
R"(", { "combineDesks": true, "allowUndo": true }])",
browser()->profile());
if (ash::DesksController::Get()->AreDesksBeingModified()) {
remove_waiter.Wait();
}
histogram_tester.ExpectBucketCount("Ash.DeskApi.RemoveDesk.Result", 1, 1);
histogram_tester.ExpectUniqueSample("Ash.DeskApi.RemoveDeskType",
ash::DeskCloseType::kCombineDesks, 1);
EXPECT_FALSE(ash::DesksTestApi::DesksControllerCanUndoDeskRemoval());
EXPECT_EQ(1, ash::DesksController::Get()->GetNumberOfDesks());
}
IN_PROC_BROWSER_TEST_F(WmDesksPrivateApiTest, LaunchAndRemoveCombine) {
auto launch_desk_function =
base::MakeRefCounted<WmDesksPrivateLaunchDeskFunction>();
ash::DeskSwitchAnimationWaiter launch_waiter;
base::HistogramTester histogram_tester;
auto desk_id = api_test_utils::RunFunctionAndReturnSingleResult(
launch_desk_function.get(), R"([{"deskName":"test"}])",
browser()->profile());
EXPECT_TRUE(desk_id->is_string());
EXPECT_TRUE(
base::Uuid::ParseCaseInsensitive(desk_id->GetString()).is_valid());
histogram_tester.ExpectBucketCount("Ash.DeskApi.LaunchDesk.Result", 1, 1);
if (ash::DesksController::Get()->AreDesksBeingModified()) {
launch_waiter.Wait();
}
ash::DeskSwitchAnimationWaiter remove_waiter;
auto remove_desk_function =
base::MakeRefCounted<WmDesksPrivateRemoveDeskFunction>();
api_test_utils::RunFunctionAndReturnSingleResult(
remove_desk_function.get(),
R"([")" + desk_id->GetString() +
R"(", { "combineDesks": true, "allowUndo": false }])",
browser()->profile());
if (ash::DesksController::Get()->AreDesksBeingModified()) {
remove_waiter.Wait();
}
histogram_tester.ExpectBucketCount("Ash.DeskApi.RemoveDesk.Result", 1, 1);
histogram_tester.ExpectUniqueSample("Ash.DeskApi.RemoveDeskType",
ash::DeskCloseType::kCombineDesks, 1);
EXPECT_EQ(1, ash::DesksController::Get()->GetNumberOfDesks());
}
IN_PROC_BROWSER_TEST_F(WmDesksPrivateApiTest, ListDesksTest) {
ash::DeskSwitchAnimationWaiter waiter;
auto launch_desk_function =
base::MakeRefCounted<WmDesksPrivateLaunchDeskFunction>();
auto desk_id = api_test_utils::RunFunctionAndReturnSingleResult(
launch_desk_function.get(), R"([{"deskName":"test"}])",
browser()->profile());
EXPECT_TRUE(desk_id->is_string());
EXPECT_TRUE(
base::Uuid::ParseCaseInsensitive(desk_id->GetString()).is_valid());
if (ash::DesksController::Get()->AreDesksBeingModified()) {
waiter.Wait();
}
auto list_desks_function =
base::MakeRefCounted<WmDesksPrivateGetAllDesksFunction>();
auto all_desks = api_test_utils::RunFunctionAndReturnSingleResult(
list_desks_function.get(), "[]", browser()->profile());
EXPECT_TRUE(all_desks->is_list());
EXPECT_EQ(2u, all_desks->GetList().size());
}
IN_PROC_BROWSER_TEST_F(WmDesksPrivateApiTest, SwitchToDifferentDeskTest) {
base::HistogramTester histogram_tester;
auto get_active_desk_function =
base::MakeRefCounted<WmDesksPrivateGetActiveDeskFunction>();
auto desk_id = api_test_utils::RunFunctionAndReturnSingleResult(
get_active_desk_function.get(), "[]", browser()->profile());
EXPECT_TRUE(desk_id->is_string());
EXPECT_TRUE(
base::Uuid::ParseCaseInsensitive(desk_id->GetString()).is_valid());
auto launch_desk_function =
base::MakeRefCounted<WmDesksPrivateLaunchDeskFunction>();
ash::DeskSwitchAnimationWaiter launch_waiter;
auto desk_id_1 = api_test_utils::RunFunctionAndReturnSingleResult(
launch_desk_function.get(), R"([{"deskName":"test"}])",
browser()->profile());
EXPECT_TRUE(desk_id_1->is_string());
EXPECT_TRUE(
base::Uuid::ParseCaseInsensitive(desk_id_1->GetString()).is_valid());
histogram_tester.ExpectBucketCount("Ash.DeskApi.LaunchDesk.Result", 1, 1);
if (ash::DesksController::Get()->AreDesksBeingModified()) {
launch_waiter.Wait();
}
ash::DeskSwitchAnimationWaiter switch_waiter;
auto switch_desk_function =
base::MakeRefCounted<WmDesksPrivateSwitchDeskFunction>();
api_test_utils::RunFunctionAndReturnSingleResult(
switch_desk_function.get(), R"([")" + desk_id->GetString() + R"("])",
browser()->profile());
if (ash::DesksController::Get()->AreDesksBeingModified()) {
switch_waiter.Wait();
}
auto get_active_desk_function_ =
base::MakeRefCounted<WmDesksPrivateGetActiveDeskFunction>();
auto desk_id_2 = api_test_utils::RunFunctionAndReturnSingleResult(
get_active_desk_function_.get(), "[]", browser()->profile());
EXPECT_TRUE(desk_id_2->is_string());
EXPECT_EQ(desk_id->GetString(), desk_id_2->GetString());
histogram_tester.ExpectBucketCount("Ash.DeskApi.SwitchDesk.Result", 1, 1);
}
IN_PROC_BROWSER_TEST_F(WmDesksPrivateApiTest, SwitchToCurrentDeskTest) {
auto get_active_desk_function =
base::MakeRefCounted<WmDesksPrivateGetActiveDeskFunction>();
auto desk_id = api_test_utils::RunFunctionAndReturnSingleResult(
get_active_desk_function.get(), "[]", browser()->profile());
EXPECT_TRUE(desk_id->is_string());
EXPECT_TRUE(
base::Uuid::ParseCaseInsensitive(desk_id->GetString()).is_valid());
auto switch_desk_function =
base::MakeRefCounted<WmDesksPrivateSwitchDeskFunction>();
api_test_utils::RunFunctionAndReturnSingleResult(
switch_desk_function.get(), R"([")" + desk_id->GetString() + R"("])",
browser()->profile());
auto get_active_desk_function_ =
base::MakeRefCounted<WmDesksPrivateGetActiveDeskFunction>();
auto desk_id_1 = api_test_utils::RunFunctionAndReturnSingleResult(
get_active_desk_function_.get(), "[]", browser()->profile());
EXPECT_TRUE(desk_id_1->is_string());
EXPECT_EQ(desk_id->GetString(), desk_id_1->GetString());
}
IN_PROC_BROWSER_TEST_F(WmDesksPrivateApiTest,
LaunchDeskWhenMaxNumberExceedTest) {
const int kMaxDeskIndex = 7;
for (int i = 0; i < kMaxDeskIndex; i++) {
ash::DesksController::Get()->NewDesk(ash::DesksCreationRemovalSource::kApi);
}
auto launch_desk_function =
base::MakeRefCounted<WmDesksPrivateLaunchDeskFunction>();
base::HistogramTester histogram_tester;
auto error = api_test_utils::RunFunctionAndReturnError(
launch_desk_function.get(), R"([{"deskName":"test"}])",
browser()->profile());
EXPECT_EQ(error, "DesksCountCheckFailedError");
histogram_tester.ExpectBucketCount("Ash.DeskApi.LaunchDesk.Result", 0, 1);
}
IN_PROC_BROWSER_TEST_F(WmDesksPrivateApiTest, RemoveDeskWithInvalidIdTest) {
base::HistogramTester histogram_tester;
auto remove_desk_function =
base::MakeRefCounted<WmDesksPrivateRemoveDeskFunction>();
auto error = api_test_utils::RunFunctionAndReturnError(
remove_desk_function.get(), R"(["invalid-id"])", browser()->profile());
EXPECT_EQ(error, "InvalidIdError");
histogram_tester.ExpectBucketCount("Ash.DeskApi.RemoveDesk.Result", 0, 1);
}
IN_PROC_BROWSER_TEST_F(WmDesksPrivateApiTest, SwitchDeskWithInvalidIdTest) {
base::HistogramTester histogram_tester;
auto switch_desk_function =
base::MakeRefCounted<WmDesksPrivateSwitchDeskFunction>();
auto error = api_test_utils::RunFunctionAndReturnError(
switch_desk_function.get(), R"(["invalid-id"])", browser()->profile());
EXPECT_EQ(error, "InvalidIdError");
histogram_tester.ExpectBucketCount("Ash.DeskApi.SwitchDesk.Result", 0, 1);
}
IN_PROC_BROWSER_TEST_F(WmDesksPrivateApiTest,
SetAllDesksWindowWithInvalidIdTest) {
base::HistogramTester histogram_tester;
auto all_desk_function =
base::MakeRefCounted<WmDesksPrivateSetWindowPropertiesFunction>();
auto error = api_test_utils::RunFunctionAndReturnError(
all_desk_function.get(), R"([123,{"allDesks":true}])",
browser()->profile());
EXPECT_EQ(error, "ResourceNotFoundError");
histogram_tester.ExpectBucketCount("Ash.DeskApi.AllDesk.Result", 0, 1);
}
IN_PROC_BROWSER_TEST_F(WmDesksPrivateApiTest, DISABLED_SaveAndRecallDeskTest) {
auto save_desk_function =
base::MakeRefCounted<WmDesksPrivateSaveActiveDeskFunction>();
ash::DeskSwitchAnimationWaiter save_desk_waiter;
auto result = api_test_utils::RunFunctionAndReturnSingleResult(
save_desk_function.get(), R"([])", browser()->profile());
EXPECT_TRUE(result->is_dict());
auto desk_id = result->GetDict().Find("savedDeskUuid")->GetString();
EXPECT_TRUE(base::Uuid::ParseCaseInsensitive(desk_id).is_valid());
if (ash::DesksController::Get()->AreDesksBeingModified()) {
save_desk_waiter.Wait();
}
auto list_desk_function =
base::MakeRefCounted<WmDesksPrivateGetSavedDesksFunction>();
auto result_1 = api_test_utils::RunFunctionAndReturnSingleResult(
list_desk_function.get(), R"([])", browser()->profile());
EXPECT_TRUE(result_1->is_list());
EXPECT_EQ(1u, result_1->GetList().size());
EXPECT_TRUE(result_1->GetList().front().GetDict().Find("savedDeskUuid"));
EXPECT_TRUE(result_1->GetList().front().GetDict().Find("savedDeskName"));
EXPECT_TRUE(result_1->GetList().front().GetDict().Find("savedDeskType"));
ash::DeskSwitchAnimationWaiter recall_desk_waiter;
auto recall_desk_function =
base::MakeRefCounted<WmDesksPrivateRecallSavedDeskFunction>();
auto desk_id_1 = api_test_utils::RunFunctionAndReturnSingleResult(
recall_desk_function.get(), R"([")" + desk_id + R"("])",
browser()->profile());
EXPECT_TRUE(desk_id_1->is_string());
EXPECT_TRUE(
base::Uuid::ParseCaseInsensitive(desk_id_1->GetString()).is_valid());
if (ash::DesksController::Get()->AreDesksBeingModified()) {
recall_desk_waiter.Wait();
}
}
#if defined(NDEBUG)
#define MAYBE_SaveAndDeleteDeskTest DISABLED_SaveAndDeleteDeskTest
#else
#define MAYBE_SaveAndDeleteDeskTest SaveAndDeleteDeskTest
#endif
IN_PROC_BROWSER_TEST_F(WmDesksPrivateApiTest, MAYBE_SaveAndDeleteDeskTest) {
auto save_desk_function =
base::MakeRefCounted<WmDesksPrivateSaveActiveDeskFunction>();
ash::DeskSwitchAnimationWaiter save_desk_waiter;
auto result = api_test_utils::RunFunctionAndReturnSingleResult(
save_desk_function.get(), R"([])", browser()->profile());
EXPECT_TRUE(result->is_dict());
auto desk_id = result->GetDict().Find("savedDeskUuid")->GetString();
EXPECT_TRUE(base::Uuid::ParseCaseInsensitive(desk_id).is_valid());
if (ash::DesksController::Get()->AreDesksBeingModified()) {
save_desk_waiter.Wait();
}
auto deleted_saved_desk_function =
base::MakeRefCounted<WmDesksPrivateDeleteSavedDeskFunction>();
api_test_utils::RunFunctionAndReturnSingleResult(
deleted_saved_desk_function.get(), R"([")" + desk_id + R"("])",
browser()->profile());
}
IN_PROC_BROWSER_TEST_F(WmDesksPrivateApiTest, GetDeskByIDTest) {
auto desk_id = api_test_utils::RunFunctionAndReturnSingleResult(
base::MakeRefCounted<WmDesksPrivateGetActiveDeskFunction>().get(), "[]",
browser()->profile());
auto get_desk_by_id_function =
base::MakeRefCounted<WmDesksPrivateGetDeskByIDFunction>();
auto result = api_test_utils::RunFunctionAndReturnSingleResult(
get_desk_by_id_function.get(), R"([")" + desk_id->GetString() + R"("])",
browser()->profile());
EXPECT_TRUE(result->is_dict());
auto* desk_id_1 = result->GetDict().Find("deskUuid");
auto* desk_name = result->GetDict().Find("deskName");
ASSERT_TRUE(desk_id_1->is_string());
EXPECT_EQ(desk_id->GetString(), desk_id_1->GetString());
EXPECT_TRUE(desk_name->is_string());
}
IN_PROC_BROWSER_TEST_F(WmDesksPrivateApiTest, GetDeskByInvalidIDTest) {
auto get_desk_by_id_function =
base::MakeRefCounted<WmDesksPrivateGetDeskByIDFunction>();
auto error = api_test_utils::RunFunctionAndReturnError(
get_desk_by_id_function.get(), R"(["invalid-id"])", browser()->profile());
EXPECT_EQ(error, "InvalidIdError");
}
IN_PROC_BROWSER_TEST_F(WmDesksPrivateApiTest, GetDeskByNonExistIDTest) {
auto desk_id = base::Uuid::GenerateRandomV4().AsLowercaseString();
auto get_desk_by_id_function =
base::MakeRefCounted<WmDesksPrivateGetDeskByIDFunction>();
auto error = api_test_utils::RunFunctionAndReturnError(
get_desk_by_id_function.get(), R"([")" + desk_id + R"("])",
browser()->profile());
EXPECT_EQ(error, "ResourceNotFoundError");
}
}