Implement TGK store API and in-memory adapter with tests
This commit is contained in:
parent
d7ac826407
commit
8b2a5f830a
|
|
@ -241,6 +241,16 @@ target_link_libraries(amduat_test_tgk1_edge
|
|||
)
|
||||
add_test(NAME tgk1_edge COMMAND amduat_test_tgk1_edge)
|
||||
|
||||
add_executable(amduat_test_tgk_store_mem tests/tgk/test_tgk_store_mem.c)
|
||||
target_include_directories(amduat_test_tgk_store_mem
|
||||
PRIVATE ${AMDUAT_INTERNAL_DIR}
|
||||
PRIVATE ${AMDUAT_INCLUDE_DIR}
|
||||
)
|
||||
target_link_libraries(amduat_test_tgk_store_mem
|
||||
PRIVATE amduat_tgk_store_mem
|
||||
)
|
||||
add_test(NAME tgk_store_mem COMMAND amduat_test_tgk_store_mem)
|
||||
|
||||
add_executable(amduat_test_pel_program_dag_exec
|
||||
tests/pel/test_pel_program_dag_exec.c)
|
||||
target_include_directories(amduat_test_pel_program_dag_exec
|
||||
|
|
|
|||
|
|
@ -0,0 +1,170 @@
|
|||
#ifndef AMDUAT_TGK_STORE_H
|
||||
#define AMDUAT_TGK_STORE_H
|
||||
|
||||
#include "amduat/asl/core.h"
|
||||
#include "amduat/asl/store.h"
|
||||
#include "amduat/tgk/core.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
GS_ERR_NOT_EDGE = 1,
|
||||
GS_ERR_ARTIFACT_ERROR = 2,
|
||||
GS_ERR_UNSUPPORTED = 3,
|
||||
GS_ERR_INTEGRITY = 4
|
||||
} amduat_tgk_graph_error_t;
|
||||
|
||||
typedef struct {
|
||||
amduat_tgk_edge_type_id_t *types;
|
||||
size_t types_len;
|
||||
} amduat_tgk_edge_type_filter_t;
|
||||
|
||||
typedef enum {
|
||||
AMDUAT_TGK_GRAPH_DIR_OUT = 1,
|
||||
AMDUAT_TGK_GRAPH_DIR_IN = 2,
|
||||
AMDUAT_TGK_GRAPH_DIR_BOTH = 3
|
||||
} amduat_tgk_graph_direction_t;
|
||||
|
||||
typedef struct {
|
||||
amduat_reference_t edge_ref;
|
||||
amduat_tgk_edge_body_t body;
|
||||
} amduat_tgk_graph_edge_view_t;
|
||||
|
||||
typedef struct {
|
||||
amduat_tgk_graph_edge_view_t *edges;
|
||||
size_t len;
|
||||
} amduat_tgk_graph_edge_view_list_t;
|
||||
|
||||
typedef struct {
|
||||
amduat_reference_t *nodes;
|
||||
size_t len;
|
||||
} amduat_tgk_node_list_t;
|
||||
|
||||
typedef struct {
|
||||
amduat_tgk_graph_edge_view_list_t edges;
|
||||
amduat_octets_t next_page_token;
|
||||
bool has_next_page;
|
||||
} amduat_tgk_graph_scan_result_t;
|
||||
|
||||
typedef struct {
|
||||
amduat_asl_encoding_profile_id_t encoding_profile;
|
||||
amduat_hash_id_t hash_id;
|
||||
} amduat_tgk_identity_domain_t;
|
||||
|
||||
typedef struct {
|
||||
amduat_tgk_identity_domain_t *domains;
|
||||
size_t domains_len;
|
||||
} amduat_tgk_id_space_config_t;
|
||||
|
||||
typedef struct {
|
||||
amduat_octets_t description;
|
||||
} amduat_tgk_artifact_scope_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t *edge_tags;
|
||||
size_t edge_tags_len;
|
||||
amduat_tgk_edge_type_id_t *edge_types;
|
||||
size_t edge_types_len;
|
||||
amduat_asl_encoding_profile_id_t *encodings;
|
||||
size_t encodings_len;
|
||||
} amduat_tgk_profile_set_t;
|
||||
|
||||
typedef struct {
|
||||
amduat_tgk_id_space_config_t id_space;
|
||||
amduat_tgk_artifact_scope_t artifact_scope;
|
||||
amduat_tgk_profile_set_t tgk_profiles;
|
||||
} amduat_tgk_store_config_t;
|
||||
|
||||
typedef struct {
|
||||
bool (*get_config)(void *ctx, amduat_tgk_store_config_t *out_config);
|
||||
amduat_tgk_graph_error_t (*resolve_edge)(void *ctx,
|
||||
amduat_reference_t ref,
|
||||
amduat_tgk_edge_body_t *out_body);
|
||||
bool (*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);
|
||||
bool (*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);
|
||||
bool (*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);
|
||||
bool (*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);
|
||||
bool (*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_ops_t;
|
||||
|
||||
typedef struct {
|
||||
amduat_tgk_store_config_t config;
|
||||
amduat_tgk_store_ops_t ops;
|
||||
void *ctx;
|
||||
} amduat_tgk_store_t;
|
||||
|
||||
void amduat_tgk_store_init(amduat_tgk_store_t *store,
|
||||
amduat_tgk_store_config_t config,
|
||||
amduat_tgk_store_ops_t ops,
|
||||
void *ctx);
|
||||
|
||||
bool amduat_tgk_store_get_config(amduat_tgk_store_t *store,
|
||||
amduat_tgk_store_config_t *out_config);
|
||||
|
||||
amduat_tgk_graph_error_t amduat_tgk_store_resolve_edge(
|
||||
amduat_tgk_store_t *store,
|
||||
amduat_reference_t ref,
|
||||
amduat_tgk_edge_body_t *out_body);
|
||||
|
||||
bool amduat_tgk_store_edges_from(amduat_tgk_store_t *store,
|
||||
amduat_reference_t node,
|
||||
amduat_tgk_edge_type_filter_t type_filter,
|
||||
amduat_tgk_graph_edge_view_list_t *out_edges);
|
||||
|
||||
bool amduat_tgk_store_edges_to(amduat_tgk_store_t *store,
|
||||
amduat_reference_t node,
|
||||
amduat_tgk_edge_type_filter_t type_filter,
|
||||
amduat_tgk_graph_edge_view_list_t *out_edges);
|
||||
|
||||
bool amduat_tgk_store_edges_incident(
|
||||
amduat_tgk_store_t *store,
|
||||
amduat_reference_t node,
|
||||
amduat_tgk_edge_type_filter_t type_filter,
|
||||
amduat_tgk_graph_edge_view_list_t *out_edges);
|
||||
|
||||
bool amduat_tgk_store_scan_edges(amduat_tgk_store_t *store,
|
||||
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);
|
||||
|
||||
bool amduat_tgk_store_neighbors(amduat_tgk_store_t *store,
|
||||
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);
|
||||
|
||||
/* Query results are owned by the caller; free with helpers below. */
|
||||
void amduat_tgk_graph_edge_view_list_free(
|
||||
amduat_tgk_graph_edge_view_list_t *list);
|
||||
void amduat_tgk_node_list_free(amduat_tgk_node_list_t *list);
|
||||
void amduat_tgk_graph_scan_result_free(amduat_tgk_graph_scan_result_t *scan);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* AMDUAT_TGK_STORE_H */
|
||||
|
|
@ -3,4 +3,40 @@
|
|||
|
||||
/* In-memory TGK store adapter public API. */
|
||||
|
||||
#include "amduat/tgk/store.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
amduat_reference_t ref;
|
||||
amduat_artifact_t artifact;
|
||||
} amduat_tgk_store_mem_artifact_t;
|
||||
|
||||
typedef struct {
|
||||
amduat_tgk_store_config_t config;
|
||||
const amduat_tgk_store_mem_artifact_t *artifacts;
|
||||
size_t artifacts_len;
|
||||
amduat_tgk_graph_edge_view_t *edges;
|
||||
size_t edges_len;
|
||||
} amduat_tgk_store_mem_t;
|
||||
|
||||
/* Artifacts are borrowed; decoded edges are owned by the store. */
|
||||
bool amduat_tgk_store_mem_init(amduat_tgk_store_mem_t *mem,
|
||||
amduat_tgk_store_config_t config,
|
||||
const amduat_tgk_store_mem_artifact_t *artifacts,
|
||||
size_t artifacts_len);
|
||||
|
||||
void amduat_tgk_store_mem_free(amduat_tgk_store_mem_t *mem);
|
||||
|
||||
amduat_tgk_store_ops_t amduat_tgk_store_mem_ops(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* AMDUAT_TGK_TGK_STORE_MEM_H */
|
||||
|
|
|
|||
|
|
@ -1,3 +1,695 @@
|
|||
#include "amduat/tgk/tgk_store_mem.h"
|
||||
|
||||
/* TODO: implement in-memory TGK store adapter. */
|
||||
#include "amduat/enc/tgk1_edge.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static bool amduat_tgk_store_mem_hash_id_supported(
|
||||
const amduat_tgk_store_mem_t *mem,
|
||||
amduat_hash_id_t hash_id) {
|
||||
size_t i;
|
||||
|
||||
if (mem == NULL) {
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < mem->config.id_space.domains_len; ++i) {
|
||||
if (mem->config.id_space.domains[i].hash_id == hash_id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool amduat_tgk_store_mem_edge_tag_supported(
|
||||
const amduat_tgk_store_mem_t *mem,
|
||||
uint32_t tag_id) {
|
||||
size_t i;
|
||||
|
||||
if (mem == NULL) {
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < mem->config.tgk_profiles.edge_tags_len; ++i) {
|
||||
if (mem->config.tgk_profiles.edge_tags[i] == tag_id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool amduat_tgk_store_mem_edge_type_supported(
|
||||
const amduat_tgk_store_mem_t *mem,
|
||||
amduat_tgk_edge_type_id_t type_id) {
|
||||
size_t i;
|
||||
|
||||
if (mem == NULL) {
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < mem->config.tgk_profiles.edge_types_len; ++i) {
|
||||
if (mem->config.tgk_profiles.edge_types[i] == type_id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool amduat_tgk_store_mem_encoding_supported(
|
||||
const amduat_tgk_store_mem_t *mem,
|
||||
amduat_asl_encoding_profile_id_t profile_id) {
|
||||
size_t i;
|
||||
|
||||
if (mem == NULL) {
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < mem->config.tgk_profiles.encodings_len; ++i) {
|
||||
if (mem->config.tgk_profiles.encodings[i] == profile_id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool amduat_tgk_store_mem_type_filter_match(
|
||||
amduat_tgk_edge_type_filter_t filter,
|
||||
amduat_tgk_edge_type_id_t type_id) {
|
||||
size_t i;
|
||||
|
||||
if (filter.types_len == 0 || filter.types == NULL) {
|
||||
return true;
|
||||
}
|
||||
for (i = 0; i < filter.types_len; ++i) {
|
||||
if (filter.types[i] == type_id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool amduat_tgk_store_mem_node_in_list(
|
||||
amduat_reference_t node,
|
||||
const amduat_reference_t *list,
|
||||
size_t len) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
if (amduat_reference_eq(node, list[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int amduat_tgk_store_mem_octets_cmp(amduat_octets_t a,
|
||||
amduat_octets_t b) {
|
||||
size_t min_len;
|
||||
int cmp;
|
||||
|
||||
min_len = a.len < b.len ? a.len : b.len;
|
||||
if (min_len != 0 && a.data != NULL && b.data != NULL) {
|
||||
cmp = memcmp(a.data, b.data, min_len);
|
||||
if (cmp != 0) {
|
||||
return cmp;
|
||||
}
|
||||
} else if (min_len != 0) {
|
||||
return (a.data == NULL) ? -1 : 1;
|
||||
}
|
||||
|
||||
if (a.len < b.len) {
|
||||
return -1;
|
||||
}
|
||||
if (a.len > b.len) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amduat_tgk_store_mem_ref_cmp(amduat_reference_t a,
|
||||
amduat_reference_t b) {
|
||||
if (a.hash_id < b.hash_id) {
|
||||
return -1;
|
||||
}
|
||||
if (a.hash_id > b.hash_id) {
|
||||
return 1;
|
||||
}
|
||||
return amduat_tgk_store_mem_octets_cmp(a.digest, b.digest);
|
||||
}
|
||||
|
||||
static int amduat_tgk_store_mem_ref_ptr_cmp(const void *a, const void *b) {
|
||||
const amduat_reference_t *ref_a = (const amduat_reference_t *)a;
|
||||
const amduat_reference_t *ref_b = (const amduat_reference_t *)b;
|
||||
|
||||
return amduat_tgk_store_mem_ref_cmp(*ref_a, *ref_b);
|
||||
}
|
||||
|
||||
static int amduat_tgk_store_mem_edge_cmp(const void *a, const void *b) {
|
||||
const amduat_tgk_graph_edge_view_t *edge_a =
|
||||
(const amduat_tgk_graph_edge_view_t *)a;
|
||||
const amduat_tgk_graph_edge_view_t *edge_b =
|
||||
(const amduat_tgk_graph_edge_view_t *)b;
|
||||
|
||||
return amduat_tgk_store_mem_ref_cmp(edge_a->edge_ref, edge_b->edge_ref);
|
||||
}
|
||||
|
||||
static bool amduat_tgk_store_mem_reference_clone(amduat_reference_t src,
|
||||
amduat_reference_t *dst) {
|
||||
uint8_t *digest_copy;
|
||||
|
||||
if (dst == NULL) {
|
||||
return false;
|
||||
}
|
||||
*dst = amduat_reference(src.hash_id, amduat_octets(NULL, 0));
|
||||
if (src.digest.len == 0) {
|
||||
return true;
|
||||
}
|
||||
if (src.digest.data == NULL) {
|
||||
return false;
|
||||
}
|
||||
digest_copy = (uint8_t *)malloc(src.digest.len);
|
||||
if (digest_copy == NULL) {
|
||||
return false;
|
||||
}
|
||||
memcpy(digest_copy, src.digest.data, src.digest.len);
|
||||
dst->digest = amduat_octets(digest_copy, src.digest.len);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void amduat_tgk_store_mem_reference_free(amduat_reference_t *ref) {
|
||||
if (ref == NULL) {
|
||||
return;
|
||||
}
|
||||
free((void *)ref->digest.data);
|
||||
ref->digest.data = NULL;
|
||||
ref->digest.len = 0;
|
||||
}
|
||||
|
||||
static bool amduat_tgk_store_mem_edge_body_clone(
|
||||
const amduat_tgk_edge_body_t *src,
|
||||
amduat_tgk_edge_body_t *dst) {
|
||||
size_t i;
|
||||
|
||||
if (src == NULL || dst == NULL) {
|
||||
return false;
|
||||
}
|
||||
memset(dst, 0, sizeof(*dst));
|
||||
dst->type = src->type;
|
||||
if (src->from_len != 0) {
|
||||
dst->from =
|
||||
(amduat_reference_t *)calloc(src->from_len,
|
||||
sizeof(amduat_reference_t));
|
||||
if (dst->from == NULL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < src->from_len; ++i) {
|
||||
if (!amduat_tgk_store_mem_reference_clone(src->from[i], &dst->from[i])) {
|
||||
dst->from_len = i;
|
||||
amduat_tgk_edge_body_free(dst);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
dst->from_len = src->from_len;
|
||||
|
||||
if (src->to_len != 0) {
|
||||
dst->to =
|
||||
(amduat_reference_t *)calloc(src->to_len,
|
||||
sizeof(amduat_reference_t));
|
||||
if (dst->to == NULL) {
|
||||
amduat_tgk_edge_body_free(dst);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < src->to_len; ++i) {
|
||||
if (!amduat_tgk_store_mem_reference_clone(src->to[i], &dst->to[i])) {
|
||||
dst->to_len = i;
|
||||
amduat_tgk_edge_body_free(dst);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
dst->to_len = src->to_len;
|
||||
|
||||
if (!amduat_tgk_store_mem_reference_clone(src->payload, &dst->payload)) {
|
||||
amduat_tgk_edge_body_free(dst);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool amduat_tgk_store_mem_edge_view_clone(
|
||||
const amduat_tgk_graph_edge_view_t *src,
|
||||
amduat_tgk_graph_edge_view_t *dst) {
|
||||
if (src == NULL || dst == NULL) {
|
||||
return false;
|
||||
}
|
||||
memset(dst, 0, sizeof(*dst));
|
||||
if (!amduat_tgk_store_mem_reference_clone(src->edge_ref, &dst->edge_ref)) {
|
||||
return false;
|
||||
}
|
||||
if (!amduat_tgk_store_mem_edge_body_clone(&src->body, &dst->body)) {
|
||||
amduat_tgk_store_mem_reference_free(&dst->edge_ref);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static const amduat_tgk_store_mem_artifact_t *
|
||||
amduat_tgk_store_mem_lookup_artifact(const amduat_tgk_store_mem_t *mem,
|
||||
amduat_reference_t ref) {
|
||||
size_t i;
|
||||
|
||||
if (mem == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < mem->artifacts_len; ++i) {
|
||||
if (amduat_reference_eq(mem->artifacts[i].ref, ref)) {
|
||||
return &mem->artifacts[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static amduat_tgk_graph_error_t amduat_tgk_store_mem_decode_edge(
|
||||
const amduat_tgk_store_mem_t *mem,
|
||||
const amduat_tgk_store_mem_artifact_t *entry,
|
||||
amduat_tgk_edge_body_t *out_body) {
|
||||
if (out_body != NULL) {
|
||||
memset(out_body, 0, sizeof(*out_body));
|
||||
}
|
||||
if (mem == NULL || entry == NULL || out_body == NULL) {
|
||||
return GS_ERR_UNSUPPORTED;
|
||||
}
|
||||
if (!entry->artifact.has_type_tag ||
|
||||
!amduat_tgk_store_mem_edge_tag_supported(
|
||||
mem, entry->artifact.type_tag.tag_id)) {
|
||||
return GS_ERR_NOT_EDGE;
|
||||
}
|
||||
if (!amduat_tgk_store_mem_encoding_supported(mem, TGK1_EDGE_ENC_V1)) {
|
||||
return GS_ERR_UNSUPPORTED;
|
||||
}
|
||||
if (entry->artifact.bytes.len != 0 &&
|
||||
entry->artifact.bytes.data == NULL) {
|
||||
return GS_ERR_INTEGRITY;
|
||||
}
|
||||
if (!amduat_enc_tgk1_edge_decode_v1(entry->artifact.bytes, out_body)) {
|
||||
return GS_ERR_INTEGRITY;
|
||||
}
|
||||
if (!amduat_tgk_edge_body_has_endpoints(out_body)) {
|
||||
amduat_tgk_edge_body_free(out_body);
|
||||
return GS_ERR_INTEGRITY;
|
||||
}
|
||||
if (!amduat_tgk_store_mem_edge_type_supported(mem, out_body->type)) {
|
||||
amduat_tgk_edge_body_free(out_body);
|
||||
return GS_ERR_NOT_EDGE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool amduat_tgk_store_mem_build_edge_list(
|
||||
const amduat_tgk_store_mem_t *mem,
|
||||
amduat_tgk_edge_type_filter_t type_filter,
|
||||
const amduat_reference_t *node,
|
||||
bool check_from,
|
||||
bool check_to,
|
||||
amduat_tgk_graph_edge_view_list_t *out_edges) {
|
||||
size_t count = 0;
|
||||
size_t i;
|
||||
size_t idx;
|
||||
|
||||
if (mem == NULL || out_edges == NULL) {
|
||||
return false;
|
||||
}
|
||||
out_edges->edges = NULL;
|
||||
out_edges->len = 0;
|
||||
|
||||
for (i = 0; i < mem->edges_len; ++i) {
|
||||
const amduat_tgk_graph_edge_view_t *edge = &mem->edges[i];
|
||||
bool matched = false;
|
||||
if (!amduat_tgk_store_mem_type_filter_match(type_filter, edge->body.type)) {
|
||||
continue;
|
||||
}
|
||||
if (node == NULL) {
|
||||
matched = true;
|
||||
} else {
|
||||
if (check_from &&
|
||||
amduat_tgk_store_mem_node_in_list(*node, edge->body.from,
|
||||
edge->body.from_len)) {
|
||||
matched = true;
|
||||
}
|
||||
if (check_to &&
|
||||
amduat_tgk_store_mem_node_in_list(*node, edge->body.to,
|
||||
edge->body.to_len)) {
|
||||
matched = true;
|
||||
}
|
||||
}
|
||||
if (matched) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
return true;
|
||||
}
|
||||
out_edges->edges =
|
||||
(amduat_tgk_graph_edge_view_t *)calloc(count,
|
||||
sizeof(amduat_tgk_graph_edge_view_t));
|
||||
if (out_edges->edges == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
idx = 0;
|
||||
for (i = 0; i < mem->edges_len; ++i) {
|
||||
const amduat_tgk_graph_edge_view_t *edge = &mem->edges[i];
|
||||
bool matched = false;
|
||||
if (!amduat_tgk_store_mem_type_filter_match(type_filter, edge->body.type)) {
|
||||
continue;
|
||||
}
|
||||
if (node == NULL) {
|
||||
matched = true;
|
||||
} else {
|
||||
if (check_from &&
|
||||
amduat_tgk_store_mem_node_in_list(*node, edge->body.from,
|
||||
edge->body.from_len)) {
|
||||
matched = true;
|
||||
}
|
||||
if (check_to &&
|
||||
amduat_tgk_store_mem_node_in_list(*node, edge->body.to,
|
||||
edge->body.to_len)) {
|
||||
matched = true;
|
||||
}
|
||||
}
|
||||
if (matched) {
|
||||
if (!amduat_tgk_store_mem_edge_view_clone(edge,
|
||||
&out_edges->edges[idx])) {
|
||||
out_edges->len = idx;
|
||||
amduat_tgk_graph_edge_view_list_free(out_edges);
|
||||
return false;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
out_edges->len = idx;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool amduat_tgk_store_mem_get_config(void *ctx,
|
||||
amduat_tgk_store_config_t *out_config) {
|
||||
amduat_tgk_store_mem_t *mem = (amduat_tgk_store_mem_t *)ctx;
|
||||
|
||||
if (mem == NULL || out_config == NULL) {
|
||||
return false;
|
||||
}
|
||||
*out_config = mem->config;
|
||||
return true;
|
||||
}
|
||||
|
||||
static amduat_tgk_graph_error_t amduat_tgk_store_mem_resolve_edge(
|
||||
void *ctx,
|
||||
amduat_reference_t ref,
|
||||
amduat_tgk_edge_body_t *out_body) {
|
||||
amduat_tgk_store_mem_t *mem = (amduat_tgk_store_mem_t *)ctx;
|
||||
const amduat_tgk_store_mem_artifact_t *entry;
|
||||
|
||||
if (out_body != NULL) {
|
||||
memset(out_body, 0, sizeof(*out_body));
|
||||
}
|
||||
if (mem == NULL || out_body == NULL) {
|
||||
return GS_ERR_UNSUPPORTED;
|
||||
}
|
||||
if (!amduat_tgk_store_mem_hash_id_supported(mem, ref.hash_id)) {
|
||||
return GS_ERR_UNSUPPORTED;
|
||||
}
|
||||
entry = amduat_tgk_store_mem_lookup_artifact(mem, ref);
|
||||
if (entry == NULL) {
|
||||
return GS_ERR_ARTIFACT_ERROR;
|
||||
}
|
||||
return amduat_tgk_store_mem_decode_edge(mem, entry, out_body);
|
||||
}
|
||||
|
||||
static bool amduat_tgk_store_mem_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_mem_t *mem = (amduat_tgk_store_mem_t *)ctx;
|
||||
|
||||
return amduat_tgk_store_mem_build_edge_list(mem, type_filter, &node, true,
|
||||
false, out_edges);
|
||||
}
|
||||
|
||||
static bool amduat_tgk_store_mem_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_mem_t *mem = (amduat_tgk_store_mem_t *)ctx;
|
||||
|
||||
return amduat_tgk_store_mem_build_edge_list(mem, type_filter, &node, false,
|
||||
true, out_edges);
|
||||
}
|
||||
|
||||
static bool amduat_tgk_store_mem_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_mem_t *mem = (amduat_tgk_store_mem_t *)ctx;
|
||||
|
||||
return amduat_tgk_store_mem_build_edge_list(mem, type_filter, &node, true,
|
||||
true, out_edges);
|
||||
}
|
||||
|
||||
static bool amduat_tgk_store_mem_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_mem_t *mem = (amduat_tgk_store_mem_t *)ctx;
|
||||
|
||||
(void)page_token;
|
||||
(void)has_page_token;
|
||||
if (out_scan == NULL) {
|
||||
return false;
|
||||
}
|
||||
out_scan->edges.edges = NULL;
|
||||
out_scan->edges.len = 0;
|
||||
out_scan->next_page_token.data = NULL;
|
||||
out_scan->next_page_token.len = 0;
|
||||
out_scan->has_next_page = false;
|
||||
|
||||
return amduat_tgk_store_mem_build_edge_list(mem, type_filter, NULL, false,
|
||||
false, &out_scan->edges);
|
||||
}
|
||||
|
||||
static bool amduat_tgk_store_mem_node_list_add(
|
||||
amduat_reference_t node,
|
||||
amduat_reference_t **nodes,
|
||||
size_t *nodes_len,
|
||||
size_t *nodes_cap) {
|
||||
size_t i;
|
||||
size_t new_cap;
|
||||
amduat_reference_t *next;
|
||||
|
||||
for (i = 0; i < *nodes_len; ++i) {
|
||||
if (amduat_reference_eq((*nodes)[i], node)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (*nodes_len == *nodes_cap) {
|
||||
new_cap = (*nodes_cap == 0) ? 4u : (*nodes_cap * 2u);
|
||||
next = (amduat_reference_t *)realloc(*nodes,
|
||||
new_cap * sizeof(amduat_reference_t));
|
||||
if (next == NULL) {
|
||||
return false;
|
||||
}
|
||||
*nodes = next;
|
||||
*nodes_cap = new_cap;
|
||||
}
|
||||
|
||||
if (!amduat_tgk_store_mem_reference_clone(node, &(*nodes)[*nodes_len])) {
|
||||
return false;
|
||||
}
|
||||
(*nodes_len)++;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool amduat_tgk_store_mem_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_mem_t *mem = (amduat_tgk_store_mem_t *)ctx;
|
||||
amduat_reference_t *nodes = NULL;
|
||||
size_t nodes_len = 0;
|
||||
size_t nodes_cap = 0;
|
||||
size_t i;
|
||||
size_t j;
|
||||
|
||||
if (mem == NULL || out_nodes == NULL) {
|
||||
return false;
|
||||
}
|
||||
out_nodes->nodes = NULL;
|
||||
out_nodes->len = 0;
|
||||
|
||||
for (i = 0; i < mem->edges_len; ++i) {
|
||||
const amduat_tgk_graph_edge_view_t *edge = &mem->edges[i];
|
||||
bool use_out = false;
|
||||
bool use_in = false;
|
||||
|
||||
if (!amduat_tgk_store_mem_type_filter_match(type_filter, edge->body.type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (direction == AMDUAT_TGK_GRAPH_DIR_OUT ||
|
||||
direction == AMDUAT_TGK_GRAPH_DIR_BOTH) {
|
||||
if (amduat_tgk_store_mem_node_in_list(node, edge->body.from,
|
||||
edge->body.from_len)) {
|
||||
use_out = true;
|
||||
}
|
||||
}
|
||||
if (direction == AMDUAT_TGK_GRAPH_DIR_IN ||
|
||||
direction == AMDUAT_TGK_GRAPH_DIR_BOTH) {
|
||||
if (amduat_tgk_store_mem_node_in_list(node, edge->body.to,
|
||||
edge->body.to_len)) {
|
||||
use_in = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_out) {
|
||||
for (j = 0; j < edge->body.to_len; ++j) {
|
||||
if (!amduat_tgk_store_mem_node_list_add(edge->body.to[j], &nodes,
|
||||
&nodes_len, &nodes_cap)) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (use_in) {
|
||||
for (j = 0; j < edge->body.from_len; ++j) {
|
||||
if (!amduat_tgk_store_mem_node_list_add(edge->body.from[j], &nodes,
|
||||
&nodes_len, &nodes_cap)) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nodes_len > 1) {
|
||||
qsort(nodes, nodes_len, sizeof(amduat_reference_t),
|
||||
amduat_tgk_store_mem_ref_ptr_cmp);
|
||||
}
|
||||
|
||||
out_nodes->nodes = nodes;
|
||||
out_nodes->len = nodes_len;
|
||||
return true;
|
||||
|
||||
cleanup:
|
||||
for (i = 0; i < nodes_len; ++i) {
|
||||
amduat_tgk_store_mem_reference_free(&nodes[i]);
|
||||
}
|
||||
free(nodes);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool amduat_tgk_store_mem_init(amduat_tgk_store_mem_t *mem,
|
||||
amduat_tgk_store_config_t config,
|
||||
const amduat_tgk_store_mem_artifact_t *artifacts,
|
||||
size_t artifacts_len) {
|
||||
size_t i;
|
||||
size_t count = 0;
|
||||
amduat_tgk_graph_edge_view_t *edges;
|
||||
|
||||
if (mem == NULL) {
|
||||
return false;
|
||||
}
|
||||
mem->config = config;
|
||||
mem->artifacts = artifacts;
|
||||
mem->artifacts_len = artifacts_len;
|
||||
mem->edges = NULL;
|
||||
mem->edges_len = 0;
|
||||
|
||||
if (artifacts_len == 0) {
|
||||
return true;
|
||||
}
|
||||
if (artifacts == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
edges = (amduat_tgk_graph_edge_view_t *)calloc(
|
||||
artifacts_len, sizeof(amduat_tgk_graph_edge_view_t));
|
||||
if (edges == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < artifacts_len; ++i) {
|
||||
amduat_tgk_edge_body_t body;
|
||||
amduat_tgk_graph_error_t err;
|
||||
const amduat_tgk_store_mem_artifact_t *entry = &artifacts[i];
|
||||
|
||||
if (!amduat_tgk_store_mem_hash_id_supported(mem, entry->ref.hash_id)) {
|
||||
continue;
|
||||
}
|
||||
err = amduat_tgk_store_mem_decode_edge(mem, entry, &body);
|
||||
if (err != 0) {
|
||||
continue;
|
||||
}
|
||||
if (!amduat_tgk_store_mem_reference_clone(entry->ref,
|
||||
&edges[count].edge_ref)) {
|
||||
amduat_tgk_edge_body_free(&body);
|
||||
goto cleanup;
|
||||
}
|
||||
edges[count].body = body;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count > 1) {
|
||||
qsort(edges, count, sizeof(amduat_tgk_graph_edge_view_t),
|
||||
amduat_tgk_store_mem_edge_cmp);
|
||||
}
|
||||
|
||||
mem->edges = edges;
|
||||
mem->edges_len = count;
|
||||
return true;
|
||||
|
||||
cleanup:
|
||||
for (i = 0; i < count; ++i) {
|
||||
amduat_tgk_store_mem_reference_free(&edges[i].edge_ref);
|
||||
amduat_tgk_edge_body_free(&edges[i].body);
|
||||
}
|
||||
free(edges);
|
||||
mem->edges = NULL;
|
||||
mem->edges_len = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
void amduat_tgk_store_mem_free(amduat_tgk_store_mem_t *mem) {
|
||||
size_t i;
|
||||
|
||||
if (mem == NULL) {
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < mem->edges_len; ++i) {
|
||||
amduat_tgk_store_mem_reference_free(&mem->edges[i].edge_ref);
|
||||
amduat_tgk_edge_body_free(&mem->edges[i].body);
|
||||
}
|
||||
free(mem->edges);
|
||||
mem->edges = NULL;
|
||||
mem->edges_len = 0;
|
||||
mem->artifacts = NULL;
|
||||
mem->artifacts_len = 0;
|
||||
}
|
||||
|
||||
amduat_tgk_store_ops_t amduat_tgk_store_mem_ops(void) {
|
||||
amduat_tgk_store_ops_t ops;
|
||||
|
||||
memset(&ops, 0, sizeof(ops));
|
||||
ops.get_config = amduat_tgk_store_mem_get_config;
|
||||
ops.resolve_edge = amduat_tgk_store_mem_resolve_edge;
|
||||
ops.edges_from = amduat_tgk_store_mem_edges_from;
|
||||
ops.edges_to = amduat_tgk_store_mem_edges_to;
|
||||
ops.edges_incident = amduat_tgk_store_mem_edges_incident;
|
||||
ops.scan_edges = amduat_tgk_store_mem_scan_edges;
|
||||
ops.neighbors = amduat_tgk_store_mem_neighbors;
|
||||
return ops;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,146 @@
|
|||
#include "amduat/tgk/store.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static void amduat_tgk_store_reference_free(amduat_reference_t *ref) {
|
||||
if (ref == NULL) {
|
||||
return;
|
||||
}
|
||||
free((void *)ref->digest.data);
|
||||
ref->digest.data = NULL;
|
||||
ref->digest.len = 0;
|
||||
}
|
||||
|
||||
void amduat_tgk_store_init(amduat_tgk_store_t *store,
|
||||
amduat_tgk_store_config_t config,
|
||||
amduat_tgk_store_ops_t ops,
|
||||
void *ctx) {
|
||||
if (store == NULL) {
|
||||
return;
|
||||
}
|
||||
store->config = config;
|
||||
store->ops = ops;
|
||||
store->ctx = ctx;
|
||||
}
|
||||
|
||||
bool amduat_tgk_store_get_config(amduat_tgk_store_t *store,
|
||||
amduat_tgk_store_config_t *out_config) {
|
||||
if (store == NULL || store->ops.get_config == NULL) {
|
||||
return false;
|
||||
}
|
||||
return store->ops.get_config(store->ctx, out_config);
|
||||
}
|
||||
|
||||
amduat_tgk_graph_error_t amduat_tgk_store_resolve_edge(
|
||||
amduat_tgk_store_t *store,
|
||||
amduat_reference_t ref,
|
||||
amduat_tgk_edge_body_t *out_body) {
|
||||
if (store == NULL || store->ops.resolve_edge == NULL) {
|
||||
return GS_ERR_UNSUPPORTED;
|
||||
}
|
||||
return store->ops.resolve_edge(store->ctx, ref, out_body);
|
||||
}
|
||||
|
||||
bool amduat_tgk_store_edges_from(amduat_tgk_store_t *store,
|
||||
amduat_reference_t node,
|
||||
amduat_tgk_edge_type_filter_t type_filter,
|
||||
amduat_tgk_graph_edge_view_list_t *out_edges) {
|
||||
if (store == NULL || store->ops.edges_from == NULL) {
|
||||
return false;
|
||||
}
|
||||
return store->ops.edges_from(store->ctx, node, type_filter, out_edges);
|
||||
}
|
||||
|
||||
bool amduat_tgk_store_edges_to(amduat_tgk_store_t *store,
|
||||
amduat_reference_t node,
|
||||
amduat_tgk_edge_type_filter_t type_filter,
|
||||
amduat_tgk_graph_edge_view_list_t *out_edges) {
|
||||
if (store == NULL || store->ops.edges_to == NULL) {
|
||||
return false;
|
||||
}
|
||||
return store->ops.edges_to(store->ctx, node, type_filter, out_edges);
|
||||
}
|
||||
|
||||
bool amduat_tgk_store_edges_incident(
|
||||
amduat_tgk_store_t *store,
|
||||
amduat_reference_t node,
|
||||
amduat_tgk_edge_type_filter_t type_filter,
|
||||
amduat_tgk_graph_edge_view_list_t *out_edges) {
|
||||
if (store == NULL || store->ops.edges_incident == NULL) {
|
||||
return false;
|
||||
}
|
||||
return store->ops.edges_incident(store->ctx, node, type_filter, out_edges);
|
||||
}
|
||||
|
||||
bool amduat_tgk_store_scan_edges(amduat_tgk_store_t *store,
|
||||
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) {
|
||||
if (store == NULL || store->ops.scan_edges == NULL) {
|
||||
return false;
|
||||
}
|
||||
return store->ops.scan_edges(store->ctx, type_filter, page_token,
|
||||
has_page_token, out_scan);
|
||||
}
|
||||
|
||||
bool amduat_tgk_store_neighbors(amduat_tgk_store_t *store,
|
||||
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) {
|
||||
if (store == NULL || store->ops.neighbors == NULL) {
|
||||
return false;
|
||||
}
|
||||
return store->ops.neighbors(store->ctx, node, type_filter, direction,
|
||||
out_nodes);
|
||||
}
|
||||
|
||||
void amduat_tgk_graph_edge_view_list_free(
|
||||
amduat_tgk_graph_edge_view_list_t *list) {
|
||||
size_t i;
|
||||
|
||||
if (list == NULL) {
|
||||
return;
|
||||
}
|
||||
if (list->edges == NULL) {
|
||||
list->len = 0;
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < list->len; ++i) {
|
||||
amduat_tgk_store_reference_free(&list->edges[i].edge_ref);
|
||||
amduat_tgk_edge_body_free(&list->edges[i].body);
|
||||
}
|
||||
free(list->edges);
|
||||
list->edges = NULL;
|
||||
list->len = 0;
|
||||
}
|
||||
|
||||
void amduat_tgk_node_list_free(amduat_tgk_node_list_t *list) {
|
||||
size_t i;
|
||||
|
||||
if (list == NULL) {
|
||||
return;
|
||||
}
|
||||
if (list->nodes == NULL) {
|
||||
list->len = 0;
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < list->len; ++i) {
|
||||
amduat_tgk_store_reference_free(&list->nodes[i]);
|
||||
}
|
||||
free(list->nodes);
|
||||
list->nodes = NULL;
|
||||
list->len = 0;
|
||||
}
|
||||
|
||||
void amduat_tgk_graph_scan_result_free(amduat_tgk_graph_scan_result_t *scan) {
|
||||
if (scan == NULL) {
|
||||
return;
|
||||
}
|
||||
amduat_tgk_graph_edge_view_list_free(&scan->edges);
|
||||
free((void *)scan->next_page_token.data);
|
||||
scan->next_page_token.data = NULL;
|
||||
scan->next_page_token.len = 0;
|
||||
scan->has_next_page = false;
|
||||
}
|
||||
433
tests/tgk/test_tgk_store_mem.c
Normal file
433
tests/tgk/test_tgk_store_mem.c
Normal file
|
|
@ -0,0 +1,433 @@
|
|||
#include "amduat/enc/asl1_core.h"
|
||||
#include "amduat/enc/tgk1_edge.h"
|
||||
#include "amduat/hash/asl1.h"
|
||||
#include "amduat/tgk/tgk_store_mem.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static const uint8_t k_non_edge_bytes[] = {0xde, 0xad, 0xbe, 0xef};
|
||||
|
||||
typedef struct {
|
||||
amduat_tgk_store_t store;
|
||||
amduat_tgk_store_mem_t mem;
|
||||
amduat_tgk_store_mem_artifact_t artifacts[5];
|
||||
amduat_octets_t edge_bytes[4];
|
||||
amduat_reference_t ref_edge1;
|
||||
amduat_reference_t ref_edge2;
|
||||
amduat_reference_t ref_edge3;
|
||||
amduat_reference_t ref_edge_bad;
|
||||
amduat_reference_t ref_non_edge;
|
||||
amduat_reference_t node_a;
|
||||
amduat_reference_t node_b;
|
||||
amduat_reference_t node_c;
|
||||
amduat_reference_t payload1;
|
||||
amduat_reference_t payload2;
|
||||
amduat_reference_t payload3;
|
||||
amduat_reference_t payload_bad;
|
||||
uint8_t digest_edge1[32];
|
||||
uint8_t digest_edge2[32];
|
||||
uint8_t digest_edge3[32];
|
||||
uint8_t digest_edge_bad[32];
|
||||
uint8_t digest_non_edge[32];
|
||||
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];
|
||||
uint8_t digest_payload3[32];
|
||||
uint8_t digest_payload_bad[32];
|
||||
amduat_tgk_identity_domain_t domains[1];
|
||||
uint32_t edge_tags[1];
|
||||
amduat_tgk_edge_type_id_t edge_types[2];
|
||||
amduat_asl_encoding_profile_id_t encodings[1];
|
||||
amduat_tgk_store_config_t config;
|
||||
} test_env_t;
|
||||
|
||||
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_edge_bytes(test_env_t *env) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
free((void *)env->edge_bytes[i].data);
|
||||
env->edge_bytes[i].data = NULL;
|
||||
env->edge_bytes[i].len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static bool init_env(test_env_t *env) {
|
||||
amduat_tgk_edge_body_t edge1;
|
||||
amduat_tgk_edge_body_t edge2;
|
||||
amduat_tgk_edge_body_t edge3;
|
||||
amduat_tgk_edge_body_t edge_bad;
|
||||
amduat_reference_t edge1_from[1];
|
||||
amduat_reference_t edge1_to[1];
|
||||
amduat_reference_t edge2_from[1];
|
||||
amduat_reference_t edge2_to[1];
|
||||
amduat_reference_t edge3_from[1];
|
||||
amduat_reference_t edge3_to[1];
|
||||
amduat_reference_t edge_bad_from[1];
|
||||
amduat_reference_t edge_bad_to[1];
|
||||
|
||||
memset(env, 0, sizeof(*env));
|
||||
|
||||
env->domains[0].encoding_profile = AMDUAT_ENC_ASL1_CORE_V1;
|
||||
env->domains[0].hash_id = AMDUAT_HASH_ASL1_ID_SHA256;
|
||||
env->edge_tags[0] = TYPE_TAG_TGK1_EDGE_V1;
|
||||
env->edge_types[0] = 0x10;
|
||||
env->edge_types[1] = 0x20;
|
||||
env->encodings[0] = TGK1_EDGE_ENC_V1;
|
||||
|
||||
env->config.id_space.domains = env->domains;
|
||||
env->config.id_space.domains_len = 1;
|
||||
env->config.artifact_scope.description = amduat_octets(NULL, 0);
|
||||
env->config.tgk_profiles.edge_tags = env->edge_tags;
|
||||
env->config.tgk_profiles.edge_tags_len = 1;
|
||||
env->config.tgk_profiles.edge_types = env->edge_types;
|
||||
env->config.tgk_profiles.edge_types_len = 2;
|
||||
env->config.tgk_profiles.encodings = env->encodings;
|
||||
env->config.tgk_profiles.encodings_len = 1;
|
||||
|
||||
env->ref_edge1 = make_ref(0x20, env->digest_edge1);
|
||||
env->ref_edge2 = make_ref(0x10, env->digest_edge2);
|
||||
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->node_a = make_ref(0xa1, env->digest_node_a);
|
||||
env->node_b = make_ref(0xb1, env->digest_node_b);
|
||||
env->node_c = make_ref(0xc1, env->digest_node_c);
|
||||
|
||||
env->payload1 = make_ref(0xe1, env->digest_payload1);
|
||||
env->payload2 = make_ref(0xe2, env->digest_payload2);
|
||||
env->payload3 = make_ref(0xe3, env->digest_payload3);
|
||||
env->payload_bad = make_ref(0xe4, env->digest_payload_bad);
|
||||
|
||||
memset(&edge1, 0, sizeof(edge1));
|
||||
edge1.type = 0x10;
|
||||
edge1_from[0] = env->node_a;
|
||||
edge1.from = edge1_from;
|
||||
edge1.from_len = 1;
|
||||
edge1_to[0] = env->node_b;
|
||||
edge1.to = edge1_to;
|
||||
edge1.to_len = 1;
|
||||
edge1.payload = env->payload1;
|
||||
|
||||
memset(&edge2, 0, sizeof(edge2));
|
||||
edge2.type = 0x10;
|
||||
edge2_from[0] = env->node_a;
|
||||
edge2.from = edge2_from;
|
||||
edge2.from_len = 1;
|
||||
edge2_to[0] = env->node_c;
|
||||
edge2.to = edge2_to;
|
||||
edge2.to_len = 1;
|
||||
edge2.payload = env->payload2;
|
||||
|
||||
memset(&edge3, 0, sizeof(edge3));
|
||||
edge3.type = 0x20;
|
||||
edge3_from[0] = env->node_b;
|
||||
edge3.from = edge3_from;
|
||||
edge3.from_len = 1;
|
||||
edge3_to[0] = env->node_a;
|
||||
edge3.to = edge3_to;
|
||||
edge3.to_len = 1;
|
||||
edge3.payload = env->payload3;
|
||||
|
||||
memset(&edge_bad, 0, sizeof(edge_bad));
|
||||
edge_bad.type = 0x99;
|
||||
edge_bad_from[0] = env->node_a;
|
||||
edge_bad.from = edge_bad_from;
|
||||
edge_bad.from_len = 1;
|
||||
edge_bad_to[0] = env->node_b;
|
||||
edge_bad.to = edge_bad_to;
|
||||
edge_bad.to_len = 1;
|
||||
edge_bad.payload = env->payload_bad;
|
||||
|
||||
if (!amduat_enc_tgk1_edge_encode_v1(&edge1, &env->edge_bytes[0]) ||
|
||||
!amduat_enc_tgk1_edge_encode_v1(&edge2, &env->edge_bytes[1]) ||
|
||||
!amduat_enc_tgk1_edge_encode_v1(&edge3, &env->edge_bytes[2]) ||
|
||||
!amduat_enc_tgk1_edge_encode_v1(&edge_bad, &env->edge_bytes[3])) {
|
||||
free_edge_bytes(env);
|
||||
return false;
|
||||
}
|
||||
|
||||
env->artifacts[0].ref = env->ref_edge1;
|
||||
env->artifacts[0].artifact =
|
||||
amduat_artifact_with_type(env->edge_bytes[0],
|
||||
amduat_type_tag(TYPE_TAG_TGK1_EDGE_V1));
|
||||
env->artifacts[1].ref = env->ref_edge2;
|
||||
env->artifacts[1].artifact =
|
||||
amduat_artifact_with_type(env->edge_bytes[1],
|
||||
amduat_type_tag(TYPE_TAG_TGK1_EDGE_V1));
|
||||
env->artifacts[2].ref = env->ref_edge3;
|
||||
env->artifacts[2].artifact =
|
||||
amduat_artifact_with_type(env->edge_bytes[2],
|
||||
amduat_type_tag(TYPE_TAG_TGK1_EDGE_V1));
|
||||
env->artifacts[3].ref = env->ref_edge_bad;
|
||||
env->artifacts[3].artifact =
|
||||
amduat_artifact_with_type(env->edge_bytes[3],
|
||||
amduat_type_tag(TYPE_TAG_TGK1_EDGE_V1));
|
||||
env->artifacts[4].ref = env->ref_non_edge;
|
||||
env->artifacts[4].artifact =
|
||||
amduat_artifact(amduat_octets(k_non_edge_bytes, sizeof(k_non_edge_bytes)));
|
||||
|
||||
if (!amduat_tgk_store_mem_init(&env->mem, env->config, env->artifacts, 5)) {
|
||||
free_edge_bytes(env);
|
||||
return false;
|
||||
}
|
||||
|
||||
amduat_tgk_store_init(&env->store, env->config, amduat_tgk_store_mem_ops(),
|
||||
&env->mem);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void free_env(test_env_t *env) {
|
||||
amduat_tgk_store_mem_free(&env->mem);
|
||||
free_edge_bytes(env);
|
||||
}
|
||||
|
||||
static int test_resolve_edge_ok(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_edge1, &body);
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "resolve_edge ok failed: %d\n", err);
|
||||
return 1;
|
||||
}
|
||||
if (body.type != 0x10 || body.from_len != 1 || body.to_len != 1) {
|
||||
fprintf(stderr, "resolve_edge body mismatch\n");
|
||||
amduat_tgk_edge_body_free(&body);
|
||||
return 1;
|
||||
}
|
||||
if (!amduat_reference_eq(body.from[0], env->node_a) ||
|
||||
!amduat_reference_eq(body.to[0], env->node_b)) {
|
||||
fprintf(stderr, "resolve_edge endpoints mismatch\n");
|
||||
amduat_tgk_edge_body_free(&body);
|
||||
return 1;
|
||||
}
|
||||
amduat_tgk_edge_body_free(&body);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_resolve_edge_not_edge(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_edge_bad, &body);
|
||||
if (err != GS_ERR_NOT_EDGE) {
|
||||
fprintf(stderr, "resolve_edge not_edge mismatch: %d\n", err);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
amduat_tgk_graph_edge_view_list_t edges;
|
||||
size_t i;
|
||||
|
||||
filter.types = types;
|
||||
filter.types_len = 1;
|
||||
|
||||
if (!amduat_tgk_store_edges_incident((amduat_tgk_store_t *)&env->store,
|
||||
env->node_a, filter, &edges)) {
|
||||
fprintf(stderr, "edges_incident type filter failed\n");
|
||||
return 1;
|
||||
}
|
||||
if (edges.len != 2) {
|
||||
fprintf(stderr, "edges_incident type filter count mismatch\n");
|
||||
amduat_tgk_graph_edge_view_list_free(&edges);
|
||||
return 1;
|
||||
}
|
||||
for (i = 0; i < edges.len; ++i) {
|
||||
if (edges.edges[i].body.type != 0x10) {
|
||||
fprintf(stderr, "edges_incident type filter type mismatch\n");
|
||||
amduat_tgk_graph_edge_view_list_free(&edges);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
amduat_tgk_graph_edge_view_list_free(&edges);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_ordering(const test_env_t *env) {
|
||||
amduat_tgk_edge_type_filter_t filter;
|
||||
amduat_tgk_graph_edge_view_list_t edges;
|
||||
|
||||
filter.types = NULL;
|
||||
filter.types_len = 0;
|
||||
|
||||
if (!amduat_tgk_store_edges_from((amduat_tgk_store_t *)&env->store,
|
||||
env->node_a, filter, &edges)) {
|
||||
fprintf(stderr, "edges_from ordering failed\n");
|
||||
return 1;
|
||||
}
|
||||
if (edges.len != 2) {
|
||||
fprintf(stderr, "edges_from ordering count mismatch\n");
|
||||
amduat_tgk_graph_edge_view_list_free(&edges);
|
||||
return 1;
|
||||
}
|
||||
if (!amduat_reference_eq(edges.edges[0].edge_ref, env->ref_edge2) ||
|
||||
!amduat_reference_eq(edges.edges[1].edge_ref, env->ref_edge1)) {
|
||||
fprintf(stderr, "edges_from ordering mismatch\n");
|
||||
amduat_tgk_graph_edge_view_list_free(&edges);
|
||||
return 1;
|
||||
}
|
||||
amduat_tgk_graph_edge_view_list_free(&edges);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_adjacency(const test_env_t *env) {
|
||||
amduat_tgk_edge_type_filter_t filter;
|
||||
amduat_tgk_graph_edge_view_list_t edges;
|
||||
|
||||
filter.types = NULL;
|
||||
filter.types_len = 0;
|
||||
|
||||
if (!amduat_tgk_store_edges_to((amduat_tgk_store_t *)&env->store,
|
||||
env->node_a, filter, &edges)) {
|
||||
fprintf(stderr, "edges_to failed\n");
|
||||
return 1;
|
||||
}
|
||||
if (edges.len != 1 ||
|
||||
!amduat_reference_eq(edges.edges[0].edge_ref, env->ref_edge3)) {
|
||||
fprintf(stderr, "edges_to mismatch\n");
|
||||
amduat_tgk_graph_edge_view_list_free(&edges);
|
||||
return 1;
|
||||
}
|
||||
amduat_tgk_graph_edge_view_list_free(&edges);
|
||||
|
||||
if (!amduat_tgk_store_edges_incident((amduat_tgk_store_t *)&env->store,
|
||||
env->node_a, filter, &edges)) {
|
||||
fprintf(stderr, "edges_incident failed\n");
|
||||
return 1;
|
||||
}
|
||||
if (edges.len != 3 ||
|
||||
!amduat_reference_eq(edges.edges[0].edge_ref, env->ref_edge2) ||
|
||||
!amduat_reference_eq(edges.edges[1].edge_ref, env->ref_edge1) ||
|
||||
!amduat_reference_eq(edges.edges[2].edge_ref, env->ref_edge3)) {
|
||||
fprintf(stderr, "edges_incident mismatch\n");
|
||||
amduat_tgk_graph_edge_view_list_free(&edges);
|
||||
return 1;
|
||||
}
|
||||
amduat_tgk_graph_edge_view_list_free(&edges);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_neighbors(const test_env_t *env) {
|
||||
amduat_tgk_edge_type_filter_t filter;
|
||||
amduat_tgk_node_list_t nodes;
|
||||
|
||||
filter.types = NULL;
|
||||
filter.types_len = 0;
|
||||
|
||||
if (!amduat_tgk_store_neighbors((amduat_tgk_store_t *)&env->store,
|
||||
env->node_a, filter,
|
||||
AMDUAT_TGK_GRAPH_DIR_OUT, &nodes)) {
|
||||
fprintf(stderr, "neighbors out failed\n");
|
||||
return 1;
|
||||
}
|
||||
if (nodes.len != 2 ||
|
||||
!amduat_reference_eq(nodes.nodes[0], env->node_b) ||
|
||||
!amduat_reference_eq(nodes.nodes[1], env->node_c)) {
|
||||
fprintf(stderr, "neighbors out mismatch\n");
|
||||
amduat_tgk_node_list_free(&nodes);
|
||||
return 1;
|
||||
}
|
||||
amduat_tgk_node_list_free(&nodes);
|
||||
|
||||
if (!amduat_tgk_store_neighbors((amduat_tgk_store_t *)&env->store,
|
||||
env->node_a, filter,
|
||||
AMDUAT_TGK_GRAPH_DIR_IN, &nodes)) {
|
||||
fprintf(stderr, "neighbors in failed\n");
|
||||
return 1;
|
||||
}
|
||||
if (nodes.len != 1 ||
|
||||
!amduat_reference_eq(nodes.nodes[0], env->node_b)) {
|
||||
fprintf(stderr, "neighbors in mismatch\n");
|
||||
amduat_tgk_node_list_free(&nodes);
|
||||
return 1;
|
||||
}
|
||||
amduat_tgk_node_list_free(&nodes);
|
||||
|
||||
if (!amduat_tgk_store_neighbors((amduat_tgk_store_t *)&env->store,
|
||||
env->node_a, filter,
|
||||
AMDUAT_TGK_GRAPH_DIR_BOTH, &nodes)) {
|
||||
fprintf(stderr, "neighbors both failed\n");
|
||||
return 1;
|
||||
}
|
||||
if (nodes.len != 2 ||
|
||||
!amduat_reference_eq(nodes.nodes[0], env->node_b) ||
|
||||
!amduat_reference_eq(nodes.nodes[1], env->node_c)) {
|
||||
fprintf(stderr, "neighbors both mismatch\n");
|
||||
amduat_tgk_node_list_free(&nodes);
|
||||
return 1;
|
||||
}
|
||||
amduat_tgk_node_list_free(&nodes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_scan_edges(const test_env_t *env) {
|
||||
amduat_tgk_edge_type_filter_t filter;
|
||||
amduat_tgk_graph_scan_result_t scan;
|
||||
|
||||
filter.types = NULL;
|
||||
filter.types_len = 0;
|
||||
|
||||
if (!amduat_tgk_store_scan_edges((amduat_tgk_store_t *)&env->store, filter,
|
||||
amduat_octets(NULL, 0), false, &scan)) {
|
||||
fprintf(stderr, "scan_edges failed\n");
|
||||
return 1;
|
||||
}
|
||||
if (scan.edges.len != 3 ||
|
||||
!amduat_reference_eq(scan.edges.edges[0].edge_ref, env->ref_edge2) ||
|
||||
!amduat_reference_eq(scan.edges.edges[1].edge_ref, env->ref_edge1) ||
|
||||
!amduat_reference_eq(scan.edges.edges[2].edge_ref, env->ref_edge3)) {
|
||||
fprintf(stderr, "scan_edges ordering mismatch\n");
|
||||
amduat_tgk_graph_scan_result_free(&scan);
|
||||
return 1;
|
||||
}
|
||||
amduat_tgk_graph_scan_result_free(&scan);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
test_env_t env;
|
||||
|
||||
if (!init_env(&env)) {
|
||||
fprintf(stderr, "failed to init tgk store mem test env\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (test_resolve_edge_ok(&env) != 0 ||
|
||||
test_resolve_edge_not_edge(&env) != 0 ||
|
||||
test_type_filter(&env) != 0 ||
|
||||
test_ordering(&env) != 0 ||
|
||||
test_adjacency(&env) != 0 ||
|
||||
test_neighbors(&env) != 0 ||
|
||||
test_scan_edges(&env) != 0) {
|
||||
free_env(&env);
|
||||
return 1;
|
||||
}
|
||||
|
||||
free_env(&env);
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in a new issue