blob: a6e4851ae09ca97629c55aed693e188471dae362 [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/policy/skyvault/migration_notification_manager.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/functional/callback_forward.h"
#include "base/notreached.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/mock_callback.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_future.h"
#include "base/time/time.h"
#include "chrome/browser/ash/policy/skyvault/local_files_migration_constants.h"
#include "chrome/browser/ash/policy/skyvault/policy_utils.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/notifications/notification_display_service_tester.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/webui/ash/skyvault/local_files_migration_dialog.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/webui_url_constants.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_utils.h"
#include "net/base/filename_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace policy::local_user_files {
// Tests the MigrationNotificationManager class, which is in charge of most
// SkyVault migration notifications and dialogs.
class MigrationNotificationManagerTest : public InProcessBrowserTest {
public:
MigrationNotificationManagerTest() {
scoped_feature_list_.InitWithFeatures(
/*enabled_features=*/{features::kSkyVault, features::kSkyVaultV2},
/*disabled_features=*/{});
}
~MigrationNotificationManagerTest() override = default;
void SetUpOnMainThread() override {
InProcessBrowserTest::SetUpOnMainThread();
tester_ = std::make_unique<NotificationDisplayServiceTester>(profile());
ASSERT_TRUE(manager());
}
protected:
Profile* profile() { return browser()->profile(); }
MigrationNotificationManager* manager() {
return MigrationNotificationManagerFactory::GetInstance()
->GetForBrowserContext(profile());
}
base::test::ScopedFeatureList scoped_feature_list_;
std::unique_ptr<NotificationDisplayServiceTester> tester_;
};
class MigrationNotificationManagerParamTest
: public MigrationNotificationManagerTest,
public ::testing::WithParamInterface<MigrationDestination> {
public:
MigrationNotificationManagerParamTest() {
EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
}
static std::string ParamToName(const testing::TestParamInfo<ParamType> info) {
switch (info.param) {
case MigrationDestination::kGoogleDrive:
return "google_drive";
case MigrationDestination::kOneDrive:
return "one_drive";
case MigrationDestination::kNotSpecified:
case MigrationDestination::kDelete:
NOTREACHED();
}
}
protected:
MigrationDestination CloudProvider() { return GetParam(); }
base::ScopedTempDir temp_dir_;
};
// Tests that a progress notification is shown, and closed when
// CloseNotifications() is called.
IN_PROC_BROWSER_TEST_P(MigrationNotificationManagerParamTest,
ShowMigrationProgressNotification) {
EXPECT_FALSE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
manager()->ShowMigrationProgressNotification(CloudProvider());
EXPECT_TRUE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
manager()->CloseNotifications();
EXPECT_FALSE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
}
// Tests that a completed notification is shown, and closed when
// CloseNotifications() is called.
IN_PROC_BROWSER_TEST_P(MigrationNotificationManagerParamTest,
ShowMigrationCompletedNotification) {
EXPECT_FALSE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
manager()->ShowMigrationCompletedNotification(
CloudProvider(),
/*destination_path=*/base::FilePath());
EXPECT_TRUE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
manager()->CloseNotifications();
EXPECT_FALSE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
}
// Tests that a deletion completed notification is shown, and closed when
// CloseNotifications() is called.
IN_PROC_BROWSER_TEST_F(MigrationNotificationManagerTest,
ShowDeletionCompletedNotification) {
EXPECT_FALSE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
manager()->ShowDeletionCompletedNotification();
EXPECT_TRUE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
manager()->CloseNotifications();
EXPECT_FALSE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
}
// Tests that an error notification is shown, and closed when
// CloseNotifications() is called.
IN_PROC_BROWSER_TEST_P(MigrationNotificationManagerParamTest,
ShowMigrationErrorNotification_CloseNotifications) {
EXPECT_FALSE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
manager()->ShowMigrationErrorNotification(
CloudProvider(), kUploadRootPrefix,
/*error_log_path=*/
base::FilePath(kErrorLogFileBasePath).Append(kErrorLogFileName));
EXPECT_TRUE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
manager()->CloseNotifications();
EXPECT_FALSE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
}
// Tests that clicking on the "Review error log" button on an error notification
// correctly openes the passed path in the browser and closes the notification.
IN_PROC_BROWSER_TEST_P(MigrationNotificationManagerParamTest,
ShowMigrationErrorNotification_ReviewErrorLog) {
const base::FilePath error_log_path =
temp_dir_.GetPath().Append(kErrorLogFileName);
{
base::ScopedAllowBlockingForTesting allow_blocking;
CHECK(WriteFile(error_log_path,
"/home/chronos/user/MyFiles/Downloads/test_file.txt - "
"Something went wrong. Try again."));
CHECK(base::PathExists(error_log_path));
}
EXPECT_FALSE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
manager()->ShowMigrationErrorNotification(CloudProvider(), kUploadRootPrefix,
error_log_path);
EXPECT_TRUE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
const GURL error_log_url = net::FilePathToFileURL(error_log_path);
EXPECT_NE(
error_log_url,
browser()->tab_strip_model()->GetActiveWebContents()->GetURL().spec());
tester_->SimulateClick(NotificationHandler::Type::TRANSIENT,
kSkyVaultMigrationNotificationId, 0, std::nullopt);
EXPECT_FALSE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
EXPECT_EQ(
error_log_url,
browser()->tab_strip_model()->GetActiveWebContents()->GetURL().spec());
}
// Tests that a policy configuration error notification is shown, and closed
// when CloseNotifications() is called.
IN_PROC_BROWSER_TEST_P(MigrationNotificationManagerParamTest,
ShowConfigurationErrorNotification) {
EXPECT_FALSE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
manager()->ShowConfigurationErrorNotification(CloudProvider());
EXPECT_TRUE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
manager()->CloseNotifications();
EXPECT_FALSE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
}
// Tests that a sign in notification is shown once, even if multiple requests
// are called, and that closing it notifies all the requesters.
IN_PROC_BROWSER_TEST_F(MigrationNotificationManagerTest,
ShowSignInNotification_CloseByUser) {
EXPECT_FALSE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
// Check that only one notification is added.
base::MockCallback<base::RepeatingClosure> cb;
EXPECT_CALL(cb, Run).Times(1);
tester_->SetNotificationAddedClosure(cb.Get());
base::test::TestFuture<base::File::Error> sign_in_future_1;
base::test::TestFuture<base::File::Error> sign_in_future_2;
base::CallbackListSubscription subscription_1 =
manager()->ShowOneDriveSignInNotification(sign_in_future_1.GetCallback());
EXPECT_TRUE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
base::CallbackListSubscription subscription_2 =
manager()->ShowOneDriveSignInNotification(sign_in_future_2.GetCallback());
EXPECT_TRUE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
// Cancel the sign in.
tester_->RemoveNotification(NotificationHandler::Type::TRANSIENT,
kSkyVaultMigrationNotificationId,
/*by_user=*/true,
/*silent=*/false);
EXPECT_FALSE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
// Both callbacks should run.
EXPECT_EQ(sign_in_future_1.Get(), base::File::Error::FILE_ERROR_FAILED);
EXPECT_EQ(sign_in_future_2.Get(), base::File::Error::FILE_ERROR_FAILED);
}
// Tests that when a sign in notification is closed by CloseNotifications(), all
// requesters to sign in are notified.
IN_PROC_BROWSER_TEST_F(MigrationNotificationManagerTest,
ShowSignInNotification_CloseNotifications) {
EXPECT_FALSE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
// Check that only one notification is added.
base::MockCallback<base::RepeatingClosure> cb;
EXPECT_CALL(cb, Run).Times(1);
tester_->SetNotificationAddedClosure(cb.Get());
base::test::TestFuture<base::File::Error> sign_in_future_1;
base::test::TestFuture<base::File::Error> sign_in_future_2;
base::CallbackListSubscription subscription_1 =
manager()->ShowOneDriveSignInNotification(sign_in_future_1.GetCallback());
EXPECT_TRUE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
base::CallbackListSubscription subscription_2 =
manager()->ShowOneDriveSignInNotification(sign_in_future_2.GetCallback());
EXPECT_TRUE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
manager()->CloseNotifications();
EXPECT_FALSE(tester_->GetNotification(kSkyVaultMigrationNotificationId));
// Both callbacks should run.
EXPECT_EQ(sign_in_future_1.Get(), base::File::Error::FILE_ERROR_FAILED);
EXPECT_EQ(sign_in_future_2.Get(), base::File::Error::FILE_ERROR_FAILED);
}
// Tests that a migration dialog is shown, and closed when CloseDialog() is
// called.
IN_PROC_BROWSER_TEST_P(MigrationNotificationManagerParamTest, ShowDialog) {
EXPECT_FALSE(LocalFilesMigrationDialog::GetDialog());
content::TestNavigationObserver navigation_observer_dialog(
(GURL(chrome::kChromeUILocalFilesMigrationURL)));
navigation_observer_dialog.StartWatchingNewWebContents();
base::MockCallback<StartMigrationCallback> mock_cb;
manager()->ShowMigrationInfoDialog(
CloudProvider(), base::Time::Now() + base::Minutes(5), mock_cb.Get());
navigation_observer_dialog.Wait();
ASSERT_TRUE(navigation_observer_dialog.last_navigation_succeeded());
ash::SystemWebDialogDelegate* dialog = LocalFilesMigrationDialog::GetDialog();
EXPECT_TRUE(dialog);
content::WebUI* web_ui = dialog->GetWebUIForTest();
EXPECT_TRUE(web_ui);
content::WebContents* web_contents = web_ui->GetWebContents();
content::WebContentsDestroyedWatcher watcher(web_contents);
manager()->CloseDialog();
watcher.Wait();
EXPECT_FALSE(LocalFilesMigrationDialog::GetDialog());
}
INSTANTIATE_TEST_SUITE_P(LocalUserFiles,
MigrationNotificationManagerParamTest,
::testing::Values(MigrationDestination::kGoogleDrive,
MigrationDestination::kOneDrive),
MigrationNotificationManagerParamTest::ParamToName);
} // namespace policy::local_user_files