[driver-unit-test] Add helper libraries.

This can be used in conjuction with zxtest libraries to
write driver unit tests.

ZX-4028 #comment

TEST= runtests -t logger-unit-test

Change-Id: Id713e23a9532616455b7f0ffc0fd17bb51198c24
diff --git a/zircon/system/fidl/BUILD.gn b/zircon/system/fidl/BUILD.gn
index 0340eaf..cc2d98a 100644
--- a/zircon/system/fidl/BUILD.gn
+++ b/zircon/system/fidl/BUILD.gn
@@ -18,6 +18,7 @@
     "fuchsia-device-manager-test",
     "fuchsia-device-test",
     "fuchsia-device-vsock",
+    "fuchsia-driver-test",
     "fuchsia-fshost",
     "fuchsia-hardware-audio",
     "fuchsia-hardware-backlight",
diff --git a/zircon/system/fidl/fuchsia-driver-test/BUILD.gn b/zircon/system/fidl/fuchsia-driver-test/BUILD.gn
new file mode 100644
index 0000000..cc375d6
--- /dev/null
+++ b/zircon/system/fidl/fuchsia-driver-test/BUILD.gn
@@ -0,0 +1,11 @@
+# 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.
+
+import("$zx/public/gn/fidl.gni")
+
+fidl_library("fuchsia-driver-test") {
+  sources = [
+    "logger.fidl",
+  ]
+}
diff --git a/zircon/system/fidl/fuchsia-driver-test/logger.fidl b/zircon/system/fidl/fuchsia-driver-test/logger.fidl
new file mode 100644
index 0000000..82ef9de
--- /dev/null
+++ b/zircon/system/fidl/fuchsia-driver-test/logger.fidl
@@ -0,0 +1,27 @@
+// 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.
+
+library fuchsia.driver.test;
+
+const uint32 LOG_MESSAGE_MAX = 1024;
+const uint32 TEST_CASE_NAME_MAX = 256;
+
+/// Contains the counts of test results within the test case.
+struct TestCaseResult {
+    /// Number of tests that passed.
+    uint64 passed;
+    /// Number of tests that failed.
+    uint64 failed;
+    /// Number of tests that were skipped.
+    uint64 skipped;
+};
+
+[Layout = "Simple"]
+protocol Logger {
+    /// Logs a message from the driver unit test.
+    LogMessage(string:LOG_MESSAGE_MAX msg);
+
+    /// Logs the results of a test case.
+    LogTestCase(string:TEST_CASE_NAME_MAX name, TestCaseResult result);
+};
diff --git a/zircon/system/ulib/BUILD.gn b/zircon/system/ulib/BUILD.gn
index 959e67b..e29d884 100644
--- a/zircon/system/ulib/BUILD.gn
+++ b/zircon/system/ulib/BUILD.gn
@@ -49,6 +49,7 @@
     "dispatcher-pool",
     "driver",
     "driver-info",
+    "driver-unit-test",
     "edid",
     "elf-search",
     "elfload",
diff --git a/zircon/system/ulib/driver-unit-test/BUILD.gn b/zircon/system/ulib/driver-unit-test/BUILD.gn
new file mode 100644
index 0000000..122fe06
--- /dev/null
+++ b/zircon/system/ulib/driver-unit-test/BUILD.gn
@@ -0,0 +1,25 @@
+# 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.
+
+library("driver-unit-test") {
+  sdk = "static"
+  sdk_headers = [
+    "driver-unit-test/logger.h",
+    "driver-unit-test/utils.h",
+  ]
+  sources = [
+    "logger.cpp",
+    "utils.cpp",
+  ]
+  configs += [ "$zx/public/gn/config:visibility_hidden" ]
+  deps = [
+    "$zx/system/fidl/fuchsia-driver-test:c",
+    "$zx/system/ulib/ddk",
+    "$zx/system/ulib/fbl",
+    "$zx/system/ulib/fidl",
+    "$zx/system/ulib/zircon",
+    "$zx/system/ulib/zx",
+    "$zx/system/ulib/zxtest",
+  ]
+}
diff --git a/zircon/system/ulib/driver-unit-test/include/lib/driver-unit-test/logger.h b/zircon/system/ulib/driver-unit-test/include/lib/driver-unit-test/logger.h
new file mode 100644
index 0000000..c0b5f9e
--- /dev/null
+++ b/zircon/system/ulib/driver-unit-test/include/lib/driver-unit-test/logger.h
@@ -0,0 +1,54 @@
+// 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.
+
+#pragma once
+
+#include <utility>
+
+#include <fbl/string.h>
+#include <fuchsia/driver/test/c/fidl.h>
+#include <lib/zx/channel.h>
+#include <zxtest/base/observer.h>
+
+namespace driver_unit_test {
+
+// Logger is used to output test events and messages to a specified channel.
+//
+// Tests can use RunZxTests to set up the logger instance, and in the tests retrieve
+// the instance via |GetInstance|. Drivers can then log custom messages using |SendLogMessage|.
+class Logger : public zxtest::LifecycleObserver {
+public:
+    // Populates |instance_| with a new logger instance.
+    static zx_status_t CreateInstance(zx::unowned_channel ch);
+    static Logger* GetInstance() { return instance_.get(); }
+    static void DeleteInstance() { instance_ = nullptr; }
+
+    // Sends a log message to the channel.
+    static zx_status_t SendLogMessage(const char* msg);
+
+    // LifecycleObserver methods.
+    void OnTestCaseStart(const zxtest::TestCase& test_case);
+    void OnTestCaseEnd(const zxtest::TestCase& test_case);
+    void OnTestSuccess(const zxtest::TestCase& test_case, const zxtest::TestInfo& test);
+    void OnTestFailure(const zxtest::TestCase& test_case, const zxtest::TestInfo& test);
+    void OnTestSkip(const zxtest::TestCase& test_case, const zxtest::TestInfo& test);
+
+private:
+    explicit Logger(zx::unowned_channel ch) : channel_(ch) {}
+
+    // Sends the test case result to the channel.
+    zx_status_t SendLogTestCase();
+
+    // This is static so that the instance is accessible to the test cases.
+    static std::unique_ptr<Logger> instance_;
+
+    // The channel to send FIDL messages to.
+    zx::unowned_channel channel_;
+
+    // Current test case information.
+    fbl::String test_case_name_;
+    fuchsia_driver_test_TestCaseResult test_case_result_;
+};
+
+}  // namespace driver_unit_test
diff --git a/zircon/system/ulib/driver-unit-test/include/lib/driver-unit-test/utils.h b/zircon/system/ulib/driver-unit-test/include/lib/driver-unit-test/utils.h
new file mode 100644
index 0000000..285c9e9
--- /dev/null
+++ b/zircon/system/ulib/driver-unit-test/include/lib/driver-unit-test/utils.h
@@ -0,0 +1,25 @@
+// 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.
+
+#pragma once
+
+#include <ddk/device.h>
+
+namespace driver_unit_test {
+
+// Should be called by the driver run test hook before running the tests.
+void SetParent(zx_device_t* parent);
+// Retrieves the device set by |SetParent|.
+zx_device_t* GetParent();
+
+// Helper function for setting up and running driver unit tests. This should be called
+// from the driver's run_unit_test hook.
+//
+// This sets the parent pointer and test logger.
+// - |name| is an identifier for the test group.
+// - |parent| is the parent device of the driver.
+// - |channel| is where test logger output will be sent to.
+bool RunZxTests(const char* name, zx_device_t* parent, zx_handle_t channel);
+
+}  // namespace driver_unit_test
diff --git a/zircon/system/ulib/driver-unit-test/logger.cpp b/zircon/system/ulib/driver-unit-test/logger.cpp
new file mode 100644
index 0000000..5bcdeb6
--- /dev/null
+++ b/zircon/system/ulib/driver-unit-test/logger.cpp
@@ -0,0 +1,122 @@
+// 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 <lib/driver-unit-test/logger.h>
+
+#include <fbl/algorithm.h>
+#include <fbl/alloc_checker.h>
+#include <fuchsia/driver/test/c/fidl.h>
+#include <lib/fidl/cpp/message.h>
+#include <lib/fidl/cpp/message_builder.h>
+#include <zxtest/base/test-case.h>
+
+namespace driver_unit_test {
+
+std::unique_ptr<Logger> Logger::instance_;
+
+zx_status_t Logger::CreateInstance(zx::unowned_channel ch) {
+    if (!ch->is_valid()) {
+        return ZX_ERR_BAD_HANDLE;
+    }
+    fbl::AllocChecker ac;
+    instance_ = std::unique_ptr<Logger>(new (&ac) Logger(std::move(ch)));
+    if (!ac.check()) {
+        return ZX_ERR_NO_MEMORY;
+    }
+    return ZX_OK;
+}
+
+// static
+zx_status_t Logger::SendLogMessage(const char* log_msg) {
+    Logger* logger = GetInstance();
+    if (!logger) {
+        return ZX_ERR_BAD_STATE;
+    }
+    size_t log_msg_size = fbl::min(strlen(log_msg),
+                                   static_cast<size_t>(fuchsia_driver_test_LOG_MESSAGE_MAX));
+
+    uint32_t len = static_cast<uint32_t>(
+        sizeof(fuchsia_driver_test_LoggerLogMessageRequest) +
+        FIDL_ALIGN(log_msg_size));
+
+    FIDL_ALIGNDECL char buf[len];
+    fidl::Builder builder(buf, len);
+
+    auto* req = builder.New<fuchsia_driver_test_LoggerLogMessageRequest>();
+    req->hdr.ordinal = fuchsia_driver_test_LoggerLogMessageOrdinal;
+    req->hdr.flags = 0;
+    req->hdr.txid = FIDL_TXID_NO_RESPONSE;
+
+    auto* data = builder.NewArray<char>(static_cast<uint32_t>(log_msg_size));
+    req->msg.data = data;
+    req->msg.size = log_msg_size;
+    memcpy(data, log_msg, log_msg_size);
+
+    fidl::Message msg(builder.Finalize(), fidl::HandlePart());
+    const char* err = nullptr;
+    auto status = msg.Encode(&fuchsia_driver_test_LoggerLogMessageRequestTable, &err);
+    if (status != ZX_OK) {
+        return status;
+    }
+    return msg.Write(logger->channel_->get(), 0);
+}
+
+zx_status_t Logger::SendLogTestCase() {
+    size_t test_name_size = fbl::min(strlen(test_case_name_.c_str()),
+                                     static_cast<size_t>(fuchsia_driver_test_TEST_CASE_NAME_MAX));
+
+    uint32_t len = static_cast<uint32_t>(
+        sizeof(fuchsia_driver_test_LoggerLogTestCaseRequest) +
+        FIDL_ALIGN(test_name_size));
+
+    FIDL_ALIGNDECL char buf[len];
+    fidl::Builder builder(buf, len);
+
+    auto* req = builder.New<fuchsia_driver_test_LoggerLogTestCaseRequest>();
+    req->hdr.ordinal = fuchsia_driver_test_LoggerLogTestCaseOrdinal;
+    req->hdr.flags = 0;
+    req->hdr.txid = FIDL_TXID_NO_RESPONSE;
+
+    auto* data = builder.NewArray<char>(static_cast<uint32_t>(test_name_size));
+    req->name.data = data;
+    req->name.size = test_name_size;
+    memcpy(data, test_case_name_.c_str(), test_name_size);
+
+    req->result.passed = test_case_result_.passed;
+    req->result.failed = test_case_result_.failed;
+    req->result.skipped = test_case_result_.skipped;
+
+    fidl::Message msg(builder.Finalize(), fidl::HandlePart());
+    const char* err = nullptr;
+    auto status = msg.Encode(&fuchsia_driver_test_LoggerLogTestCaseRequestTable, &err);
+    if (status != ZX_OK) {
+        return status;
+    }
+    return msg.Write(channel_->get(), 0);
+}
+
+void Logger::OnTestCaseStart(const zxtest::TestCase& test_case) {
+    test_case_name_ = test_case.name();
+    test_case_result_.passed = 0;
+    test_case_result_.failed = 0;
+    test_case_result_.skipped = 0;
+}
+
+void Logger::OnTestCaseEnd(const zxtest::TestCase& test_case) {
+    SendLogTestCase();
+}
+
+void Logger::OnTestSuccess(const zxtest::TestCase& test_case, const zxtest::TestInfo& test) {
+    test_case_result_.passed++;
+}
+
+void Logger::OnTestFailure(const zxtest::TestCase& test_case, const zxtest::TestInfo& test) {
+    test_case_result_.failed++;
+}
+
+void Logger::OnTestSkip(const zxtest::TestCase& test_case, const zxtest::TestInfo& test) {
+    test_case_result_.skipped++;
+}
+
+}  // namespace driver_unit_test
diff --git a/zircon/system/ulib/driver-unit-test/test/BUILD.gn b/zircon/system/ulib/driver-unit-test/test/BUILD.gn
new file mode 100644
index 0000000..3edd1ca
--- /dev/null
+++ b/zircon/system/ulib/driver-unit-test/test/BUILD.gn
@@ -0,0 +1,23 @@
+# 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.
+
+group("test") {
+  testonly = true
+  deps = [
+    ":logger-unit",
+  ]
+}
+
+test("logger-unit") {
+  sources = [
+    "logger-test.cpp",
+  ]
+  deps = [
+    "$zx/system/fidl/fuchsia-driver-test:c",
+    "$zx/system/ulib/driver-unit-test",
+    "$zx/system/ulib/fdio",
+    "$zx/system/ulib/fidl",
+    "$zx/system/ulib/zxtest",
+  ]
+}
diff --git a/zircon/system/ulib/driver-unit-test/test/logger-test.cpp b/zircon/system/ulib/driver-unit-test/test/logger-test.cpp
new file mode 100644
index 0000000..e393afe
--- /dev/null
+++ b/zircon/system/ulib/driver-unit-test/test/logger-test.cpp
@@ -0,0 +1,161 @@
+// 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 <lib/driver-unit-test/logger.h>
+#include <lib/fidl/coding.h>
+#include <lib/zx/channel.h>
+#include <zircon/syscalls.h>
+#include <zxtest/zxtest.h>
+
+namespace {
+
+constexpr size_t kMaxFidlMsgSize = 8096;
+constexpr char kLogMessage[] = "test log message";
+
+const char* kFakeTestCaseName = "test_case";
+const zxtest::TestCase kFakeTestCase = zxtest::TestCase{
+    kFakeTestCaseName, zxtest::Test::SetUpTestCase, zxtest::Test::TearDownTestCase };
+const zxtest::TestInfo kFakeTestInfo = zxtest::TestInfo("test", zxtest::SourceLocation{}, nullptr);
+
+class LoggerTest : public zxtest::Test {
+protected:
+    void SetUp() override {
+        ASSERT_EQ(ZX_OK, zx::channel::create(0, &local_, &remote_));
+        ASSERT_EQ(ZX_OK,
+                  driver_unit_test::Logger::CreateInstance(zx::unowned_channel(remote_.get())));
+        logger_ = driver_unit_test::Logger::GetInstance();
+        ASSERT_NOT_NULL(logger_);
+    }
+
+    void TearDown() override {
+        driver_unit_test::Logger::DeleteInstance();
+        ASSERT_NULL(driver_unit_test::Logger::GetInstance());
+    }
+
+    zx::channel local_, remote_;
+    driver_unit_test::Logger* logger_;
+};
+
+TEST_F(LoggerTest, CreateWithInvalidChannel) {
+    driver_unit_test::Logger::DeleteInstance();
+    ASSERT_NULL(driver_unit_test::Logger::GetInstance());
+
+    ASSERT_NE(ZX_OK, driver_unit_test::Logger::CreateInstance(zx::unowned_channel()));
+    ASSERT_NULL(driver_unit_test::Logger::GetInstance());
+    ASSERT_NE(ZX_OK, driver_unit_test::Logger::SendLogMessage(kLogMessage));
+}
+
+// Waits for a FIDL message on the channel and populates |out_data| with a pointer to the
+// decoded data.
+void DecodeMessage(const zx::channel& channel, uint32_t want_ordinal, const fidl_type_t* want_type,
+                   fbl::unique_ptr<uint8_t[]>* out_data, uint32_t* out_data_size) {
+    // Verify we receive the expected signal on the channel.
+    zx_signals_t pending;
+    const zx_signals_t wait = ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED;
+    auto deadline = zx::deadline_after(zx::sec(5));
+    ASSERT_EQ(ZX_OK, channel.wait_one(wait, deadline, &pending));
+    ASSERT_TRUE(pending & ZX_CHANNEL_READABLE);
+
+    // Create the data buffer and copy the data into it.
+    const uint32_t buf_size = kMaxFidlMsgSize;
+    fbl::unique_ptr<uint8_t[]> buf(new uint8_t[buf_size]);
+    fidl_msg_t fidl_msg = {
+        .bytes = buf.get(),
+        .handles = nullptr,
+        .num_bytes = buf_size,
+        .num_handles = 0,
+    };
+
+    ASSERT_EQ(ZX_OK, channel.read(0, buf.get(), nullptr /* handles */, buf_size,
+                                  0 /* num_handles */, &fidl_msg.num_bytes, nullptr));
+    ASSERT_GE(fidl_msg.num_bytes, sizeof(fidl_message_header_t));
+
+    // Decode the message in-place.
+    auto* hdr = static_cast<fidl_message_header_t*>(fidl_msg.bytes);
+    ASSERT_EQ(want_ordinal, hdr->ordinal);
+    ASSERT_EQ(ZX_OK, fidl_decode_msg(want_type, &fidl_msg, nullptr));
+
+    *out_data = std::move(buf);
+    *out_data_size = fidl_msg.num_bytes;
+}
+
+TEST_F(LoggerTest, LogMessage) {
+    ASSERT_EQ(ZX_OK, driver_unit_test::Logger::SendLogMessage(kLogMessage));
+
+    fbl::unique_ptr<uint8_t[]> data_buf;
+    uint32_t data_size;
+    ASSERT_NO_FATAL_FAILURES(
+        DecodeMessage(local_,
+                      fuchsia_driver_test_LoggerLogMessageOrdinal,
+                      &fuchsia_driver_test_LoggerLogMessageRequestTable,
+                      &data_buf,
+                      &data_size),
+        "could not decode message");
+    ASSERT_GE(data_size, sizeof(fuchsia_driver_test_LoggerLogMessageRequest));
+
+    auto request = reinterpret_cast<fuchsia_driver_test_LoggerLogMessageRequest*>(data_buf.get());
+    ASSERT_EQ(strlen(kLogMessage), request->msg.size);
+    ASSERT_EQ(0, strncmp(kLogMessage, request->msg.data, request->msg.size));
+}
+
+// Read and decode the FIDL message from the channel and check that it equals the wanted result.
+void ValidateReceivedTestCase(const zx::channel& log_ch,
+                            const fuchsia_driver_test_TestCaseResult& want) {
+    fbl::unique_ptr<uint8_t[]> data_buf;
+    uint32_t data_size;
+    ASSERT_NO_FATAL_FAILURES(
+        DecodeMessage(log_ch,
+                      fuchsia_driver_test_LoggerLogTestCaseOrdinal,
+                      &fuchsia_driver_test_LoggerLogTestCaseRequestTable,
+                      &data_buf,
+                      &data_size),
+        "could not decode message");
+    ASSERT_GE(data_size, sizeof(fuchsia_driver_test_LoggerLogTestCaseRequest));
+
+    auto request = reinterpret_cast<fuchsia_driver_test_LoggerLogTestCaseRequest*>(data_buf.get());
+    ASSERT_EQ(strlen(kFakeTestCaseName), request->name.size);
+    ASSERT_EQ(0, strncmp(kFakeTestCaseName, request->name.data, request->name.size));
+
+    auto got = request->result;
+    ASSERT_EQ(want.passed, got.passed);
+    ASSERT_EQ(want.failed, got.failed);
+    ASSERT_EQ(want.skipped, got.skipped);
+}
+
+TEST_F(LoggerTest, LogEmptyTestCase) {
+    logger_->OnTestCaseStart(kFakeTestCase);
+    logger_->OnTestCaseEnd(kFakeTestCase);
+
+    auto want_result = fuchsia_driver_test_TestCaseResult{};
+    ASSERT_NO_FATAL_FAILURES(ValidateReceivedTestCase(local_, want_result));
+}
+
+TEST_F(LoggerTest, LogSingleTest) {
+    logger_->OnTestCaseStart(kFakeTestCase);
+    logger_->OnTestSuccess(kFakeTestCase, kFakeTestInfo);
+    logger_->OnTestCaseEnd(kFakeTestCase);
+
+    auto want_result = fuchsia_driver_test_TestCaseResult{};
+    want_result.passed = 1;
+    ASSERT_NO_FATAL_FAILURES(ValidateReceivedTestCase(local_, want_result));
+}
+
+TEST_F(LoggerTest, LogMultipleTest) {
+    logger_->OnTestCaseStart(kFakeTestCase);
+    logger_->OnTestFailure(kFakeTestCase, kFakeTestInfo);
+    logger_->OnTestFailure(kFakeTestCase, kFakeTestInfo);
+    logger_->OnTestSuccess(kFakeTestCase, kFakeTestInfo);
+    logger_->OnTestSkip(kFakeTestCase, kFakeTestInfo);
+    logger_->OnTestSuccess(kFakeTestCase, kFakeTestInfo);
+    logger_->OnTestSuccess(kFakeTestCase, kFakeTestInfo);
+    logger_->OnTestCaseEnd(kFakeTestCase);
+
+    auto want_result = fuchsia_driver_test_TestCaseResult{};
+    want_result.passed = 3;
+    want_result.failed = 2;
+    want_result.skipped = 1;
+    ASSERT_NO_FATAL_FAILURES(ValidateReceivedTestCase(local_, want_result));
+}
+
+}  // anonymous namespace
diff --git a/zircon/system/ulib/driver-unit-test/utils.cpp b/zircon/system/ulib/driver-unit-test/utils.cpp
new file mode 100644
index 0000000..9a3c431
--- /dev/null
+++ b/zircon/system/ulib/driver-unit-test/utils.cpp
@@ -0,0 +1,44 @@
+// 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 <lib/driver-unit-test/utils.h>
+
+#include <fbl/auto_call.h>
+#include <lib/driver-unit-test/logger.h>
+#include <zxtest/zxtest.h>
+
+namespace {
+    zx_device_t* parent_device = nullptr;
+}  // namespace
+
+namespace driver_unit_test {
+
+void SetParent(zx_device_t* parent) {
+    parent_device = parent;
+}
+
+zx_device_t* GetParent() {
+    return parent_device;
+}
+
+bool RunZxTests(const char* name, zx_device_t* parent, zx_handle_t channel) {
+    SetParent(parent);
+
+    auto cleanup = fbl::MakeAutoCall([]() {
+        SetParent(nullptr);
+        Logger::DeleteInstance();
+    });
+
+    if (channel != ZX_HANDLE_INVALID) {
+        zx_status_t status = Logger::CreateInstance(zx::unowned_channel(channel));
+        if (status == ZX_OK) {
+            zxtest::Runner::GetInstance()->AddObserver(driver_unit_test::Logger::GetInstance());
+        }
+    }
+    const int kArgc = 1;
+    const char* argv[kArgc] = {name};
+    return RUN_ALL_TESTS(kArgc, const_cast<char**>(argv));
+}
+
+}  // namespace driver_unit_test
diff --git a/zircon/system/utest/BUILD.gn b/zircon/system/utest/BUILD.gn
index ea76f6f..1a0fe34 100644
--- a/zircon/system/utest/BUILD.gn
+++ b/zircon/system/utest/BUILD.gn
@@ -84,6 +84,7 @@
       "$zx/system/ulib/digest/test",
       "$zx/system/ulib/disk-inspector/test",
       "$zx/system/ulib/driver-integration-test/test",
+      "$zx/system/ulib/driver-unit-test/test",
       "$zx/system/ulib/elf-search/test",
       "$zx/system/ulib/fbl/test",
       "$zx/system/ulib/fs/metrics/test:metrics",