blob: 7d99b24c8ccd79712489d4bf3a8b7b1dd5f28319 [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 "ash/scanner/scanner_controller.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "ash/constants/ash_features.h"
#include "ash/public/cpp/scanner/scanner_delegate.h"
#include "ash/public/cpp/scanner/scanner_enums.h"
#include "ash/public/cpp/scanner/scanner_system_state.h"
#include "ash/public/cpp/system/toast_manager.h"
#include "ash/scanner/fake_scanner_profile_scoped_delegate.h"
#include "ash/scanner/scanner_action_view_model.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_future.h"
#include "components/manta/manta_status.h"
#include "components/manta/proto/scanner.pb.h"
#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/message_center/message_center.h"
#include "url/gurl.h"
namespace ash {
namespace {
using ::base::test::InvokeFuture;
using ::base::test::RunOnceCallback;
using ::testing::IsEmpty;
using ::testing::Return;
using ::testing::SizeIs;
using ::testing::WithArg;
constexpr char kScannerActionSuccessToastId[] = "scanner_action_success";
constexpr char kScannerActionFailureToastId[] = "scanner_action_failure";
FakeScannerProfileScopedDelegate* GetFakeScannerProfileScopedDelegate(
ScannerController& scanner_controller) {
return static_cast<FakeScannerProfileScopedDelegate*>(
scanner_controller.delegate_for_testing()->GetProfileScopedDelegate());
}
class ScannerControllerTest : public AshTestBase {
public:
ScannerControllerTest() = default;
ScannerControllerTest(const ScannerControllerTest&) = delete;
ScannerControllerTest& operator=(const ScannerControllerTest&) = delete;
~ScannerControllerTest() override = default;
private:
base::test::ScopedFeatureList scoped_feature_list_{features::kScannerUpdate};
};
TEST_F(ScannerControllerTest, CanStartSessionIfSystemStateEnabled) {
ScannerController* scanner_controller = Shell::Get()->scanner_controller();
ASSERT_TRUE(scanner_controller);
ON_CALL(*GetFakeScannerProfileScopedDelegate(*scanner_controller),
GetSystemState)
.WillByDefault(Return(
ScannerSystemState(ScannerStatus::kEnabled, /*failed_checks=*/{})));
EXPECT_TRUE(scanner_controller->CanStartSession());
EXPECT_TRUE(scanner_controller->StartNewSession());
}
TEST_F(ScannerControllerTest, CanNotStartSessionIfSystemStateBlocked) {
ScannerController* scanner_controller = Shell::Get()->scanner_controller();
ASSERT_TRUE(scanner_controller);
ON_CALL(*GetFakeScannerProfileScopedDelegate(*scanner_controller),
GetSystemState)
.WillByDefault(Return(
ScannerSystemState(ScannerStatus::kBlocked, /*failed_checks=*/{})));
EXPECT_FALSE(scanner_controller->CanStartSession());
EXPECT_FALSE(scanner_controller->StartNewSession());
}
TEST_F(ScannerControllerTest, FetchesActionsDuringActiveSession) {
base::test::TestFuture<std::vector<ScannerActionViewModel>> actions_future;
ScannerController* scanner_controller = Shell::Get()->scanner_controller();
ASSERT_TRUE(scanner_controller);
EXPECT_TRUE(scanner_controller->StartNewSession());
auto output = std::make_unique<manta::proto::ScannerOutput>();
output->add_objects()->add_actions()->mutable_new_event()->set_title(
"Event title");
EXPECT_CALL(*GetFakeScannerProfileScopedDelegate(*scanner_controller),
FetchActionsForImage)
.WillOnce(RunOnceCallback<1>(std::move(output), manta::MantaStatus()));
scanner_controller->FetchActionsForImage(/*jpeg_bytes=*/nullptr,
actions_future.GetCallback());
EXPECT_THAT(actions_future.Take(), SizeIs(1));
}
TEST_F(ScannerControllerTest, NoActionsFetchedWhenNoActiveSession) {
base::test::TestFuture<std::vector<ScannerActionViewModel>> actions_future;
ScannerController* scanner_controller = Shell::Get()->scanner_controller();
ASSERT_TRUE(scanner_controller);
scanner_controller->FetchActionsForImage(/*jpeg_bytes=*/nullptr,
actions_future.GetCallback());
EXPECT_THAT(actions_future.Take(), IsEmpty());
}
TEST_F(ScannerControllerTest, ResetsScannerSessionWhenActiveUserChanges) {
SimulateUserLogin("user1@gmail.com");
ScannerController* scanner_controller = Shell::Get()->scanner_controller();
ASSERT_TRUE(scanner_controller);
EXPECT_TRUE(scanner_controller->StartNewSession());
EXPECT_TRUE(scanner_controller->HasActiveSessionForTesting());
// Switch to a different user.
SimulateUserLogin("user2@gmail.com");
EXPECT_FALSE(scanner_controller->HasActiveSessionForTesting());
}
TEST_F(ScannerControllerTest, ShowsNotificationWhileExecutingAction) {
base::test::TestFuture<std::vector<ScannerActionViewModel>> actions_future;
ScannerController* scanner_controller = Shell::Get()->scanner_controller();
ASSERT_TRUE(scanner_controller);
EXPECT_TRUE(scanner_controller->StartNewSession());
manta::proto::ScannerOutput output;
output.add_objects()->add_actions()->mutable_new_event()->set_title(
"Event 1");
FakeScannerProfileScopedDelegate& fake_profile_scoped_delegate =
*GetFakeScannerProfileScopedDelegate(*scanner_controller);
EXPECT_CALL(fake_profile_scoped_delegate, FetchActionsForImage)
.WillOnce(RunOnceCallback<1>(
std::make_unique<manta::proto::ScannerOutput>(output),
manta::MantaStatus()));
base::test::TestFuture<manta::ScannerProvider::ScannerProtoResponseCallback>
fetch_action_details_future;
EXPECT_CALL(fake_profile_scoped_delegate, FetchActionDetailsForImage)
.WillOnce(WithArg<2>(InvokeFuture(fetch_action_details_future)));
// Fetch an action and execute it.
scanner_controller->FetchActionsForImage(/*jpeg_bytes=*/nullptr,
actions_future.GetCallback());
std::vector<ScannerActionViewModel> actions = actions_future.Take();
ASSERT_THAT(actions, SizeIs(1));
scanner_controller->ExecuteAction(actions[0]);
// Notification should be shown while action is executing.
EXPECT_THAT(message_center::MessageCenter::Get()->GetVisibleNotifications(),
SizeIs(1));
// Finish executing the action.
fetch_action_details_future.Take().Run(
std::make_unique<manta::proto::ScannerOutput>(output),
manta::MantaStatus());
// Notification should be hidden.
EXPECT_THAT(message_center::MessageCenter::Get()->GetVisibleNotifications(),
IsEmpty());
}
TEST_F(ScannerControllerTest, ShowsToastAfterActionSuccess) {
base::test::TestFuture<std::vector<ScannerActionViewModel>> actions_future;
ScannerController* scanner_controller = Shell::Get()->scanner_controller();
ASSERT_TRUE(scanner_controller);
EXPECT_TRUE(scanner_controller->StartNewSession());
manta::proto::ScannerOutput output;
output.add_objects()
->add_actions()
->mutable_copy_to_clipboard()
->set_html_text("<b>Hello</b>");
FakeScannerProfileScopedDelegate& fake_profile_scoped_delegate =
*GetFakeScannerProfileScopedDelegate(*scanner_controller);
// Mock a successful action.
EXPECT_CALL(fake_profile_scoped_delegate, FetchActionsForImage)
.WillOnce(RunOnceCallback<1>(
std::make_unique<manta::proto::ScannerOutput>(output),
manta::MantaStatus()));
EXPECT_CALL(fake_profile_scoped_delegate, FetchActionDetailsForImage)
.WillOnce(RunOnceCallback<2>(
std::make_unique<manta::proto::ScannerOutput>(output),
manta::MantaStatus{.status_code = manta::MantaStatusCode::kOk}));
// Fetch an action and execute it.
scanner_controller->FetchActionsForImage(/*jpeg_bytes=*/nullptr,
actions_future.GetCallback());
std::vector<ScannerActionViewModel> actions = actions_future.Take();
ASSERT_THAT(actions, SizeIs(1));
scanner_controller->ExecuteAction(actions[0]);
EXPECT_TRUE(ToastManager::Get()->IsToastShown(kScannerActionSuccessToastId));
}
TEST_F(ScannerControllerTest, ShowsToastAfterActionFailure) {
base::test::TestFuture<std::vector<ScannerActionViewModel>> actions_future;
ScannerController* scanner_controller = Shell::Get()->scanner_controller();
ASSERT_TRUE(scanner_controller);
EXPECT_TRUE(scanner_controller->StartNewSession());
auto output = std::make_unique<manta::proto::ScannerOutput>();
output->add_objects()->add_actions()->mutable_new_event()->set_title(
"Event title");
FakeScannerProfileScopedDelegate& fake_profile_scoped_delegate =
*GetFakeScannerProfileScopedDelegate(*scanner_controller);
EXPECT_CALL(fake_profile_scoped_delegate, FetchActionsForImage)
.WillOnce(RunOnceCallback<1>(std::move(output), manta::MantaStatus()));
// Mock a failure to fetch action details.
EXPECT_CALL(fake_profile_scoped_delegate, FetchActionDetailsForImage)
.WillOnce(RunOnceCallback<2>(
/*output=*/nullptr,
manta::MantaStatus{.status_code =
manta::MantaStatusCode::kBackendFailure}));
// Fetch an action and try to execute it.
scanner_controller->FetchActionsForImage(/*jpeg_bytes=*/nullptr,
actions_future.GetCallback());
std::vector<ScannerActionViewModel> actions = actions_future.Take();
ASSERT_THAT(actions, SizeIs(1));
scanner_controller->ExecuteAction(actions[0]);
EXPECT_TRUE(ToastManager::Get()->IsToastShown(kScannerActionFailureToastId));
}
} // namespace
} // namespace ash