126 lines
6.2 KiB
C++
126 lines
6.2 KiB
C++
#include "zeroerr/assert.h"
|
|
#include "zeroerr/unittest.h"
|
|
|
|
#include "common/Module.h"
|
|
#include "policyregistry/PolicyRegistry.h"
|
|
|
|
#include <simplesquirrel/simplesquirrel.hpp>
|
|
|
|
#include <string>
|
|
|
|
using namespace eve::policyregistry;
|
|
|
|
TEST_CASE("policyregistry.registersCanonicalDescriptors") {
|
|
PolicyRegistry registry;
|
|
REQUIRE(registry.registerPolicy("movement", "ground", 2, 10, true, "builtin", "move.schema", "{\"z\":2,\"a\":1}"));
|
|
const auto* policy = registry.resolve("movement", "ground");
|
|
REQUIRE(policy != nullptr);
|
|
CHECK_EQ(policy->version, 2);
|
|
CHECK_EQ(policy->priority, 10);
|
|
CHECK(policy->enabled);
|
|
CHECK_EQ(implementationKindName(policy->kind), std::string("builtin"));
|
|
CHECK_EQ(policy->metadataJson, std::string("{\"a\":1,\"z\":2}"));
|
|
CHECK(!registry.registerPolicy("movement", "ground", 1, 0, true, "script", "", "{}"));
|
|
CHECK(!registry.registerPolicy("", "bad", 1, 0, true, "script", "", "{}"));
|
|
CHECK(!registry.registerPolicy("movement", "bad", 0, 0, true, "script", "", "{}"));
|
|
CHECK(!registry.registerPolicy("movement", "bad", 1, 0, true, "remote", "", "{}"));
|
|
CHECK(!registry.registerPolicy("movement", "bad", 1, 0, true, "script", "", "[]"));
|
|
}
|
|
|
|
TEST_CASE("policyregistry.selectsEnabledPriorityThenName") {
|
|
PolicyRegistry registry;
|
|
REQUIRE(registry.registerPolicy("targeting", "zeta", 1, 20, true, "script", "", "{}"));
|
|
REQUIRE(registry.registerPolicy("targeting", "alpha", 1, 20, true, "batch", "", "{}"));
|
|
REQUIRE(registry.registerPolicy("targeting", "disabled", 1, 99, false, "builtin", "", "{}"));
|
|
REQUIRE(registry.select("targeting") != nullptr);
|
|
CHECK_EQ(registry.select("targeting")->name, std::string("alpha"));
|
|
REQUIRE(registry.enable("targeting", "disabled", true));
|
|
CHECK_EQ(registry.select("targeting")->name, std::string("disabled"));
|
|
REQUIRE(registry.enable("targeting", "disabled", false));
|
|
CHECK_EQ(registry.select("targeting")->name, std::string("alpha"));
|
|
CHECK(registry.select("missing") == nullptr);
|
|
}
|
|
|
|
TEST_CASE("policyregistry.generationsInvalidateStaleHandles") {
|
|
PolicyRegistry registry;
|
|
REQUIRE(registry.registerPolicy("economy", "tax", 1, 0, true, "script", "tax.v1", "{}"));
|
|
const auto old = registry.handle("economy", "tax");
|
|
REQUIRE(registry.resolveHandle(old) != nullptr);
|
|
REQUIRE(registry.replacePolicy("economy", "tax", 2, 1, true, "batch", "tax.v2", "{}"));
|
|
CHECK(registry.resolveHandle(old) == nullptr);
|
|
CHECK_EQ(registry.resolve("economy", "tax")->generation, uint64_t{2});
|
|
REQUIRE(registry.remove("economy", "tax"));
|
|
REQUIRE(registry.registerPolicy("economy", "tax", 3, 2, true, "script", "tax.v3", "{}"));
|
|
CHECK_EQ(registry.resolve("economy", "tax")->generation, uint64_t{4});
|
|
}
|
|
|
|
TEST_CASE("policyregistry.enumeratesDeterministically") {
|
|
PolicyRegistry registry;
|
|
REQUIRE(registry.registerPolicy("z", "last", 1, 0, true, "script", "", "{}"));
|
|
REQUIRE(registry.registerPolicy("a", "two", 1, 0, true, "script", "", "{}"));
|
|
REQUIRE(registry.registerPolicy("a", "one", 1, 0, true, "script", "", "{}"));
|
|
CHECK_EQ(registry.size(), 3);
|
|
CHECK_EQ(registry.countDomain("a"), 2);
|
|
CHECK_EQ(registry.at(0)->domain, std::string("a"));
|
|
CHECK_EQ(registry.atDomain("a", 0)->name, std::string("one"));
|
|
CHECK_EQ(registry.atDomain("a", 1)->name, std::string("two"));
|
|
CHECK_EQ(registry.at(2)->domain, std::string("z"));
|
|
}
|
|
|
|
TEST_CASE("policyregistry.eventsAreOrderedAndDescriptive") {
|
|
PolicyRegistry registry;
|
|
REQUIRE(registry.registerPolicy("ai", "default", 1, 0, true, "script", "", "{}"));
|
|
REQUIRE(registry.enable("ai", "default", false));
|
|
REQUIRE(registry.replacePolicy("ai", "default", 2, 5, true, "batch", "", "{}"));
|
|
REQUIRE(registry.remove("ai", "default"));
|
|
CHECK_EQ(registry.eventCount(), 4);
|
|
CHECK_EQ(registry.eventAt(0)->name, std::string("policy_registered"));
|
|
CHECK_EQ(registry.eventAt(1)->name, std::string("policy_enabled"));
|
|
CHECK(!registry.eventAt(1)->enabled);
|
|
CHECK_EQ(registry.eventAt(3)->name, std::string("policy_removed"));
|
|
CHECK_EQ(registry.eventAt(3)->sequence, uint64_t{4});
|
|
registry.clearEvents();
|
|
REQUIRE(registry.registerPolicy("ai", "default", 3, 0, true, "script", "", "{}"));
|
|
CHECK_EQ(registry.eventAt(0)->sequence, uint64_t{5});
|
|
}
|
|
|
|
TEST_CASE("policyregistry.snapshotRoundTripsTransactionally") {
|
|
PolicyRegistry original;
|
|
REQUIRE(original.registerPolicy("orders", "safe", 1, 5, true, "script", "orders.policy", "{\"label\":\"Safe\"}"));
|
|
REQUIRE(original.registerPolicy("orders", "old", 1, 0, true, "builtin", "", "{}"));
|
|
REQUIRE(original.remove("orders", "old"));
|
|
const auto snapshot = original.snapshotJson();
|
|
|
|
PolicyRegistry restored;
|
|
REQUIRE(restored.restoreJson(snapshot));
|
|
CHECK_EQ(restored.snapshotJson(), snapshot);
|
|
CHECK_EQ(restored.select("orders")->name, std::string("safe"));
|
|
REQUIRE(restored.registerPolicy("orders", "old", 2, 0, true, "batch", "", "{}"));
|
|
CHECK_EQ(restored.resolve("orders", "old")->generation, uint64_t{3});
|
|
|
|
const auto before = restored.snapshotJson();
|
|
CHECK(!restored.restoreJson("{\"version\":1}"));
|
|
CHECK_EQ(restored.snapshotJson(), before);
|
|
}
|
|
|
|
TEST_CASE("policyregistry.scriptDiscoversButDoesNotStoreCallbacks") {
|
|
ssq::VM vm(1024, ssq::Libs::ALL);
|
|
eve::ModuleManager::expose(vm);
|
|
vm.run(vm.compileSource(R"(
|
|
result <- "fail";
|
|
local module = eve.PolicyRegistryModule();
|
|
local registry = module.newRegistry();
|
|
local callback = function(subject) { return subject + ":handled"; };
|
|
if (registry.registerPolicy("administration", "governor", 1, 8, true, "script",
|
|
"governor.policy", "{\"owner\":\"game-script\"}")) {
|
|
local generation = registry.resolve("administration", "governor").getGeneration();
|
|
local snapshot = registry.snapshotJson();
|
|
local copy = module.newRegistry();
|
|
if (copy.restoreJson(snapshot) && copy.select("administration").getName() == "governor" &&
|
|
copy.resolveGeneration("administration", "governor", generation).getKind() == "script")
|
|
result = callback("general-7");
|
|
}
|
|
)"));
|
|
CHECK_EQ(vm.find("result").toString(), std::string("general-7:handled"));
|
|
}
|