Add tgk store fs adapter and tests

This commit is contained in:
Carl Niklas Rydberg 2025-12-21 19:23:41 +01:00
parent 257280934f
commit 05baf8e847
5 changed files with 778 additions and 1 deletions

View file

@ -251,6 +251,16 @@ target_link_libraries(amduat_test_tgk_store_mem
)
add_test(NAME tgk_store_mem COMMAND amduat_test_tgk_store_mem)
add_executable(amduat_test_tgk_store_fs tests/tgk/test_tgk_store_fs.c)
target_include_directories(amduat_test_tgk_store_fs
PRIVATE ${AMDUAT_INTERNAL_DIR}
PRIVATE ${AMDUAT_INCLUDE_DIR}
)
target_link_libraries(amduat_test_tgk_store_fs
PRIVATE amduat_tgk_store_fs
)
add_test(NAME tgk_store_fs COMMAND amduat_test_tgk_store_fs)
add_executable(amduat_test_tgk_prov tests/tgk/test_tgk_prov.c)
target_include_directories(amduat_test_tgk_prov
PRIVATE ${AMDUAT_INTERNAL_DIR}

View file

@ -3,4 +3,50 @@
/* Filesystem-backed TGK store adapter public API. */
#include "amduat/asl/asl_store_fs.h"
#include "amduat/asl/store.h"
#include "amduat/format/ref.h"
#include "amduat/tgk/store.h"
#include "amduat/tgk/tgk_store_mem.h"
#include <stdbool.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Manifest contract:
* - AMDUAT_FORMAT_REF_HEX: ASCII hex tokens of ASL1 ReferenceBytes,
* separated by whitespace.
* - AMDUAT_FORMAT_REF_BYTES: raw concatenation of ASL1 ReferenceBytes
* (hash_id big-endian + digest). */
typedef struct {
amduat_tgk_store_mem_t mem;
amduat_tgk_store_mem_artifact_t *artifacts;
size_t artifacts_len;
} amduat_tgk_store_fs_t;
bool amduat_tgk_store_fs_init(amduat_tgk_store_fs_t *fs,
amduat_tgk_store_config_t config,
const char *manifest_path,
amduat_format_ref_format_t manifest_format,
amduat_asl_store_t *asl_store);
bool amduat_tgk_store_fs_init_with_asl_fs(
amduat_tgk_store_fs_t *fs,
amduat_tgk_store_config_t config,
const char *manifest_path,
amduat_format_ref_format_t manifest_format,
amduat_asl_store_config_t asl_config,
const char *asl_root_path);
void amduat_tgk_store_fs_free(amduat_tgk_store_fs_t *fs);
amduat_tgk_store_ops_t amduat_tgk_store_fs_ops(void);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* AMDUAT_TGK_TGK_STORE_FS_H */

View file

@ -1,3 +1,268 @@
#include "amduat/tgk/tgk_store_fs.h"
/* TODO: implement filesystem-backed TGK store adapter. */
#include "amduat/asl/io.h"
#include "amduat/asl/ref_io.h"
#include <stdlib.h>
#include <string.h>
static void amduat_tgk_store_fs_reference_free(amduat_reference_t *ref) {
if (ref == NULL) {
return;
}
free((void *)ref->digest.data);
ref->digest.data = NULL;
ref->digest.len = 0;
}
static void amduat_tgk_store_fs_artifact_bytes_free(
amduat_tgk_store_mem_artifact_t *artifact) {
if (artifact == NULL) {
return;
}
free((void *)artifact->artifact.bytes.data);
artifact->artifact.bytes.data = NULL;
artifact->artifact.bytes.len = 0;
artifact->artifact.has_type_tag = false;
artifact->artifact.type_tag.tag_id = 0;
}
static void amduat_tgk_store_fs_artifact_full_free(
amduat_tgk_store_mem_artifact_t *artifact) {
if (artifact == NULL) {
return;
}
amduat_tgk_store_fs_artifact_bytes_free(artifact);
amduat_tgk_store_fs_reference_free(&artifact->ref);
}
static bool amduat_tgk_store_fs_load_manifest(
const char *manifest_path,
amduat_format_ref_format_t manifest_format,
amduat_reference_t **out_refs,
size_t *out_len) {
uint8_t *bytes = NULL;
size_t len = 0;
bool ok;
if (out_refs == NULL || out_len == NULL || manifest_path == NULL) {
return false;
}
*out_refs = NULL;
*out_len = 0;
if (!amduat_asl_read_path(manifest_path, &bytes, &len)) {
free(bytes);
return false;
}
ok = amduat_asl_ref_list_parse(amduat_octets(bytes, len), manifest_format,
out_refs, out_len);
free(bytes);
return ok;
}
static bool amduat_tgk_store_fs_get_config(void *ctx,
amduat_tgk_store_config_t *out_config) {
amduat_tgk_store_fs_t *fs = (amduat_tgk_store_fs_t *)ctx;
amduat_tgk_store_ops_t mem_ops = amduat_tgk_store_mem_ops();
if (fs == NULL || mem_ops.get_config == NULL) {
return false;
}
return mem_ops.get_config(&fs->mem, out_config);
}
static amduat_tgk_graph_error_t amduat_tgk_store_fs_resolve_edge(
void *ctx,
amduat_reference_t ref,
amduat_tgk_edge_body_t *out_body) {
amduat_tgk_store_fs_t *fs = (amduat_tgk_store_fs_t *)ctx;
amduat_tgk_store_ops_t mem_ops = amduat_tgk_store_mem_ops();
if (fs == NULL || mem_ops.resolve_edge == NULL) {
return GS_ERR_UNSUPPORTED;
}
return mem_ops.resolve_edge(&fs->mem, ref, out_body);
}
static bool amduat_tgk_store_fs_edges_from(
void *ctx,
amduat_reference_t node,
amduat_tgk_edge_type_filter_t type_filter,
amduat_tgk_graph_edge_view_list_t *out_edges) {
amduat_tgk_store_fs_t *fs = (amduat_tgk_store_fs_t *)ctx;
amduat_tgk_store_ops_t mem_ops = amduat_tgk_store_mem_ops();
if (fs == NULL || mem_ops.edges_from == NULL) {
return false;
}
return mem_ops.edges_from(&fs->mem, node, type_filter, out_edges);
}
static bool amduat_tgk_store_fs_edges_to(
void *ctx,
amduat_reference_t node,
amduat_tgk_edge_type_filter_t type_filter,
amduat_tgk_graph_edge_view_list_t *out_edges) {
amduat_tgk_store_fs_t *fs = (amduat_tgk_store_fs_t *)ctx;
amduat_tgk_store_ops_t mem_ops = amduat_tgk_store_mem_ops();
if (fs == NULL || mem_ops.edges_to == NULL) {
return false;
}
return mem_ops.edges_to(&fs->mem, node, type_filter, out_edges);
}
static bool amduat_tgk_store_fs_edges_incident(
void *ctx,
amduat_reference_t node,
amduat_tgk_edge_type_filter_t type_filter,
amduat_tgk_graph_edge_view_list_t *out_edges) {
amduat_tgk_store_fs_t *fs = (amduat_tgk_store_fs_t *)ctx;
amduat_tgk_store_ops_t mem_ops = amduat_tgk_store_mem_ops();
if (fs == NULL || mem_ops.edges_incident == NULL) {
return false;
}
return mem_ops.edges_incident(&fs->mem, node, type_filter, out_edges);
}
static bool amduat_tgk_store_fs_scan_edges(
void *ctx,
amduat_tgk_edge_type_filter_t type_filter,
amduat_octets_t page_token,
bool has_page_token,
amduat_tgk_graph_scan_result_t *out_scan) {
amduat_tgk_store_fs_t *fs = (amduat_tgk_store_fs_t *)ctx;
amduat_tgk_store_ops_t mem_ops = amduat_tgk_store_mem_ops();
if (fs == NULL || mem_ops.scan_edges == NULL) {
return false;
}
return mem_ops.scan_edges(&fs->mem, type_filter, page_token, has_page_token,
out_scan);
}
static bool amduat_tgk_store_fs_neighbors(
void *ctx,
amduat_reference_t node,
amduat_tgk_edge_type_filter_t type_filter,
amduat_tgk_graph_direction_t direction,
amduat_tgk_node_list_t *out_nodes) {
amduat_tgk_store_fs_t *fs = (amduat_tgk_store_fs_t *)ctx;
amduat_tgk_store_ops_t mem_ops = amduat_tgk_store_mem_ops();
if (fs == NULL || mem_ops.neighbors == NULL) {
return false;
}
return mem_ops.neighbors(&fs->mem, node, type_filter, direction, out_nodes);
}
bool amduat_tgk_store_fs_init(amduat_tgk_store_fs_t *fs,
amduat_tgk_store_config_t config,
const char *manifest_path,
amduat_format_ref_format_t manifest_format,
amduat_asl_store_t *asl_store) {
amduat_reference_t *refs = NULL;
size_t refs_len = 0;
amduat_tgk_store_mem_artifact_t *artifacts = NULL;
size_t i;
if (fs == NULL || manifest_path == NULL || asl_store == NULL) {
return false;
}
memset(fs, 0, sizeof(*fs));
if (!amduat_tgk_store_fs_load_manifest(manifest_path,
manifest_format,
&refs,
&refs_len)) {
return false;
}
if (refs_len != 0u) {
artifacts = (amduat_tgk_store_mem_artifact_t *)calloc(
refs_len, sizeof(*artifacts));
if (artifacts == NULL) {
amduat_asl_ref_list_free(refs, refs_len);
return false;
}
}
for (i = 0; i < refs_len; ++i) {
amduat_asl_store_error_t err;
artifacts[i].ref = refs[i];
artifacts[i].artifact = amduat_artifact(amduat_octets(NULL, 0));
err = amduat_asl_store_get(asl_store, refs[i], &artifacts[i].artifact);
if (err != AMDUAT_ASL_STORE_OK) {
size_t j;
for (j = 0; j < i; ++j) {
amduat_tgk_store_fs_artifact_bytes_free(&artifacts[j]);
}
amduat_asl_ref_list_free(refs, refs_len);
free(artifacts);
return false;
}
}
free(refs);
fs->artifacts = artifacts;
fs->artifacts_len = refs_len;
if (!amduat_tgk_store_mem_init(&fs->mem, config, fs->artifacts,
fs->artifacts_len)) {
amduat_tgk_store_fs_free(fs);
return false;
}
return true;
}
bool amduat_tgk_store_fs_init_with_asl_fs(
amduat_tgk_store_fs_t *fs,
amduat_tgk_store_config_t config,
const char *manifest_path,
amduat_format_ref_format_t manifest_format,
amduat_asl_store_config_t asl_config,
const char *asl_root_path) {
amduat_asl_store_fs_t asl_fs;
amduat_asl_store_t store;
if (fs == NULL || manifest_path == NULL || asl_root_path == NULL) {
return false;
}
if (!amduat_asl_store_fs_init(&asl_fs, asl_config, asl_root_path)) {
return false;
}
amduat_asl_store_init(&store, asl_config, amduat_asl_store_fs_ops(), &asl_fs);
return amduat_tgk_store_fs_init(fs, config, manifest_path, manifest_format,
&store);
}
void amduat_tgk_store_fs_free(amduat_tgk_store_fs_t *fs) {
size_t i;
if (fs == NULL) {
return;
}
amduat_tgk_store_mem_free(&fs->mem);
for (i = 0; i < fs->artifacts_len; ++i) {
amduat_tgk_store_fs_artifact_full_free(&fs->artifacts[i]);
}
free(fs->artifacts);
fs->artifacts = NULL;
fs->artifacts_len = 0;
}
amduat_tgk_store_ops_t amduat_tgk_store_fs_ops(void) {
amduat_tgk_store_ops_t ops;
memset(&ops, 0, sizeof(ops));
ops.get_config = amduat_tgk_store_fs_get_config;
ops.resolve_edge = amduat_tgk_store_fs_resolve_edge;
ops.edges_from = amduat_tgk_store_fs_edges_from;
ops.edges_to = amduat_tgk_store_fs_edges_to;
ops.edges_incident = amduat_tgk_store_fs_edges_incident;
ops.scan_edges = amduat_tgk_store_fs_scan_edges;
ops.neighbors = amduat_tgk_store_fs_neighbors;
return ops;
}

View file

@ -0,0 +1,392 @@
#include "amduat/asl/asl_store_fs.h"
#include "amduat/asl/ref_text.h"
#include "amduat/enc/asl1_core.h"
#include "amduat/enc/tgk1_edge.h"
#include "amduat/hash/asl1.h"
#include "amduat/tgk/store.h"
#include "amduat/tgk/tgk_store_fs.h"
#include <dirent.h>
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
static void fill_digest(uint8_t *out, uint8_t value) {
memset(out, value, 32);
}
static amduat_reference_t make_ref(uint8_t value, uint8_t *storage) {
fill_digest(storage, value);
return amduat_reference(AMDUAT_HASH_ASL1_ID_SHA256,
amduat_octets(storage, 32));
}
static void free_ref(amduat_reference_t *ref) {
if (ref == NULL) {
return;
}
free((void *)ref->digest.data);
ref->digest.data = NULL;
ref->digest.len = 0;
}
static bool join_path(const char *base, const char *segment, char **out_path) {
size_t base_len;
size_t seg_len;
bool needs_sep;
size_t total_len;
char *buffer;
size_t offset;
if (base == NULL || segment == NULL || out_path == NULL) {
return false;
}
if (base[0] == '\0' || segment[0] == '\0') {
return false;
}
base_len = strlen(base);
seg_len = strlen(segment);
needs_sep = base[base_len - 1u] != '/';
total_len = base_len + (needs_sep ? 1u : 0u) + seg_len + 1u;
buffer = (char *)malloc(total_len);
if (buffer == NULL) {
return false;
}
offset = 0u;
memcpy(buffer + offset, base, base_len);
offset += base_len;
if (needs_sep) {
buffer[offset++] = '/';
}
memcpy(buffer + offset, segment, seg_len);
offset += seg_len;
buffer[offset] = '\0';
*out_path = buffer;
return true;
}
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 = NULL;
if (strcmp(entry->d_name, ".") == 0 ||
strcmp(entry->d_name, "..") == 0) {
continue;
}
if (!join_path(path, entry->d_name, &child)) {
closedir(dir);
return false;
}
if (!remove_tree(child)) {
free(child);
closedir(dir);
return false;
}
free(child);
}
if (closedir(dir) != 0) {
return false;
}
return rmdir(path) == 0;
}
static char *make_temp_root(void) {
char *templ;
const char template_prefix[] = "/tmp/amduat_test_tgk_store_fs_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 write_manifest(const char *path,
const amduat_reference_t *refs,
size_t refs_len) {
FILE *stream;
size_t i;
if (path == NULL || (refs_len != 0 && refs == NULL)) {
return false;
}
stream = fopen(path, "wb");
if (stream == NULL) {
return false;
}
for (i = 0; i < refs_len; ++i) {
char *hex = NULL;
if (!amduat_asl_ref_encode_hex(refs[i], &hex)) {
fclose(stream);
return false;
}
if (fprintf(stream, "%s\n", hex) < 0) {
free(hex);
fclose(stream);
return false;
}
free(hex);
}
return fclose(stream) == 0;
}
static int test_manifest_load(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[2];
amduat_reference_t ref_edge1;
amduat_reference_t ref_edge2;
amduat_reference_t node_a;
amduat_reference_t node_b;
amduat_reference_t node_c;
amduat_reference_t payload1;
amduat_reference_t payload2;
uint8_t digest_node_a[32];
uint8_t digest_node_b[32];
uint8_t digest_node_c[32];
uint8_t digest_payload1[32];
uint8_t digest_payload2[32];
amduat_tgk_graph_edge_view_list_t edges;
amduat_tgk_edge_body_t body;
amduat_tgk_edge_body_t edge1;
amduat_tgk_edge_body_t edge2;
amduat_reference_t edge1_from[1];
amduat_reference_t edge1_to[1];
amduat_reference_t edge2_from[1];
amduat_reference_t edge2_to[1];
char *root = NULL;
char *manifest_path = NULL;
int exit_code = 1;
bool fs_ready = false;
memset(&edges, 0, sizeof(edges));
memset(&body, 0, sizeof(body));
edge_bytes[0] = amduat_octets(NULL, 0);
edge_bytes[1] = amduat_octets(NULL, 0);
memset(&ref_edge1, 0, sizeof(ref_edge1));
memset(&ref_edge2, 0, sizeof(ref_edge2));
memset(&fs, 0, sizeof(fs));
root = make_temp_root();
if (root == NULL) {
fprintf(stderr, "temp root failed\n");
goto cleanup;
}
if (!join_path(root, "manifest.txt", &manifest_path)) {
fprintf(stderr, "manifest path 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, "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;
memset(&tgk_config, 0, sizeof(tgk_config));
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;
node_a = make_ref(0xa1, digest_node_a);
node_b = make_ref(0xb1, digest_node_b);
node_c = make_ref(0xc1, digest_node_c);
payload1 = make_ref(0xe1, digest_payload1);
payload2 = make_ref(0xe2, digest_payload2);
memset(&edge1, 0, sizeof(edge1));
edge1.type = 0x10;
edge1_from[0] = node_a;
edge1.from = edge1_from;
edge1.from_len = 1;
edge1_to[0] = node_b;
edge1.to = edge1_to;
edge1.to_len = 1;
edge1.payload = payload1;
memset(&edge2, 0, sizeof(edge2));
edge2.type = 0x10;
edge2_from[0] = node_a;
edge2.from = edge2_from;
edge2.from_len = 1;
edge2_to[0] = node_c;
edge2.to = edge2_to;
edge2.to_len = 1;
edge2.payload = payload2;
if (!amduat_enc_tgk1_edge_encode_v1(&edge1, &edge_bytes[0]) ||
!amduat_enc_tgk1_edge_encode_v1(&edge2, &edge_bytes[1])) {
fprintf(stderr, "edge encode failed\n");
goto cleanup;
}
if (amduat_asl_store_put(
&asl_store,
amduat_artifact_with_type(edge_bytes[0],
amduat_type_tag(TYPE_TAG_TGK1_EDGE_V1)),
&ref_edge1) != AMDUAT_ASL_STORE_OK ||
amduat_asl_store_put(
&asl_store,
amduat_artifact_with_type(edge_bytes[1],
amduat_type_tag(TYPE_TAG_TGK1_EDGE_V1)),
&ref_edge2) != AMDUAT_ASL_STORE_OK) {
fprintf(stderr, "asl store put failed\n");
goto cleanup;
}
{
amduat_reference_t refs[2];
refs[0] = ref_edge1;
refs[1] = ref_edge2;
if (!write_manifest(manifest_path, refs, 2)) {
fprintf(stderr, "manifest write failed\n");
goto cleanup;
}
}
if (!amduat_tgk_store_fs_init(&fs, tgk_config, manifest_path,
AMDUAT_FORMAT_REF_HEX, &asl_store)) {
fprintf(stderr, "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_resolve_edge(&store, ref_edge1, &body) != 0) {
fprintf(stderr, "resolve_edge failed\n");
goto cleanup;
}
if (body.type != 0x10 || body.from_len != 1 || body.to_len != 1 ||
!amduat_reference_eq(body.from[0], node_a) ||
!amduat_reference_eq(body.to[0], node_b)) {
fprintf(stderr, "resolve_edge mismatch\n");
amduat_tgk_edge_body_free(&body);
goto cleanup;
}
amduat_tgk_edge_body_free(&body);
memset(&body, 0, sizeof(body));
{
amduat_tgk_edge_type_filter_t filter;
amduat_tgk_edge_type_id_t types[1] = {0x10};
size_t seen_b = 0;
size_t seen_c = 0;
size_t i;
filter.types = types;
filter.types_len = 1;
if (!amduat_tgk_store_edges_from(&store, node_a, filter, &edges)) {
fprintf(stderr, "edges_from failed\n");
goto cleanup;
}
if (edges.len != 2) {
fprintf(stderr, "edges_from len mismatch\n");
goto cleanup;
}
for (i = 0; i < edges.len; ++i) {
const amduat_tgk_graph_edge_view_t *edge = &edges.edges[i];
if (edge->body.type != 0x10 || edge->body.from_len != 1 ||
edge->body.to_len != 1 ||
!amduat_reference_eq(edge->body.from[0], node_a)) {
fprintf(stderr, "edges_from body mismatch\n");
goto cleanup;
}
if (amduat_reference_eq(edge->body.to[0], node_b)) {
seen_b++;
} else if (amduat_reference_eq(edge->body.to[0], node_c)) {
seen_c++;
} else {
fprintf(stderr, "edges_from unexpected endpoint\n");
goto cleanup;
}
}
if (seen_b != 1 || seen_c != 1) {
fprintf(stderr, "edges_from endpoints mismatch\n");
goto cleanup;
}
}
exit_code = 0;
cleanup:
amduat_tgk_graph_edge_view_list_free(&edges);
amduat_tgk_edge_body_free(&body);
if (fs_ready) {
amduat_tgk_store_fs_free(&fs);
}
free((void *)edge_bytes[0].data);
free((void *)edge_bytes[1].data);
free_ref(&ref_edge1);
free_ref(&ref_edge2);
free(manifest_path);
if (root != NULL) {
remove_tree(root);
}
free(root);
return exit_code;
}
int main(void) {
return test_manifest_load();
}

View file

@ -21,6 +21,7 @@ typedef struct {
amduat_reference_t ref_edge3;
amduat_reference_t ref_edge_bad;
amduat_reference_t ref_non_edge;
amduat_reference_t ref_missing;
amduat_reference_t node_a;
amduat_reference_t node_b;
amduat_reference_t node_c;
@ -33,6 +34,7 @@ typedef struct {
uint8_t digest_edge3[32];
uint8_t digest_edge_bad[32];
uint8_t digest_non_edge[32];
uint8_t digest_missing[32];
uint8_t digest_node_a[32];
uint8_t digest_node_b[32];
uint8_t digest_node_c[32];
@ -105,6 +107,7 @@ static bool init_env(test_env_t *env) {
env->ref_edge3 = make_ref(0x30, env->digest_edge3);
env->ref_edge_bad = make_ref(0x40, env->digest_edge_bad);
env->ref_non_edge = make_ref(0x50, env->digest_non_edge);
env->ref_missing = make_ref(0x60, env->digest_missing);
env->node_a = make_ref(0xa1, env->digest_node_a);
env->node_b = make_ref(0xb1, env->digest_node_b);
@ -236,6 +239,65 @@ static int test_resolve_edge_not_edge(const test_env_t *env) {
return 0;
}
static int test_resolve_edge_missing(const test_env_t *env) {
amduat_tgk_edge_body_t body;
amduat_tgk_graph_error_t err;
err = amduat_tgk_store_resolve_edge((amduat_tgk_store_t *)&env->store,
env->ref_missing, &body);
if (err != GS_ERR_ARTIFACT_ERROR) {
fprintf(stderr, "resolve_edge missing mismatch: %d\n", err);
return 1;
}
return 0;
}
static bool make_ref_for_hash(amduat_hash_id_t hash_id,
uint8_t value,
amduat_reference_t *out_ref) {
const amduat_hash_asl1_desc_t *desc;
uint8_t *digest;
if (out_ref == NULL) {
return false;
}
desc = amduat_hash_asl1_desc_lookup(hash_id);
if (desc == NULL || desc->digest_len == 0) {
return false;
}
digest = (uint8_t *)malloc(desc->digest_len);
if (digest == NULL) {
return false;
}
memset(digest, value, desc->digest_len);
*out_ref = amduat_reference(hash_id, amduat_octets(digest, desc->digest_len));
return true;
}
static int test_resolve_edge_unsupported(const test_env_t *env) {
amduat_reference_t ref;
amduat_tgk_edge_body_t body;
amduat_tgk_graph_error_t err;
int exit_code = 1;
if (!make_ref_for_hash(0x0002, 0x6au, &ref)) {
fprintf(stderr, "unsupported ref alloc failed\n");
return 1;
}
err = amduat_tgk_store_resolve_edge((amduat_tgk_store_t *)&env->store, ref,
&body);
if (err != GS_ERR_UNSUPPORTED) {
fprintf(stderr, "resolve_edge unsupported mismatch: %d\n", err);
goto cleanup;
}
exit_code = 0;
cleanup:
free_ref(&ref);
return exit_code;
}
static int test_type_filter(const test_env_t *env) {
amduat_tgk_edge_type_id_t types[1] = {0x10};
amduat_tgk_edge_type_filter_t filter;
@ -419,6 +481,8 @@ int main(void) {
if (test_resolve_edge_ok(&env) != 0 ||
test_resolve_edge_not_edge(&env) != 0 ||
test_resolve_edge_missing(&env) != 0 ||
test_resolve_edge_unsupported(&env) != 0 ||
test_type_filter(&env) != 0 ||
test_ordering(&env) != 0 ||
test_adjacency(&env) != 0 ||