423 lines
11 KiB
C++
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
|