// tests/glue_ports.cpp: unit checks of src/glue on a throwaway TAI_HOME (no model, no network). // // every port of agent::ports() is wired after AppBundle::open // JsonBridge round trips between the module json types // StoreAdapter: records, chunks, search, tags, edges, secrets, schedules, sessions through the StorePort // SchedulerDbAdapter: claim_once is exclusive // StdoutCapture and SysInfoProbe // // Build (from taicpp/, after `make` so build/src/**/*.o exist) and run, in sh: // INC=""; for d in $(find src -type d); do INC="$INC -I$d"; done // g++ -std=c++23 -Wall -Wextra -Ibuild/gen -Isrc $INC -I../../moloapp/src tests/glue_ports.cpp // $(find build/src -name '*.o') -lsqlite3 -lcurl -lz -pthread -lutil -o build/glue_ports (one line) // build/glue_ports #include #include #include #include #include "glue/app_bundle.h" #include "glue/json_bridge.h" #include "glue/stdout_capture.h" #include "glue/sysinfo_probe.h" using namespace detz; static int g_checks = 0, g_fails = 0; #define CHECK(cond) \ do { \ ++g_checks; \ if (!(cond)) { \ ++g_fails; \ std::fprintf(stderr, "FAIL %s:%d %s\n", __FILE__, __LINE__, #cond); \ } \ } while (0) static void json_bridge() { store::Json s = store::Json::loads(R"({"a": [1, 2.5, "x"], "b": {"c": null, "d": true}})"); json::Value v = glue::JsonBridge::value(s); CHECK(v.get("a").size() == 3); CHECK(v.get("b").get("d").as_bool()); CHECK(glue::JsonBridge::store(v).dumps() == s.dumps()); wire::Json w = glue::JsonBridge::wire(v); CHECK(w.dumps() == s.dumps()); misc::Json m = glue::JsonBridge::misc(v); CHECK(m.dumps() == s.dumps()); } static void ports_wired(glue::AppBundle& b) { agent::Ports& p = agent::ports(); CHECK(p.runtime && p.shell && p.ui && p.mcp && p.skills && p.plexer && p.tui && p.ops && p.scheduler_db); CHECK(llm::log_sink() != nullptr); CHECK(llm::box_port() != nullptr); CHECK(b.agent().store == &b.store_port()); CHECK(!b.agent().messages.is_null() && b.agent().messages.size() >= 1); CHECK(b.agent().messages.at(0).get("role").str() == "system"); // runtime port: a worker store is a second connection on the same vault auto worker = p.runtime->open_store(); CHECK(worker != nullptr); CHECK(worker->profile() == b.agent().profile || !worker->profile().empty()); } static void store_port(glue::AppBundle& b) { agent::StorePort& s = b.store_port(); std::string id = s.add_record("note", "glue title", "alpha beta gamma unique-token-9137", {"glue"}, ""); CHECK(id.rfind("mem:", 0) == 0); s.add_chunks("record", id, {"alpha beta gamma unique-token-9137"}, ""); agent::Value read = s.read_record(id, 0, 100, ""); CHECK(read.is_object() && read.get("slice").str().find("unique-token-9137") != std::string::npos); agent::Value hits = s.fts_search("unique-token-9137", {}, "", 5); CHECK(hits.is_array() && hits.size() >= 1); agent::Value found = s.search_records("glue", std::nullopt, {}, 5, ""); CHECK(found.is_array() && found.size() >= 1); CHECK(s.item_tags(id, "").size() >= 1); std::string other = s.add_record("note", "second", "second record", {}, ""); std::string edge = s.add_edge(id, other, agent::Value("linked"), ""); CHECK(!edge.empty()); CHECK(s.edges_for(id, "").size() >= 1); CHECK(s.delete_record(id, "")); CHECK(s.read_record(id, 0, 10, "").is_null()); s.save_secret("glue-secret", "value-1", agent::Value(), {}, ""); CHECK(s.load_secret("glue-secret", "").value_or("") == "value-1"); CHECK(s.list_secret_infos("").size() >= 1); s.delete_secret("glue-secret", ""); CHECK(!s.load_secret("glue-secret", "").has_value()); int64_t sched = s.add_schedule("n", "do it", s.profile(), 0, "2999-01-01T00:00:00+00:00", 600, {}); CHECK(sched > 0); CHECK(s.list_schedules("").size() >= 1); s.remove_schedule(sched, ""); agent::Value msgs = agent::Value::array(); agent::Value m1 = agent::Value::object(); m1.set("role", "user"); m1.set("content", "hello glue"); msgs.push(m1); s.save_session("glue-prof", msgs, "main", "ctx-test"); agent::Value back = s.load_session("glue-prof", "main", "ctx-test"); CHECK(back.size() == 1 && back.at(0).get("content").str() == "hello glue"); agent::Value rows = s.sql_rows("SELECT 1, 'x', NULL", agent::Value::array()); CHECK(rows.size() == 1 && rows.at(0).at(0).as_int() == 1 && rows.at(0).at(1).str() == "x" && rows.at(0).at(2).is_null()); } static void scheduler_port(glue::AppBundle& b) { agent::StorePort& s = b.store_port(); int64_t id = s.add_schedule("", "run once", s.profile(), 0, "2000-01-01T00:00:00+00:00", 600, {}); auto due = b.scheduler_db().select_due("2001-01-01T00:00:00+00:00"); bool seen = false; for (const auto& d : due) if (d.id == id) seen = true; CHECK(seen); CHECK(b.scheduler_db().claim_once(id, "2001-01-01T00:00:00+00:00")); CHECK(!b.scheduler_db().claim_once(id, "2001-01-01T00:00:01+00:00")); b.scheduler_db().note_result(id, "done", "ok"); s.remove_schedule(id, ""); } static void helpers() { { glue::StdoutCapture cap; std::printf("captured-line\n"); std::string out = cap.finish(); CHECK(out == "captured-line\n"); } std::string info = glue::SysInfoProbe::collect(std::vector{"cpu", "root"}); CHECK(info.find("cpu: ") != std::string::npos && info.find("root: ") != std::string::npos && info.find("os: ") == std::string::npos); } int main() { char dir[] = "/tmp/detz-glue-ports-XXXXXX"; if (!mkdtemp(dir)) return 2; setenv("TAI_HOME", dir, 1); setenv("HOME", dir, 1); setenv("TAI_PASSPHRASE", "", 1); json_bridge(); helpers(); glue::BundleOptions o; o.version = "test"; o.mode = "test"; auto bundle = glue::AppBundle::open(o); ports_wired(*bundle); store_port(*bundle); scheduler_port(*bundle); bundle.reset(); CHECK(agent::ports().shell == nullptr); // the bundle clears the ports std::printf("%d checks, %d failures\n", g_checks, g_fails); return g_fails ? 1 : 0; }