blob: 5cbbb8cbcc2553efbfa40e74b0fe2869b40dd5d5 [file] [log] [blame]
// Copyright 2020 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/async-loop/cpp/loop.h>
#include <lib/syslog/cpp/log_settings.h>
#include <lib/syslog/cpp/macros.h>
#include <set>
#include "gtest/gtest.h"
#include "src/lib/fsl/io/device_watcher.h"
#include "src/lib/fxl/command_line.h"
#include "src/lib/fxl/test/test_settings.h"
#include "src/media/audio/drivers/test/test_base.h"
namespace media::audio::drivers::test {
static const struct {
const char* path;
DeviceType device_type;
} kAudioDevNodes[] = {
{.path = "/dev/class/audio-input", .device_type = DeviceType::Input},
{.path = "/dev/class/audio-output", .device_type = DeviceType::Output},
};
// static
static std::vector<std::unique_ptr<fsl::DeviceWatcher>>& device_watchers() {
static std::vector<std::unique_ptr<fsl::DeviceWatcher>>* device_watchers =
new std::vector<std::unique_ptr<fsl::DeviceWatcher>>();
return *device_watchers;
}
static std::set<DeviceEntry>& device_entries() {
static std::set<DeviceEntry>* device_entries = new std::set<DeviceEntry>();
return *device_entries;
}
// Called once, before RUN_ALL_TESTS() is invoked. This generates the set of device entries.
void DetectDevices() {
async::Loop loop{&kAsyncLoopConfigAttachToCurrentThread};
// Set up the watchers, etc. If any fail, automatically stop monitoring all device sources.
for (const auto& devnode : kAudioDevNodes) {
bool initial_enumeration_done = false;
auto watcher = fsl::DeviceWatcher::CreateWithIdleCallback(
devnode.path,
[dev_type = devnode.device_type](int dir_fd, const std::string& filename) {
FX_LOGS(TRACE) << "dir_fd " << dir_fd << " for '" << filename << "'";
device_entries().insert({dir_fd, filename, dev_type});
},
[&initial_enumeration_done]() { initial_enumeration_done = true; });
if (watcher == nullptr) {
ASSERT_FALSE(watcher == nullptr)
<< "AudioDriver::TestBase failed creating DeviceWatcher for '" << devnode.path << "'.";
}
device_watchers().emplace_back(std::move(watcher));
while (!initial_enumeration_done) {
loop.Run(zx::deadline_after(zx::msec(1)));
}
}
// Also add a device entry for the a2dp-source output device driver, which we always test.
device_entries().insert({DeviceEntry::kA2dp, "Bluetooth-A2DP", DeviceType::Output});
}
// TODO(fxbug.dev/65580): Convert to value-parameterized testing and the INSTANTIATE_TEST_SUITE_P
// macro, moving DetectDevices to a function called at static initialization time. If we cannot
// access the cmdline flags at that time, we may need to always register admin tests, and then skip
// them at runtime based on the cmdline flag.
extern void RegisterBasicTestsForDevice(const DeviceEntry& device_entry);
extern void RegisterAdminTestsForDevice(const DeviceEntry& device_entry,
bool expect_audio_core_connected);
// Create testcase instances for each device entry.
void RegisterTests(bool expect_audio_core_connected) {
for (auto& device_entry : device_entries()) {
RegisterBasicTestsForDevice(device_entry);
RegisterAdminTestsForDevice(device_entry, expect_audio_core_connected);
}
}
}; // namespace media::audio::drivers::test
int main(int argc, char** argv) {
auto command_line = fxl::CommandLineFromArgcArgv(argc, argv);
if (!fxl::SetTestSettings(command_line)) {
return EXIT_FAILURE;
}
testing::InitGoogleTest(&argc, argv);
syslog::SetTags({"audio_driver_tests"});
// --admin Validate commands that require the privileged channel, such as SetFormat.
bool expect_audio_core_connected = !command_line.HasOption("admin");
media::audio::drivers::test::DetectDevices();
media::audio::drivers::test::RegisterTests(expect_audio_core_connected);
return RUN_ALL_TESTS();
}