#include "amduat/asl/asl_derivation_index_fs.h" #include "amduat/asl/asl_store_index_fs.h" #include "amduat/asl/collection.h" #include "amduat/asl/log_cursor.h" #include "amduat/asl/projection_checkpoint.h" #include "amduat/asl/record.h" #include "amduat/asl/store.h" #include "amduat/enc/asl1_core.h" #include "amduat/enc/tgk1_edge.h" #include "amduat/hash/asl1.h" #include "amduat/pel/derivation_sid.h" #include "amduat/tgk/store.h" #include "amduat/tgk/tgk_store_asl_index_fs.h" #include #include #include #include #include #include #include #include #include #include static char *make_temp_root(void) { char *templ; const char template_prefix[] = "/tmp/amduat_test_scriptlab_adapter_XXXXXX"; templ = (char *)malloc(sizeof(template_prefix)); if (templ == NULL) { return NULL; } memcpy(templ, template_prefix, sizeof(template_prefix)); if (mkdtemp(templ) == NULL) { free(templ); return NULL; } return templ; } static bool remove_tree(const char *path) { struct stat st; DIR *dir; struct dirent *entry; if (path == NULL) { return false; } if (lstat(path, &st) != 0) { return errno == ENOENT; } if (!S_ISDIR(st.st_mode)) { return unlink(path) == 0; } dir = opendir(path); if (dir == NULL) { return false; } while ((entry = readdir(dir)) != NULL) { char child[2048]; if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { continue; } snprintf(child, sizeof(child), "%s/%s", path, entry->d_name); if (!remove_tree(child)) { closedir(dir); return false; } } closedir(dir); return rmdir(path) == 0; } static bool ref_list_contains(amduat_reference_t needle, const amduat_reference_t *list, size_t len) { for (size_t i = 0u; i < len; ++i) { if (amduat_reference_eq(needle, list[i])) { return true; } } return false; } static int test_scriptlab_adapter_flow(void) { amduat_asl_store_config_t config; amduat_asl_store_index_fs_t asl_fs; amduat_asl_store_t asl_store; amduat_asl_collection_store_t collection_store; amduat_asl_derivation_index_fs_t deriv_index; amduat_reference_t node_a; amduat_reference_t node_b; amduat_reference_t edge_payload_ref; amduat_reference_t edge_ref; amduat_reference_t snapshot_ref; amduat_reference_t program_ref; amduat_reference_t checkpoint_ref; amduat_octets_t edge_bytes = amduat_octets(NULL, 0u); amduat_octets_t checkpoint_bytes = amduat_octets(NULL, 0u); amduat_octets_t sid = amduat_octets(NULL, 0u); amduat_asl_log_record_t *log_records = NULL; size_t log_count = 0u; amduat_asl_log_position_t next_logseq = 0u; bool log_end = true; amduat_asl_index_state_t index_state; uint64_t collection_offset = 0u; bool swapped = false; char *root; int exit_code = 1; root = make_temp_root(); if (root == NULL) { fprintf(stderr, "temp root failed\n"); return 1; } memset(&config, 0, sizeof(config)); config.encoding_profile_id = AMDUAT_ENC_ASL1_CORE_V1; config.hash_id = AMDUAT_HASH_ASL1_ID_SHA256; if (!amduat_asl_store_index_fs_init(&asl_fs, config, root)) { fprintf(stderr, "index fs init failed\n"); goto cleanup_root; } amduat_asl_store_init(&asl_store, config, amduat_asl_store_index_fs_ops(), &asl_fs); if (!amduat_asl_collection_store_init(&collection_store, root, &asl_store)) { fprintf(stderr, "collection store init failed\n"); goto cleanup_root; } if (!amduat_asl_derivation_index_fs_init(&deriv_index, root)) { fprintf(stderr, "derivation index init failed\n"); goto cleanup_root; } if (amduat_asl_record_store_put( &asl_store, amduat_octets("scriptlab/node", strlen("scriptlab/node")), amduat_octets("A", 1u), &node_a) != AMDUAT_ASL_STORE_OK) { fprintf(stderr, "node A store failed\n"); goto cleanup_root; } if (amduat_asl_record_store_put( &asl_store, amduat_octets("scriptlab/node", strlen("scriptlab/node")), amduat_octets("B", 1u), &node_b) != AMDUAT_ASL_STORE_OK) { fprintf(stderr, "node B store failed\n"); goto cleanup_nodes; } if (amduat_asl_record_store_put( &asl_store, amduat_octets("tgk/edge_payload", strlen("tgk/edge_payload")), amduat_octets("relates", strlen("relates")), &edge_payload_ref) != AMDUAT_ASL_STORE_OK) { fprintf(stderr, "edge payload store failed\n"); goto cleanup_nodes; } { amduat_tgk_edge_body_t edge; amduat_reference_t from_refs[1] = {node_a}; amduat_reference_t to_refs[1] = {node_b}; memset(&edge, 0, sizeof(edge)); edge.type = 1u; edge.from = from_refs; edge.from_len = 1u; edge.to = to_refs; edge.to_len = 1u; edge.payload = edge_payload_ref; if (!amduat_enc_tgk1_edge_encode_v1(&edge, &edge_bytes)) { fprintf(stderr, "edge encode failed\n"); goto cleanup_nodes; } } { amduat_artifact_t edge_artifact = amduat_artifact_with_type( edge_bytes, amduat_type_tag(AMDUAT_TYPE_TAG_TGK1_EDGE_V1)); if (amduat_asl_store_put(&asl_store, edge_artifact, &edge_ref) != AMDUAT_ASL_STORE_OK) { fprintf(stderr, "edge store failed\n"); goto cleanup_edge_bytes; } } amduat_octets_free(&edge_bytes); if (amduat_asl_collection_append(&collection_store, "tgk_edges", edge_ref, 0u, amduat_octets(NULL, 0u), &collection_offset) != AMDUAT_ASL_COLLECTION_OK) { fprintf(stderr, "collection append failed\n"); goto cleanup_edge_ref; } if (amduat_asl_collection_snapshot(&collection_store, "tgk_edges", UINT64_MAX, &snapshot_ref, &swapped) != AMDUAT_ASL_COLLECTION_OK) { fprintf(stderr, "collection snapshot failed\n"); goto cleanup_edge_ref; } { amduat_asl_record_t snapshot_record; if (amduat_asl_record_store_get(&asl_store, snapshot_ref, &snapshot_record) != AMDUAT_ASL_STORE_OK) { fprintf(stderr, "snapshot record fetch failed\n"); goto cleanup_snapshot_ref; } { amduat_asl_collection_snapshot_payload_t payload; if (!amduat_asl_collection_snapshot_payload_decode_v1( snapshot_record.payload, &payload)) { fprintf(stderr, "snapshot payload decode failed\n"); amduat_asl_record_free(&snapshot_record); goto cleanup_snapshot_ref; } if (!ref_list_contains(edge_ref, payload.refs, payload.refs_len)) { fprintf(stderr, "snapshot missing edge ref\n"); amduat_asl_collection_snapshot_payload_free(&payload); amduat_asl_record_free(&snapshot_record); goto cleanup_snapshot_ref; } amduat_asl_collection_snapshot_payload_free(&payload); } amduat_asl_record_free(&snapshot_record); } if (amduat_asl_record_store_put( &asl_store, amduat_octets("scriptlab/transform", strlen("scriptlab/transform")), amduat_octets("tgk_snapshot_v1", strlen("tgk_snapshot_v1")), &program_ref) != AMDUAT_ASL_STORE_OK) { fprintf(stderr, "program record store failed\n"); goto cleanup_snapshot_ref; } { amduat_pel_derivation_sid_input_t sid_input; amduat_asl_derivation_record_t record; amduat_octets_t exec_profile = amduat_octets("scriptlab/adapter", strlen("scriptlab/adapter")); amduat_reference_t inputs[1] = {edge_ref}; memset(&sid_input, 0, sizeof(sid_input)); sid_input.program_ref = program_ref; sid_input.input_refs = inputs; sid_input.input_refs_len = 1u; sid_input.has_params_ref = false; sid_input.has_exec_profile = true; sid_input.exec_profile = exec_profile; if (!amduat_pel_derivation_sid_compute(&sid_input, &sid)) { fprintf(stderr, "sid compute failed\n"); goto cleanup_program_ref; } memset(&record, 0, sizeof(record)); record.sid = sid; record.program_ref = program_ref; record.output_index = 0u; record.input_refs = inputs; record.input_refs_len = 1u; record.has_params_ref = false; record.has_exec_profile = true; record.exec_profile = exec_profile; if (amduat_asl_derivation_index_fs_add(&deriv_index, snapshot_ref, &record) != AMDUAT_ASL_STORE_OK) { fprintf(stderr, "derivation index add failed\n"); goto cleanup_sid; } } if (!amduat_asl_index_current_state(&asl_store, &index_state)) { fprintf(stderr, "index state read failed\n"); goto cleanup_sid; } if (!amduat_asl_log_read_since(&asl_store, 0u, 0u, &log_records, &log_count, &next_logseq, &log_end)) { fprintf(stderr, "log read since failed\n"); goto cleanup_sid; } { amduat_asl_projection_checkpoint_v1_t checkpoint; amduat_asl_projection_checkpoint_v1_t decoded; memset(&checkpoint, 0, sizeof(checkpoint)); checkpoint.checkpoint_version = AMDUAT_ASL_PROJECTION_CHECKPOINT_VERSION_V1; checkpoint.projection_name = amduat_octets("scriptlab", strlen("scriptlab")); checkpoint.projection_schema_version = 1u; checkpoint.has_snapshot_id = true; checkpoint.snapshot_id = index_state.snapshot_id; checkpoint.log_position = next_logseq; checkpoint.created_at = 0u; checkpoint.builder_id = amduat_octets("scriptlab-adapter", strlen("scriptlab-adapter")); checkpoint.has_artifact_count = true; checkpoint.artifact_count = log_count; if (!amduat_asl_projection_checkpoint_encode_v1(&checkpoint, &checkpoint_bytes)) { fprintf(stderr, "checkpoint encode failed\n"); goto cleanup_log_records; } if (amduat_asl_record_store_put( &asl_store, amduat_octets("projection/checkpoint", strlen("projection/checkpoint")), checkpoint_bytes, &checkpoint_ref) != AMDUAT_ASL_STORE_OK) { fprintf(stderr, "checkpoint store failed\n"); goto cleanup_checkpoint_bytes; } if (!amduat_asl_projection_checkpoint_decode_v1(checkpoint_bytes, &decoded)) { fprintf(stderr, "checkpoint decode failed\n"); goto cleanup_checkpoint_ref; } if (decoded.log_position != next_logseq) { fprintf(stderr, "checkpoint log position mismatch\n"); amduat_asl_projection_checkpoint_free(&decoded); goto cleanup_checkpoint_ref; } amduat_asl_projection_checkpoint_free(&decoded); } { 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_config_t tgk_config; amduat_tgk_store_asl_index_fs_t tgk_fs; amduat_tgk_store_t tgk_store; amduat_tgk_edge_type_filter_t filter; amduat_tgk_graph_edge_view_list_t edges; bool found = false; memset(&tgk_config, 0, sizeof(tgk_config)); domains[0].encoding_profile = AMDUAT_ENC_ASL1_CORE_V1; domains[0].hash_id = AMDUAT_HASH_ASL1_ID_SHA256; tgk_config.id_space.domains = domains; tgk_config.id_space.domains_len = 1u; tgk_config.artifact_scope.description = amduat_octets(NULL, 0u); edge_tags[0] = AMDUAT_TYPE_TAG_TGK1_EDGE_V1; edge_types[0] = 1u; encodings[0] = TGK1_EDGE_ENC_V1; tgk_config.tgk_profiles.edge_tags = edge_tags; tgk_config.tgk_profiles.edge_tags_len = 1u; tgk_config.tgk_profiles.edge_types = edge_types; tgk_config.tgk_profiles.edge_types_len = 1u; tgk_config.tgk_profiles.encodings = encodings; tgk_config.tgk_profiles.encodings_len = 1u; if (!amduat_tgk_store_asl_index_fs_init(&tgk_fs, tgk_config, &asl_fs)) { fprintf(stderr, "tgk store init failed\n"); goto cleanup_checkpoint_ref; } amduat_tgk_store_init(&tgk_store, tgk_config, amduat_tgk_store_asl_index_fs_ops(), &tgk_fs); filter.types = edge_types; filter.types_len = 1u; if (!amduat_tgk_store_edges_from(&tgk_store, node_a, filter, &edges)) { fprintf(stderr, "tgk edges_from failed\n"); goto cleanup_checkpoint_ref; } for (size_t i = 0u; i < edges.len; ++i) { amduat_tgk_edge_body_t *body = &edges.edges[i].body; if (ref_list_contains(node_b, body->to, body->to_len)) { found = true; break; } } amduat_tgk_graph_edge_view_list_free(&edges); if (!found) { fprintf(stderr, "tgk traversal missing expected edge\n"); goto cleanup_checkpoint_ref; } } exit_code = 0; cleanup_checkpoint_ref: amduat_reference_free(&checkpoint_ref); cleanup_log_records: amduat_enc_asl_log_free(log_records, log_count); cleanup_checkpoint_bytes: amduat_octets_free(&checkpoint_bytes); cleanup_sid: amduat_octets_free(&sid); cleanup_program_ref: amduat_reference_free(&program_ref); cleanup_snapshot_ref: amduat_reference_free(&snapshot_ref); cleanup_edge_ref: amduat_reference_free(&edge_ref); cleanup_edge_bytes: amduat_octets_free(&edge_bytes); cleanup_nodes: amduat_reference_free(&edge_payload_ref); amduat_reference_free(&node_b); amduat_reference_free(&node_a); cleanup_root: if (!remove_tree(root)) { fprintf(stderr, "cleanup failed\n"); exit_code = 1; } free(root); return exit_code; } int main(void) { return test_scriptlab_adapter_flow(); }