blob: 07a8eb45e42e1ccc2c568de37d75642c738da146 [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.
#include "src/iwlwifi/platform/driver-inspector.h"
#include <lib/inspect/cpp/hierarchy.h>
#include <lib/inspect/cpp/reader.h>
#include <cstring>
#include <vector>
#include <zxtest/zxtest.h>
namespace wlan::testing {
namespace {
// Test DriverInspector creation with different parameters.
TEST(DriverInspectorTest, CreationOptions) {
auto d1 = wlan::iwlwifi::DriverInspector();
EXPECT_TRUE(d1.GetRoot());
auto d2 = wlan::iwlwifi::DriverInspector(
wlan::iwlwifi::DriverInspectorOptions{.vmo_size = 4 * 1024, .core_dump_capacity = 4 * 1024});
EXPECT_TRUE(d2.GetRoot());
auto d3 = wlan::iwlwifi::DriverInspector(
wlan::iwlwifi::DriverInspectorOptions{.vmo_size = 4 * 1024, .core_dump_capacity = 0});
EXPECT_TRUE(d3.GetRoot());
auto d4 = wlan::iwlwifi::DriverInspector(
wlan::iwlwifi::DriverInspectorOptions{.vmo_size = 0, .core_dump_capacity = 0});
EXPECT_FALSE(d4.GetRoot());
}
// Test DriverInspector core dump functionality.
TEST(DriverInspectorTest, PublishCoreDump) {
auto inspector = wlan::iwlwifi::DriverInspector(wlan::iwlwifi::DriverInspectorOptions{
.root_name = "test_inspector", .vmo_size = 8 * 1024, .core_dump_capacity = 2 * 1024});
ASSERT_TRUE(inspector.GetRoot());
auto large_buffer = std::vector<char>(2 * 1024 + 1);
EXPECT_NOT_OK(inspector.PublishCoreDump("too large", large_buffer));
// Create 5 buffers of 512 bytes each.
std::vector<std::vector<char>> buffers;
for (size_t i = 0; i < 5; ++i) {
buffers.emplace_back(512, i);
}
// Insert the first 4 buffers as crash dumps, incrementally verifying that they all appear in the
// Inspect hierarchy.
for (size_t i = 0; i < 4; ++i) {
char buffer_name[16];
std::snprintf(buffer_name, sizeof(buffer_name), "buffer%zu", i);
EXPECT_OK(inspector.PublishCoreDump(buffer_name, buffers[i]));
auto root_hierarchy = ::inspect::ReadFromVmo(inspector.DuplicateVmo()).take_value();
EXPECT_EQ(1, root_hierarchy.children().size());
auto hierarchy = root_hierarchy.GetByPath({"test_inspector"});
EXPECT_NOT_NULL(hierarchy);
if (hierarchy != nullptr) {
auto& node = hierarchy->node();
EXPECT_EQ(i + 1, node.properties().size());
for (size_t j = 0; j < node.properties().size(); ++j) {
char property_name[16];
std::snprintf(property_name, sizeof(property_name), "buffer%zu", j);
auto prop = node.get_property<inspect::ByteVectorPropertyValue>(property_name);
EXPECT_NOT_NULL(prop);
if (prop != nullptr) {
EXPECT_EQ(512, prop->value().size());
EXPECT_EQ(0, std::memcmp(buffers[j].data(), prop->value().data(),
std::min(buffers[j].size(), prop->value().size())));
}
}
}
}
// Adding the fifth buffer should cause the oldest crash dump to be replaced.
EXPECT_OK(inspector.PublishCoreDump("buffer4", buffers[4]));
auto root_hierarchy = ::inspect::ReadFromVmo(inspector.DuplicateVmo()).take_value();
EXPECT_EQ(1, root_hierarchy.children().size());
auto hierarchy = root_hierarchy.GetByPath({"test_inspector"});
EXPECT_NOT_NULL(hierarchy);
if (hierarchy != nullptr) {
auto& node = hierarchy->node();
EXPECT_EQ(4, node.properties().size());
for (size_t j = 1; j < 5; ++j) {
char property_name[16];
std::snprintf(property_name, sizeof(property_name), "buffer%zu", j);
auto prop = node.get_property<inspect::ByteVectorPropertyValue>(property_name);
EXPECT_NOT_NULL(prop);
if (prop != nullptr) {
EXPECT_EQ(512, prop->value().size());
EXPECT_EQ(0, std::memcmp(buffers[j].data(), prop->value().data(),
std::min(buffers[j].size(), prop->value().size())));
}
}
}
}
} // namespace
} // namespace wlan::testing