blob: f74a35cec2a85149f8cdb16c041e7101d8e52d86 [file] [log] [blame]
// Copyright 2021 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 SRC_DEVICES_BIN_DRIVER_RUNTIME_RUNTIME_TEST_CASE_H_
#define SRC_DEVICES_BIN_DRIVER_RUNTIME_RUNTIME_TEST_CASE_H_
#include <lib/fdf/arena.h>
#include <lib/fdf/cpp/channel_read.h>
#include <lib/fdf/dispatcher.h>
#include <lib/fdf/types.h>
#include <lib/sync/completion.h>
#include <lib/sync/cpp/completion.h>
#include <lib/zx/event.h>
#include <zxtest/zxtest.h>
class RuntimeTestCase : public zxtest::Test {
public:
// Registers a wait_async request on |ch| and signals |completion| once it
// is ready for reading.
static void SignalOnChannelReadable(fdf_handle_t ch, fdf_dispatcher_t* dispatcher,
sync_completion_t* completion);
// Registers a wait_async request on |ch| and blocks until it is ready for reading.
static void WaitUntilReadReady(fdf_handle_t ch, fdf_dispatcher_t* dispatcher);
// Reads a message from |ch| and asserts that it matches the wanted parameters.
// If |out_arena| is provided, it will be populated with the transferred arena.
static void AssertRead(fdf_handle_t ch, void* want_data, size_t want_num_bytes,
zx_handle_t* want_handles, uint32_t want_num_handles,
fdf_arena_t** out_arena = nullptr);
// Returns a fake driver pointer that can be used with driver_context APIs.
// Do not try to access the internals of the pointer.
const void* CreateFakeDriver() {
// We don't actually need a real pointer.
int driver = next_driver_;
next_driver_++;
return reinterpret_cast<const void*>(driver);
}
// Example usage:
// DispatcherShutdownObserver observer;
// driver_runtime::Dispatcher* dispatcher;
// fdf_status_t status =
// driver_runtime::Dispatcher::Create(..., observer.fdf_observer(), &dispatcher);
// ...
// dispatcher->Destroy();
// ASSERT_OK(observer.WaitUntilShutdown());
class DispatcherShutdownObserver {
public:
// |require_callback| specifies whether the destructor will check that the callback was called.
// This can be set to false for tests that expect construction of the dispatcher to fail,
// but want to pass in a valid observer.
explicit DispatcherShutdownObserver(bool require_callback = true)
: require_callback_(require_callback) {
observer_.fdf_observer.handler = DispatcherDestructedHandler;
}
~DispatcherShutdownObserver() {
if (require_callback_) {
ASSERT_TRUE(observer_.signal.signaled());
}
}
DispatcherShutdownObserver(const DispatcherShutdownObserver&) = delete;
DispatcherShutdownObserver& operator=(const DispatcherShutdownObserver&) = delete;
DispatcherShutdownObserver& operator=(DispatcherShutdownObserver&&) = delete;
DispatcherShutdownObserver(DispatcherShutdownObserver&&) = delete;
zx_status_t WaitUntilShutdown() { return observer_.signal.Wait(zx::time::infinite()); }
// Returns the observer that can be passed to |driver_runtime::Dispatcher::Create|.
fdf_dispatcher_shutdown_observer_t* fdf_observer() { return &observer_.fdf_observer; }
// Returns the dispatcher that was shutdown, nullptr if no shutdown event has occurred.
fdf_dispatcher_t* shutdown_dispatcher() { return shutdown_dispatcher_; }
private:
struct ShutdownObserver {
fdf_dispatcher_shutdown_observer_t fdf_observer;
libsync::Completion signal;
};
static void DispatcherDestructedHandler(fdf_dispatcher_t* dispatcher,
fdf_dispatcher_shutdown_observer_t* fdf_observer) {
DispatcherShutdownObserver* observer =
reinterpret_cast<DispatcherShutdownObserver*>(fdf_observer);
observer->shutdown_dispatcher_ = dispatcher;
observer->observer_.signal.Signal();
}
ShutdownObserver observer_;
bool require_callback_;
fdf_dispatcher_t* shutdown_dispatcher_ = nullptr;
};
private:
int next_driver_ = 1;
};
#endif // SRC_DEVICES_BIN_DRIVER_RUNTIME_RUNTIME_TEST_CASE_H_