blob: eba2ff8912b7a8712293d2391d1f29f69422f622 [file] [log] [blame] [edit]
// Copyright 2023 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.
#ifndef LIB_DRIVER_TESTING_CPP_DRIVER_LIFECYCLE_H_
#define LIB_DRIVER_TESTING_CPP_DRIVER_LIFECYCLE_H_
#include <lib/driver/component/cpp/driver_base.h>
#include <lib/driver/runtime/testing/cpp/dispatcher.h>
#include <lib/driver/symbols/symbols.h>
// This is the exported driver lifecycle symbol that the driver framework looks for.
// NOLINTNEXTLINE(bugprone-reserved-identifier)
extern "C" const DriverLifecycle __fuchsia_driver_lifecycle__;
namespace fdf_testing {
using OpaqueDriverPtr = void*;
// The |DriverUnderTest| is a templated class so we pull out the non-template specifics into this
// base class so we don't have to put the implementation in the header.
class DriverUnderTestBase {
public:
explicit DriverUnderTestBase(
fdf_dispatcher_t* driver_dispatcher = nullptr,
const DriverLifecycle& driver_lifecycle_symbol = __fuchsia_driver_lifecycle__);
~DriverUnderTestBase();
zx::result<std::shared_ptr<libsync::Completion>> Start(fdf::DriverStartArgs start_args);
zx::result<std::shared_ptr<libsync::Completion>> StartWithErrorHandler(
fdf::DriverStartArgs start_args, fit::callback<void(zx_status_t error)> error_handler);
std::shared_ptr<libsync::Completion> PrepareStop();
std::shared_ptr<libsync::Completion> PrepareStopWithErrorHandler(
fit::callback<void(zx_status_t error)> error_handler);
zx::result<> Stop();
protected:
async::synchronization_checker& checker() { return checker_; }
std::optional<OpaqueDriverPtr>& driver() { return driver_; }
private:
fdf_dispatcher_t* driver_dispatcher_;
const DriverLifecycle& driver_lifecycle_symbol_;
async::synchronization_checker checker_;
std::optional<OpaqueDriverPtr> driver_ __TA_GUARDED(checker_);
std::shared_ptr<libsync::Completion> prepare_stop_completer_ __TA_GUARDED(checker_);
};
// This is a RAII wrapper over a driver under test. On destruction, it will stop the driver.
// # Thread safety
//
// This class is thread-unsafe. Instances must be managed and used from a synchronized dispatcher.
// See
// https://fuchsia.dev/fuchsia-src/development/languages/c-cpp/thread-safe-async#synchronized-dispatcher
//
template <typename Driver>
class DriverUnderTest : public DriverUnderTestBase {
public:
Driver* operator->() {
std::lock_guard guard(checker());
ZX_ASSERT_MSG(driver().has_value(), "Driver does not exist.");
return static_cast<Driver*>(driver().value());
}
Driver* operator*() {
std::lock_guard guard(checker());
ZX_ASSERT_MSG(driver().has_value(), "Driver does not exist.");
return static_cast<Driver*>(driver().value());
}
};
// Start a driver using the DriverLifecycle symbol's start hook. This is optional to use, the test
// can also construct and start the driver on its own if it wants to do so.
//
// This MUST be called from the main test thread.
zx::result<OpaqueDriverPtr> StartDriver(
fdf::DriverStartArgs start_args, fdf::TestSynchronizedDispatcher& driver_dispatcher,
const DriverLifecycle& driver_lifecycle_symbol = __fuchsia_driver_lifecycle__);
// Templated version of |StartDriver| which will return the requested driver type.
template <typename Driver>
zx::result<Driver*> StartDriver(
fdf::DriverStartArgs start_args, fdf::TestSynchronizedDispatcher& driver_dispatcher,
const DriverLifecycle& driver_lifecycle_symbol = __fuchsia_driver_lifecycle__) {
zx::result result =
StartDriver(std::move(start_args), driver_dispatcher, driver_lifecycle_symbol);
if (result.is_error()) {
return result.take_error();
}
return zx::ok(static_cast<Driver*>(result.value()));
}
// Initiates the teardown of the driver and the driver dispatcher. Teardown consist of using the
// prepare_stop hook, waiting for the completion, and calling the stop lifecycle hook.
//
// This MUST be called from the main test thread.
zx::result<> TeardownDriver(
OpaqueDriverPtr driver, fdf::TestSynchronizedDispatcher& driver_dispatcher,
const DriverLifecycle& driver_lifecycle_symbol = __fuchsia_driver_lifecycle__);
} // namespace fdf_testing
#endif // LIB_DRIVER_TESTING_CPP_DRIVER_LIFECYCLE_H_