mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-05-20 22:31:44 +00:00
Add: mirror command
Tidy: test
This commit is contained in:
@@ -4,8 +4,9 @@ set -euo pipefail
|
||||
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CLI_DIR="$(cd -- "$SCRIPT_DIR/.." && pwd)"
|
||||
cd "$CLI_DIR"
|
||||
|
||||
CLI_CMD=(npm --silent run cli -- -v)
|
||||
source "$SCRIPT_DIR/test-helpers.sh"
|
||||
VERBOSE_TEST_LOGGING="${VERBOSE_TEST_LOGGING:-0}"
|
||||
cli_test_init_cli_cmd
|
||||
RUN_BUILD="${RUN_BUILD:-1}"
|
||||
KEEP_TEST_DATA="${KEEP_TEST_DATA:-0}"
|
||||
TEST_ENV_FILE="${TEST_ENV_FILE:-$CLI_DIR/.test.env}"
|
||||
@@ -36,27 +37,24 @@ COUCHDB_URI=""
|
||||
COUCHDB_DBNAME=""
|
||||
MINIO_BUCKET=""
|
||||
|
||||
require_env() {
|
||||
local var_name="$1"
|
||||
if [[ -z "${!var_name:-}" ]]; then
|
||||
echo "[ERROR] required variable '$var_name' is missing in $TEST_ENV_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ "$REMOTE_TYPE" == "COUCHDB" ]]; then
|
||||
require_env hostname
|
||||
require_env dbname
|
||||
require_env username
|
||||
require_env password
|
||||
cli_test_require_env hostname "$TEST_ENV_FILE"
|
||||
cli_test_require_env dbname "$TEST_ENV_FILE"
|
||||
cli_test_require_env username "$TEST_ENV_FILE"
|
||||
cli_test_require_env password "$TEST_ENV_FILE"
|
||||
COUCHDB_URI="${hostname%/}"
|
||||
COUCHDB_DBNAME="${dbname}-${DB_SUFFIX}"
|
||||
COUCHDB_USER="${username:-}"
|
||||
COUCHDB_PASSWORD="${password:-}"
|
||||
elif [[ "$REMOTE_TYPE" == "MINIO" ]]; then
|
||||
require_env accessKey
|
||||
require_env secretKey
|
||||
require_env minioEndpoint
|
||||
require_env bucketName
|
||||
cli_test_require_env accessKey "$TEST_ENV_FILE"
|
||||
cli_test_require_env secretKey "$TEST_ENV_FILE"
|
||||
cli_test_require_env minioEndpoint "$TEST_ENV_FILE"
|
||||
cli_test_require_env bucketName "$TEST_ENV_FILE"
|
||||
MINIO_BUCKET="${bucketName}-${DB_SUFFIX}"
|
||||
MINIO_ENDPOINT="${minioEndpoint:-}"
|
||||
MINIO_ACCESS_KEY="${accessKey:-}"
|
||||
MINIO_SECRET_KEY="${secretKey:-}"
|
||||
else
|
||||
echo "[ERROR] unsupported REMOTE_TYPE: $REMOTE_TYPE (use COUCHDB or MINIO)" >&2
|
||||
exit 1
|
||||
@@ -65,9 +63,9 @@ fi
|
||||
cleanup() {
|
||||
local exit_code=$?
|
||||
if [[ "$REMOTE_TYPE" == "COUCHDB" ]]; then
|
||||
bash "$CLI_DIR/util/couchdb-stop.sh" >/dev/null 2>&1 || true
|
||||
cli_test_stop_couchdb
|
||||
else
|
||||
bash "$CLI_DIR/util/minio-stop.sh" >/dev/null 2>&1 || true
|
||||
cli_test_stop_minio
|
||||
fi
|
||||
|
||||
if [[ "$KEEP_TEST_DATA" != "1" ]]; then
|
||||
@@ -83,10 +81,6 @@ cleanup() {
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
run_cli() {
|
||||
"${CLI_CMD[@]}" "$@"
|
||||
}
|
||||
|
||||
run_cli_a() {
|
||||
run_cli "$VAULT_A" --settings "$SETTINGS_A" "$@"
|
||||
}
|
||||
@@ -95,191 +89,28 @@ run_cli_b() {
|
||||
run_cli "$VAULT_B" --settings "$SETTINGS_B" "$@"
|
||||
}
|
||||
|
||||
assert_contains() {
|
||||
local haystack="$1"
|
||||
local needle="$2"
|
||||
local message="$3"
|
||||
if ! grep -Fq "$needle" <<< "$haystack"; then
|
||||
echo "[FAIL] $message" >&2
|
||||
echo "[FAIL] expected to find: $needle" >&2
|
||||
echo "[FAIL] actual output:" >&2
|
||||
echo "$haystack" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
assert_equal() {
|
||||
local expected="$1"
|
||||
local actual="$2"
|
||||
local message="$3"
|
||||
if [[ "$expected" != "$actual" ]]; then
|
||||
echo "[FAIL] $message" >&2
|
||||
echo "[FAIL] expected: $expected" >&2
|
||||
echo "[FAIL] actual: $actual" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
assert_command_fails() {
|
||||
local message="$1"
|
||||
shift
|
||||
set +e
|
||||
"$@" >"$WORK_DIR/failed-command.log" 2>&1
|
||||
local exit_code=$?
|
||||
set -e
|
||||
if [[ "$exit_code" -eq 0 ]]; then
|
||||
echo "[FAIL] $message" >&2
|
||||
cat "$WORK_DIR/failed-command.log" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
assert_files_equal() {
|
||||
local expected_file="$1"
|
||||
local actual_file="$2"
|
||||
local message="$3"
|
||||
if ! cmp -s "$expected_file" "$actual_file"; then
|
||||
echo "[FAIL] $message" >&2
|
||||
echo "[FAIL] expected sha256: $(sha256sum "$expected_file" | awk '{print $1}')" >&2
|
||||
echo "[FAIL] actual sha256: $(sha256sum "$actual_file" | awk '{print $1}')" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
sanitise_cat_stdout() {
|
||||
sed '/^\[CLIWatchAdapter\] File watching is not enabled in CLI version$/d'
|
||||
}
|
||||
|
||||
extract_json_string_field() {
|
||||
local field_name="$1"
|
||||
node -e '
|
||||
const fs = require("node:fs");
|
||||
const fieldName = process.argv[1];
|
||||
const data = JSON.parse(fs.readFileSync(0, "utf-8"));
|
||||
const value = data[fieldName];
|
||||
if (typeof value === "string") {
|
||||
process.stdout.write(value);
|
||||
}
|
||||
' "$field_name"
|
||||
}
|
||||
|
||||
sync_both() {
|
||||
run_cli_a sync >/dev/null
|
||||
run_cli_b sync >/dev/null
|
||||
}
|
||||
|
||||
curl_json() {
|
||||
curl -4 -sS --fail --connect-timeout 3 --max-time 15 "$@"
|
||||
}
|
||||
|
||||
configure_remote_settings() {
|
||||
local settings_file="$1"
|
||||
SETTINGS_FILE="$settings_file" \
|
||||
REMOTE_TYPE="$REMOTE_TYPE" \
|
||||
COUCHDB_URI="$COUCHDB_URI" \
|
||||
COUCHDB_USER="${username:-}" \
|
||||
COUCHDB_PASSWORD="${password:-}" \
|
||||
COUCHDB_DBNAME="$COUCHDB_DBNAME" \
|
||||
MINIO_ENDPOINT="${minioEndpoint:-}" \
|
||||
MINIO_BUCKET="$MINIO_BUCKET" \
|
||||
MINIO_ACCESS_KEY="${accessKey:-}" \
|
||||
MINIO_SECRET_KEY="${secretKey:-}" \
|
||||
ENCRYPT="$ENCRYPT" \
|
||||
E2E_PASSPHRASE="$E2E_PASSPHRASE" \
|
||||
node <<'NODE'
|
||||
const fs = require("node:fs");
|
||||
const settingsPath = process.env.SETTINGS_FILE;
|
||||
const data = JSON.parse(fs.readFileSync(settingsPath, "utf-8"));
|
||||
|
||||
const remoteType = process.env.REMOTE_TYPE;
|
||||
if (remoteType === "COUCHDB") {
|
||||
data.remoteType = "";
|
||||
data.couchDB_URI = process.env.COUCHDB_URI;
|
||||
data.couchDB_USER = process.env.COUCHDB_USER;
|
||||
data.couchDB_PASSWORD = process.env.COUCHDB_PASSWORD;
|
||||
data.couchDB_DBNAME = process.env.COUCHDB_DBNAME;
|
||||
} else if (remoteType === "MINIO") {
|
||||
data.remoteType = "MINIO";
|
||||
data.bucket = process.env.MINIO_BUCKET;
|
||||
data.endpoint = process.env.MINIO_ENDPOINT;
|
||||
data.accessKey = process.env.MINIO_ACCESS_KEY;
|
||||
data.secretKey = process.env.MINIO_SECRET_KEY;
|
||||
data.region = "auto";
|
||||
data.forcePathStyle = true;
|
||||
}
|
||||
|
||||
data.liveSync = true;
|
||||
data.syncOnStart = false;
|
||||
data.syncOnSave = false;
|
||||
data.usePluginSync = false;
|
||||
|
||||
data.encrypt = process.env.ENCRYPT === "1";
|
||||
data.passphrase = data.encrypt ? process.env.E2E_PASSPHRASE : "";
|
||||
|
||||
data.isConfigured = true;
|
||||
|
||||
fs.writeFileSync(settingsPath, JSON.stringify(data, null, 2), "utf-8");
|
||||
NODE
|
||||
cli_test_apply_remote_sync_settings "$settings_file"
|
||||
}
|
||||
|
||||
init_settings() {
|
||||
local settings_file="$1"
|
||||
run_cli init-settings --force "$settings_file" >/dev/null
|
||||
cli_test_init_settings_file "$settings_file"
|
||||
configure_remote_settings "$settings_file"
|
||||
cat "$settings_file"
|
||||
}
|
||||
|
||||
wait_for_minio_bucket() {
|
||||
local retries=30
|
||||
local delay_sec=2
|
||||
local i
|
||||
for ((i = 1; i <= retries; i++)); do
|
||||
if docker run --rm --network host --entrypoint=/bin/sh minio/mc -c "mc alias set myminio $minioEndpoint $accessKey $secretKey >/dev/null 2>&1 && mc ls myminio/$MINIO_BUCKET >/dev/null 2>&1"; then
|
||||
return 0
|
||||
fi
|
||||
bucketName="$MINIO_BUCKET" bash "$CLI_DIR/util/minio-init.sh" >/dev/null 2>&1 || true
|
||||
sleep "$delay_sec"
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
start_remote() {
|
||||
if [[ "$REMOTE_TYPE" == "COUCHDB" ]]; then
|
||||
echo "[INFO] stopping leftover CouchDB container if present"
|
||||
bash "$CLI_DIR/util/couchdb-stop.sh" >/dev/null 2>&1 || true
|
||||
|
||||
echo "[INFO] starting CouchDB test container"
|
||||
bash "$CLI_DIR/util/couchdb-start.sh"
|
||||
|
||||
echo "[INFO] initialising CouchDB test container"
|
||||
bash "$CLI_DIR/util/couchdb-init.sh"
|
||||
|
||||
echo "[INFO] CouchDB create test database: $COUCHDB_DBNAME"
|
||||
until (curl_json -X PUT --user "${username}:${password}" "${hostname}/${COUCHDB_DBNAME}"); do sleep 5; done
|
||||
cli_test_start_couchdb "$COUCHDB_URI" "$COUCHDB_USER" "$COUCHDB_PASSWORD" "$COUCHDB_DBNAME"
|
||||
else
|
||||
echo "[INFO] stopping leftover MinIO container if present"
|
||||
bash "$CLI_DIR/util/minio-stop.sh" >/dev/null 2>&1 || true
|
||||
|
||||
echo "[INFO] starting MinIO test container"
|
||||
bucketName="$MINIO_BUCKET" bash "$CLI_DIR/util/minio-start.sh"
|
||||
|
||||
echo "[INFO] initialising MinIO test bucket: $MINIO_BUCKET"
|
||||
local minio_init_ok=0
|
||||
for _ in 1 2 3 4 5; do
|
||||
if bucketName="$MINIO_BUCKET" bash "$CLI_DIR/util/minio-init.sh"; then
|
||||
minio_init_ok=1
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
if [[ "$minio_init_ok" != "1" ]]; then
|
||||
echo "[FAIL] could not initialise MinIO bucket after retries: $MINIO_BUCKET" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! wait_for_minio_bucket; then
|
||||
echo "[FAIL] MinIO bucket not ready: $MINIO_BUCKET" >&2
|
||||
exit 1
|
||||
fi
|
||||
cli_test_start_minio "$MINIO_ENDPOINT" "$MINIO_ACCESS_KEY" "$MINIO_SECRET_KEY" "$MINIO_BUCKET"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -313,14 +144,14 @@ TARGET_CONFLICT="e2e/conflict.md"
|
||||
echo "[CASE] A puts and A can get info"
|
||||
printf 'alpha-from-a\n' | run_cli_a put "$TARGET_A_ONLY" >/dev/null
|
||||
INFO_A_ONLY="$(run_cli_a info "$TARGET_A_ONLY")"
|
||||
assert_contains "$INFO_A_ONLY" "\"path\": \"$TARGET_A_ONLY\"" "A info should include path after put"
|
||||
cli_test_assert_contains "$INFO_A_ONLY" "\"path\": \"$TARGET_A_ONLY\"" "A info should include path after put"
|
||||
echo "[PASS] A put/info"
|
||||
|
||||
echo "[CASE] A puts, both sync, and B can get info"
|
||||
printf 'visible-after-sync\n' | run_cli_a put "$TARGET_SYNC" >/dev/null
|
||||
sync_both
|
||||
INFO_B_SYNC="$(run_cli_b info "$TARGET_SYNC")"
|
||||
assert_contains "$INFO_B_SYNC" "\"path\": \"$TARGET_SYNC\"" "B info should include path after sync"
|
||||
cli_test_assert_contains "$INFO_B_SYNC" "\"path\": \"$TARGET_SYNC\"" "B info should include path after sync"
|
||||
echo "[PASS] sync A->B and B info"
|
||||
|
||||
echo "[CASE] A pushes and puts, both sync, and B can pull and cat"
|
||||
@@ -331,9 +162,9 @@ run_cli_a push "$PUSH_SRC" "$TARGET_PUSH" >/dev/null
|
||||
printf 'put-content-%s\n' "$DB_SUFFIX" | run_cli_a put "$TARGET_PUT" >/dev/null
|
||||
sync_both
|
||||
run_cli_b pull "$TARGET_PUSH" "$PULL_DST" >/dev/null
|
||||
assert_files_equal "$PUSH_SRC" "$PULL_DST" "B pull result does not match pushed source"
|
||||
CAT_B_PUT="$(run_cli_b cat "$TARGET_PUT" | sanitise_cat_stdout)"
|
||||
assert_equal "put-content-$DB_SUFFIX" "$CAT_B_PUT" "B cat should return A put content"
|
||||
cli_test_assert_files_equal "$PUSH_SRC" "$PULL_DST" "B pull result does not match pushed source"
|
||||
CAT_B_PUT="$(run_cli_b cat "$TARGET_PUT" | cli_test_sanitise_cat_stdout)"
|
||||
cli_test_assert_equal "put-content-$DB_SUFFIX" "$CAT_B_PUT" "B cat should return A put content"
|
||||
echo "[PASS] push/pull and put/cat across vaults"
|
||||
|
||||
echo "[CASE] A pushes binary, both sync, and B can pull identical bytes"
|
||||
@@ -343,31 +174,44 @@ head -c 4096 /dev/urandom > "$PUSH_BINARY_SRC"
|
||||
run_cli_a push "$PUSH_BINARY_SRC" "$TARGET_PUSH_BINARY" >/dev/null
|
||||
sync_both
|
||||
run_cli_b pull "$TARGET_PUSH_BINARY" "$PULL_BINARY_DST" >/dev/null
|
||||
assert_files_equal "$PUSH_BINARY_SRC" "$PULL_BINARY_DST" "B pull result does not match pushed binary source"
|
||||
cli_test_assert_files_equal "$PUSH_BINARY_SRC" "$PULL_BINARY_DST" "B pull result does not match pushed binary source"
|
||||
echo "[PASS] binary push/pull across vaults"
|
||||
|
||||
echo "[CASE] A removes, both sync, and B can no longer cat"
|
||||
run_cli_a rm "$TARGET_PUT" >/dev/null
|
||||
sync_both
|
||||
assert_command_fails "B cat should fail after A removed the file and synced" run_cli_b cat "$TARGET_PUT"
|
||||
cli_test_assert_command_fails "B cat should fail after A removed the file and synced" "$WORK_DIR/failed-command.log" run_cli_b cat "$TARGET_PUT"
|
||||
echo "[PASS] rm is replicated"
|
||||
|
||||
echo "[CASE] verify conflict detection"
|
||||
printf 'conflict-base\n' | run_cli_a put "$TARGET_CONFLICT" >/dev/null
|
||||
sync_both
|
||||
INFO_B_BASE="$(run_cli_b info "$TARGET_CONFLICT")"
|
||||
assert_contains "$INFO_B_BASE" "\"path\": \"$TARGET_CONFLICT\"" "B should be able to info before creating conflict"
|
||||
cli_test_assert_contains "$INFO_B_BASE" "\"path\": \"$TARGET_CONFLICT\"" "B should be able to info before creating conflict"
|
||||
|
||||
printf 'conflict-from-a-%s\n' "$DB_SUFFIX" | run_cli_a put "$TARGET_CONFLICT" >/dev/null
|
||||
printf 'conflict-from-b-%s\n' "$DB_SUFFIX" | run_cli_b put "$TARGET_CONFLICT" >/dev/null
|
||||
|
||||
run_cli_a sync >/dev/null
|
||||
run_cli_b sync >/dev/null
|
||||
run_cli_a sync >/dev/null
|
||||
INFO_A_CONFLICT=""
|
||||
INFO_B_CONFLICT=""
|
||||
CONFLICT_DETECTED=0
|
||||
|
||||
INFO_A_CONFLICT="$(run_cli_a info "$TARGET_CONFLICT")"
|
||||
INFO_B_CONFLICT="$(run_cli_b info "$TARGET_CONFLICT")"
|
||||
if grep -qF '"conflicts": "N/A"' <<< "$INFO_A_CONFLICT" && grep -qF '"conflicts": "N/A"' <<< "$INFO_B_CONFLICT"; then
|
||||
for side in a b a; do
|
||||
if [[ "$side" == "a" ]]; then
|
||||
run_cli_a sync >/dev/null
|
||||
else
|
||||
run_cli_b sync >/dev/null
|
||||
fi
|
||||
|
||||
INFO_A_CONFLICT="$(run_cli_a info "$TARGET_CONFLICT")"
|
||||
INFO_B_CONFLICT="$(run_cli_b info "$TARGET_CONFLICT")"
|
||||
if ! grep -qF '"conflicts": "N/A"' <<< "$INFO_A_CONFLICT" || ! grep -qF '"conflicts": "N/A"' <<< "$INFO_B_CONFLICT"; then
|
||||
CONFLICT_DETECTED=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$CONFLICT_DETECTED" != "1" ]]; then
|
||||
echo "[FAIL] conflict was expected but both A and B show Conflicts: N/A" >&2
|
||||
echo "--- A info ---" >&2
|
||||
echo "$INFO_A_CONFLICT" >&2
|
||||
@@ -399,7 +243,7 @@ fi
|
||||
echo "[PASS] ls marks conflicts"
|
||||
|
||||
echo "[CASE] resolve conflict on A and verify both vaults are clean"
|
||||
KEEP_REVISION="$(printf '%s' "$INFO_A_CONFLICT" | extract_json_string_field revision)"
|
||||
KEEP_REVISION="$(printf '%s' "$INFO_A_CONFLICT" | cli_test_json_string_field_from_stdin revision)"
|
||||
if [[ -z "$KEEP_REVISION" ]]; then
|
||||
echo "[FAIL] could not extract current revision from A info output" >&2
|
||||
echo "$INFO_A_CONFLICT" >&2
|
||||
@@ -411,7 +255,7 @@ run_cli_a resolve "$TARGET_CONFLICT" "$KEEP_REVISION" >/dev/null
|
||||
INFO_A_RESOLVED=""
|
||||
INFO_B_RESOLVED=""
|
||||
RESOLVE_PROPAGATED=0
|
||||
for _ in 1 2 3 4 5; do
|
||||
for _ in 1 2 3 4 5 6; do
|
||||
sync_both
|
||||
INFO_A_RESOLVED="$(run_cli_a info "$TARGET_CONFLICT")"
|
||||
INFO_B_RESOLVED="$(run_cli_b info "$TARGET_CONFLICT")"
|
||||
@@ -419,19 +263,15 @@ for _ in 1 2 3 4 5; do
|
||||
RESOLVE_PROPAGATED=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [[ "$RESOLVE_PROPAGATED" != "1" ]]; then
|
||||
KEEP_REVISION_B="$(printf '%s' "$INFO_B_RESOLVED" | extract_json_string_field revision)"
|
||||
if [[ -n "$KEEP_REVISION_B" ]]; then
|
||||
run_cli_b resolve "$TARGET_CONFLICT" "$KEEP_REVISION_B" >/dev/null
|
||||
sync_both
|
||||
INFO_A_RESOLVED="$(run_cli_a info "$TARGET_CONFLICT")"
|
||||
INFO_B_RESOLVED="$(run_cli_b info "$TARGET_CONFLICT")"
|
||||
if grep -qF '"conflicts": "N/A"' <<< "$INFO_A_RESOLVED" && grep -qF '"conflicts": "N/A"' <<< "$INFO_B_RESOLVED"; then
|
||||
RESOLVE_PROPAGATED=1
|
||||
|
||||
# Retry from A only when conflict remains due to eventual consistency.
|
||||
if ! grep -qF '"conflicts": "N/A"' <<< "$INFO_A_RESOLVED"; then
|
||||
KEEP_REVISION_A="$(printf '%s' "$INFO_A_RESOLVED" | cli_test_json_string_field_from_stdin revision)"
|
||||
if [[ -n "$KEEP_REVISION_A" ]]; then
|
||||
run_cli_a resolve "$TARGET_CONFLICT" "$KEEP_REVISION_A" >/dev/null || true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$RESOLVE_PROPAGATED" != "1" ]]; then
|
||||
echo "[FAIL] conflicts should be resolved on both vaults" >&2
|
||||
@@ -453,9 +293,9 @@ if [[ "$LS_A_RESOLVED_REV" == *"*" || "$LS_B_RESOLVED_REV" == *"*" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CAT_A_RESOLVED="$(run_cli_a cat "$TARGET_CONFLICT" | sanitise_cat_stdout)"
|
||||
CAT_B_RESOLVED="$(run_cli_b cat "$TARGET_CONFLICT" | sanitise_cat_stdout)"
|
||||
assert_equal "$CAT_A_RESOLVED" "$CAT_B_RESOLVED" "resolved content should match across both vaults"
|
||||
CAT_A_RESOLVED="$(run_cli_a cat "$TARGET_CONFLICT" | cli_test_sanitise_cat_stdout)"
|
||||
CAT_B_RESOLVED="$(run_cli_b cat "$TARGET_CONFLICT" | cli_test_sanitise_cat_stdout)"
|
||||
cli_test_assert_equal "$CAT_A_RESOLVED" "$CAT_B_RESOLVED" "resolved content should match across both vaults"
|
||||
echo "[PASS] resolve is replicated and ls reflects resolved state"
|
||||
|
||||
echo "[PASS] all requested E2E scenarios completed (${TEST_LABEL})"
|
||||
|
||||
Reference in New Issue
Block a user