blob: a95b9b3ba2580672f397b31196145641a7590dd2 [file] [log] [blame]
// 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 "chromeos/services/assistant/assistant_manager_service_impl.h"
#include <string>
#include <utility>
#include "ash/public/cpp/assistant/controller/assistant_alarm_timer_controller.h"
#include "base/json/json_reader.h"
#include "base/optional.h"
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/values.h"
#include "chromeos/assistant/internal/internal_util.h"
#include "chromeos/assistant/internal/test_support/fake_alarm_timer_manager.h"
#include "chromeos/assistant/internal/test_support/fake_assistant_manager.h"
#include "chromeos/assistant/internal/test_support/fake_assistant_manager_internal.h"
#include "chromeos/dbus/power/fake_power_manager_client.h"
#include "chromeos/services/assistant/assistant_manager_service.h"
#include "chromeos/services/assistant/proxy/libassistant_service_host.h"
#include "chromeos/services/assistant/public/cpp/assistant_service.h"
#include "chromeos/services/assistant/public/cpp/features.h"
#include "chromeos/services/assistant/public/cpp/migration/fake_assistant_manager_service_delegate.h"
#include "chromeos/services/assistant/public/cpp/migration/libassistant_v1_api.h"
#include "chromeos/services/assistant/service_context.h"
#include "chromeos/services/assistant/test_support/fake_libassistant_service.h"
#include "chromeos/services/assistant/test_support/fake_service_context.h"
#include "chromeos/services/assistant/test_support/fully_initialized_assistant_state.h"
#include "chromeos/services/assistant/test_support/mock_assistant_interaction_subscriber.h"
#include "chromeos/services/assistant/test_support/mock_media_manager.h"
#include "chromeos/services/assistant/test_support/scoped_assistant_client.h"
#include "chromeos/services/assistant/test_support/scoped_device_actions.h"
#include "libassistant/shared/internal_api/assistant_manager_internal.h"
#include "libassistant/shared/public/assistant_manager.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/media_session/public/mojom/media_session.mojom-shared.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
namespace assistant {
using media_session::mojom::MediaSessionAction;
using testing::ElementsAre;
using testing::Invoke;
using testing::NiceMock;
using testing::StrictMock;
using CommunicationErrorType = AssistantManagerService::CommunicationErrorType;
using UserInfo = AssistantManagerService::UserInfo;
namespace {
const char* kNoValue = FakeAssistantManager::kNoValue;
#define EXPECT_STATE(_state) \
EXPECT_EQ(_state, assistant_manager_service()->GetState());
// Adds an AlarmTimerEvent of the given |type| to |events|.
static void AddAlarmTimerEvent(
std::vector<assistant_client::AlarmTimerEvent>* events,
assistant_client::AlarmTimerEvent::Type type) {
events->push_back(assistant_client::AlarmTimerEvent());
events->back().type = type;
}
// Adds an AlarmTimerEvent of type TIMER with the given |state| to |events|.
static void AddTimerEvent(
std::vector<assistant_client::AlarmTimerEvent>* events,
assistant_client::Timer::State state) {
AddAlarmTimerEvent(events, assistant_client::AlarmTimerEvent::TIMER);
events->back().timer_data.state = state;
}
// Return the list of all libassistant error codes that are considered to be
// authentication errors. This list is created on demand as there is no clear
// enum that defines these, and we don't want to hard code this list in the
// test.
static std::vector<int> GetAuthenticationErrorCodes() {
const int kMinErrorCode = GetLowestErrorCode();
const int kMaxErrorCode = GetHighestErrorCode();
std::vector<int> result;
for (int code = kMinErrorCode; code <= kMaxErrorCode; ++code) {
if (IsAuthError(code))
result.push_back(code);
}
return result;
}
// Return a list of some libassistant error codes that are not considered to be
// authentication errors. Note we do not return all such codes as there are
// simply too many and testing them all significantly slows down the tests.
static std::vector<int> GetNonAuthenticationErrorCodes() {
return {-99999, 0, 1};
}
// Waits until the AssistantManagerService is in the given state, or until the
// timeout is hit.
class StateWaiter : private AssistantManagerService::StateObserver {
public:
const base::TimeDelta kDefaultTimeout = base::TimeDelta::FromSeconds(5);
explicit StateWaiter(AssistantManagerService* service) : service_(service) {
service_->AddAndFireStateObserver(this);
}
~StateWaiter() override { service_->RemoveStateObserver(this); }
void RunUntilState(AssistantManagerService::State expected_state) {
if (current_state() == expected_state)
return;
expected_state_ = expected_state;
// Ensure we time out after kDefaultTimeout.
base::test::ScopedRunLoopTimeout timeout(FROM_HERE, kDefaultTimeout);
base::RunLoop run_loop;
base::AutoReset<base::OnceClosure> quit_loop(&quit_loop_,
run_loop.QuitClosure());
// And wait until we hit the expected state.
EXPECT_NO_FATAL_FAILURE(run_loop.Run())
<< "Failed waiting for AssistantManagerService::State change."
<< " Expected state " << expected_state_ << " but have "
<< current_state();
}
private:
// StateObserver implementation:
void OnStateChanged(AssistantManagerService::State new_state) override {
if (quit_loop_ && (new_state == expected_state_))
std::move(quit_loop_).Run();
}
AssistantManagerService::State current_state() {
return service_->GetState();
}
AssistantManagerService* const service_;
AssistantManagerService::State expected_state_;
base::OnceClosure quit_loop_;
};
class AssistantAlarmTimerControllerMock
: public ash::AssistantAlarmTimerController {
public:
AssistantAlarmTimerControllerMock() = default;
AssistantAlarmTimerControllerMock(const AssistantAlarmTimerControllerMock&) =
delete;
AssistantAlarmTimerControllerMock& operator=(
const AssistantAlarmTimerControllerMock&) = delete;
~AssistantAlarmTimerControllerMock() override = default;
// ash::AssistantAlarmTimerController:
MOCK_METHOD((const ash::AssistantAlarmTimerModel*),
GetModel,
(),
(const, override));
MOCK_METHOD(void,
OnTimerStateChanged,
(std::vector<ash::AssistantTimerPtr>),
(override));
};
class CommunicationErrorObserverMock
: public AssistantManagerService::CommunicationErrorObserver {
public:
CommunicationErrorObserverMock() = default;
~CommunicationErrorObserverMock() override = default;
MOCK_METHOD(void,
OnCommunicationError,
(AssistantManagerService::CommunicationErrorType error));
private:
DISALLOW_COPY_AND_ASSIGN(CommunicationErrorObserverMock);
};
class FakeLibassistantServiceHost : public LibassistantServiceHost {
public:
explicit FakeLibassistantServiceHost(FakeLibassistantService* service)
: service_(service) {}
void Launch(
mojo::PendingReceiver<LibassistantServiceMojom> receiver) override {
service_->Bind(std::move(receiver));
}
void Stop() override { service_->Unbind(); }
private:
FakeLibassistantService* service_;
};
class StateObserverMock : public AssistantManagerService::StateObserver {
public:
StateObserverMock() = default;
~StateObserverMock() override = default;
MOCK_METHOD(void, OnStateChanged, (AssistantManagerService::State new_state));
private:
DISALLOW_COPY_AND_ASSIGN(StateObserverMock);
};
class AssistantManagerServiceImplTest : public testing::Test {
public:
AssistantManagerServiceImplTest() = default;
~AssistantManagerServiceImplTest() override = default;
void SetUp() override {
PowerManagerClient::InitializeFake();
FakePowerManagerClient::Get()->SetTabletMode(
PowerManagerClient::TabletMode::OFF, base::TimeTicks());
mojo::PendingRemote<device::mojom::BatteryMonitor> battery_monitor;
assistant_client_.RequestBatteryMonitor(
battery_monitor.InitWithNewPipeAndPassReceiver());
shared_url_loader_factory_ =
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&url_loader_factory_);
service_context_ = std::make_unique<FakeServiceContext>();
service_context_
->set_main_task_runner(task_environment.GetMainThreadTaskRunner())
.set_power_manager_client(PowerManagerClient::Get())
.set_assistant_state(&assistant_state_);
CreateAssistantManagerServiceImpl(/*libassistant_config=*/{});
}
void CreateAssistantManagerServiceImpl(
base::Optional<std::string> s3_server_uri_override = base::nullopt) {
// We can not have 2 instances of |AssistantManagerServiceImpl| at the same
// time, so we must destroy the old one before creating a new one.
assistant_manager_service_.reset();
assistant_manager_service_ = std::make_unique<AssistantManagerServiceImpl>(
service_context_.get(),
std::make_unique<FakeAssistantManagerServiceDelegate>(),
shared_url_loader_factory_->Clone(), s3_server_uri_override,
/*device_id_override=*/base::nullopt,
std::make_unique<FakeLibassistantServiceHost>(&libassistant_service_));
}
void TearDown() override {
assistant_manager_service_.reset();
PowerManagerClient::Shutdown();
}
FakeServiceController& mojom_service_controller() {
return libassistant_service_.service_controller();
}
AssistantManagerServiceImpl* assistant_manager_service() {
return assistant_manager_service_.get();
}
ash::AssistantState* assistant_state() { return &assistant_state_; }
FakeAssistantManager* fake_assistant_manager() { return &assistant_manager_; }
FakeAssistantManagerInternal* fake_assistant_manager_internal() {
return &fake_assistant_manager()->assistant_manager_internal();
}
FakeAlarmTimerManager* fake_alarm_timer_manager() {
return static_cast<FakeAlarmTimerManager*>(
fake_assistant_manager_internal()->GetAlarmTimerManager());
}
FakeServiceContext* fake_service_context() { return service_context_.get(); }
action::CrosActionModule* action_module() {
return assistant_manager_service_->action_module_for_testing();
}
void Start() {
assistant_manager_service()->Start(UserInfo("<user-id>", "<access-token>"),
/*enable_hotword=*/false);
}
void RunUntilIdle() { base::RunLoop().RunUntilIdle(); }
// Adds a state observer mock, and add the expectation for the fact that it
// auto-fires the observer.
void AddStateObserver(StateObserverMock* observer) {
EXPECT_CALL(*observer,
OnStateChanged(assistant_manager_service()->GetState()));
assistant_manager_service()->AddAndFireStateObserver(observer);
}
void WaitForState(AssistantManagerService::State expected_state) {
StateWaiter waiter(assistant_manager_service());
waiter.RunUntilState(expected_state);
}
// Raise all the |libassistant_error_codes| as communication errors from
// libassistant, and check that they are reported to our
// |AssistantCommunicationErrorObserver| as errors of type |expected_type|.
void TestCommunicationErrors(const std::vector<int>& libassistant_error_codes,
CommunicationErrorType expected_error) {
Start();
WaitForState(AssistantManagerService::STARTED);
auto* delegate =
fake_assistant_manager_internal()->assistant_manager_delegate();
for (int code : libassistant_error_codes) {
CommunicationErrorObserverMock observer;
assistant_manager_service()->AddCommunicationErrorObserver(&observer);
EXPECT_CALL(observer, OnCommunicationError(expected_error));
delegate->OnCommunicationError(code);
RunUntilIdle();
assistant_manager_service()->RemoveCommunicationErrorObserver(&observer);
ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&observer))
<< "Failure for error code " << code;
}
}
private:
base::test::SingleThreadTaskEnvironment task_environment;
ScopedAssistantClient assistant_client_;
ScopedDeviceActions device_actions_;
FullyInitializedAssistantState assistant_state_;
// Fake implementation of the Libassistant Mojom service.
FakeLibassistantService libassistant_service_;
FakeAssistantManager assistant_manager_;
LibassistantV1Api libassistant_v1_api_{
&assistant_manager_, &assistant_manager_.assistant_manager_internal()};
std::unique_ptr<FakeServiceContext> service_context_;
network::TestURLLoaderFactory url_loader_factory_;
scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
std::unique_ptr<AssistantManagerServiceImpl> assistant_manager_service_;
DISALLOW_COPY_AND_ASSIGN(AssistantManagerServiceImplTest);
};
// Tests if the JSON string contains the given path with the given value
#define EXPECT_HAS_PATH_WITH_VALUE(config_string, path, expected_value) \
({ \
base::Optional<base::Value> config = \
base::JSONReader::Read(config_string); \
ASSERT_TRUE(config.has_value()); \
const base::Value* actual = config->FindPath(path); \
base::Value expected = base::Value(expected_value); \
ASSERT_NE(actual, nullptr) \
<< "Path '" << path << "' not found in config: " << config_string; \
EXPECT_EQ(*actual, expected); \
})
} // namespace
TEST_F(AssistantManagerServiceImplTest, StateShouldStartAsStopped) {
EXPECT_STATE(AssistantManagerService::STOPPED);
}
TEST_F(AssistantManagerServiceImplTest,
StateShouldChangeToStartingAfterCallingStart) {
Start();
EXPECT_STATE(AssistantManagerService::STARTING);
}
TEST_F(AssistantManagerServiceImplTest,
StateShouldRemainStartingUntilLibassistantServiceIsStarted) {
mojom_service_controller().BlockStartCalls();
Start();
WaitForState(AssistantManagerService::STARTING);
mojom_service_controller().UnblockStartCalls();
WaitForState(AssistantManagerService::STARTED);
}
TEST_F(AssistantManagerServiceImplTest,
StateShouldBecomeRunningAfterLibassistantSignalsOnStartFinished) {
NiceMock<AssistantAlarmTimerControllerMock> alarm_timer_controller;
fake_service_context()->set_assistant_alarm_timer_controller(
&alarm_timer_controller);
Start();
WaitForState(AssistantManagerService::STARTED);
fake_assistant_manager()->device_state_listener()->OnStartFinished();
WaitForState(AssistantManagerService::RUNNING);
}
TEST_F(AssistantManagerServiceImplTest, ShouldSetStateToStoppedAfterStopping) {
Start();
WaitForState(AssistantManagerService::STARTED);
assistant_manager_service()->Stop();
WaitForState(AssistantManagerService::STOPPED);
}
TEST_F(AssistantManagerServiceImplTest,
ShouldReportAuthenticationErrorsToCommunicationErrorObservers) {
TestCommunicationErrors(GetAuthenticationErrorCodes(),
CommunicationErrorType::AuthenticationError);
}
TEST_F(AssistantManagerServiceImplTest,
ShouldReportNonAuthenticationErrorsToCommunicationErrorObservers) {
std::vector<int> non_authentication_errors = GetNonAuthenticationErrorCodes();
// check to ensure these are not authentication errors.
for (int code : non_authentication_errors)
ASSERT_FALSE(IsAuthError(code));
// Run the actual unittest
TestCommunicationErrors(non_authentication_errors,
CommunicationErrorType::Other);
}
TEST_F(AssistantManagerServiceImplTest,
ShouldPassUserInfoToAssistantManagerWhenStarting) {
assistant_manager_service()->Start(UserInfo("<user-id>", "<access-token>"),
/*enable_hotword=*/false);
WaitForState(AssistantManagerService::STARTED);
EXPECT_EQ("<user-id>", fake_assistant_manager()->user_id());
EXPECT_EQ("<access-token>", fake_assistant_manager()->access_token());
}
TEST_F(AssistantManagerServiceImplTest, ShouldPassUserInfoToAssistantManager) {
Start();
WaitForState(AssistantManagerService::STARTED);
assistant_manager_service()->SetUser(
UserInfo("<new-user-id>", "<new-access-token>"));
EXPECT_EQ("<new-user-id>", fake_assistant_manager()->user_id());
EXPECT_EQ("<new-access-token>", fake_assistant_manager()->access_token());
}
TEST_F(AssistantManagerServiceImplTest,
ShouldPassEmptyUserInfoToAssistantManager) {
Start();
WaitForState(AssistantManagerService::STARTED);
assistant_manager_service()->SetUser(base::nullopt);
EXPECT_EQ(kNoValue, fake_assistant_manager()->user_id());
EXPECT_EQ(kNoValue, fake_assistant_manager()->access_token());
}
TEST_F(AssistantManagerServiceImplTest,
ShouldNotCrashWhenSettingUserInfoBeforeStartIsFinished) {
EXPECT_STATE(AssistantManagerService::STOPPED);
assistant_manager_service()->SetUser(UserInfo("<user-id>", "<access-token>"));
Start();
EXPECT_STATE(AssistantManagerService::STARTING);
assistant_manager_service()->SetUser(UserInfo("<user-id>", "<access-token>"));
}
TEST_F(AssistantManagerServiceImplTest,
ShouldPassS3ServerUriOverrideToAssistantManager) {
CreateAssistantManagerServiceImpl("the-uri-override");
Start();
WaitForState(AssistantManagerService::STARTED);
EXPECT_HAS_PATH_WITH_VALUE(mojom_service_controller().libassistant_config(),
"testing.s3_grpc_server_uri", "the-uri-override");
}
TEST_F(AssistantManagerServiceImplTest, ShouldPauseMediaManagerOnPause) {
StrictMock<MockMediaManager> mock;
fake_assistant_manager()->SetMediaManager(&mock);
Start();
WaitForState(AssistantManagerService::STARTED);
EXPECT_CALL(mock, Pause);
assistant_manager_service()->UpdateInternalMediaPlayerStatus(
MediaSessionAction::kPause);
}
TEST_F(AssistantManagerServiceImplTest, ShouldResumeMediaManagerOnPlay) {
StrictMock<MockMediaManager> mock;
fake_assistant_manager()->SetMediaManager(&mock);
Start();
WaitForState(AssistantManagerService::STARTED);
EXPECT_CALL(mock, Resume);
assistant_manager_service()->UpdateInternalMediaPlayerStatus(
MediaSessionAction::kPlay);
}
TEST_F(AssistantManagerServiceImplTest, ShouldIgnoreOtherMediaManagerActions) {
const auto unsupported_media_session_actions = {
MediaSessionAction::kPreviousTrack, MediaSessionAction::kNextTrack,
MediaSessionAction::kSeekBackward, MediaSessionAction::kSeekForward,
MediaSessionAction::kSkipAd, MediaSessionAction::kStop,
MediaSessionAction::kSeekTo, MediaSessionAction::kScrubTo,
};
StrictMock<MockMediaManager> mock;
fake_assistant_manager()->SetMediaManager(&mock);
Start();
WaitForState(AssistantManagerService::STARTED);
for (auto action : unsupported_media_session_actions) {
// If this is not ignored, |mock| will complain about an uninterested call.
assistant_manager_service()->UpdateInternalMediaPlayerStatus(action);
}
}
TEST_F(AssistantManagerServiceImplTest,
ShouldNotCrashWhenMediaManagerIsAbsent) {
Start();
WaitForState(AssistantManagerService::STARTED);
assistant_manager_service()->UpdateInternalMediaPlayerStatus(
media_session::mojom::MediaSessionAction::kPlay);
}
TEST_F(AssistantManagerServiceImplTest, ShouldFireStateObserverWhenAddingIt) {
StrictMock<StateObserverMock> observer;
EXPECT_CALL(observer,
OnStateChanged(AssistantManagerService::State::STOPPED));
assistant_manager_service()->AddAndFireStateObserver(&observer);
assistant_manager_service()->RemoveStateObserver(&observer);
}
TEST_F(AssistantManagerServiceImplTest, ShouldFireStateObserverWhenStarting) {
StrictMock<StateObserverMock> observer;
AddStateObserver(&observer);
fake_assistant_manager()->BlockStartCalls();
EXPECT_CALL(observer,
OnStateChanged(AssistantManagerService::State::STARTING));
Start();
assistant_manager_service()->RemoveStateObserver(&observer);
fake_assistant_manager()->UnblockStartCalls();
}
TEST_F(AssistantManagerServiceImplTest, ShouldFireStateObserverWhenStarted) {
StrictMock<StateObserverMock> observer;
AddStateObserver(&observer);
EXPECT_CALL(observer,
OnStateChanged(AssistantManagerService::State::STARTING));
EXPECT_CALL(observer,
OnStateChanged(AssistantManagerService::State::STARTED));
Start();
WaitForState(AssistantManagerService::STARTED);
assistant_manager_service()->RemoveStateObserver(&observer);
}
TEST_F(AssistantManagerServiceImplTest,
ShouldFireStateObserverWhenLibAssistantSignalsOnStartFinished) {
NiceMock<AssistantAlarmTimerControllerMock> alarm_timer_controller;
fake_service_context()->set_assistant_alarm_timer_controller(
&alarm_timer_controller);
Start();
WaitForState(AssistantManagerService::STARTED);
StrictMock<StateObserverMock> observer;
AddStateObserver(&observer);
EXPECT_CALL(observer,
OnStateChanged(AssistantManagerService::State::RUNNING));
fake_assistant_manager()->device_state_listener()->OnStartFinished();
assistant_manager_service()->RemoveStateObserver(&observer);
}
TEST_F(AssistantManagerServiceImplTest, ShouldFireStateObserverWhenStopping) {
Start();
WaitForState(AssistantManagerService::STARTED);
StrictMock<StateObserverMock> observer;
AddStateObserver(&observer);
EXPECT_CALL(observer,
OnStateChanged(AssistantManagerService::State::STOPPED));
assistant_manager_service()->Stop();
assistant_manager_service()->RemoveStateObserver(&observer);
}
TEST_F(AssistantManagerServiceImplTest,
ShouldNotFireStateObserverAfterItIsRemoved) {
StrictMock<StateObserverMock> observer;
AddStateObserver(&observer);
assistant_manager_service()->RemoveStateObserver(&observer);
EXPECT_CALL(observer, OnStateChanged).Times(0);
Start();
}
TEST_F(AssistantManagerServiceImplTest,
ShouldUpdateActionModuleWhenAmbientModeStateChanged) {
EXPECT_FALSE(action_module()->IsAmbientModeEnabledForTesting());
assistant_manager_service()->EnableAmbientMode(true);
EXPECT_TRUE(action_module()->IsAmbientModeEnabledForTesting());
assistant_manager_service()->EnableAmbientMode(false);
EXPECT_FALSE(action_module()->IsAmbientModeEnabledForTesting());
}
TEST_F(AssistantManagerServiceImplTest,
ShouldNotifyAlarmTimerControllerOfOnlyRingingTimersInV1) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndDisableFeature(features::kAssistantTimersV2);
Start();
WaitForState(AssistantManagerService::STARTED);
assistant_manager_service()->OnStartFinished();
StrictMock<AssistantAlarmTimerControllerMock> alarm_timer_controller;
fake_service_context()->set_assistant_alarm_timer_controller(
&alarm_timer_controller);
EXPECT_CALL(alarm_timer_controller, OnTimerStateChanged)
.WillOnce(Invoke([](auto timers) {
ASSERT_EQ(1u, timers.size());
EXPECT_EQ(ash::AssistantTimerState::kFired, timers[0]->state);
}));
std::vector<assistant_client::AlarmTimerEvent> events;
// Ignore NONE, ALARMs, and SCHEDULED/PAUSED timers.
AddAlarmTimerEvent(&events, assistant_client::AlarmTimerEvent::Type::NONE);
AddAlarmTimerEvent(&events, assistant_client::AlarmTimerEvent::Type::ALARM);
AddTimerEvent(&events, assistant_client::Timer::State::SCHEDULED);
AddTimerEvent(&events, assistant_client::Timer::State::PAUSED);
// Accept FIRED timers.
AddTimerEvent(&events, assistant_client::Timer::State::FIRED);
fake_alarm_timer_manager()->SetAllEvents(std::move(events));
fake_alarm_timer_manager()->NotifyRingingStateListeners();
base::RunLoop().RunUntilIdle();
}
TEST_F(AssistantManagerServiceImplTest,
ShouldNotifyAlarmTimerControllerOfAnyTimersInV2) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kAssistantTimersV2);
StrictMock<AssistantAlarmTimerControllerMock> alarm_timer_controller;
fake_service_context()->set_assistant_alarm_timer_controller(
&alarm_timer_controller);
// We expect OnTimerStateChanged() to be invoked when starting LibAssistant.
EXPECT_CALL(alarm_timer_controller, OnTimerStateChanged).Times(1);
Start();
WaitForState(AssistantManagerService::STARTED);
assistant_manager_service()->OnStartFinished();
testing::Mock::VerifyAndClearExpectations(&alarm_timer_controller);
EXPECT_CALL(alarm_timer_controller, OnTimerStateChanged)
.WillOnce(Invoke([](auto timers) {
ASSERT_EQ(3u, timers.size());
EXPECT_EQ(ash::AssistantTimerState::kScheduled, timers[0]->state);
EXPECT_EQ(ash::AssistantTimerState::kPaused, timers[1]->state);
EXPECT_EQ(ash::AssistantTimerState::kFired, timers[2]->state);
}));
std::vector<assistant_client::AlarmTimerEvent> events;
// Ignore NONE and ALARMs.
AddAlarmTimerEvent(&events, assistant_client::AlarmTimerEvent::Type::NONE);
AddAlarmTimerEvent(&events, assistant_client::AlarmTimerEvent::Type::ALARM);
// Accept SCHEDULED/PAUSED/FIRED timers.
AddTimerEvent(&events, assistant_client::Timer::State::SCHEDULED);
AddTimerEvent(&events, assistant_client::Timer::State::PAUSED);
AddTimerEvent(&events, assistant_client::Timer::State::FIRED);
fake_alarm_timer_manager()->SetAllEvents(std::move(events));
fake_alarm_timer_manager()->NotifyRingingStateListeners();
base::RunLoop().RunUntilIdle();
}
TEST_F(AssistantManagerServiceImplTest,
ShouldNotifyAlarmTimerControllerOfTimersWhenStartingLibAssistantInV2) {
// Enable timers V2.
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kAssistantTimersV2);
// Pre-populate the AlarmTimerManager with a single scheduled timer.
std::vector<assistant_client::AlarmTimerEvent> events;
AddTimerEvent(&events, assistant_client::Timer::State::SCHEDULED);
fake_alarm_timer_manager()->SetAllEvents(std::move(events));
// Bind AssistantAlarmTimerController.
StrictMock<AssistantAlarmTimerControllerMock> alarm_timer_controller;
fake_service_context()->set_assistant_alarm_timer_controller(
&alarm_timer_controller);
// Expect |timers| to be sent to AssistantAlarmTimerController. Verify
// AssistantAlarmTimerController is notified of the scheduled timer.
EXPECT_CALL(alarm_timer_controller, OnTimerStateChanged)
.WillOnce(Invoke([](auto timers) {
ASSERT_EQ(1u, timers.size());
EXPECT_EQ(ash::AssistantTimerState::kScheduled, timers[0]->state);
}));
// Start LibAssistant.
Start();
WaitForState(AssistantManagerService::STARTED);
assistant_manager_service()->OnStartFinished();
}
} // namespace assistant
} // namespace chromeos