blob: ef67939c5c1fe64d582c045f0bf051e866b0f415 [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_tracker_connection.h"
#include <fuchsia/ui/activity/cpp/fidl.h>
#include <memory>
#include "garnet/public/lib/gtest/test_loop_fixture.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 ActivityTrackerConnectionTest : public ::gtest::TestLoopFixture {
public:
ActivityTrackerConnectionTest() : driver_(dispatcher()) {}
void SetUp() override {
conn_ = std::make_unique<ActivityTrackerConnection>(&driver_, dispatcher(),
client_.NewRequest(dispatcher()));
// Some tests rely on subtracting from Now(), so advance to a nonzero time
RunLoopFor(zx::hour(1));
}
protected:
StateMachineDriver driver_;
std::unique_ptr<ActivityTrackerConnection> conn_;
fuchsia::ui::activity::TrackerPtr client_;
};
TEST_F(ActivityTrackerConnectionTest, ReportActivity) {
int callback_invocations = 0;
auto callback = [&callback_invocations]() { callback_invocations++; };
client_->ReportDiscreteActivity(DiscreteActivity(), Now().get(), std::move(callback));
RunLoopUntilIdle();
EXPECT_EQ(driver_.GetState(), fuchsia::ui::activity::State::ACTIVE);
EXPECT_EQ(callback_invocations, 1);
}
TEST_F(ActivityTrackerConnectionTest, ReportActivity_StaleEventIgnored) {
std::optional<zx_status_t> epitaph;
client_.set_error_handler([&epitaph](zx_status_t status) { epitaph = status; });
// Send an event and then let the state machine driver time out (returning to IDLE).
driver_.ReceiveDiscreteActivity(DiscreteActivity(), Now(), []() {});
RunLoopUntilIdle();
auto timeout = driver_.state_machine().TimeoutFor(fuchsia::ui::activity::State::ACTIVE);
ASSERT_NE(timeout, std::nullopt);
RunLoopFor(*timeout);
int callback_invocations = 0;
auto callback = [&callback_invocations]() { callback_invocations++; };
auto old_time = Now() - zx::duration(zx::sec(5));
client_->ReportDiscreteActivity(DiscreteActivity(), old_time.get(), std::move(callback));
RunLoopUntilIdle();
EXPECT_EQ(driver_.GetState(), fuchsia::ui::activity::State::IDLE);
// Make sure no channel errors were received and the callback was invoked
EXPECT_FALSE(epitaph);
EXPECT_EQ(callback_invocations, 1);
}
TEST_F(ActivityTrackerConnectionTest, ReportActivity_OutOfOrder) {
std::optional<zx_status_t> epitaph;
client_.set_error_handler([&epitaph](zx_status_t status) { epitaph = status; });
int callback1_invocations = 0;
auto callback1 = [&callback1_invocations]() { callback1_invocations++; };
client_->ReportDiscreteActivity(DiscreteActivity(), Now().get(), std::move(callback1));
RunLoopUntilIdle();
int callback2_invocations = 0;
auto callback2 = [&callback2_invocations]() { callback2_invocations++; };
auto old_time = Now() - zx::duration(zx::sec(5));
client_->ReportDiscreteActivity(DiscreteActivity(), old_time.get(), std::move(callback2));
RunLoopUntilIdle();
EXPECT_TRUE(epitaph);
EXPECT_EQ(*epitaph, ZX_ERR_OUT_OF_RANGE);
EXPECT_EQ(callback1_invocations, 1);
EXPECT_EQ(callback2_invocations, 0);
}
TEST_F(ActivityTrackerConnectionTest, StartStopOngoingActivity) {
int start_callback_invocations = 0;
auto start_callback = [&start_callback_invocations]() { start_callback_invocations++; };
const OngoingActivityId activity_id = 1234;
client_->StartOngoingActivity(activity_id, OngoingActivity(), Now().get(),
std::move(start_callback));
RunLoopUntilIdle();
EXPECT_EQ(driver_.GetState(), fuchsia::ui::activity::State::ACTIVE);
EXPECT_EQ(start_callback_invocations, 1);
// Timeouts should not be processed
auto timeout = driver_.state_machine().TimeoutFor(fuchsia::ui::activity::State::ACTIVE);
ASSERT_NE(timeout, std::nullopt);
RunLoopFor(*timeout);
EXPECT_EQ(driver_.GetState(), fuchsia::ui::activity::State::ACTIVE);
int end_callback_invocations = 0;
auto end_callback = [&end_callback_invocations]() { end_callback_invocations++; };
client_->EndOngoingActivity(activity_id, Now().get(), std::move(end_callback));
RunLoopUntilIdle();
EXPECT_EQ(driver_.GetState(), fuchsia::ui::activity::State::ACTIVE);
EXPECT_EQ(end_callback_invocations, 1);
// The activity has ended so timeouts should now be respected
RunLoopFor(*timeout);
EXPECT_EQ(driver_.GetState(), fuchsia::ui::activity::State::IDLE);
}
TEST_F(ActivityTrackerConnectionTest, StartOngoingActivity_StaleEventsIgnored) {
std::optional<zx_status_t> epitaph;
client_.set_error_handler([&epitaph](zx_status_t status) { epitaph = status; });
// Send an event and then let the state machine driver time out (returning to IDLE).
driver_.ReceiveDiscreteActivity(DiscreteActivity(), Now(), []() {});
RunLoopUntilIdle();
auto timeout = driver_.state_machine().TimeoutFor(fuchsia::ui::activity::State::ACTIVE);
ASSERT_NE(timeout, std::nullopt);
RunLoopFor(*timeout);
int callback_invocations = 0;
auto callback = [&callback_invocations]() { callback_invocations++; };
auto old_time = Now() - zx::duration(zx::sec(5));
OngoingActivityId id = 1234;
client_->StartOngoingActivity(id, OngoingActivity(), old_time.get(), std::move(callback));
RunLoopUntilIdle();
EXPECT_EQ(driver_.GetState(), fuchsia::ui::activity::State::IDLE);
// Make sure no channel errors were received and the callback was invoked
EXPECT_FALSE(epitaph);
EXPECT_EQ(callback_invocations, 1);
}
TEST_F(ActivityTrackerConnectionTest, StartOngoingActivity_OutOfOrder) {
// Send a discrete activity to bring the state machine to ACTIVE
client_->ReportDiscreteActivity(DiscreteActivity(), Now().get(), []() {});
RunLoopUntilIdle();
EXPECT_EQ(driver_.GetState(), fuchsia::ui::activity::State::ACTIVE);
std::optional<zx_status_t> epitaph;
client_.set_error_handler([&epitaph](zx_status_t status) { epitaph = status; });
auto old_time = Now() - zx::duration(zx::sec(5));
client_->StartOngoingActivity(1234, OngoingActivity(), old_time.get(),
[]() { ASSERT_FALSE("Callback was unexpectedly invoked"); });
RunLoopUntilIdle();
EXPECT_EQ(driver_.GetState(), fuchsia::ui::activity::State::ACTIVE);
ASSERT_TRUE(epitaph);
EXPECT_EQ(*epitaph, ZX_ERR_OUT_OF_RANGE);
// Timeouts should still be processed (no ongoing activity should have started)
auto timeout = driver_.state_machine().TimeoutFor(fuchsia::ui::activity::State::ACTIVE);
ASSERT_NE(timeout, std::nullopt);
RunLoopFor(*timeout);
EXPECT_EQ(driver_.GetState(), fuchsia::ui::activity::State::IDLE);
}
TEST_F(ActivityTrackerConnectionTest, CleansUpOngoingActivitiesOnStop) {
int callback_invocations = 0;
client_->StartOngoingActivity(1234, OngoingActivity(), Now().get(),
[&callback_invocations]() { callback_invocations = true; });
RunLoopUntilIdle();
EXPECT_EQ(driver_.GetState(), fuchsia::ui::activity::State::ACTIVE);
EXPECT_EQ(callback_invocations, 1);
conn_->Stop();
RunLoopUntilIdle();
// Timeouts will now be processed since the activity was cleaned up
auto timeout = driver_.state_machine().TimeoutFor(fuchsia::ui::activity::State::ACTIVE);
ASSERT_NE(timeout, std::nullopt);
RunLoopFor(*timeout);
EXPECT_EQ(driver_.GetState(), fuchsia::ui::activity::State::IDLE);
}
TEST_F(ActivityTrackerConnectionTest, CleansUpOngoingActivitiesOnDestruction) {
int callback_invocations = 0;
client_->StartOngoingActivity(1234, OngoingActivity(), Now().get(),
[&callback_invocations]() { callback_invocations++; });
RunLoopUntilIdle();
EXPECT_EQ(driver_.GetState(), fuchsia::ui::activity::State::ACTIVE);
EXPECT_EQ(callback_invocations, 1);
conn_.reset();
RunLoopUntilIdle();
// Timeouts will now be processed since the activity was cleaned up
auto timeout = driver_.state_machine().TimeoutFor(fuchsia::ui::activity::State::ACTIVE);
ASSERT_NE(timeout, std::nullopt);
RunLoopFor(*timeout);
EXPECT_EQ(driver_.GetState(), fuchsia::ui::activity::State::IDLE);
}
} // namespace activity