From d3224b26acb639870074a52a48fc2a207cdc964c Mon Sep 17 00:00:00 2001 From: Carl Niklas Rydberg Date: Sun, 21 Dec 2025 21:23:55 +0100 Subject: [PATCH] Added targeted ingest/remove + epoch tests in test_tgk_store_mem.c Added the FS ingest/remove + epoch test in test_tgk_store_fs.c and fixed the missing ref_edge initialization --- tests/tgk/test_tgk_store_fs.c | 182 ++++++++++++++++++++++++++++++++- tests/tgk/test_tgk_store_mem.c | 145 ++++++++++++++++++++++++++ 2 files changed, 326 insertions(+), 1 deletion(-) diff --git a/tests/tgk/test_tgk_store_fs.c b/tests/tgk/test_tgk_store_fs.c index 3d571f0..fa3f7ed 100644 --- a/tests/tgk/test_tgk_store_fs.c +++ b/tests/tgk/test_tgk_store_fs.c @@ -469,6 +469,7 @@ static int test_manifest_duplicate_refs(void) { uint8_t digest_node_a[32]; uint8_t digest_node_b[32]; uint8_t digest_payload[32]; + uint8_t digest_edge[32]; amduat_tgk_graph_scan_result_t scan; amduat_tgk_edge_body_t body; amduat_tgk_edge_body_t edge; @@ -522,6 +523,7 @@ static int test_manifest_duplicate_refs(void) { node_a = make_ref(0xa1, digest_node_a); node_b = make_ref(0xb1, digest_node_b); payload = make_ref(0xe1, digest_payload); + ref_edge = make_ref(0x71, digest_edge); memset(&edge, 0, sizeof(edge)); edge.type = 0x10; @@ -601,10 +603,188 @@ cleanup: return exit_code; } +static int test_ingest_remove_epoch(void) { + amduat_asl_store_config_t asl_config; + amduat_asl_store_fs_t asl_fs; + amduat_asl_store_t asl_store; + amduat_tgk_store_config_t tgk_config; + amduat_tgk_store_t store; + amduat_tgk_store_fs_t fs; + amduat_tgk_identity_domain_t domains[1]; + uint32_t edge_tags[1]; + amduat_tgk_edge_type_id_t edge_types[1]; + amduat_asl_encoding_profile_id_t encodings[1]; + amduat_octets_t edge_bytes; + amduat_reference_t ref_edge; + amduat_reference_t node_a; + amduat_reference_t node_b; + amduat_reference_t payload; + uint8_t digest_node_a[32]; + uint8_t digest_node_b[32]; + uint8_t digest_payload[32]; + amduat_tgk_edge_body_t edge; + amduat_reference_t edge_from[1]; + amduat_reference_t edge_to[1]; + amduat_tgk_snapshot_id_t epoch_before = 0; + amduat_tgk_snapshot_id_t epoch_after = 0; + amduat_tgk_graph_scan_result_t scan; + char *root = NULL; + char *manifest_path = NULL; + int exit_code = 1; + bool fs_ready = false; + + memset(&tgk_config, 0, sizeof(tgk_config)); + memset(&fs, 0, sizeof(fs)); + memset(&edge, 0, sizeof(edge)); + edge_bytes = amduat_octets(NULL, 0); + + root = make_temp_root(); + if (root == NULL) { + fprintf(stderr, "fs epoch temp root failed\n"); + goto cleanup; + } + if (!join_path(root, "manifest.txt", &manifest_path)) { + fprintf(stderr, "fs epoch manifest path failed\n"); + goto cleanup; + } + if (!write_manifest(manifest_path, NULL, 0)) { + fprintf(stderr, "fs epoch manifest write failed\n"); + goto cleanup; + } + + asl_config.encoding_profile_id = AMDUAT_ENC_ASL1_CORE_V1; + asl_config.hash_id = AMDUAT_HASH_ASL1_ID_SHA256; + if (!amduat_asl_store_fs_init(&asl_fs, asl_config, root)) { + fprintf(stderr, "fs epoch asl store fs init failed\n"); + goto cleanup; + } + amduat_asl_store_init(&asl_store, asl_config, amduat_asl_store_fs_ops(), + &asl_fs); + + domains[0].encoding_profile = AMDUAT_ENC_ASL1_CORE_V1; + domains[0].hash_id = AMDUAT_HASH_ASL1_ID_SHA256; + edge_tags[0] = TYPE_TAG_TGK1_EDGE_V1; + edge_types[0] = 0x10; + encodings[0] = TGK1_EDGE_ENC_V1; + + tgk_config.id_space.domains = domains; + tgk_config.id_space.domains_len = 1; + tgk_config.artifact_scope.description = amduat_octets(NULL, 0); + tgk_config.tgk_profiles.edge_tags = edge_tags; + tgk_config.tgk_profiles.edge_tags_len = 1; + tgk_config.tgk_profiles.edge_types = edge_types; + tgk_config.tgk_profiles.edge_types_len = 1; + tgk_config.tgk_profiles.encodings = encodings; + tgk_config.tgk_profiles.encodings_len = 1; + + if (!amduat_tgk_store_fs_init(&fs, tgk_config, manifest_path, + AMDUAT_FORMAT_REF_HEX, &asl_store)) { + fprintf(stderr, "fs epoch tgk store fs init failed\n"); + goto cleanup; + } + fs_ready = true; + amduat_tgk_store_init(&store, tgk_config, amduat_tgk_store_fs_ops(), &fs); + + if (!amduat_tgk_store_snapshot_id(&store, &epoch_before)) { + fprintf(stderr, "fs epoch get failed\n"); + goto cleanup; + } + + node_a = make_ref(0xa1, digest_node_a); + node_b = make_ref(0xb1, digest_node_b); + payload = make_ref(0xe1, digest_payload); + + edge.type = 0x10; + edge_from[0] = node_a; + edge.from = edge_from; + edge.from_len = 1; + edge_to[0] = node_b; + edge.to = edge_to; + edge.to_len = 1; + edge.payload = payload; + + if (!amduat_enc_tgk1_edge_encode_v1(&edge, &edge_bytes)) { + fprintf(stderr, "fs epoch edge encode failed\n"); + goto cleanup; + } + + if (!amduat_tgk_store_ingest_artifact( + &store, ref_edge, + amduat_artifact_with_type(edge_bytes, + amduat_type_tag(TYPE_TAG_TGK1_EDGE_V1)))) { + fprintf(stderr, "fs epoch ingest failed\n"); + goto cleanup; + } + + if (!amduat_tgk_store_snapshot_id(&store, &epoch_after)) { + fprintf(stderr, "fs epoch get after ingest failed\n"); + goto cleanup; + } + if (epoch_after != epoch_before + 1u) { + fprintf(stderr, "fs epoch did not increment on ingest\n"); + goto cleanup; + } + + if (!amduat_tgk_store_scan_edges(&store, + (amduat_tgk_edge_type_filter_t){0}, + amduat_octets(NULL, 0), false, &scan)) { + fprintf(stderr, "fs epoch scan failed\n"); + goto cleanup; + } + if (scan.edges.len != 1) { + fprintf(stderr, "fs epoch scan count mismatch\n"); + amduat_tgk_graph_scan_result_free(&scan); + goto cleanup; + } + amduat_tgk_graph_scan_result_free(&scan); + + if (!amduat_tgk_store_remove_artifact(&store, ref_edge)) { + fprintf(stderr, "fs epoch remove failed\n"); + goto cleanup; + } + if (!amduat_tgk_store_snapshot_id(&store, &epoch_after)) { + fprintf(stderr, "fs epoch get after remove failed\n"); + goto cleanup; + } + if (epoch_after != epoch_before + 2u) { + fprintf(stderr, "fs epoch did not increment on remove\n"); + goto cleanup; + } + + if (!amduat_tgk_store_scan_edges(&store, + (amduat_tgk_edge_type_filter_t){0}, + amduat_octets(NULL, 0), false, &scan)) { + fprintf(stderr, "fs epoch scan after remove failed\n"); + goto cleanup; + } + if (scan.edges.len != 0) { + fprintf(stderr, "fs epoch scan not empty after remove\n"); + amduat_tgk_graph_scan_result_free(&scan); + goto cleanup; + } + amduat_tgk_graph_scan_result_free(&scan); + + exit_code = 0; + +cleanup: + if (fs_ready) { + amduat_tgk_store_fs_free(&fs); + } + free((void *)edge_bytes.data); + free_ref(&ref_edge); + free(manifest_path); + if (root != NULL) { + remove_tree(root); + } + free(root); + return exit_code; +} + int main(void) { if (test_manifest_load() != 0 || test_init_rejects_duplicate_hash_id() != 0 || - test_manifest_duplicate_refs() != 0) { + test_manifest_duplicate_refs() != 0 || + test_ingest_remove_epoch() != 0) { return 1; } return 0; diff --git a/tests/tgk/test_tgk_store_mem.c b/tests/tgk/test_tgk_store_mem.c index 14b864c..f3ae3ba 100644 --- a/tests/tgk/test_tgk_store_mem.c +++ b/tests/tgk/test_tgk_store_mem.c @@ -774,6 +774,150 @@ cleanup: return exit_code; } +static int test_ingest_remove_epoch(void) { + amduat_tgk_store_mem_t mem; + amduat_tgk_store_t store; + amduat_tgk_store_config_t config; + amduat_tgk_identity_domain_t domains[1]; + uint32_t edge_tags[1]; + amduat_tgk_edge_type_id_t edge_types[1]; + amduat_asl_encoding_profile_id_t encodings[1]; + amduat_tgk_store_mem_artifact_t artifacts[1]; + amduat_octets_t edge_bytes; + amduat_reference_t ref_edge; + amduat_reference_t node_a; + amduat_reference_t node_b; + amduat_reference_t payload; + uint8_t digest_edge[32]; + uint8_t digest_a[32]; + uint8_t digest_b[32]; + uint8_t digest_payload[32]; + amduat_tgk_edge_body_t edge; + amduat_reference_t edge_from[1]; + amduat_reference_t edge_to[1]; + amduat_tgk_snapshot_id_t epoch_before = 0; + amduat_tgk_snapshot_id_t epoch_after = 0; + amduat_tgk_graph_scan_result_t scan; + int exit_code = 1; + + memset(&mem, 0, sizeof(mem)); + memset(&config, 0, sizeof(config)); + memset(&edge, 0, sizeof(edge)); + edge_bytes = amduat_octets(NULL, 0); + + domains[0].encoding_profile = AMDUAT_ENC_ASL1_CORE_V1; + domains[0].hash_id = AMDUAT_HASH_ASL1_ID_SHA256; + edge_tags[0] = TYPE_TAG_TGK1_EDGE_V1; + edge_types[0] = 0x10; + encodings[0] = TGK1_EDGE_ENC_V1; + + config.id_space.domains = domains; + config.id_space.domains_len = 1; + config.tgk_profiles.edge_tags = edge_tags; + config.tgk_profiles.edge_tags_len = 1; + config.tgk_profiles.edge_types = edge_types; + config.tgk_profiles.edge_types_len = 1; + config.tgk_profiles.encodings = encodings; + config.tgk_profiles.encodings_len = 1; + + ref_edge = make_ref(0x71, digest_edge); + node_a = make_ref(0xa1, digest_a); + node_b = make_ref(0xb1, digest_b); + payload = make_ref(0xe1, digest_payload); + + edge.type = 0x10; + edge_from[0] = node_a; + edge.from = edge_from; + edge.from_len = 1; + edge_to[0] = node_b; + edge.to = edge_to; + edge.to_len = 1; + edge.payload = payload; + + if (!amduat_enc_tgk1_edge_encode_v1(&edge, &edge_bytes)) { + fprintf(stderr, "epoch encode failed\n"); + return 1; + } + + artifacts[0].ref = ref_edge; + artifacts[0].artifact = + amduat_artifact_with_type(edge_bytes, + amduat_type_tag(TYPE_TAG_TGK1_EDGE_V1)); + + if (!amduat_tgk_store_mem_init(&mem, config, artifacts, 1)) { + fprintf(stderr, "epoch init failed\n"); + goto cleanup; + } + amduat_tgk_store_init(&store, config, amduat_tgk_store_mem_ops(), &mem); + + if (!amduat_tgk_store_snapshot_id(&store, &epoch_before)) { + fprintf(stderr, "epoch get failed\n"); + goto cleanup_mem; + } + + if (!amduat_tgk_store_ingest_artifact(&store, ref_edge, + artifacts[0].artifact)) { + fprintf(stderr, "epoch ingest failed\n"); + goto cleanup_mem; + } + if (!amduat_tgk_store_snapshot_id(&store, &epoch_after)) { + fprintf(stderr, "epoch get after ingest failed\n"); + goto cleanup_mem; + } + if (epoch_after != epoch_before) { + fprintf(stderr, "epoch changed on no-op ingest\n"); + goto cleanup_mem; + } + + if (!amduat_tgk_store_remove_artifact(&store, ref_edge)) { + fprintf(stderr, "epoch remove failed\n"); + goto cleanup_mem; + } + if (!amduat_tgk_store_snapshot_id(&store, &epoch_after)) { + fprintf(stderr, "epoch get after remove failed\n"); + goto cleanup_mem; + } + if (epoch_after != epoch_before + 1u) { + fprintf(stderr, "epoch did not increment on remove\n"); + goto cleanup_mem; + } + + if (!amduat_tgk_store_scan_edges(&store, + (amduat_tgk_edge_type_filter_t){0}, + amduat_octets(NULL, 0), false, &scan)) { + fprintf(stderr, "epoch scan failed\n"); + goto cleanup_mem; + } + if (scan.edges.len != 0) { + fprintf(stderr, "epoch scan not empty after remove\n"); + amduat_tgk_graph_scan_result_free(&scan); + goto cleanup_mem; + } + amduat_tgk_graph_scan_result_free(&scan); + + if (!amduat_tgk_store_ingest_artifact(&store, ref_edge, + artifacts[0].artifact)) { + fprintf(stderr, "epoch re-ingest failed\n"); + goto cleanup_mem; + } + if (!amduat_tgk_store_snapshot_id(&store, &epoch_after)) { + fprintf(stderr, "epoch get after re-ingest failed\n"); + goto cleanup_mem; + } + if (epoch_after != epoch_before + 2u) { + fprintf(stderr, "epoch did not increment on ingest\n"); + goto cleanup_mem; + } + + exit_code = 0; + +cleanup_mem: + amduat_tgk_store_mem_free(&mem); +cleanup: + free((void *)edge_bytes.data); + return exit_code; +} + static int test_resolve_edge_unsupported(const test_env_t *env) { amduat_reference_t ref; amduat_tgk_edge_body_t body; @@ -989,6 +1133,7 @@ int main(void) { test_duplicate_edge_ref_same_artifact() != 0 || test_duplicate_edge_ref_conflict() != 0 || test_scan_edges_pagination() != 0 || + test_ingest_remove_epoch() != 0 || test_type_filter(&env) != 0 || test_ordering(&env) != 0 || test_adjacency(&env) != 0 ||