blob: c889ee1e7c31ade1c6154f5ec0c8a54110b8a1b9 [file] [log] [blame]
// Copyright 2019 The Fuchsia 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 "src/sys/activity/activity_app.h"
#include <fuchsia/ui/activity/control/cpp/fidl.h>
#include <fuchsia/ui/activity/cpp/fidl.h>
#include <memory>
#include "garnet/public/lib/gtest/test_loop_fixture.h"
#include "src/sys/activity/fake_listener.h"
#include "src/sys/activity/state_machine_driver.h"
namespace {
fuchsia::ui::activity::DiscreteActivity DiscreteActivity() {
fuchsia::ui::activity::GenericActivity generic;
fuchsia::ui::activity::DiscreteActivity activity;
activity.set_generic(std::move(generic));
return activity;
};
fuchsia::ui::activity::OngoingActivity OngoingActivity() {
fuchsia::ui::activity::GenericActivity generic;
fuchsia::ui::activity::OngoingActivity activity;
activity.set_generic(std::move(generic));
return activity;
};
} // namespace
namespace activity {
class ActivityAppTest : public ::gtest::TestLoopFixture {
public:
ActivityAppTest() = default;
void SetUp() override {
auto driver = std::make_unique<StateMachineDriver>(dispatcher());
driver_ = driver.get();
app_ = std::make_unique<ActivityApp>(std::move(driver), dispatcher());
}
protected:
std::unique_ptr<ActivityApp> app_;
const StateMachineDriver* driver_;
};
namespace {
TEST_F(ActivityAppTest, Tracker_ConnectDisconnect) {
{
fuchsia::ui::activity::TrackerPtr tracker;
app_->AddTrackerBinding(tracker.NewRequest(dispatcher()));
}
RunLoopUntilIdle();
EXPECT_EQ(app_->tracker_bindings().size(), 0u);
}
TEST_F(ActivityAppTest, Tracker_Multiple_ConnectDisconnect) {
{
fuchsia::ui::activity::TrackerPtr tracker1, tracker2;
app_->AddTrackerBinding(tracker1.NewRequest(dispatcher()));
app_->AddTrackerBinding(tracker2.NewRequest(dispatcher()));
RunLoopUntilIdle();
EXPECT_EQ(app_->tracker_bindings().size(), 2u);
}
RunLoopUntilIdle();
EXPECT_EQ(app_->tracker_bindings().size(), 0u);
}
TEST_F(ActivityAppTest, Tracker_SendActivity) {
fuchsia::ui::activity::TrackerPtr tracker;
app_->AddTrackerBinding(tracker.NewRequest(dispatcher()));
ASSERT_EQ(driver_->GetState(), fuchsia::ui::activity::State::IDLE);
int callback_invocations = 0;
tracker->ReportDiscreteActivity(DiscreteActivity(), Now().get(),
[&callback_invocations]() { callback_invocations++; });
RunLoopUntilIdle();
EXPECT_EQ(driver_->GetState(), fuchsia::ui::activity::State::ACTIVE);
EXPECT_EQ(callback_invocations, 1);
}
TEST_F(ActivityAppTest, Tracker_OngoingActivity) {
fuchsia::ui::activity::TrackerPtr tracker;
app_->AddTrackerBinding(tracker.NewRequest(dispatcher()));
ASSERT_EQ(driver_->GetState(), fuchsia::ui::activity::State::IDLE);
OngoingActivityId id = 1234;
int start_callback_invocations = 0;
tracker->StartOngoingActivity(id, OngoingActivity(), Now().get(),
[&start_callback_invocations]() { start_callback_invocations++; });
RunLoopUntilIdle();
EXPECT_EQ(driver_->GetState(), fuchsia::ui::activity::State::ACTIVE);
EXPECT_EQ(start_callback_invocations, 1);
auto timeout = driver_->state_machine().TimeoutFor(fuchsia::ui::activity::State::ACTIVE);
ASSERT_NE(timeout, std::nullopt);
RunLoopFor(*timeout);
// No state change expected after timeout since there is an ongoing activity
EXPECT_EQ(driver_->GetState(), fuchsia::ui::activity::State::ACTIVE);
int end_callback_invocations = 0;
tracker->EndOngoingActivity(id, Now().get(),
[&end_callback_invocations]() { end_callback_invocations++; });
RunLoopFor(*timeout);
EXPECT_EQ(driver_->GetState(), fuchsia::ui::activity::State::IDLE);
EXPECT_EQ(end_callback_invocations, 1);
}
TEST_F(ActivityAppTest, Provider_ConnectDisconnect) {
{
fuchsia::ui::activity::ProviderPtr provider;
app_->AddProviderBinding(provider.NewRequest(dispatcher()));
testing::FakeListener listener;
provider->WatchState(listener.NewHandle(dispatcher()));
}
RunLoopUntilIdle();
EXPECT_EQ(app_->provider_bindings().size(), 0u);
}
TEST_F(ActivityAppTest, Provider_ReceivesInitialState) {
fuchsia::ui::activity::ProviderPtr provider;
app_->AddProviderBinding(provider.NewRequest(dispatcher()));
testing::FakeListener listener;
provider->WatchState(listener.NewHandle(dispatcher()));
RunLoopUntilIdle();
EXPECT_EQ(listener.StateChanges().size(), 1u);
EXPECT_EQ(listener.StateChanges().front().state, fuchsia::ui::activity::State::IDLE);
}
TEST_F(ActivityAppTest, Provider_ReceivesSubsequentStates) {
fuchsia::ui::activity::ProviderPtr provider;
app_->AddProviderBinding(provider.NewRequest(dispatcher()));
fuchsia::ui::activity::TrackerPtr tracker;
app_->AddTrackerBinding(tracker.NewRequest(dispatcher()));
testing::FakeListener listener;
provider->WatchState(listener.NewHandle(dispatcher()));
RunLoopUntilIdle();
int callback_invocations = 0;
tracker->ReportDiscreteActivity(DiscreteActivity(), Now().get(),
[&callback_invocations]() { callback_invocations++; });
auto timeout = driver_->state_machine().TimeoutFor(fuchsia::ui::activity::State::ACTIVE);
ASSERT_NE(timeout, std::nullopt);
RunLoopFor(*timeout);
ASSERT_EQ(callback_invocations, 1);
ASSERT_EQ(listener.StateChanges().size(), 3u);
EXPECT_EQ(listener.StateChanges()[0].state, fuchsia::ui::activity::State::IDLE);
EXPECT_EQ(listener.StateChanges()[1].state, fuchsia::ui::activity::State::ACTIVE);
EXPECT_EQ(listener.StateChanges()[2].state, fuchsia::ui::activity::State::IDLE);
}
TEST_F(ActivityAppTest, Provider_MultipleProviders_ConnectDisconnect) {
{
fuchsia::ui::activity::ProviderPtr provider1, provider2;
app_->AddProviderBinding(provider1.NewRequest(dispatcher()));
app_->AddProviderBinding(provider2.NewRequest(dispatcher()));
testing::FakeListener listener1, listener2;
provider1->WatchState(listener1.NewHandle(dispatcher()));
provider2->WatchState(listener2.NewHandle(dispatcher()));
RunLoopUntilIdle();
EXPECT_EQ(app_->provider_bindings().size(), 2u);
}
RunLoopUntilIdle();
EXPECT_EQ(app_->provider_bindings().size(), 0u);
}
TEST_F(ActivityAppTest, Provider_MultipleProviders_AllReceiveState) {
fuchsia::ui::activity::ProviderPtr provider1, provider2;
app_->AddProviderBinding(provider1.NewRequest(dispatcher()));
app_->AddProviderBinding(provider2.NewRequest(dispatcher()));
fuchsia::ui::activity::TrackerPtr tracker;
app_->AddTrackerBinding(tracker.NewRequest(dispatcher()));
testing::FakeListener listener1, listener2;
provider1->WatchState(listener1.NewHandle(dispatcher()));
provider2->WatchState(listener2.NewHandle(dispatcher()));
RunLoopUntilIdle();
int callback_invocations = 0;
tracker->ReportDiscreteActivity(DiscreteActivity(), Now().get(),
[&callback_invocations]() { callback_invocations++; });
auto timeout = driver_->state_machine().TimeoutFor(fuchsia::ui::activity::State::ACTIVE);
ASSERT_NE(timeout, std::nullopt);
RunLoopFor(*timeout);
ASSERT_EQ(callback_invocations, 1);
ASSERT_EQ(listener1.StateChanges().size(), 3u);
EXPECT_EQ(listener1.StateChanges()[0].state, fuchsia::ui::activity::State::IDLE);
EXPECT_EQ(listener1.StateChanges()[1].state, fuchsia::ui::activity::State::ACTIVE);
EXPECT_EQ(listener1.StateChanges()[2].state, fuchsia::ui::activity::State::IDLE);
ASSERT_EQ(listener2.StateChanges().size(), 3u);
EXPECT_EQ(listener2.StateChanges()[0].state, fuchsia::ui::activity::State::IDLE);
EXPECT_EQ(listener2.StateChanges()[1].state, fuchsia::ui::activity::State::ACTIVE);
EXPECT_EQ(listener2.StateChanges()[2].state, fuchsia::ui::activity::State::IDLE);
}
TEST_F(ActivityAppTest, Control_OverrideState) {
fuchsia::ui::activity::ProviderPtr provider1, provider2;
app_->AddProviderBinding(provider1.NewRequest(dispatcher()));
app_->AddProviderBinding(provider2.NewRequest(dispatcher()));
fuchsia::ui::activity::control::ControlPtr control;
app_->AddControlBinding(control.NewRequest(dispatcher()));
testing::FakeListener listener1, listener2;
provider1->WatchState(listener1.NewHandle(dispatcher()));
provider2->WatchState(listener2.NewHandle(dispatcher()));
RunLoopUntilIdle();
control->SetState(fuchsia::ui::activity::State::ACTIVE);
RunLoopUntilIdle();
ASSERT_EQ(listener1.StateChanges().size(), 2u);
EXPECT_EQ(listener1.StateChanges()[0].state, fuchsia::ui::activity::State::IDLE);
EXPECT_EQ(listener1.StateChanges()[1].state, fuchsia::ui::activity::State::ACTIVE);
ASSERT_EQ(listener2.StateChanges().size(), 2u);
EXPECT_EQ(listener2.StateChanges()[0].state, fuchsia::ui::activity::State::IDLE);
EXPECT_EQ(listener2.StateChanges()[1].state, fuchsia::ui::activity::State::ACTIVE);
auto timeout = driver_->state_machine().TimeoutFor(fuchsia::ui::activity::State::ACTIVE);
ASSERT_NE(timeout, std::nullopt);
RunLoopFor(*timeout);
// Timeouts do not trigger notification since the override state is set
EXPECT_EQ(listener1.StateChanges().size(), 2u);
EXPECT_EQ(listener2.StateChanges().size(), 2u);
control->SetState(fuchsia::ui::activity::State::IDLE);
RunLoopUntilIdle();
ASSERT_EQ(listener1.StateChanges().size(), 3u);
EXPECT_EQ(listener1.StateChanges()[0].state, fuchsia::ui::activity::State::IDLE);
EXPECT_EQ(listener1.StateChanges()[1].state, fuchsia::ui::activity::State::ACTIVE);
EXPECT_EQ(listener1.StateChanges()[2].state, fuchsia::ui::activity::State::IDLE);
ASSERT_EQ(listener2.StateChanges().size(), 3u);
EXPECT_EQ(listener2.StateChanges()[0].state, fuchsia::ui::activity::State::IDLE);
EXPECT_EQ(listener2.StateChanges()[1].state, fuchsia::ui::activity::State::ACTIVE);
EXPECT_EQ(listener2.StateChanges()[2].state, fuchsia::ui::activity::State::IDLE);
}
TEST_F(ActivityAppTest, Control_OverrideState_TrackerInputsNotSentToListeners) {
fuchsia::ui::activity::ProviderPtr provider;
app_->AddProviderBinding(provider.NewRequest(dispatcher()));
fuchsia::ui::activity::control::ControlPtr control;
app_->AddControlBinding(control.NewRequest(dispatcher()));
fuchsia::ui::activity::TrackerPtr tracker;
app_->AddTrackerBinding(tracker.NewRequest(dispatcher()));
testing::FakeListener listener;
provider->WatchState(listener.NewHandle(dispatcher()));
RunLoopUntilIdle();
control->SetState(fuchsia::ui::activity::State::ACTIVE);
RunLoopUntilIdle();
ASSERT_EQ(listener.StateChanges().size(), 2u);
EXPECT_EQ(listener.StateChanges()[0].state, fuchsia::ui::activity::State::IDLE);
EXPECT_EQ(listener.StateChanges()[1].state, fuchsia::ui::activity::State::ACTIVE);
int callback_invocations = 0;
tracker->ReportDiscreteActivity(DiscreteActivity(), Now().get(),
[&callback_invocations]() { callback_invocations++; });
RunLoopUntilIdle();
// No additional transitions
EXPECT_EQ(listener.StateChanges().size(), 2u);
// Callback still invoked
EXPECT_EQ(callback_invocations, 1);
auto timeout = driver_->state_machine().TimeoutFor(fuchsia::ui::activity::State::ACTIVE);
ASSERT_NE(timeout, std::nullopt);
RunLoopFor(*timeout);
// No additional transitions
EXPECT_EQ(listener.StateChanges().size(), 2u);
}
} // namespace
} // namespace activity