blob: 114eebbcbfe73d084f42d9eb1ad22716bb3e8575 [file] [log] [blame]
// 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 <ddk/metadata/test.h>
#include <ddk/platform-defs.h>
#include <fcntl.h>
#include <fuchsia/device/c/fidl.h>
#include <fuchsia/device/test/c/fidl.h>
#include <lib/devmgr-integration-test/fixture.h>
#include <lib/fdio/fdio.h>
#include <lib/zx/channel.h>
#include <lib/zx/vmo.h>
#include <limits.h>
#include <zxtest/zxtest.h>
namespace {
using devmgr_integration_test::IsolatedDevmgr;
static constexpr const char kDevPrefix[] = "/dev/";
static constexpr const char kDriverTestDir[] = "/boot/driver/test";
static constexpr const char kPassDriverName[] = "unit-test-pass.so";
static constexpr const char kFailDriverName[] = "unit-test-fail.so";
zx_status_t GetArguments(const fbl::Vector<const char*>& arguments, zx::vmo* out,
uint32_t* length) {
size_t size = 0;
for (const char* arg : arguments) {
// Add 1 for the null byte.
size += strlen(arg) + 1;
}
zx::vmo vmo;
zx_status_t status = zx::vmo::create(size, 0, &vmo);
size_t offset = 0;
for (const char* arg : arguments) {
// Add 1 for the null byte.
size_t length = strlen(arg) + 1;
status = vmo.write(arg, offset, length);
if (status != ZX_OK) {
return status;
}
offset += length;
}
*length = static_cast<uint32_t>(size);
*out = std::move(vmo);
return status;
}
void CreateTestDevice(const IsolatedDevmgr& devmgr, const char* driver_name,
zx::channel* dev_channel) {
fbl::unique_fd root_fd;
zx_status_t status =
devmgr_integration_test::RecursiveWaitForFile(devmgr.devfs_root(), "test/test", &root_fd);
ASSERT_OK(status);
zx::channel test_root;
status = fdio_get_service_handle(root_fd.release(), test_root.reset_and_get_address());
ASSERT_OK(status);
char devpath[fuchsia_device_test_MAX_DEVICE_PATH_LEN + 1];
size_t devpath_count;
zx_status_t call_status;
status = fuchsia_device_test_RootDeviceCreateDevice(test_root.get(), driver_name,
strlen(driver_name), &call_status, devpath,
sizeof(devpath) - 1, &devpath_count);
ASSERT_OK(status);
ASSERT_OK(call_status);
devpath[devpath_count] = 0;
ASSERT_STR_NE(devpath, kDevPrefix);
const char* relative_devpath = devpath + strlen(kDevPrefix);
fbl::unique_fd fd;
status =
devmgr_integration_test::RecursiveWaitForFile(devmgr.devfs_root(), relative_devpath, &fd);
ASSERT_OK(status);
status = fdio_get_service_handle(fd.release(), dev_channel->reset_and_get_address());
ASSERT_OK(status);
}
TEST(DeviceControllerIntegrationTest, AllTestsEnabledBind) {
IsolatedDevmgr devmgr;
auto args = IsolatedDevmgr::DefaultArgs();
args.use_system_svchost = true;
fbl::Vector<const char*> arguments;
arguments.push_back("driver.tests.enable=true");
args.get_arguments = [&arguments](zx::vmo* out, uint32_t* length) {
return GetArguments(arguments, out, length);
};
zx_status_t status = IsolatedDevmgr::Create(std::move(args), &devmgr);
ASSERT_OK(status);
zx::channel dev_channel;
CreateTestDevice(devmgr, kPassDriverName, &dev_channel);
char libpath[PATH_MAX];
int len = snprintf(libpath, sizeof(libpath), "%s/%s", kDriverTestDir, kPassDriverName);
zx_status_t call_status;
status = fuchsia_device_ControllerBind(dev_channel.get(), libpath, len, &call_status);
ASSERT_OK(status);
ASSERT_OK(call_status);
fuchsia_device_test_DeviceDestroy(dev_channel.get());
}
TEST(DeviceControllerIntegrationTest, AllTestsEnabledBindFail) {
IsolatedDevmgr devmgr;
auto args = IsolatedDevmgr::DefaultArgs();
args.use_system_svchost = true;
fbl::Vector<const char*> arguments;
arguments.push_back("driver.tests.enable=true");
args.get_arguments = [&arguments](zx::vmo* out, uint32_t* length) {
return GetArguments(arguments, out, length);
};
zx_status_t status = IsolatedDevmgr::Create(std::move(args), &devmgr);
ASSERT_OK(status);
zx::channel dev_channel;
CreateTestDevice(devmgr, kFailDriverName, &dev_channel);
char libpath[PATH_MAX];
int len = snprintf(libpath, sizeof(libpath), "%s/%s", kDriverTestDir, kFailDriverName);
zx_status_t call_status;
status = fuchsia_device_ControllerBind(dev_channel.get(), libpath, len, &call_status);
ASSERT_OK(status);
ASSERT_EQ(ZX_ERR_BAD_STATE, call_status);
fuchsia_device_test_DeviceDestroy(dev_channel.get());
}
// Test the flag using bind failure as a proxy for "the unit test did run".
TEST(DeviceControllerIntegrationTest, SpecificTestEnabledBindFail) {
IsolatedDevmgr devmgr;
auto args = IsolatedDevmgr::DefaultArgs();
args.use_system_svchost = true;
fbl::Vector<const char*> arguments;
arguments.push_back("driver.unit_test_fail.tests.enable=true");
args.get_arguments = [&arguments](zx::vmo* out, uint32_t* length) {
return GetArguments(arguments, out, length);
};
zx_status_t status = IsolatedDevmgr::Create(std::move(args), &devmgr);
ASSERT_OK(status);
zx::channel dev_channel;
CreateTestDevice(devmgr, kFailDriverName, &dev_channel);
char libpath[PATH_MAX];
int len = snprintf(libpath, sizeof(libpath), "%s/%s", kDriverTestDir, kFailDriverName);
zx_status_t call_status;
status = fuchsia_device_ControllerBind(dev_channel.get(), libpath, len, &call_status);
ASSERT_OK(status);
ASSERT_EQ(ZX_ERR_BAD_STATE, call_status);
fuchsia_device_test_DeviceDestroy(dev_channel.get());
}
// Test the flag using bind success as a proxy for "the unit test didn't run".
TEST(DeviceControllerIntegrationTest, DefaultTestsDisabledBind) {
IsolatedDevmgr devmgr;
auto args = IsolatedDevmgr::DefaultArgs();
args.use_system_svchost = true;
zx_status_t status = IsolatedDevmgr::Create(std::move(args), &devmgr);
ASSERT_OK(status);
zx::channel dev_channel;
CreateTestDevice(devmgr, kFailDriverName, &dev_channel);
char libpath[PATH_MAX];
int len = snprintf(libpath, sizeof(libpath), "%s/%s", kDriverTestDir, kFailDriverName);
zx_status_t call_status;
status = fuchsia_device_ControllerBind(dev_channel.get(), libpath, len, &call_status);
ASSERT_OK(status);
ASSERT_OK(call_status);
fuchsia_device_test_DeviceDestroy(dev_channel.get());
}
// Test the flag using bind success as a proxy for "the unit test didn't run".
TEST(DeviceControllerIntegrationTest, SpecificTestDisabledBind) {
IsolatedDevmgr devmgr;
auto args = IsolatedDevmgr::DefaultArgs();
args.use_system_svchost = true;
fbl::Vector<const char*> arguments;
arguments.push_back("driver.tests.enable=true");
arguments.push_back("driver.unit_test_fail.tests.enable=false");
args.get_arguments = [&arguments](zx::vmo* out, uint32_t* length) {
return GetArguments(arguments, out, length);
};
zx_status_t status = IsolatedDevmgr::Create(std::move(args), &devmgr);
ASSERT_OK(status);
zx::channel dev_channel;
CreateTestDevice(devmgr, kFailDriverName, &dev_channel);
char libpath[PATH_MAX];
int len = snprintf(libpath, sizeof(libpath), "%s/%s", kDriverTestDir, kFailDriverName);
zx_status_t call_status;
status = fuchsia_device_ControllerBind(dev_channel.get(), libpath, len, &call_status);
ASSERT_OK(status);
ASSERT_OK(call_status);
fuchsia_device_test_DeviceDestroy(dev_channel.get());
}
} // namespace