#define _POSIX_C_SOURCE 200809L #include "cst_parliament.h" #include "cst_realm.h" #include "cst_test_util.h" #include "os_compat.h" #include #include #include #include int main(void) { char dir[2048], cfg[512]; assert(!test_tmpdir(dir, sizeof(dir), "parliament")); assert(snprintf(cfg, sizeof(cfg), "%s/cfg", dir) < (int)sizeof(cfg)); assert(!os_mkdir_p(cfg, 0700)); setenv("XDG_CONFIG_HOME", cfg, 1); char realm[OS_PATH_MAX]; assert(cst_realm_dir(realm, sizeof(realm)) == 0); assert(cst_realm_init_password(realm, "correct horse battery") == 0); assert(cst_realm_is_password_mode(realm)); cst_realm_keys_t bad, good; assert(cst_realm_unlock_password(realm, "wrong", &bad) != 0); assert(cst_realm_unlock_password(realm, "correct horse battery", &good) == 0); /* Password Realm alone must not force parliament (solo keeps workers). */ unsetenv("CST_COLLABORATION"); assert(!cst_parliament_is_active()); char err[128]; char *hand = cst_parliament_login("correct horse battery", "phone-1", "pixel", err, sizeof(err)); assert(hand && strstr(hand, "LOGIN_OK") && strstr(hand, "chair=phone-1")); free(hand); assert(cst_parliament_is_chair()); assert(cst_parliament_sync_pending()); /* login bumps context path request */ cst_parliament_meta_t m; assert(cst_parliament_load(&m) == 0); assert(!strcmp(m.chair_instance, "phone-1")); assert(cst_parliament_context_put("shared agenda v1") == 0); assert(cst_parliament_sync_pending()); cst_parliament_sync_ack(); assert(!cst_parliament_sync_pending()); hand = cst_parliament_login("correct horse battery", "laptop-2", "thinkpad", err, sizeof(err)); assert(hand && strstr(hand, "handover_from=phone-1")); assert(strstr(hand, "shared agenda v1")); free(hand); assert(cst_parliament_load(&m) == 0); assert(!strcmp(m.chair_instance, "laptop-2")); assert(cst_parliament_is_chair()); assert(cst_parliament_session_ok(NULL, 0)); /* Member seat can join without stealing the chair. */ hand = cst_parliament_seat_join("correct horse battery", "tablet-3", "pad", err, sizeof(err)); assert(hand && strstr(hand, "JOIN_OK") && strstr(hand, "role=member")); assert(strstr(hand, "chair=laptop-2")); free(hand); /* Join rewrote the local seat ticket to tablet-3 (this process). */ { char sid[64] = {0}; assert(cst_parliament_session_ok(sid, sizeof(sid))); assert(!strcmp(sid, "tablet-3")); assert(!cst_parliament_is_chair()); } assert(cst_parliament_load(&m) == 0); assert(!strcmp(m.chair_instance, "laptop-2")); assert(cst_parliament_context_append("tablet-3", "status", "ready to take the UI slice") == 0); char *ctx = cst_parliament_context_get(); assert(ctx && strstr(ctx, "shared agenda v1")); assert(strstr(ctx, "seat=tablet-3") && strstr(ctx, "ready to take the UI")); free(ctx); assert(cst_parliament_sync_pending()); cst_parliament_sync_ack(); assert(cst_parliament_new_project("proj-b") == 0); ctx = cst_parliament_context_get(); assert(ctx && ctx[0] == 0); free(ctx); assert(cst_parliament_load(&m) == 0); assert(!strcmp(m.project_id, "proj-b")); assert(m.chair_instance[0] == 0); assert(!cst_parliament_session_ok(NULL, 0)); hand = cst_parliament_login("correct horse battery", "local-a", "dev", err, sizeof(err)); assert(hand && strstr(hand, "LOGIN_OK")); free(hand); assert(cst_parliament_is_chair()); assert(cst_parliament_session_ok(NULL, 0)); assert(cst_parliament_apply_sync(9, "parl-x", "proj-c", "chair-z", "synced-body") == 0); ctx = cst_parliament_context_get(); assert(ctx && strstr(ctx, "synced-body")); free(ctx); assert(cst_parliament_load(&m) == 0); assert(m.revision == 9); assert(!strcmp(m.chair_instance, "chair-z")); /* Remote chair takeover clears the demoted chair's local ticket. */ assert(!cst_parliament_session_ok(NULL, 0)); char *st = cst_parliament_status_text(); assert(st && strstr(st, "parliament")); assert(strstr(st, "service")); assert(strstr(st, "peer_sync") && strstr(st, "sealed")); assert(strstr(st, "role")); free(st); assert(cst_parliament_is_active()); assert(cst_parliament_daemon_info(NULL, NULL, 0, NULL) != 0); char def[64]; assert(cst_parliament_default_instance(def, sizeof(def)) == 0); assert(def[0]); test_rmrf(dir); puts("test_parliament: OK"); return 0; }