OrangePi3588Media/tests/test_config_expand.cpp

423 lines
11 KiB
C++

#include <gtest/gtest.h>
#include <string>
#include "utils/config_expand.h"
#include "utils/config_schema.h"
#include "utils/simple_json.h"
namespace rk3588 {
namespace {
TEST(ConfigExpandTest, ExpandEmptyConfig) {
SimpleJson root;
std::string err;
EXPECT_TRUE(ParseSimpleJson("{}", root, err));
SimpleJson expanded;
EXPECT_TRUE(ExpandRootConfig(root, expanded, err));
EXPECT_TRUE(expanded.IsObject());
}
TEST(ConfigExpandTest, PassthroughGraphs) {
const char* json = R"({
"graphs": [
{
"name": "test",
"nodes": [{"id": "n1", "type": "input_file", "role": "source"}],
"edges": []
}
]
})";
SimpleJson root;
std::string err;
EXPECT_TRUE(ParseSimpleJson(json, root, err));
SimpleJson expanded;
EXPECT_TRUE(ExpandRootConfig(root, expanded, err));
const SimpleJson* graphs = expanded.Find("graphs");
ASSERT_NE(graphs, nullptr);
EXPECT_TRUE(graphs->IsArray());
EXPECT_EQ(graphs->AsArray().size(), 1u);
EXPECT_EQ(graphs->AsArray()[0].ValueOr<std::string>("name", ""), "test");
}
TEST(ConfigExpandTest, ExpandTemplate) {
const char* json = R"({
"templates": {
"simple": {
"nodes": [
{"id": "src", "type": "input_file", "role": "source", "path": "${path}"}
],
"edges": []
}
},
"instances": [
{
"name": "cam1",
"template": "simple",
"params": {"path": "/video/test.mp4"}
}
]
})";
SimpleJson root;
std::string err;
EXPECT_TRUE(ParseSimpleJson(json, root, err));
SimpleJson expanded;
EXPECT_TRUE(ExpandRootConfig(root, expanded, err));
const SimpleJson* graphs = expanded.Find("graphs");
ASSERT_NE(graphs, nullptr);
EXPECT_EQ(graphs->AsArray().size(), 1u);
const SimpleJson& g = graphs->AsArray()[0];
EXPECT_EQ(g.ValueOr<std::string>("name", ""), "cam1");
const SimpleJson* nodes = g.Find("nodes");
ASSERT_NE(nodes, nullptr);
EXPECT_EQ(nodes->AsArray().size(), 1u);
// Node ID should be prefixed with instance name
EXPECT_EQ(nodes->AsArray()[0].ValueOr<std::string>("id", ""), "cam1_src");
// Placeholder should be replaced
EXPECT_EQ(nodes->AsArray()[0].ValueOr<std::string>("path", ""), "/video/test.mp4");
}
TEST(ConfigExpandTest, ExpandMultipleInstances) {
const char* json = R"({
"templates": {
"t": {
"nodes": [{"id": "n", "type": "test", "role": "source"}],
"edges": []
}
},
"instances": [
{"name": "i1", "template": "t", "params": {}},
{"name": "i2", "template": "t", "params": {}}
]
})";
SimpleJson root;
std::string err;
EXPECT_TRUE(ParseSimpleJson(json, root, err));
SimpleJson expanded;
EXPECT_TRUE(ExpandRootConfig(root, expanded, err));
const SimpleJson* graphs = expanded.Find("graphs");
ASSERT_NE(graphs, nullptr);
EXPECT_EQ(graphs->AsArray().size(), 2u);
EXPECT_EQ(graphs->AsArray()[0].ValueOr<std::string>("name", ""), "i1");
EXPECT_EQ(graphs->AsArray()[1].ValueOr<std::string>("name", ""), "i2");
}
TEST(ConfigExpandTest, ExpandWithOverride) {
const char* json = R"({
"templates": {
"t": {
"nodes": [
{"id": "n1", "type": "test", "role": "source", "enable": true},
{"id": "n2", "type": "filter", "role": "filter"}
],
"edges": [["n1", "n2"]]
}
},
"instances": [
{
"name": "inst",
"template": "t",
"params": {},
"override": {
"nodes": {
"n1": {"enable": false}
}
}
}
]
})";
SimpleJson root;
std::string err;
EXPECT_TRUE(ParseSimpleJson(json, root, err));
SimpleJson expanded;
EXPECT_TRUE(ExpandRootConfig(root, expanded, err));
const SimpleJson* graphs = expanded.Find("graphs");
ASSERT_NE(graphs, nullptr);
const SimpleJson* nodes = graphs->AsArray()[0].Find("nodes");
ASSERT_NE(nodes, nullptr);
// Find the overridden node
bool found = false;
for (const auto& n : nodes->AsArray()) {
if (n.ValueOr<std::string>("id", "") == "inst_n1") {
found = true;
EXPECT_FALSE(n.ValueOr<bool>("enable", true));
break;
}
}
EXPECT_TRUE(found);
}
TEST(ConfigExpandTest, EdgeIdPrefixing) {
const char* json = R"({
"templates": {
"t": {
"nodes": [
{"id": "src", "type": "source", "role": "source"},
{"id": "sink", "type": "sink", "role": "sink"}
],
"edges": [["src", "sink"]]
}
},
"instances": [
{"name": "g1", "template": "t", "params": {}}
]
})";
SimpleJson root;
std::string err;
EXPECT_TRUE(ParseSimpleJson(json, root, err));
SimpleJson expanded;
EXPECT_TRUE(ExpandRootConfig(root, expanded, err));
const SimpleJson* graphs = expanded.Find("graphs");
ASSERT_NE(graphs, nullptr);
const SimpleJson* edges = graphs->AsArray()[0].Find("edges");
ASSERT_NE(edges, nullptr);
EXPECT_EQ(edges->AsArray().size(), 1u);
// Edge endpoints should be prefixed
const SimpleJson& edge = edges->AsArray()[0];
EXPECT_TRUE(edge.IsArray());
EXPECT_EQ(edge.AsArray()[0].AsString(), "g1_src");
EXPECT_EQ(edge.AsArray()[1].AsString(), "g1_sink");
}
TEST(ConfigExpandTest, QueueConfigPreserved) {
const char* json = R"({
"queue": {"size": 16, "strategy": "drop_newest"},
"graphs": [
{
"name": "test",
"nodes": [],
"edges": []
}
]
})";
SimpleJson root;
std::string err;
EXPECT_TRUE(ParseSimpleJson(json, root, err));
SimpleJson expanded;
EXPECT_TRUE(ExpandRootConfig(root, expanded, err));
const SimpleJson* queue = expanded.Find("queue");
ASSERT_NE(queue, nullptr);
EXPECT_EQ(queue->ValueOr<int>("size", 0), 16);
EXPECT_EQ(queue->ValueOr<std::string>("strategy", ""), "drop_newest");
}
TEST(ConfigExpandTest, TemplateExecutorPreserved) {
const char* json = R"({
"templates": {
"t": {
"executor": {"batch_size": 2, "run_budget": "${budget}"},
"nodes": [{"id": "n", "type": "test", "role": "source"}],
"edges": []
}
},
"instances": [
{
"name": "cam1",
"template": "t",
"params": {"budget": 8}
}
]
})";
SimpleJson root;
std::string err;
EXPECT_TRUE(ParseSimpleJson(json, root, err));
SimpleJson expanded;
EXPECT_TRUE(ExpandRootConfig(root, expanded, err));
const SimpleJson* graphs = expanded.Find("graphs");
ASSERT_NE(graphs, nullptr);
ASSERT_EQ(graphs->AsArray().size(), 1u);
const SimpleJson* executor = graphs->AsArray()[0].Find("executor");
ASSERT_NE(executor, nullptr);
EXPECT_EQ(executor->ValueOr<int>("batch_size", 0), 2);
EXPECT_EQ(executor->ValueOr<std::string>("run_budget", ""), "8");
}
TEST(ConfigExpandTest, GlobalConfigPreserved) {
const char* json = R"({
"global": {"metrics_port": 8080, "log_level": "debug"},
"graphs": []
})";
SimpleJson root;
std::string err;
EXPECT_TRUE(ParseSimpleJson(json, root, err));
SimpleJson expanded;
EXPECT_TRUE(ExpandRootConfig(root, expanded, err));
const SimpleJson* global = expanded.Find("global");
ASSERT_NE(global, nullptr);
EXPECT_EQ(global->ValueOr<int>("metrics_port", 0), 8080);
EXPECT_EQ(global->ValueOr<std::string>("log_level", ""), "debug");
}
TEST(ConfigExpandTest, MissingTemplateError) {
const char* json = R"({
"templates": {},
"instances": [
{"name": "inst", "template": "nonexistent", "params": {}}
]
})";
SimpleJson root;
std::string err;
EXPECT_TRUE(ParseSimpleJson(json, root, err));
SimpleJson expanded;
EXPECT_FALSE(ExpandRootConfig(root, expanded, err));
EXPECT_FALSE(err.empty());
}
// Schema validation tests
TEST(ConfigSchemaTest, ValidGraphConfig) {
const char* json = R"({
"graphs": [
{
"name": "valid",
"nodes": [
{"id": "n1", "type": "input_file", "role": "source"},
{"id": "n2", "type": "output", "role": "sink"}
],
"edges": [["n1", "n2"]]
}
]
})";
SimpleJson root;
std::string err;
EXPECT_TRUE(ParseSimpleJson(json, root, err));
SimpleJson expanded;
EXPECT_TRUE(ExpandRootConfig(root, expanded, err));
EXPECT_TRUE(ValidateExpandedRootConfig(expanded, err)) << err;
}
TEST(ConfigSchemaTest, MissingGraphsArray) {
const char* json = R"({})";
SimpleJson root;
std::string err;
EXPECT_TRUE(ParseSimpleJson(json, root, err));
SimpleJson expanded;
EXPECT_TRUE(ExpandRootConfig(root, expanded, err));
// Should pass since empty graphs is allowed after expand
}
TEST(ConfigSchemaTest, NodeMissingId) {
const char* json = R"({
"graphs": [
{
"name": "test",
"nodes": [{"type": "input", "role": "source"}],
"edges": []
}
]
})";
SimpleJson root;
std::string err;
EXPECT_TRUE(ParseSimpleJson(json, root, err));
SimpleJson expanded;
EXPECT_TRUE(ExpandRootConfig(root, expanded, err));
EXPECT_FALSE(ValidateExpandedRootConfig(expanded, err));
}
TEST(ConfigSchemaTest, NodeMissingType) {
const char* json = R"({
"graphs": [
{
"name": "test",
"nodes": [{"id": "n1", "role": "source"}],
"edges": []
}
]
})";
SimpleJson root;
std::string err;
EXPECT_TRUE(ParseSimpleJson(json, root, err));
SimpleJson expanded;
EXPECT_TRUE(ExpandRootConfig(root, expanded, err));
EXPECT_FALSE(ValidateExpandedRootConfig(expanded, err));
}
TEST(ConfigSchemaTest, DuplicateNodeId) {
const char* json = R"({
"graphs": [
{
"name": "test",
"nodes": [
{"id": "same", "type": "t1", "role": "source"},
{"id": "same", "type": "t2", "role": "sink"}
],
"edges": []
}
]
})";
SimpleJson root;
std::string err;
EXPECT_TRUE(ParseSimpleJson(json, root, err));
SimpleJson expanded;
EXPECT_TRUE(ExpandRootConfig(root, expanded, err));
EXPECT_FALSE(ValidateExpandedRootConfig(expanded, err));
}
TEST(ConfigSchemaTest, EdgeReferencesUnknownNode) {
const char* json = R"({
"graphs": [
{
"name": "test",
"nodes": [{"id": "n1", "type": "t", "role": "source"}],
"edges": [["n1", "unknown"]]
}
]
})";
SimpleJson root;
std::string err;
EXPECT_TRUE(ParseSimpleJson(json, root, err));
SimpleJson expanded;
EXPECT_TRUE(ExpandRootConfig(root, expanded, err));
EXPECT_FALSE(ValidateExpandedRootConfig(expanded, err));
}
} // namespace
} // namespace rk3588