Add GET /v1/space/mounts/resolve with local mount resolution tests
This commit is contained in:
parent
8eea0cb69b
commit
a870b188e9
|
|
@ -32,7 +32,8 @@ set(amduatd_sources src/amduatd.c src/amduatd_http.c src/amduatd_caps.c
|
||||||
src/amduatd_fed_pull_plan.c src/amduatd_fed_push_plan.c
|
src/amduatd_fed_pull_plan.c src/amduatd_fed_push_plan.c
|
||||||
src/amduatd_fed_pull_apply.c src/amduatd_fed_push_apply.c
|
src/amduatd_fed_pull_apply.c src/amduatd_fed_push_apply.c
|
||||||
src/amduatd_space_doctor.c src/amduatd_space_roots.c
|
src/amduatd_space_doctor.c src/amduatd_space_roots.c
|
||||||
src/amduatd_space_manifest.c)
|
src/amduatd_space_manifest.c
|
||||||
|
src/amduatd_space_mounts.c)
|
||||||
if(AMDUATD_ENABLE_UI)
|
if(AMDUATD_ENABLE_UI)
|
||||||
list(APPEND amduatd_sources src/amduatd_ui.c)
|
list(APPEND amduatd_sources src/amduatd_ui.c)
|
||||||
endif()
|
endif()
|
||||||
|
|
@ -389,6 +390,30 @@ target_link_libraries(amduatd_test_space_manifest
|
||||||
|
|
||||||
add_test(NAME amduatd_space_manifest COMMAND amduatd_test_space_manifest)
|
add_test(NAME amduatd_space_manifest COMMAND amduatd_test_space_manifest)
|
||||||
|
|
||||||
|
add_executable(amduatd_test_space_mounts
|
||||||
|
tests/test_amduatd_space_mounts.c
|
||||||
|
src/amduatd_space_mounts.c
|
||||||
|
src/amduatd_space_manifest.c
|
||||||
|
src/amduatd_http.c
|
||||||
|
src/amduatd_fed_cursor.c
|
||||||
|
src/amduatd_space.c
|
||||||
|
src/amduatd_store.c
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(amduatd_test_space_mounts
|
||||||
|
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||||
|
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/vendor/amduat/include
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(amduatd_test_space_mounts
|
||||||
|
PRIVATE amduat_asl_store_fs amduat_asl_pointer_fs amduat_asl_record
|
||||||
|
amduat_asl_store_index_fs amduat_asl amduat_enc amduat_util
|
||||||
|
amduat_hash_asl1
|
||||||
|
)
|
||||||
|
|
||||||
|
add_test(NAME amduatd_space_mounts COMMAND amduatd_test_space_mounts)
|
||||||
|
|
||||||
add_executable(amduatd_test_space_sync_status
|
add_executable(amduatd_test_space_sync_status
|
||||||
tests/test_amduatd_space_sync_status.c
|
tests/test_amduatd_space_sync_status.c
|
||||||
src/amduatd_space_roots.c
|
src/amduatd_space_roots.c
|
||||||
|
|
|
||||||
14
README.md
14
README.md
|
|
@ -282,6 +282,20 @@ curl --unix-socket amduatd.sock \
|
||||||
|
|
||||||
`If-Match` can be replaced with `?expected_ref=<manifest_ref>` if needed.
|
`If-Match` can be replaced with `?expected_ref=<manifest_ref>` if needed.
|
||||||
|
|
||||||
|
## Space mount resolution
|
||||||
|
|
||||||
|
`/v1/space/mounts/resolve` returns a deterministic, local-only view of the
|
||||||
|
space manifest mounts with their local pull cursor state. It performs no
|
||||||
|
network I/O and does not mutate storage. Track mounts indicate intent; syncing
|
||||||
|
remains a separate concern.
|
||||||
|
If no manifest head is present, the endpoint returns a 404.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
curl --unix-socket amduatd.sock \
|
||||||
|
'http://localhost/v1/space/mounts/resolve' \
|
||||||
|
-H 'X-Amduat-Space: demo'
|
||||||
|
```
|
||||||
|
|
||||||
To fail `/v1/pel/run` if the derivation index write fails:
|
To fail `/v1/pel/run` if the derivation index write fails:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
{"method": "GET", "path": "/v1/space/roots"},
|
{"method": "GET", "path": "/v1/space/roots"},
|
||||||
{"method": "GET", "path": "/v1/space/manifest"},
|
{"method": "GET", "path": "/v1/space/manifest"},
|
||||||
{"method": "PUT", "path": "/v1/space/manifest"},
|
{"method": "PUT", "path": "/v1/space/manifest"},
|
||||||
|
{"method": "GET", "path": "/v1/space/mounts/resolve"},
|
||||||
{"method": "GET", "path": "/v1/space/sync/status"},
|
{"method": "GET", "path": "/v1/space/sync/status"},
|
||||||
{"method": "POST", "path": "/v1/capabilities"},
|
{"method": "POST", "path": "/v1/capabilities"},
|
||||||
{"method": "GET", "path": "/v1/cap/resolve"},
|
{"method": "GET", "path": "/v1/cap/resolve"},
|
||||||
|
|
@ -239,6 +240,15 @@
|
||||||
"previous_ref": {"type": "string"},
|
"previous_ref": {"type": "string"},
|
||||||
"manifest": {"$ref": "#/schemas/space_manifest"}
|
"manifest": {"$ref": "#/schemas/space_manifest"}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"space_mounts_resolve_response": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["effective_space", "manifest_ref", "mounts"],
|
||||||
|
"properties": {
|
||||||
|
"effective_space": {"type": "object"},
|
||||||
|
"manifest_ref": {"type": "string"},
|
||||||
|
"mounts": {"type": "array"}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
127
src/amduatd.c
127
src/amduatd.c
|
|
@ -52,6 +52,7 @@
|
||||||
#include "amduatd_space_doctor.h"
|
#include "amduatd_space_doctor.h"
|
||||||
#include "amduatd_space_roots.h"
|
#include "amduatd_space_roots.h"
|
||||||
#include "amduatd_space_manifest.h"
|
#include "amduatd_space_manifest.h"
|
||||||
|
#include "amduatd_space_mounts.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
@ -129,6 +130,7 @@ static const char k_amduatd_contract_v1_json[] =
|
||||||
"{\"method\":\"GET\",\"path\":\"/v1/space/roots\"},"
|
"{\"method\":\"GET\",\"path\":\"/v1/space/roots\"},"
|
||||||
"{\"method\":\"GET\",\"path\":\"/v1/space/manifest\"},"
|
"{\"method\":\"GET\",\"path\":\"/v1/space/manifest\"},"
|
||||||
"{\"method\":\"PUT\",\"path\":\"/v1/space/manifest\"},"
|
"{\"method\":\"PUT\",\"path\":\"/v1/space/manifest\"},"
|
||||||
|
"{\"method\":\"GET\",\"path\":\"/v1/space/mounts/resolve\"},"
|
||||||
"{\"method\":\"GET\",\"path\":\"/v1/space/sync/status\"},"
|
"{\"method\":\"GET\",\"path\":\"/v1/space/sync/status\"},"
|
||||||
"{\"method\":\"POST\",\"path\":\"/v1/capabilities\"},"
|
"{\"method\":\"POST\",\"path\":\"/v1/capabilities\"},"
|
||||||
"{\"method\":\"GET\",\"path\":\"/v1/cap/resolve\"},"
|
"{\"method\":\"GET\",\"path\":\"/v1/cap/resolve\"},"
|
||||||
|
|
@ -332,6 +334,15 @@ static const char k_amduatd_contract_v1_json[] =
|
||||||
"\"previous_ref\":{\"type\":\"string\"},"
|
"\"previous_ref\":{\"type\":\"string\"},"
|
||||||
"\"manifest\":{\"$ref\":\"#/schemas/space_manifest\"}"
|
"\"manifest\":{\"$ref\":\"#/schemas/space_manifest\"}"
|
||||||
"}"
|
"}"
|
||||||
|
"},"
|
||||||
|
"\"space_mounts_resolve_response\":{"
|
||||||
|
"\"type\":\"object\","
|
||||||
|
"\"required\":[\"effective_space\",\"manifest_ref\",\"mounts\"],"
|
||||||
|
"\"properties\":{"
|
||||||
|
"\"effective_space\":{\"type\":\"object\"},"
|
||||||
|
"\"manifest_ref\":{\"type\":\"string\"},"
|
||||||
|
"\"mounts\":{\"type\":\"array\"}"
|
||||||
|
"}"
|
||||||
"}"
|
"}"
|
||||||
"}"
|
"}"
|
||||||
"}\n";
|
"}\n";
|
||||||
|
|
@ -1307,6 +1318,112 @@ manifest_cleanup:
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool amduatd_handle_get_space_mounts_resolve(
|
||||||
|
int fd,
|
||||||
|
amduat_asl_store_t *store,
|
||||||
|
const amduatd_http_req_t *req,
|
||||||
|
const amduatd_cfg_t *dcfg,
|
||||||
|
const amduatd_caps_t *caps,
|
||||||
|
const char *root_path) {
|
||||||
|
amduat_asl_pointer_store_t pointer_store;
|
||||||
|
amduat_reference_t manifest_ref;
|
||||||
|
amduatd_space_mounts_status_t status;
|
||||||
|
amduatd_strbuf_t b;
|
||||||
|
char *manifest_ref_hex = NULL;
|
||||||
|
char *mounts_json = NULL;
|
||||||
|
size_t mounts_len = 0u;
|
||||||
|
bool ok = false;
|
||||||
|
|
||||||
|
memset(&manifest_ref, 0, sizeof(manifest_ref));
|
||||||
|
memset(&b, 0, sizeof(b));
|
||||||
|
|
||||||
|
if (store == NULL || req == NULL || dcfg == NULL || root_path == NULL) {
|
||||||
|
return amduatd_send_json_error(fd, 500, "Internal Server Error",
|
||||||
|
"internal error");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (caps != NULL && caps->enabled && req->x_capability[0] != '\0') {
|
||||||
|
const char *reason = NULL;
|
||||||
|
if (!amduatd_caps_check_space(caps, dcfg, req, &reason)) {
|
||||||
|
if (reason != NULL && strcmp(reason, "wrong-space") == 0) {
|
||||||
|
return amduatd_send_json_error(fd, 403, "Forbidden",
|
||||||
|
"space not permitted by capability");
|
||||||
|
}
|
||||||
|
return amduatd_send_json_error(fd, 403, "Forbidden",
|
||||||
|
"invalid capability");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!amduat_asl_pointer_store_init(&pointer_store, root_path)) {
|
||||||
|
return amduatd_send_json_error(fd, 500, "Internal Server Error",
|
||||||
|
"pointer store error");
|
||||||
|
}
|
||||||
|
|
||||||
|
status = amduatd_space_mounts_resolve(store,
|
||||||
|
&pointer_store,
|
||||||
|
req->effective_space,
|
||||||
|
&manifest_ref,
|
||||||
|
&mounts_json,
|
||||||
|
&mounts_len);
|
||||||
|
if (status == AMDUATD_SPACE_MOUNTS_ERR_NOT_FOUND) {
|
||||||
|
return amduatd_send_json_error(fd, 404, "Not Found",
|
||||||
|
"manifest not found");
|
||||||
|
}
|
||||||
|
if (status == AMDUATD_SPACE_MOUNTS_ERR_STORE) {
|
||||||
|
return amduatd_send_json_error(fd, 500, "Internal Server Error",
|
||||||
|
"store error");
|
||||||
|
}
|
||||||
|
if (status != AMDUATD_SPACE_MOUNTS_OK) {
|
||||||
|
return amduatd_send_json_error(fd, 500, "Internal Server Error",
|
||||||
|
"manifest decode failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!amduat_asl_ref_encode_hex(manifest_ref, &manifest_ref_hex)) {
|
||||||
|
free(mounts_json);
|
||||||
|
amduat_reference_free(&manifest_ref);
|
||||||
|
return amduatd_send_json_error(fd, 500, "Internal Server Error",
|
||||||
|
"encode error");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!amduatd_strbuf_append_cstr(&b, "{\"effective_space\":{")) {
|
||||||
|
goto mounts_cleanup;
|
||||||
|
}
|
||||||
|
if (req->effective_space != NULL && req->effective_space->enabled &&
|
||||||
|
req->effective_space->space_id.data != NULL) {
|
||||||
|
const char *space_id = (const char *)req->effective_space->space_id.data;
|
||||||
|
if (!amduatd_strbuf_append_cstr(&b, "\"mode\":\"scoped\",") ||
|
||||||
|
!amduatd_strbuf_append_cstr(&b, "\"space_id\":\"") ||
|
||||||
|
!amduatd_strbuf_append_cstr(&b, space_id) ||
|
||||||
|
!amduatd_strbuf_append_cstr(&b, "\"")) {
|
||||||
|
goto mounts_cleanup;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!amduatd_strbuf_append_cstr(&b, "\"mode\":\"unscoped\",") ||
|
||||||
|
!amduatd_strbuf_append_cstr(&b, "\"space_id\":null")) {
|
||||||
|
goto mounts_cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!amduatd_strbuf_append_cstr(&b, "},\"manifest_ref\":\"") ||
|
||||||
|
!amduatd_strbuf_append_cstr(&b, manifest_ref_hex) ||
|
||||||
|
!amduatd_strbuf_append_cstr(&b, "\",\"mounts\":") ||
|
||||||
|
!amduatd_strbuf_append(&b, mounts_json, mounts_len) ||
|
||||||
|
!amduatd_strbuf_append_cstr(&b, "}\n")) {
|
||||||
|
goto mounts_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = amduatd_http_send_json(fd, 200, "OK", b.data, false);
|
||||||
|
|
||||||
|
mounts_cleanup:
|
||||||
|
if (!ok) {
|
||||||
|
ok = amduatd_send_json_error(fd, 500, "Internal Server Error", "error");
|
||||||
|
}
|
||||||
|
amduat_reference_free(&manifest_ref);
|
||||||
|
free(manifest_ref_hex);
|
||||||
|
free(mounts_json);
|
||||||
|
amduatd_strbuf_free(&b);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
static bool amduatd_handle_put_space_manifest(
|
static bool amduatd_handle_put_space_manifest(
|
||||||
int fd,
|
int fd,
|
||||||
amduat_asl_store_t *store,
|
amduat_asl_store_t *store,
|
||||||
|
|
@ -8162,6 +8279,16 @@ static bool amduatd_handle_conn(int fd,
|
||||||
root_path);
|
root_path);
|
||||||
goto conn_cleanup;
|
goto conn_cleanup;
|
||||||
}
|
}
|
||||||
|
if (strcmp(req.method, "GET") == 0 &&
|
||||||
|
strcmp(no_query, "/v1/space/mounts/resolve") == 0) {
|
||||||
|
ok = amduatd_handle_get_space_mounts_resolve(fd,
|
||||||
|
store,
|
||||||
|
&req,
|
||||||
|
effective_cfg,
|
||||||
|
caps,
|
||||||
|
root_path);
|
||||||
|
goto conn_cleanup;
|
||||||
|
}
|
||||||
if (strcmp(req.method, "PUT") == 0 &&
|
if (strcmp(req.method, "PUT") == 0 &&
|
||||||
strcmp(no_query, "/v1/space/manifest") == 0) {
|
strcmp(no_query, "/v1/space/manifest") == 0) {
|
||||||
ok = amduatd_handle_put_space_manifest(fd,
|
ok = amduatd_handle_put_space_manifest(fd,
|
||||||
|
|
|
||||||
331
src/amduatd_space_mounts.c
Normal file
331
src/amduatd_space_mounts.c
Normal file
|
|
@ -0,0 +1,331 @@
|
||||||
|
#include "amduatd_space_mounts.h"
|
||||||
|
|
||||||
|
#include "amduat/asl/ref_text.h"
|
||||||
|
#include "amduatd_fed_cursor.h"
|
||||||
|
#include "amduatd_space_manifest.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *data;
|
||||||
|
size_t len;
|
||||||
|
size_t cap;
|
||||||
|
} amduatd_mounts_buf_t;
|
||||||
|
|
||||||
|
static void amduatd_mounts_buf_free(amduatd_mounts_buf_t *b) {
|
||||||
|
if (b == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
free(b->data);
|
||||||
|
b->data = NULL;
|
||||||
|
b->len = 0;
|
||||||
|
b->cap = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool amduatd_mounts_buf_reserve(amduatd_mounts_buf_t *b, size_t extra) {
|
||||||
|
size_t need;
|
||||||
|
size_t next_cap;
|
||||||
|
char *next;
|
||||||
|
|
||||||
|
if (b == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (extra > (SIZE_MAX - b->len)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
need = b->len + extra;
|
||||||
|
if (need <= b->cap) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
next_cap = b->cap != 0u ? b->cap : 256u;
|
||||||
|
while (next_cap < need) {
|
||||||
|
if (next_cap > (SIZE_MAX / 2u)) {
|
||||||
|
next_cap = need;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
next_cap *= 2u;
|
||||||
|
}
|
||||||
|
next = (char *)realloc(b->data, next_cap);
|
||||||
|
if (next == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
b->data = next;
|
||||||
|
b->cap = next_cap;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool amduatd_mounts_buf_append(amduatd_mounts_buf_t *b,
|
||||||
|
const char *s,
|
||||||
|
size_t n) {
|
||||||
|
if (b == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (n == 0u) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (s == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!amduatd_mounts_buf_reserve(b, n + 1u)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memcpy(b->data + b->len, s, n);
|
||||||
|
b->len += n;
|
||||||
|
b->data[b->len] = '\0';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool amduatd_mounts_buf_append_cstr(amduatd_mounts_buf_t *b,
|
||||||
|
const char *s) {
|
||||||
|
return amduatd_mounts_buf_append(
|
||||||
|
b, s != NULL ? s : "", s != NULL ? strlen(s) : 0u);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool amduatd_mounts_buf_append_char(amduatd_mounts_buf_t *b, char c) {
|
||||||
|
return amduatd_mounts_buf_append(b, &c, 1u);
|
||||||
|
}
|
||||||
|
|
||||||
|
static amduatd_space_mounts_status_t amduatd_space_mounts_append_tracking(
|
||||||
|
amduatd_mounts_buf_t *b,
|
||||||
|
amduat_asl_store_t *store,
|
||||||
|
amduat_asl_pointer_store_t *pointer_store,
|
||||||
|
const amduatd_space_t *effective_space,
|
||||||
|
const amduatd_space_manifest_mount_t *mount) {
|
||||||
|
amduatd_fed_cursor_record_t cursor;
|
||||||
|
amduat_reference_t cursor_ref;
|
||||||
|
amduatd_fed_cursor_status_t status;
|
||||||
|
bool cursor_present = false;
|
||||||
|
char *cursor_ref_hex = NULL;
|
||||||
|
|
||||||
|
amduatd_fed_cursor_record_init(&cursor);
|
||||||
|
cursor_ref = amduat_reference(0u, amduat_octets(NULL, 0u));
|
||||||
|
|
||||||
|
if (mount->mode == AMDUATD_SPACE_MANIFEST_MOUNT_TRACK) {
|
||||||
|
status = amduatd_fed_cursor_get(store,
|
||||||
|
pointer_store,
|
||||||
|
effective_space,
|
||||||
|
mount->peer_key,
|
||||||
|
&cursor,
|
||||||
|
&cursor_ref);
|
||||||
|
if (status == AMDUATD_FED_CURSOR_ERR_NOT_FOUND) {
|
||||||
|
cursor_present = false;
|
||||||
|
} else if (status == AMDUATD_FED_CURSOR_OK) {
|
||||||
|
cursor_present = true;
|
||||||
|
} else if (status == AMDUATD_FED_CURSOR_ERR_CODEC) {
|
||||||
|
amduatd_fed_cursor_record_free(&cursor);
|
||||||
|
amduat_reference_free(&cursor_ref);
|
||||||
|
return AMDUATD_SPACE_MOUNTS_ERR_CODEC;
|
||||||
|
} else {
|
||||||
|
amduatd_fed_cursor_record_free(&cursor);
|
||||||
|
amduat_reference_free(&cursor_ref);
|
||||||
|
return AMDUATD_SPACE_MOUNTS_ERR_STORE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!amduatd_mounts_buf_append_cstr(b, ",\"local_tracking\":{") ||
|
||||||
|
!amduatd_mounts_buf_append_cstr(
|
||||||
|
b,
|
||||||
|
"\"cursor_scope\":\"per-peer-per-local-space\","
|
||||||
|
"\"remote_space_id\":\"") ||
|
||||||
|
!amduatd_mounts_buf_append_cstr(b, mount->space_id) ||
|
||||||
|
!amduatd_mounts_buf_append_cstr(b, "\",\"pull_cursor\":{") ||
|
||||||
|
!amduatd_mounts_buf_append_cstr(b,
|
||||||
|
cursor_present ? "\"present\":true"
|
||||||
|
: "\"present\":false")) {
|
||||||
|
amduatd_fed_cursor_record_free(&cursor);
|
||||||
|
amduat_reference_free(&cursor_ref);
|
||||||
|
return AMDUATD_SPACE_MOUNTS_ERR_STORE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor_present && cursor.has_logseq) {
|
||||||
|
char tmp[32];
|
||||||
|
int n = snprintf(tmp, sizeof(tmp), "%llu",
|
||||||
|
(unsigned long long)cursor.last_logseq);
|
||||||
|
if (n <= 0 || (size_t)n >= sizeof(tmp)) {
|
||||||
|
amduatd_fed_cursor_record_free(&cursor);
|
||||||
|
amduat_reference_free(&cursor_ref);
|
||||||
|
return AMDUATD_SPACE_MOUNTS_ERR_STORE;
|
||||||
|
}
|
||||||
|
if (!amduatd_mounts_buf_append_cstr(b, ",\"last_logseq\":") ||
|
||||||
|
!amduatd_mounts_buf_append_cstr(b, tmp)) {
|
||||||
|
amduatd_fed_cursor_record_free(&cursor);
|
||||||
|
amduat_reference_free(&cursor_ref);
|
||||||
|
return AMDUATD_SPACE_MOUNTS_ERR_STORE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor_present && cursor.has_record_ref) {
|
||||||
|
if (!amduat_asl_ref_encode_hex(cursor.last_record_ref, &cursor_ref_hex)) {
|
||||||
|
amduatd_fed_cursor_record_free(&cursor);
|
||||||
|
amduat_reference_free(&cursor_ref);
|
||||||
|
return AMDUATD_SPACE_MOUNTS_ERR_STORE;
|
||||||
|
}
|
||||||
|
if (!amduatd_mounts_buf_append_cstr(b, ",\"ref\":\"") ||
|
||||||
|
!amduatd_mounts_buf_append_cstr(b, cursor_ref_hex) ||
|
||||||
|
!amduatd_mounts_buf_append_cstr(b, "\"")) {
|
||||||
|
free(cursor_ref_hex);
|
||||||
|
amduatd_fed_cursor_record_free(&cursor);
|
||||||
|
amduat_reference_free(&cursor_ref);
|
||||||
|
return AMDUATD_SPACE_MOUNTS_ERR_STORE;
|
||||||
|
}
|
||||||
|
free(cursor_ref_hex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!amduatd_mounts_buf_append_cstr(b, "}}")) {
|
||||||
|
amduatd_fed_cursor_record_free(&cursor);
|
||||||
|
amduat_reference_free(&cursor_ref);
|
||||||
|
return AMDUATD_SPACE_MOUNTS_ERR_STORE;
|
||||||
|
}
|
||||||
|
|
||||||
|
amduatd_fed_cursor_record_free(&cursor);
|
||||||
|
amduat_reference_free(&cursor_ref);
|
||||||
|
return AMDUATD_SPACE_MOUNTS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
amduatd_space_mounts_status_t amduatd_space_mounts_resolve(
|
||||||
|
amduat_asl_store_t *store,
|
||||||
|
amduat_asl_pointer_store_t *pointer_store,
|
||||||
|
const amduatd_space_t *effective_space,
|
||||||
|
amduat_reference_t *out_manifest_ref,
|
||||||
|
char **out_mounts_json,
|
||||||
|
size_t *out_mounts_len) {
|
||||||
|
amduatd_space_manifest_t manifest;
|
||||||
|
amduat_reference_t manifest_ref;
|
||||||
|
amduatd_space_manifest_status_t status;
|
||||||
|
amduatd_mounts_buf_t b;
|
||||||
|
|
||||||
|
if (out_manifest_ref != NULL) {
|
||||||
|
*out_manifest_ref = amduat_reference(0u, amduat_octets(NULL, 0u));
|
||||||
|
}
|
||||||
|
if (out_mounts_json != NULL) {
|
||||||
|
*out_mounts_json = NULL;
|
||||||
|
}
|
||||||
|
if (out_mounts_len != NULL) {
|
||||||
|
*out_mounts_len = 0u;
|
||||||
|
}
|
||||||
|
if (store == NULL || pointer_store == NULL || out_manifest_ref == NULL ||
|
||||||
|
out_mounts_json == NULL || out_mounts_len == NULL) {
|
||||||
|
return AMDUATD_SPACE_MOUNTS_ERR_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&manifest, 0, sizeof(manifest));
|
||||||
|
memset(&manifest_ref, 0, sizeof(manifest_ref));
|
||||||
|
status = amduatd_space_manifest_get(store,
|
||||||
|
pointer_store,
|
||||||
|
effective_space,
|
||||||
|
&manifest_ref,
|
||||||
|
&manifest);
|
||||||
|
if (status == AMDUATD_SPACE_MANIFEST_ERR_NOT_FOUND) {
|
||||||
|
return AMDUATD_SPACE_MOUNTS_ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
if (status == AMDUATD_SPACE_MANIFEST_ERR_STORE) {
|
||||||
|
return AMDUATD_SPACE_MOUNTS_ERR_STORE;
|
||||||
|
}
|
||||||
|
if (status != AMDUATD_SPACE_MANIFEST_OK) {
|
||||||
|
return AMDUATD_SPACE_MOUNTS_ERR_CODEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&b, 0, sizeof(b));
|
||||||
|
if (!amduatd_mounts_buf_append_char(&b, '[')) {
|
||||||
|
amduatd_space_manifest_free(&manifest);
|
||||||
|
amduat_reference_free(&manifest_ref);
|
||||||
|
return AMDUATD_SPACE_MOUNTS_ERR_STORE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0u; i < manifest.mounts_len; ++i) {
|
||||||
|
const amduatd_space_manifest_mount_t *mount = &manifest.mounts[i];
|
||||||
|
char *pinned_hex = NULL;
|
||||||
|
|
||||||
|
if (i != 0u) {
|
||||||
|
if (!amduatd_mounts_buf_append_char(&b, ',')) {
|
||||||
|
amduatd_space_manifest_free(&manifest);
|
||||||
|
amduat_reference_free(&manifest_ref);
|
||||||
|
amduatd_mounts_buf_free(&b);
|
||||||
|
return AMDUATD_SPACE_MOUNTS_ERR_STORE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!amduatd_mounts_buf_append_cstr(&b, "{\"name\":\"") ||
|
||||||
|
!amduatd_mounts_buf_append_cstr(&b, mount->name) ||
|
||||||
|
!amduatd_mounts_buf_append_cstr(&b, "\",\"peer_key\":\"") ||
|
||||||
|
!amduatd_mounts_buf_append_cstr(&b, mount->peer_key) ||
|
||||||
|
!amduatd_mounts_buf_append_cstr(&b, "\",\"space_id\":\"") ||
|
||||||
|
!amduatd_mounts_buf_append_cstr(&b, mount->space_id) ||
|
||||||
|
!amduatd_mounts_buf_append_cstr(&b, "\",\"mode\":\"") ||
|
||||||
|
!amduatd_mounts_buf_append_cstr(
|
||||||
|
&b,
|
||||||
|
mount->mode == AMDUATD_SPACE_MANIFEST_MOUNT_PINNED ? "pinned"
|
||||||
|
: "track") ||
|
||||||
|
!amduatd_mounts_buf_append_cstr(&b, "\"")) {
|
||||||
|
amduatd_space_manifest_free(&manifest);
|
||||||
|
amduat_reference_free(&manifest_ref);
|
||||||
|
amduatd_mounts_buf_free(&b);
|
||||||
|
return AMDUATD_SPACE_MOUNTS_ERR_STORE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mount->mode == AMDUATD_SPACE_MANIFEST_MOUNT_PINNED &&
|
||||||
|
mount->has_pinned_root_ref) {
|
||||||
|
if (!amduat_asl_ref_encode_hex(mount->pinned_root_ref, &pinned_hex)) {
|
||||||
|
amduatd_space_manifest_free(&manifest);
|
||||||
|
amduat_reference_free(&manifest_ref);
|
||||||
|
amduatd_mounts_buf_free(&b);
|
||||||
|
return AMDUATD_SPACE_MOUNTS_ERR_STORE;
|
||||||
|
}
|
||||||
|
if (!amduatd_mounts_buf_append_cstr(&b, ",\"pinned_root_ref\":\"") ||
|
||||||
|
!amduatd_mounts_buf_append_cstr(&b, pinned_hex) ||
|
||||||
|
!amduatd_mounts_buf_append_cstr(&b, "\"")) {
|
||||||
|
free(pinned_hex);
|
||||||
|
amduatd_space_manifest_free(&manifest);
|
||||||
|
amduat_reference_free(&manifest_ref);
|
||||||
|
amduatd_mounts_buf_free(&b);
|
||||||
|
return AMDUATD_SPACE_MOUNTS_ERR_STORE;
|
||||||
|
}
|
||||||
|
free(pinned_hex);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
amduatd_space_mounts_status_t track_status =
|
||||||
|
amduatd_space_mounts_append_tracking(&b,
|
||||||
|
store,
|
||||||
|
pointer_store,
|
||||||
|
effective_space,
|
||||||
|
mount);
|
||||||
|
if (track_status != AMDUATD_SPACE_MOUNTS_OK) {
|
||||||
|
amduatd_space_manifest_free(&manifest);
|
||||||
|
amduat_reference_free(&manifest_ref);
|
||||||
|
amduatd_mounts_buf_free(&b);
|
||||||
|
return track_status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!amduatd_mounts_buf_append_cstr(&b, "}")) {
|
||||||
|
amduatd_space_manifest_free(&manifest);
|
||||||
|
amduat_reference_free(&manifest_ref);
|
||||||
|
amduatd_mounts_buf_free(&b);
|
||||||
|
return AMDUATD_SPACE_MOUNTS_ERR_STORE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!amduatd_mounts_buf_append_char(&b, ']')) {
|
||||||
|
amduatd_space_manifest_free(&manifest);
|
||||||
|
amduat_reference_free(&manifest_ref);
|
||||||
|
amduatd_mounts_buf_free(&b);
|
||||||
|
return AMDUATD_SPACE_MOUNTS_ERR_STORE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!amduat_reference_clone(manifest_ref, out_manifest_ref)) {
|
||||||
|
amduatd_space_manifest_free(&manifest);
|
||||||
|
amduat_reference_free(&manifest_ref);
|
||||||
|
amduatd_mounts_buf_free(&b);
|
||||||
|
return AMDUATD_SPACE_MOUNTS_ERR_STORE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_mounts_json = b.data;
|
||||||
|
*out_mounts_len = b.len;
|
||||||
|
amduatd_space_manifest_free(&manifest);
|
||||||
|
amduat_reference_free(&manifest_ref);
|
||||||
|
return AMDUATD_SPACE_MOUNTS_OK;
|
||||||
|
}
|
||||||
35
src/amduatd_space_mounts.h
Normal file
35
src/amduatd_space_mounts.h
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
#ifndef AMDUATD_SPACE_MOUNTS_H
|
||||||
|
#define AMDUATD_SPACE_MOUNTS_H
|
||||||
|
|
||||||
|
#include "amduat/asl/asl_pointer_fs.h"
|
||||||
|
#include "amduat/asl/store.h"
|
||||||
|
#include "amduatd_space.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
AMDUATD_SPACE_MOUNTS_OK = 0,
|
||||||
|
AMDUATD_SPACE_MOUNTS_ERR_INVALID = 1,
|
||||||
|
AMDUATD_SPACE_MOUNTS_ERR_NOT_FOUND = 2,
|
||||||
|
AMDUATD_SPACE_MOUNTS_ERR_STORE = 3,
|
||||||
|
AMDUATD_SPACE_MOUNTS_ERR_CODEC = 4
|
||||||
|
} amduatd_space_mounts_status_t;
|
||||||
|
|
||||||
|
amduatd_space_mounts_status_t amduatd_space_mounts_resolve(
|
||||||
|
amduat_asl_store_t *store,
|
||||||
|
amduat_asl_pointer_store_t *pointer_store,
|
||||||
|
const amduatd_space_t *effective_space,
|
||||||
|
amduat_reference_t *out_manifest_ref,
|
||||||
|
char **out_mounts_json,
|
||||||
|
size_t *out_mounts_len);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* AMDUATD_SPACE_MOUNTS_H */
|
||||||
356
tests/test_amduatd_space_mounts.c
Normal file
356
tests/test_amduatd_space_mounts.c
Normal file
|
|
@ -0,0 +1,356 @@
|
||||||
|
#ifndef _POSIX_C_SOURCE
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "amduatd_space_mounts.h"
|
||||||
|
|
||||||
|
#include "amduatd_fed_cursor.h"
|
||||||
|
#include "amduatd_space.h"
|
||||||
|
#include "amduatd_space_manifest.h"
|
||||||
|
#include "amduatd_store.h"
|
||||||
|
|
||||||
|
#include "amduat/asl/asl_pointer_fs.h"
|
||||||
|
#include "amduat/asl/asl_store_fs_meta.h"
|
||||||
|
#include "amduat/asl/record.h"
|
||||||
|
#include "amduat/asl/ref_text.h"
|
||||||
|
#include "amduat/hash/asl1.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static int failures = 0;
|
||||||
|
|
||||||
|
static void expect(bool cond, const char *msg) {
|
||||||
|
if (!cond) {
|
||||||
|
fprintf(stderr, "FAIL: %s\n", msg);
|
||||||
|
failures++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *amduatd_test_make_temp_dir(void) {
|
||||||
|
char tmpl[] = "/tmp/amduatd-space-mounts-XXXXXX";
|
||||||
|
char *dir = mkdtemp(tmpl);
|
||||||
|
size_t len;
|
||||||
|
char *copy;
|
||||||
|
if (dir == NULL) {
|
||||||
|
perror("mkdtemp");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
len = strlen(dir);
|
||||||
|
copy = (char *)malloc(len + 1u);
|
||||||
|
if (copy == NULL) {
|
||||||
|
fprintf(stderr, "failed to allocate temp dir copy\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memcpy(copy, dir, len + 1u);
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool amduatd_make_test_ref(uint8_t fill, amduat_reference_t *out_ref) {
|
||||||
|
uint8_t digest_bytes[32];
|
||||||
|
amduat_octets_t digest;
|
||||||
|
if (out_ref == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memset(digest_bytes, fill, sizeof(digest_bytes));
|
||||||
|
if (!amduat_octets_clone(amduat_octets(digest_bytes, sizeof(digest_bytes)),
|
||||||
|
&digest)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*out_ref = amduat_reference(AMDUAT_HASH_ASL1_ID_SHA256, digest);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int amduatd_test_mounts_missing(void) {
|
||||||
|
char *root = amduatd_test_make_temp_dir();
|
||||||
|
amduat_asl_store_fs_config_t cfg;
|
||||||
|
amduatd_store_ctx_t store_ctx;
|
||||||
|
amduat_asl_store_t store;
|
||||||
|
amduat_asl_pointer_store_t pointer_store;
|
||||||
|
amduatd_space_t space;
|
||||||
|
amduat_reference_t manifest_ref;
|
||||||
|
char *mounts_json = NULL;
|
||||||
|
size_t mounts_len = 0u;
|
||||||
|
amduatd_space_mounts_status_t status;
|
||||||
|
|
||||||
|
if (root == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
memset(&cfg, 0, sizeof(cfg));
|
||||||
|
if (!amduat_asl_store_fs_init_root(root, NULL, &cfg)) {
|
||||||
|
fprintf(stderr, "failed to init store root\n");
|
||||||
|
free(root);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
memset(&store_ctx, 0, sizeof(store_ctx));
|
||||||
|
memset(&store, 0, sizeof(store));
|
||||||
|
if (!amduatd_store_init(&store,
|
||||||
|
&cfg,
|
||||||
|
&store_ctx,
|
||||||
|
root,
|
||||||
|
AMDUATD_STORE_BACKEND_FS)) {
|
||||||
|
fprintf(stderr, "failed to init store\n");
|
||||||
|
free(root);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!amduat_asl_pointer_store_init(&pointer_store, root)) {
|
||||||
|
fprintf(stderr, "failed to init pointer store\n");
|
||||||
|
free(root);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!amduatd_space_init(&space, "alpha", false)) {
|
||||||
|
fprintf(stderr, "failed to init space\n");
|
||||||
|
free(root);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&manifest_ref, 0, sizeof(manifest_ref));
|
||||||
|
status = amduatd_space_mounts_resolve(&store,
|
||||||
|
&pointer_store,
|
||||||
|
&space,
|
||||||
|
&manifest_ref,
|
||||||
|
&mounts_json,
|
||||||
|
&mounts_len);
|
||||||
|
expect(status == AMDUATD_SPACE_MOUNTS_ERR_NOT_FOUND,
|
||||||
|
"missing manifest returns not found");
|
||||||
|
expect(mounts_json == NULL, "mounts json unset on missing");
|
||||||
|
amduat_reference_free(&manifest_ref);
|
||||||
|
free(root);
|
||||||
|
return failures == 0 ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int amduatd_test_mounts_resolve(void) {
|
||||||
|
char *root = amduatd_test_make_temp_dir();
|
||||||
|
amduat_asl_store_fs_config_t cfg;
|
||||||
|
amduatd_store_ctx_t store_ctx;
|
||||||
|
amduat_asl_store_t store;
|
||||||
|
amduat_asl_pointer_store_t pointer_store;
|
||||||
|
amduatd_space_t space;
|
||||||
|
amduat_reference_t pinned_ref;
|
||||||
|
char *pinned_hex = NULL;
|
||||||
|
char payload[512];
|
||||||
|
amduat_reference_t record_ref;
|
||||||
|
amduat_octets_t pointer_name = amduat_octets(NULL, 0u);
|
||||||
|
bool swapped = false;
|
||||||
|
amduatd_fed_cursor_record_t cursor;
|
||||||
|
amduat_reference_t cursor_ref;
|
||||||
|
amduat_reference_t cursor_last_ref;
|
||||||
|
char *cursor_last_hex = NULL;
|
||||||
|
amduat_reference_t manifest_ref;
|
||||||
|
char *mounts_json = NULL;
|
||||||
|
size_t mounts_len = 0u;
|
||||||
|
amduatd_space_mounts_status_t status;
|
||||||
|
const char *m0 = NULL;
|
||||||
|
const char *m1 = NULL;
|
||||||
|
const char *m2 = NULL;
|
||||||
|
|
||||||
|
if (root == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
memset(&cfg, 0, sizeof(cfg));
|
||||||
|
if (!amduat_asl_store_fs_init_root(root, NULL, &cfg)) {
|
||||||
|
fprintf(stderr, "failed to init store root\n");
|
||||||
|
free(root);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
memset(&store_ctx, 0, sizeof(store_ctx));
|
||||||
|
memset(&store, 0, sizeof(store));
|
||||||
|
if (!amduatd_store_init(&store,
|
||||||
|
&cfg,
|
||||||
|
&store_ctx,
|
||||||
|
root,
|
||||||
|
AMDUATD_STORE_BACKEND_FS)) {
|
||||||
|
fprintf(stderr, "failed to init store\n");
|
||||||
|
free(root);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!amduat_asl_pointer_store_init(&pointer_store, root)) {
|
||||||
|
fprintf(stderr, "failed to init pointer store\n");
|
||||||
|
free(root);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!amduatd_space_init(&space, "alpha", false)) {
|
||||||
|
fprintf(stderr, "failed to init space\n");
|
||||||
|
free(root);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!amduatd_make_test_ref(0x11, &pinned_ref)) {
|
||||||
|
fprintf(stderr, "failed to make pinned ref\n");
|
||||||
|
free(root);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!amduat_asl_ref_encode_hex(pinned_ref, &pinned_hex)) {
|
||||||
|
fprintf(stderr, "failed to encode pinned ref\n");
|
||||||
|
amduat_reference_free(&pinned_ref);
|
||||||
|
free(root);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int n = snprintf(
|
||||||
|
payload,
|
||||||
|
sizeof(payload),
|
||||||
|
"{"
|
||||||
|
"\"version\":1,"
|
||||||
|
"\"mounts\":["
|
||||||
|
"{\"name\":\"beta\",\"peer_key\":\"peer-2\",\"space_id\":\"zeta\","
|
||||||
|
"\"mode\":\"track\"},"
|
||||||
|
"{\"name\":\"alpha\",\"peer_key\":\"peer-1\",\"space_id\":\"zeta\","
|
||||||
|
"\"mode\":\"pinned\",\"pinned_root_ref\":\"%s\"},"
|
||||||
|
"{\"name\":\"alpha\",\"peer_key\":\"peer-1\",\"space_id\":\"beta\","
|
||||||
|
"\"mode\":\"track\"}"
|
||||||
|
"]"
|
||||||
|
"}",
|
||||||
|
pinned_hex);
|
||||||
|
if (n <= 0 || (size_t)n >= sizeof(payload)) {
|
||||||
|
fprintf(stderr, "failed to build manifest payload\n");
|
||||||
|
free(pinned_hex);
|
||||||
|
amduat_reference_free(&pinned_ref);
|
||||||
|
free(root);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(pinned_hex);
|
||||||
|
|
||||||
|
if (amduat_asl_record_store_put(
|
||||||
|
&store,
|
||||||
|
amduat_octets(AMDUATD_SPACE_MANIFEST_1,
|
||||||
|
strlen(AMDUATD_SPACE_MANIFEST_1)),
|
||||||
|
amduat_octets((const uint8_t *)payload, strlen(payload)),
|
||||||
|
&record_ref) != AMDUAT_ASL_STORE_OK) {
|
||||||
|
fprintf(stderr, "failed to store manifest record\n");
|
||||||
|
amduat_reference_free(&pinned_ref);
|
||||||
|
free(root);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!amduatd_space_scope_name(&space, "manifest/head", &pointer_name)) {
|
||||||
|
fprintf(stderr, "failed to build manifest pointer name\n");
|
||||||
|
amduat_reference_free(&record_ref);
|
||||||
|
amduat_reference_free(&pinned_ref);
|
||||||
|
free(root);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (amduat_asl_pointer_cas(&pointer_store,
|
||||||
|
(const char *)pointer_name.data,
|
||||||
|
false,
|
||||||
|
NULL,
|
||||||
|
&record_ref,
|
||||||
|
&swapped) != AMDUAT_ASL_POINTER_OK ||
|
||||||
|
!swapped) {
|
||||||
|
fprintf(stderr, "failed to set manifest pointer\n");
|
||||||
|
amduat_octets_free(&pointer_name);
|
||||||
|
amduat_reference_free(&record_ref);
|
||||||
|
amduat_reference_free(&pinned_ref);
|
||||||
|
free(root);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
amduat_octets_free(&pointer_name);
|
||||||
|
|
||||||
|
if (!amduatd_make_test_ref(0x22, &cursor_last_ref)) {
|
||||||
|
fprintf(stderr, "failed to make cursor ref\n");
|
||||||
|
amduat_reference_free(&record_ref);
|
||||||
|
amduat_reference_free(&pinned_ref);
|
||||||
|
free(root);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!amduat_asl_ref_encode_hex(cursor_last_ref, &cursor_last_hex)) {
|
||||||
|
fprintf(stderr, "failed to encode cursor ref\n");
|
||||||
|
amduat_reference_free(&cursor_last_ref);
|
||||||
|
amduat_reference_free(&record_ref);
|
||||||
|
amduat_reference_free(&pinned_ref);
|
||||||
|
free(root);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
amduatd_fed_cursor_record_init(&cursor);
|
||||||
|
cursor.peer_key = strdup("peer-1");
|
||||||
|
cursor.space_id = strdup("alpha");
|
||||||
|
cursor.has_logseq = true;
|
||||||
|
cursor.last_logseq = 42u;
|
||||||
|
cursor.has_record_ref = true;
|
||||||
|
cursor.last_record_ref = cursor_last_ref;
|
||||||
|
memset(&cursor_ref, 0, sizeof(cursor_ref));
|
||||||
|
if (amduatd_fed_cursor_cas_set(&store,
|
||||||
|
&pointer_store,
|
||||||
|
&space,
|
||||||
|
"peer-1",
|
||||||
|
NULL,
|
||||||
|
&cursor,
|
||||||
|
&cursor_ref) != AMDUATD_FED_CURSOR_OK) {
|
||||||
|
fprintf(stderr, "failed to set cursor\n");
|
||||||
|
amduatd_fed_cursor_record_free(&cursor);
|
||||||
|
amduat_reference_free(&cursor_ref);
|
||||||
|
amduat_reference_free(&record_ref);
|
||||||
|
amduat_reference_free(&pinned_ref);
|
||||||
|
free(cursor_last_hex);
|
||||||
|
free(root);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
amduatd_fed_cursor_record_free(&cursor);
|
||||||
|
amduat_reference_free(&cursor_ref);
|
||||||
|
|
||||||
|
memset(&manifest_ref, 0, sizeof(manifest_ref));
|
||||||
|
status = amduatd_space_mounts_resolve(&store,
|
||||||
|
&pointer_store,
|
||||||
|
&space,
|
||||||
|
&manifest_ref,
|
||||||
|
&mounts_json,
|
||||||
|
&mounts_len);
|
||||||
|
expect(status == AMDUATD_SPACE_MOUNTS_OK, "mounts resolve ok");
|
||||||
|
expect(amduat_reference_eq(manifest_ref, record_ref),
|
||||||
|
"resolve manifest ref matches pointer");
|
||||||
|
expect(mounts_json != NULL && mounts_len != 0u,
|
||||||
|
"resolve mounts json populated");
|
||||||
|
|
||||||
|
if (mounts_json != NULL) {
|
||||||
|
m0 = strstr(mounts_json,
|
||||||
|
"\"name\":\"alpha\",\"peer_key\":\"peer-1\",\"space_id\":\"beta\"");
|
||||||
|
m1 = strstr(mounts_json,
|
||||||
|
"\"name\":\"alpha\",\"peer_key\":\"peer-1\",\"space_id\":\"zeta\"");
|
||||||
|
m2 = strstr(mounts_json,
|
||||||
|
"\"name\":\"beta\",\"peer_key\":\"peer-2\",\"space_id\":\"zeta\"");
|
||||||
|
expect(m0 != NULL && m1 != NULL && m2 != NULL,
|
||||||
|
"mounts include all entries");
|
||||||
|
if (m0 != NULL && m1 != NULL && m2 != NULL) {
|
||||||
|
expect(m0 < m1 && m1 < m2, "mounts are in canonical order");
|
||||||
|
}
|
||||||
|
expect(strstr(mounts_json, "\"mode\":\"pinned\"") != NULL,
|
||||||
|
"pinned mode present");
|
||||||
|
expect(strstr(mounts_json, "\"pinned_root_ref\":\"") != NULL,
|
||||||
|
"pinned root ref present");
|
||||||
|
expect(strstr(mounts_json, "\"cursor_scope\":\"per-peer-per-local-space\"") != NULL,
|
||||||
|
"cursor scope present");
|
||||||
|
expect(strstr(mounts_json, "\"remote_space_id\":\"beta\"") != NULL,
|
||||||
|
"remote space id present");
|
||||||
|
expect(strstr(mounts_json, "\"pull_cursor\":{\"present\":true") != NULL,
|
||||||
|
"cursor present true");
|
||||||
|
expect(strstr(mounts_json, "\"last_logseq\":42") != NULL,
|
||||||
|
"cursor last_logseq present");
|
||||||
|
expect(strstr(mounts_json, cursor_last_hex) != NULL,
|
||||||
|
"cursor ref present");
|
||||||
|
expect(strstr(mounts_json, "\"pull_cursor\":{\"present\":false") != NULL,
|
||||||
|
"cursor present false");
|
||||||
|
}
|
||||||
|
|
||||||
|
free(mounts_json);
|
||||||
|
amduat_reference_free(&manifest_ref);
|
||||||
|
amduat_reference_free(&record_ref);
|
||||||
|
amduat_reference_free(&pinned_ref);
|
||||||
|
free(cursor_last_hex);
|
||||||
|
free(root);
|
||||||
|
return failures == 0 ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
if (amduatd_test_mounts_missing() != 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (amduatd_test_mounts_resolve() != 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return failures == 0 ? 0 : 1;
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue