blob: b9201b4a80748b26663b3a8b94e3ba39c5aa818d [file] [log] [blame]
// Copyright 2024 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/devices/bin/driver_manager/bootup_tracker.h"
#include "src/devices/bin/driver_manager/tests/bind_manager_test_base.h"
class TestBootupTracker : public driver_manager::BootupTracker {
public:
TestBootupTracker(driver_manager::BindManager* manager, async_dispatcher_t* dispatcher)
: driver_manager::BootupTracker(manager, dispatcher) {}
void ResetBootupTimer() override {}
virtual bool IsUpdateDeadlineExceeded() const override { return should_exceed_update_deadline; }
void TimeoutBootup() { OnBootupTimeout(); }
bool should_exceed_update_deadline = false;
};
class BootupTrackerTest : public BindManagerTestBase {
public:
void SetUp() override {
BindManagerTestBase::SetUp();
tracker = std::make_unique<TestBootupTracker>(bind_manager(), dispatcher());
tracker->Start();
}
void TriggerBootupTimeout() {
tracker->TimeoutBootup();
RunLoopUntilIdle();
}
void WaitForBootup() {
tracker->WaitForBootup([this]() { bootup_completed_ = true; });
}
bool bootup_completed() const { return bootup_completed_; }
protected:
std::unique_ptr<TestBootupTracker> tracker;
private:
bool bootup_completed_ = false;
};
TEST_F(BootupTrackerTest, NoDrivers) {
WaitForBootup();
TriggerBootupTimeout();
EXPECT_TRUE(bootup_completed());
}
TEST_F(BootupTrackerTest, StartRequestsOnly) {
WaitForBootup();
tracker->NotifyNewStartRequest("node_1", "driver_url");
TriggerBootupTimeout();
EXPECT_FALSE(bootup_completed());
tracker->NotifyNewStartRequest("node_2", "driver_url");
tracker->NotifyStartComplete("node_1");
TriggerBootupTimeout();
EXPECT_FALSE(bootup_completed());
tracker->NotifyStartComplete("node_2");
TriggerBootupTimeout();
EXPECT_TRUE(bootup_completed());
}
TEST_F(BootupTrackerTest, StartAndBindRequests) {
WaitForBootup();
// Invoke bind for a new node in the bind manager.
AddAndBindNode_EXPECT_BIND_START("node-a");
VerifyBindOngoingWithRequests({{"node-a", 1}});
// Bootup shouldn't be complete with an ongoing bind process.
TriggerBootupTimeout();
EXPECT_FALSE(bootup_completed());
// Add a new start request for node_1.
tracker->NotifyNewStartRequest("node_1", "driver_url");
TriggerBootupTimeout();
EXPECT_FALSE(bootup_completed());
// Add a new start request for node_2 and complete node_1.
tracker->NotifyNewStartRequest("node_2", "driver_url");
tracker->NotifyStartComplete("node_1");
TriggerBootupTimeout();
EXPECT_FALSE(bootup_completed());
// Complete node_2.
tracker->NotifyStartComplete("node_2");
TriggerBootupTimeout();
EXPECT_FALSE(bootup_completed());
// Complete the ongoing bind. Bootup should be complete.
DriverIndexReplyWithDriver("node-a");
VerifyNoOngoingBind();
TriggerBootupTimeout();
EXPECT_TRUE(bootup_completed());
}
TEST_F(BootupTrackerTest, OverlappingBindRequests) {
WaitForBootup();
AddAndOrphanNode("node-a");
AddAndOrphanNode("node-b");
// Invoke TryBindAllAvailable().
InvokeTryBindAllAvailable_EXPECT_BIND_START();
VerifyBindOngoingWithRequests({{"node-a", 1}, {"node-b", 1}});
TriggerBootupTimeout();
EXPECT_FALSE(bootup_completed());
AddAndBindNode_EXPECT_QUEUED("node-c");
TriggerBootupTimeout();
EXPECT_FALSE(bootup_completed());
// Complete the ongoing bind. This should kickstart another ongoing bind.
DriverIndexReplyWithDriver("node-b");
DriverIndexReplyWithDriver("node-a");
VerifyBindOngoingWithRequests({{"node-c", 1}});
TriggerBootupTimeout();
EXPECT_FALSE(bootup_completed());
// Complete the ongoing bind. Bootup should be complete.
DriverIndexReplyWithDriver("node-c");
VerifyNoOngoingBind();
TriggerBootupTimeout();
EXPECT_TRUE(bootup_completed());
}
TEST_F(BootupTrackerTest, WaitForBootupAfterComplete) {
tracker->NotifyNewStartRequest("node_1", "driver_url");
tracker->NotifyStartComplete("node_1");
TriggerBootupTimeout();
// If bootup already completed. then the wait call should immediately succeed.
WaitForBootup();
RunLoopUntilIdle();
EXPECT_TRUE(bootup_completed());
}