Once you are familiar with the Driver Framework v2 testing framework, follow this quick start to write a test for drivers that need to make synchronous FIDL (see driver FIDL test code). If your driver doesn't need to make synchronous FIDL calls, see the driver base test.
Include library dependencies
To test drivers, unit tests need to have access to the various resources and environments needed by the drivers themselves. For example, these are the library dependencies for the Driver FIDL test:
#include <fidl/fuchsia.driver.component.test/cpp/driver/wire.h>
#include <fidl/fuchsia.driver.component.test/cpp/wire.h>
#include <lib/async_patterns/testing/cpp/dispatcher_bound.h>
#include <lib/component/incoming/cpp/service.h>
#include <lib/driver/component/cpp/tests/test_driver.h>
#include <lib/driver/incoming/cpp/namespace.h>
#include <lib/driver/testing/cpp/driver_lifecycle.h>
#include <lib/driver/testing/cpp/driver_runtime.h>
#include <lib/driver/testing/cpp/test_environment.h>
#include <lib/driver/testing/cpp/test_node.h>
#include <lib/fdio/directory.h>
#include <gtest/gtest.h>
DispatcherBound is required to test how the driver uses FIDL clients when calling into its environment. It ensures a server-end object runs in a single dispatcher, enabling the test to construct, call methods on, and destroy the object used (see Threading tips in tests).
GTest Runner
is a test runner that launches a gtest
binary as a component, parses its
output, and translates it to fuchsia.test.Suite
protocol on behalf of the
test.
Provide handler to easily add server bindings
It's good practice for servers to provide a GetInstanceHandler
to easily add
server bindings and run them off a binding group. The bindings should be added
on the current driver dispatcher. The expectation is that this class is run
inside of a dispatcher bound to the environment. For example,
Driver FIDL test, line 35-52,
provides a handler to the driver service:
class DriverProtocolServer : public fdf::WireServer<fuchsia_driver_component_test::DriverProtocol> {
public:
fuchsia_driver_component_test::DriverService::InstanceHandler GetInstanceHandler() {
return fuchsia_driver_component_test::DriverService::InstanceHandler({
.device = bindings_.CreateHandler(this, fdf::Dispatcher::GetCurrent()->get(),
fidl::kIgnoreBindingClosure),
});
}
private:
// fdf::WireServer<fuchsia_driver_component_test::DriverProtocol>
void DriverMethod(fdf::Arena& arena, DriverMethodCompleter::Sync& completer) override {
fdf::Arena reply_arena('TEST');
completer.buffer(reply_arena).ReplySuccess();
}
fdf::ServerBindingGroup<fuchsia_driver_component_test::DriverProtocol> bindings_;
};
Set up testing framework
Create driver runtime
Creating the driver runtime automatically attaches a foreground dispatcher, Driver FIDL test, line 115:
fdf_testing::DriverRuntime runtime_;
Start background dispatcher
The driver dispatcher is set as a background dispatcher, Driver FIDL test, line 118:
fdf::UnownedSynchronizedDispatcher env_dispatcher_ = runtime_.StartBackgroundDispatcher();
Create TestNode object
The test node serves the fdf::Node protocol
to the driver,
Driver FIDL test, lines 127-128:
async_patterns::TestDispatcherBound<fdf_testing::TestNode> node_server_{
env_dispatcher(), std::in_place, std::string("root")};
Create TestEnvironment object
The environment can serve both the Zircon and Driver transport based protocols to the driver, Driver FIDL test, lines 131-132:
async_patterns::TestDispatcherBound<fdf_testing::TestEnvironment> test_environment_{
env_dispatcher(), std::in_place};
Create custom FIDL server
The custom FIDL server lives on the background environment dispatcher and has to be wrapped in a dispatcher bound, Driver FIDL test, lines 121-124:
async_patterns::TestDispatcherBound<ZirconProtocolServer> zircon_proto_server_{env_dispatcher(),
std::in_place};
async_patterns::TestDispatcherBound<DriverProtocolServer> driver_proto_server_{env_dispatcher(),
std::in_place};
Get custom FIDL server handler
Get the instance handler for the driver protocol, Driver FIDL test, lines 71-74:
fuchsia_driver_component_test::ZirconService::InstanceHandler zircon_proto_handler =
zircon_proto_server_.SyncCall(&ZirconProtocolServer::GetInstanceHandler);
fuchsia_driver_component_test::DriverService::InstanceHandler driver_proto_handler =
driver_proto_server_.SyncCall(&DriverProtocolServer::GetInstanceHandler);
Move custom FIDL server handler
Move the instance handler into our driver's incoming namespace, Driver FIDL test, lines 76-87:
test_environment_.SyncCall([zircon_proto_handler = std::move(zircon_proto_handler),
driver_proto_handler = std::move(driver_proto_handler)](
fdf_testing::TestEnvironment* env) mutable {
zx::result result =
env->incoming_directory().AddService<fuchsia_driver_component_test::ZirconService>(
std::move(zircon_proto_handler));
ASSERT_EQ(ZX_OK, result.status_value());
result = env->incoming_directory().AddService<fuchsia_driver_component_test::DriverService>(
std::move(driver_proto_handler));
ASSERT_EQ(ZX_OK, result.status_value());
});
Call CreateStartArgsAndServe
Create and serve the start_args table
,
Driver FIDL test, lines 59-60:
zx::result start_args = node_server_.SyncCall(&fdf_testing::TestNode::CreateStartArgsAndServe);
ASSERT_EQ(ZX_OK, start_args.status_value());
Initialize test environment
Initialize the test environment, Driver FIDL test, lines 65-68:
zx::result init_result =
test_environment_.SyncCall(&fdf_testing::TestEnvironment::Initialize,
std::move(start_args->incoming_directory_server));
ASSERT_EQ(ZX_OK, init_result.status_value());
Run tests
Add the driver under test
Add the driver under test which will use the foreground dispatcher, Driver FIDL test, lines 167:
fdf_testing::DriverUnderTest<TestDriver> driver_;
Start driver
Start the driver, Driver FIDL test, lines 237-238:
zx::result result = runtime().RunToCompletion(driver_.SyncCall(
&fdf_testing::DriverUnderTest<TestDriver>::Start, std::move(start_args())));
Add tests
Use the arrow operator on the DriverUnderTest
to add tests for the driver.
The arrow operator gives access to the driver type
(specified in the DriverUnderTest
template), for example,
Driver FIDL test, lines 384-287:
driver().SyncCall([](fdf_testing::DriverUnderTest<TestDriver>* driver) {
zx::result result = (*driver)->ServeDriverService();
ASSERT_EQ(ZX_OK, result.status_value());
});
Call PrepareStop
PrepareStop
has to be called manually by tests,
Driver FIDL test, line 159:
zx::result result = runtime().RunToCompletion(driver_.PrepareStop());
Run unit tests
Execute the following command to run the driver tests (for the iwlwifi driver):
tools/bazel test third_party/iwlwifi/test:iwlwifi_test_pkg