#ifndef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 200809L #endif #include "amduatd_fed_cursor.h" #include "amduatd_store.h" #include "amduat/asl/asl_store_fs_meta.h" #include "amduat/hash/asl1.h" #include #include #include #include static int failures = 0; static void expect(bool cond, const char *msg) { if (!cond) { fprintf(stderr, "FAIL: %s\n", msg); failures++; } } static char *amduatd_test_make_temp_dir(void) { char tmpl[] = "/tmp/amduatd-fed-cursor-XXXXXX"; char *dir = mkdtemp(tmpl); size_t len; char *copy; if (dir == NULL) { perror("mkdtemp"); return NULL; } len = strlen(dir); copy = (char *)malloc(len + 1u); if (copy == NULL) { fprintf(stderr, "failed to allocate temp dir copy\n"); return NULL; } memcpy(copy, dir, len + 1u); return copy; } static bool amduatd_make_test_ref(uint8_t fill, amduat_reference_t *out_ref) { uint8_t digest_bytes[32]; amduat_octets_t digest; if (out_ref == NULL) { return false; } memset(digest_bytes, fill, sizeof(digest_bytes)); if (!amduat_octets_clone(amduat_octets(digest_bytes, sizeof(digest_bytes)), &digest)) { return false; } *out_ref = amduat_reference(AMDUAT_HASH_ASL1_ID_SHA256, digest); return true; } int main(void) { char *root = amduatd_test_make_temp_dir(); amduat_asl_store_fs_config_t cfg; amduatd_store_ctx_t store_ctx; amduat_asl_store_t store; amduat_asl_pointer_store_t pointer_store; amduatd_space_t space; amduatd_fed_cfg_t fed_cfg; amduatd_fed_cursor_record_t cursor; amduatd_fed_cursor_record_t fetched; amduat_reference_t record_ref; amduat_reference_t wrong_ref; amduat_reference_t new_ref; amduat_reference_t get_ref; amduatd_fed_cursor_status_t status; if (root == NULL) { return 1; } memset(&cfg, 0, sizeof(cfg)); if (!amduat_asl_store_fs_init_root(root, NULL, &cfg)) { fprintf(stderr, "failed to init store root\n"); free(root); return 1; } memset(&store_ctx, 0, sizeof(store_ctx)); memset(&store, 0, sizeof(store)); if (!amduatd_store_init(&store, &cfg, &store_ctx, root, AMDUATD_STORE_BACKEND_FS)) { fprintf(stderr, "failed to init store\n"); free(root); return 1; } if (!amduat_asl_pointer_store_init(&pointer_store, root)) { fprintf(stderr, "failed to init pointer store\n"); free(root); return 1; } if (!amduatd_space_init(&space, "alpha", false)) { fprintf(stderr, "failed to init space\n"); free(root); return 1; } amduatd_fed_cfg_init(&fed_cfg); expect(amduatd_fed_cursor_check_enabled(&fed_cfg) == AMDUATD_FED_CURSOR_ERR_DISABLED, "disabled federation status"); amduatd_fed_cursor_record_init(&fetched); memset(&get_ref, 0, sizeof(get_ref)); status = amduatd_fed_cursor_get(&store, &pointer_store, &space, "peer-a", &fetched, &get_ref); expect(status == AMDUATD_FED_CURSOR_ERR_NOT_FOUND, "empty cursor not found"); amduatd_fed_cursor_record_free(&fetched); amduatd_fed_cursor_record_init(&cursor); cursor.peer_key = strdup("peer-a"); cursor.space_id = strdup("alpha"); if (cursor.peer_key == NULL || cursor.space_id == NULL) { fprintf(stderr, "failed to allocate cursor identifiers\n"); amduatd_fed_cursor_record_free(&cursor); free(root); return 1; } cursor.has_logseq = true; cursor.last_logseq = 42u; if (!amduatd_make_test_ref(0x11, &record_ref)) { fprintf(stderr, "failed to make record ref\n"); amduatd_fed_cursor_record_free(&cursor); free(root); return 1; } cursor.has_record_ref = true; cursor.last_record_ref = record_ref; memset(&new_ref, 0, sizeof(new_ref)); status = amduatd_fed_cursor_cas_set(&store, &pointer_store, &space, "peer-a", NULL, &cursor, &new_ref); expect(status == AMDUATD_FED_CURSOR_OK, "cursor set ok"); amduatd_fed_cursor_record_init(&fetched); memset(&get_ref, 0, sizeof(get_ref)); status = amduatd_fed_cursor_get(&store, &pointer_store, &space, "peer-a", &fetched, &get_ref); expect(status == AMDUATD_FED_CURSOR_OK, "cursor get ok"); expect(strcmp(fetched.peer_key, "peer-a") == 0, "peer key match"); expect(fetched.space_id != NULL && strcmp(fetched.space_id, "alpha") == 0, "space match"); expect(fetched.has_logseq && fetched.last_logseq == 42u, "logseq match"); expect(fetched.has_record_ref && amduat_reference_eq(fetched.last_record_ref, record_ref), "record ref match"); expect(amduat_reference_eq(get_ref, new_ref), "pointer ref match"); amduatd_fed_cursor_record_free(&fetched); amduat_reference_free(&get_ref); if (!amduatd_make_test_ref(0x22, &wrong_ref)) { fprintf(stderr, "failed to make wrong ref\n"); amduat_reference_free(&new_ref); amduatd_fed_cursor_record_free(&cursor); free(root); return 1; } status = amduatd_fed_cursor_cas_set(&store, &pointer_store, &space, "peer-a", &wrong_ref, &cursor, NULL); expect(status == AMDUATD_FED_CURSOR_ERR_CONFLICT, "cursor cas conflict"); amduat_reference_free(&wrong_ref); amduatd_fed_cursor_record_free(&cursor); amduat_reference_free(&new_ref); { amduat_octets_t name = amduat_octets(NULL, 0u); bool ok = amduatd_fed_cursor_pointer_name(&space, "bad peer", &name); expect(!ok, "peer validation rejects invalid key"); amduat_octets_free(&name); } free(root); return failures == 0 ? 0 : 1; }