#include "zeroerr/assert.h" #include "zeroerr/unittest.h" #include "common/Module.h" #include "orders/Orders.h" #include #include using namespace eve::orders; TEST_CASE("orders.append.priorityAndStableIds") { OrderQueue queue; const auto first = queue.append("first", 1); const auto low = queue.append("low", 1); const auto high = queue.append("high", 10); CHECK_EQ(first, std::string("order-0000000000000001")); CHECK_EQ(low, std::string("order-0000000000000002")); CHECK_EQ(high, std::string("order-0000000000000003")); REQUIRE(queue.current() != nullptr); CHECK_EQ(queue.current()->kind, std::string("first")); CHECK(queue.complete(first)); CHECK_EQ(queue.current()->kind, std::string("high")); CHECK(queue.complete(high)); CHECK_EQ(queue.current()->kind, std::string("low")); } TEST_CASE("orders.replace.cancelsUnfinishedDeterministically") { OrderQueue queue; const auto active = queue.append("work"); const auto queued = queue.append("later"); const auto next = queue.replace("replacement", 5); CHECK_EQ(static_cast(queue.find(active)->state), static_cast(OrderState::Cancelled)); CHECK_EQ(static_cast(queue.find(queued)->state), static_cast(OrderState::Cancelled)); CHECK_EQ(queue.current()->id, next); REQUIRE(queue.eventCount() == 7); CHECK_EQ(queue.eventAt(0)->sequence, uint64_t{1}); CHECK_EQ(static_cast(queue.eventAt(0)->to), static_cast(OrderState::Queued)); CHECK_EQ(queue.eventAt(3)->orderId, active); CHECK_EQ(queue.eventAt(3)->reason, std::string("replaced")); CHECK_EQ(queue.eventAt(4)->orderId, queued); CHECK_EQ(queue.eventAt(5)->orderId, next); CHECK_EQ(static_cast(queue.eventAt(6)->to), static_cast(OrderState::Active)); } TEST_CASE("orders.interrupt.honoursPriority") { OrderQueue queue; const auto active = queue.append("critical", 20); CHECK(queue.interrupt("weak", 19).empty()); CHECK_EQ(queue.current()->id, active); const auto urgent = queue.interrupt("urgent", 20); CHECK(!urgent.empty()); CHECK_EQ(static_cast(queue.find(active)->state), static_cast(OrderState::Cancelled)); CHECK_EQ(queue.find(active)->reason, std::string("interrupted")); CHECK_EQ(queue.current()->id, urgent); } TEST_CASE("orders.lifecycle.completeFailCancel") { OrderQueue queue; const auto one = queue.append("one"); const auto two = queue.append("two"); const auto three = queue.append("three"); CHECK(queue.complete(one)); CHECK_EQ(static_cast(queue.find(one)->state), static_cast(OrderState::Completed)); CHECK(queue.fail(two, "policy_rejected")); CHECK_EQ(static_cast(queue.find(two)->state), static_cast(OrderState::Failed)); CHECK_EQ(queue.find(two)->reason, std::string("policy_rejected")); CHECK(queue.cancel(three, "owner_removed")); CHECK_EQ(static_cast(queue.find(three)->state), static_cast(OrderState::Cancelled)); CHECK(queue.current() == nullptr); CHECK(!queue.complete(three)); } TEST_CASE("orders.timeout.failsAndActivatesNext") { OrderQueue queue; const auto timed = queue.append("timed", 0, 0.5); const auto next = queue.append("next"); queue.update(0.25); CHECK_EQ(queue.current()->id, timed); queue.update(0.25); CHECK_EQ(static_cast(queue.find(timed)->state), static_cast(OrderState::Failed)); CHECK_EQ(queue.find(timed)->reason, std::string("timeout")); CHECK_EQ(queue.current()->id, next); } TEST_CASE("orders.payload.isDeterministicJsonCompatible") { OrderQueue queue; const auto id = queue.append("custom"); auto* payload = &queue.find(id)->payload; REQUIRE(payload != nullptr); payload->setString("name", "A\nB"); payload->setNumber("x", 12.5); payload->setBool("enabled", true); CHECK(payload->setJson("nested", "{\"target\":7}")); CHECK(!payload->setJson("bad", "not-json")); CHECK_EQ(payload->toJson(), std::string("{\"enabled\":true,\"name\":\"A\\nB\"," "\"nested\":{\"target\":7},\"x\":12.5}")); } TEST_CASE("orders.script.queueAndPayloadApi") { ssq::VM vm(1024, ssq::Libs::ALL); eve::ModuleManager::expose(vm); vm.run(vm.compileSource(R"( result <- "fail"; local module = eve.Orders(); local queue = module.newQueue(); local id = queue.append("custom_action", 7, 1.0); local order = queue.current(); order.getPayload().setJson("context", "{\"zone\":3}"); if (order.getId() == id && order.getKind() == "custom_action" && order.getPayload().getJson("context") == "{\"zone\":3}") { queue.complete(id); result = order.getState(); } )")); CHECK_EQ(vm.find("result").toString(), std::string("completed")); }