mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-05-01 05:18:34 +00:00
Add e2e-test (not passed yet)
Refine readme
This commit is contained in:
8
src/apps/cli/.test.env
Normal file
8
src/apps/cli/.test.env
Normal file
@@ -0,0 +1,8 @@
|
||||
hostname=http://127.0.0.1:5989/
|
||||
dbname=livesync-test-db2
|
||||
minioEndpoint=http://127.0.0.1:9000
|
||||
username=admin
|
||||
password=testpassword
|
||||
accessKey=minioadmin
|
||||
secretKey=minioadmin
|
||||
bucketName=livesync-test-bucket
|
||||
@@ -16,12 +16,12 @@ This CLI version is built using the same core as the Obsidian plugin:
|
||||
```
|
||||
CLI Main
|
||||
└─ LiveSyncBaseCore<ServiceContext, IMinimumLiveSyncCommands>
|
||||
├─ HeadlessServiceHub (All services without Obsidian dependencies)
|
||||
└─ ServiceModules (Ported from main.ts)
|
||||
├─ NodeServiceHub (All services without Obsidian dependencies)
|
||||
└─ ServiceModules (wired by initialiseServiceModulesCLI)
|
||||
├─ FileAccessCLI (Node.js FileSystemAdapter)
|
||||
├─ StorageEventManagerCLI
|
||||
├─ ServiceFileAccessCLI
|
||||
├─ ServiceDatabaseFileAccess
|
||||
├─ ServiceDatabaseFileAccessCLI
|
||||
├─ ServiceFileHandler
|
||||
└─ ServiceRebuilder
|
||||
```
|
||||
@@ -33,10 +33,14 @@ CLI Main
|
||||
- Implements same interface as Obsidian's file system
|
||||
|
||||
2. **Service Modules** (`serviceModules/`)
|
||||
- Direct port from `main.ts` `initialiseServiceModules`
|
||||
- Initialised by `initialiseServiceModulesCLI`
|
||||
- All core sync functionality preserved
|
||||
|
||||
3. **Main Entry Point** (`main.ts`)
|
||||
3. **Service Hub and Settings Services** (`services/`)
|
||||
- `NodeServiceHub` provides the CLI service context
|
||||
- Node-specific settings and key-value services are provided without Obsidian dependencies
|
||||
|
||||
4. **Main Entry Point** (`main.ts`)
|
||||
- Command-line interface
|
||||
- Settings management (JSON file)
|
||||
- Graceful shutdown handling
|
||||
@@ -59,43 +63,43 @@ As you know, the CLI is designed to be used in a headless environment. Hence all
|
||||
|
||||
```bash
|
||||
# Sync local database with CouchDB (no files will be changed).
|
||||
node dist/index.cjs /path/to/your-local-database --settings /path/to/settings.json sync
|
||||
npm run cli -- /path/to/your-local-database --settings /path/to/settings.json sync
|
||||
|
||||
# Push files to local database
|
||||
node dist/index.cjs /path/to/your-local-database --settings /path/to/settings.json push /your/storage/file.md /vault/path/file.md
|
||||
npm run cli -- /path/to/your-local-database --settings /path/to/settings.json push /your/storage/file.md /vault/path/file.md
|
||||
|
||||
# Pull files from local database
|
||||
node dist/index.cjs /path/to/your-local-database --settings /path/to/settings.json pull /vault/path/file.md /your/storage/file.md
|
||||
npm run cli -- /path/to/your-local-database --settings /path/to/settings.json pull /vault/path/file.md /your/storage/file.md
|
||||
|
||||
# Verbose logging
|
||||
node dist/index.cjs /path/to/your-local-database --settings /path/to/settings.json --verbose
|
||||
npm run cli -- /path/to/your-local-database --settings /path/to/settings.json --verbose
|
||||
|
||||
# Apply setup URI to settings file (settings only; does not run synchronisation)
|
||||
node dist/index.cjs /path/to/your-local-database --settings /path/to/settings.json setup "obsidian://setuplivesync?settings=..."
|
||||
npm run cli -- /path/to/your-local-database --settings /path/to/settings.json setup "obsidian://setuplivesync?settings=..."
|
||||
|
||||
# Put text from stdin into local database
|
||||
echo "Hello from stdin" | node dist/index.cjs /path/to/your-local-database --settings /path/to/settings.json put /vault/path/file.md
|
||||
echo "Hello from stdin" | npm run cli -- /path/to/your-local-database --settings /path/to/settings.json put /vault/path/file.md
|
||||
|
||||
# Output a file from local database to stdout
|
||||
node dist/index.cjs /path/to/your-local-database --settings /path/to/settings.json cat /vault/path/file.md
|
||||
npm run cli -- /path/to/your-local-database --settings /path/to/settings.json cat /vault/path/file.md
|
||||
|
||||
# Output a specific revision of a file from local database
|
||||
node dist/index.cjs /path/to/your-local-database --settings /path/to/settings.json cat-rev /vault/path/file.md 3-abcdef
|
||||
npm run cli -- /path/to/your-local-database --settings /path/to/settings.json cat-rev /vault/path/file.md 3-abcdef
|
||||
|
||||
# Pull a specific revision of a file from local database to local storage
|
||||
node dist/index.cjs /path/to/your-local-database --settings /path/to/settings.json pull-rev /vault/path/file.md /your/storage/file.old.md 3-abcdef
|
||||
npm run cli -- /path/to/your-local-database --settings /path/to/settings.json pull-rev /vault/path/file.md /your/storage/file.old.md 3-abcdef
|
||||
|
||||
# List files in local database
|
||||
node dist/index.cjs /path/to/your-local-database --settings /path/to/settings.json ls /vault/path/
|
||||
npm run cli -- /path/to/your-local-database --settings /path/to/settings.json ls /vault/path/
|
||||
|
||||
# Show metadata for a file in local database
|
||||
node dist/index.cjs /path/to/your-local-database --settings /path/to/settings.json info /vault/path/file.md
|
||||
npm run cli -- /path/to/your-local-database --settings /path/to/settings.json info /vault/path/file.md
|
||||
|
||||
# Mark a file as deleted in local database
|
||||
node dist/index.cjs /path/to/your-local-database --settings /path/to/settings.json rm /vault/path/file.md
|
||||
npm run cli -- /path/to/your-local-database --settings /path/to/settings.json rm /vault/path/file.md
|
||||
|
||||
# Resolve conflict by keeping a specific revision
|
||||
node dist/index.cjs /path/to/your-local-database --settings /path/to/settings.json resolve /vault/path/file.md 3-abcdef
|
||||
npm run cli -- /path/to/your-local-database --settings /path/to/settings.json resolve /vault/path/file.md 3-abcdef
|
||||
```
|
||||
|
||||
### Configuration
|
||||
@@ -157,15 +161,21 @@ Commands:
|
||||
resolve <vaultPath> <revision> Resolve conflict by keeping the specified revision
|
||||
```
|
||||
|
||||
Run via npm script:
|
||||
|
||||
```bash
|
||||
npm run cli -- [database-path] [options] [command] [command-args]
|
||||
```
|
||||
|
||||
`info` output fields:
|
||||
|
||||
- `ID`: Document ID
|
||||
- `Revision`: Current revision
|
||||
- `Conflicts`: Conflicted revisions, or `N/A`
|
||||
- `Filename`: Basename of path
|
||||
- `Path`: Vault-relative path
|
||||
- `Size`: Size in bytes
|
||||
- `PastRevisions`: Available non-current revisions
|
||||
- `id`: Document ID
|
||||
- `revision`: Current revision
|
||||
- `conflicts`: Conflicted revisions, or `N/A`
|
||||
- `filename`: Basename of path
|
||||
- `path`: Vault-relative path
|
||||
- `size`: Size in bytes
|
||||
- `revisions`: Available non-current revisions
|
||||
- `Chunks`: Number of chunk IDs
|
||||
- `child: ...`: Chunk ID list
|
||||
|
||||
@@ -187,9 +197,9 @@ TODO: Conflict and resolution checks for real local databases.
|
||||
Create default settings, apply a setup URI, then run one sync cycle.
|
||||
|
||||
```bash
|
||||
node dist/index.cjs init-settings /data/livesync-settings.json
|
||||
printf '%s\n' "$SETUP_PASSPHRASE" | node dist/index.cjs /data/vault --settings /data/livesync-settings.json setup "$SETUP_URI"
|
||||
node dist/index.cjs /data/vault --settings /data/livesync-settings.json sync
|
||||
npm run cli -- init-settings /data/livesync-settings.json
|
||||
printf '%s\n' "$SETUP_PASSPHRASE" | npm run cli -- /data/vault --settings /data/livesync-settings.json setup "$SETUP_URI"
|
||||
npm run cli -- /data/vault --settings /data/livesync-settings.json sync
|
||||
```
|
||||
|
||||
### 2. Scripted import and export
|
||||
@@ -197,8 +207,8 @@ node dist/index.cjs /data/vault --settings /data/livesync-settings.json sync
|
||||
Push local files into the database from automation, and pull them back for export or backup.
|
||||
|
||||
```bash
|
||||
node dist/index.cjs /data/vault --settings /data/livesync-settings.json push ./note.md notes/note.md
|
||||
node dist/index.cjs /data/vault --settings /data/livesync-settings.json pull notes/note.md ./exports/note.md
|
||||
npm run cli -- /data/vault --settings /data/livesync-settings.json push ./note.md notes/note.md
|
||||
npm run cli -- /data/vault --settings /data/livesync-settings.json pull notes/note.md ./exports/note.md
|
||||
```
|
||||
|
||||
### 3. Revision inspection and restore
|
||||
@@ -206,9 +216,9 @@ node dist/index.cjs /data/vault --settings /data/livesync-settings.json pull not
|
||||
List metadata, find an older revision, then restore it by content (`cat-rev`) or file output (`pull-rev`).
|
||||
|
||||
```bash
|
||||
node dist/index.cjs /data/vault --settings /data/livesync-settings.json info notes/note.md
|
||||
node dist/index.cjs /data/vault --settings /data/livesync-settings.json cat-rev notes/note.md 3-abcdef
|
||||
node dist/index.cjs /data/vault --settings /data/livesync-settings.json pull-rev notes/note.md ./restore/note.old.md 3-abcdef
|
||||
npm run cli -- /data/vault --settings /data/livesync-settings.json info notes/note.md
|
||||
npm run cli -- /data/vault --settings /data/livesync-settings.json cat-rev notes/note.md 3-abcdef
|
||||
npm run cli -- /data/vault --settings /data/livesync-settings.json pull-rev notes/note.md ./restore/note.old.md 3-abcdef
|
||||
```
|
||||
|
||||
### 4. Conflict and cleanup workflow
|
||||
@@ -216,9 +226,9 @@ node dist/index.cjs /data/vault --settings /data/livesync-settings.json pull-rev
|
||||
Inspect conflicted revisions, resolve by keeping one revision, then delete obsolete files.
|
||||
|
||||
```bash
|
||||
node dist/index.cjs /data/vault --settings /data/livesync-settings.json info notes/note.md
|
||||
node dist/index.cjs /data/vault --settings /data/livesync-settings.json resolve notes/note.md 3-abcdef
|
||||
node dist/index.cjs /data/vault --settings /data/livesync-settings.json rm notes/obsolete.md
|
||||
npm run cli -- /data/vault --settings /data/livesync-settings.json info notes/note.md
|
||||
npm run cli -- /data/vault --settings /data/livesync-settings.json resolve notes/note.md 3-abcdef
|
||||
npm run cli -- /data/vault --settings /data/livesync-settings.json rm notes/obsolete.md
|
||||
```
|
||||
|
||||
### 5. CI smoke test for content round-trip
|
||||
@@ -226,8 +236,8 @@ node dist/index.cjs /data/vault --settings /data/livesync-settings.json rm notes
|
||||
Validate that `put`/`cat` is behaving as expected in a pipeline.
|
||||
|
||||
```bash
|
||||
echo "hello-ci" | node dist/index.cjs /data/vault --settings /data/livesync-settings.json put ci/test.md
|
||||
node dist/index.cjs /data/vault --settings /data/livesync-settings.json cat ci/test.md
|
||||
echo "hello-ci" | npm run cli -- /data/vault --settings /data/livesync-settings.json put ci/test.md
|
||||
npm run cli -- /data/vault --settings /data/livesync-settings.json cat ci/test.md
|
||||
```
|
||||
|
||||
## Development
|
||||
@@ -236,26 +246,40 @@ node dist/index.cjs /data/vault --settings /data/livesync-settings.json cat ci/t
|
||||
|
||||
```
|
||||
src/apps/cli/
|
||||
├── commands/ # Command dispatcher and command utilities
|
||||
├── commands/ # Command dispatcher and command utilities
|
||||
│ ├── runCommand.ts
|
||||
│ ├── types.ts
|
||||
│ └── utils.ts
|
||||
├── adapters/ # Node.js FileSystem Adapter
|
||||
├── adapters/ # Node.js FileSystem Adapter
|
||||
│ ├── NodeConversionAdapter.ts
|
||||
│ ├── NodeFileSystemAdapter.ts
|
||||
│ ├── NodePathAdapter.ts
|
||||
│ ├── NodeTypeGuardAdapter.ts
|
||||
│ ├── NodeConversionAdapter.ts
|
||||
│ ├── NodeStorageAdapter.ts
|
||||
│ ├── NodeVaultAdapter.ts
|
||||
│ └── NodeTypes.ts
|
||||
├── managers/ # CLI-specific managers
|
||||
│ ├── NodeTypeGuardAdapter.ts
|
||||
│ ├── NodeTypes.ts
|
||||
│ └── NodeVaultAdapter.ts
|
||||
├── lib/
|
||||
│ └── pouchdb-node.ts
|
||||
├── managers/ # CLI-specific managers
|
||||
│ ├── CLIStorageEventManagerAdapter.ts
|
||||
│ └── StorageEventManagerCLI.ts
|
||||
├── serviceModules/ # Service modules (ported from main.ts)
|
||||
├── serviceModules/ # Service modules (ported from main.ts)
|
||||
│ ├── CLIServiceModules.ts
|
||||
│ ├── DatabaseFileAccess.ts
|
||||
│ ├── FileAccessCLI.ts
|
||||
│ ├── ServiceFileAccessImpl.ts
|
||||
│ └── DatabaseFileAccess.ts
|
||||
├── main.ts # CLI entry point
|
||||
└── README.md # This file
|
||||
│ └── ServiceFileAccessImpl.ts
|
||||
├── services/
|
||||
│ ├── NodeKeyValueDBService.ts
|
||||
│ ├── NodeServiceHub.ts
|
||||
│ └── NodeSettingService.ts
|
||||
├── test/
|
||||
│ ├── test-push-pull-linux.sh
|
||||
│ ├── test-setup-put-cat-linux.sh
|
||||
│ └── test-sync-two-local-databases-linux.sh
|
||||
├── .gitignore
|
||||
├── main.ts # CLI entry point
|
||||
├── package.json
|
||||
├── README.md # This file
|
||||
├── tsconfig.json
|
||||
└── vite.config.ts
|
||||
```
|
||||
|
||||
@@ -237,22 +237,19 @@ export async function runCommand(options: CLIOptions, context: CLICommandContext
|
||||
})
|
||||
.map((entry: { rev: string }) => entry.rev);
|
||||
const pastRevisionsText =
|
||||
pastRevisions.length > 0 ? pastRevisions.map((rev: string) => ` rev: ${rev}`) : [" N/A"];
|
||||
|
||||
const out =
|
||||
[
|
||||
`ID: ${doc._id}`,
|
||||
`Revision: ${doc._rev ?? ""}`,
|
||||
`Conflicts: ${conflictsText}`,
|
||||
`Filename: ${filename}`,
|
||||
`Path: ${docPath}`,
|
||||
`Size: ${doc.size}`,
|
||||
`PastRevisions:`,
|
||||
...pastRevisionsText,
|
||||
`Chunks: ${children.length}`,
|
||||
...children.map((id) => ` child: ${id}`),
|
||||
].join("\n") + "\n";
|
||||
process.stdout.write(out);
|
||||
pastRevisions.length > 0 ? pastRevisions.map((rev: string) => `${rev}`) : ["N/A"];
|
||||
const out = {
|
||||
id: doc._id,
|
||||
revision: doc._rev ?? "",
|
||||
conflicts: conflictsText,
|
||||
filename: filename,
|
||||
path: docPath,
|
||||
size: doc.size,
|
||||
revisions: pastRevisionsText,
|
||||
chunks: children.length,
|
||||
children: children,
|
||||
};
|
||||
process.stdout.write(JSON.stringify(out, null, 2) + "\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,14 +2,16 @@
|
||||
"name": "self-hosted-livesync-cli",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"main": "dist/index.cjs",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"run": "node dist/index.cjs",
|
||||
"buildRun": "npm run build && npm run",
|
||||
"check": "svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json"
|
||||
"cli": "node dist/index.cjs",
|
||||
"buildRun": "npm run build && npm run cli --",
|
||||
"check": "svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json",
|
||||
"test:e2e:two-vaults": "bash test/test-e2e-two-vaults-with-docker-linux.sh"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {}
|
||||
|
||||
247
src/apps/cli/test/test-e2e-two-vaults-with-docker-linux.sh
Normal file
247
src/apps/cli/test/test-e2e-two-vaults-with-docker-linux.sh
Normal file
@@ -0,0 +1,247 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CLI_DIR="$(cd -- "$SCRIPT_DIR/.." && pwd)"
|
||||
cd "$CLI_DIR"
|
||||
|
||||
# verbose
|
||||
CLI_CMD=(npm run cli -- -v )
|
||||
RUN_BUILD="${RUN_BUILD:-1}"
|
||||
KEEP_TEST_DATA="${KEEP_TEST_DATA:-0}"
|
||||
TEST_ENV_FILE="${TEST_ENV_FILE:-$CLI_DIR/.test.env}"
|
||||
|
||||
if [[ ! -f "$TEST_ENV_FILE" ]]; then
|
||||
echo "[ERROR] test env file not found: $TEST_ENV_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -a
|
||||
source "$TEST_ENV_FILE"
|
||||
set +a
|
||||
|
||||
for var in hostname dbname username password; do
|
||||
if [[ -z "${!var:-}" ]]; then
|
||||
echo "[ERROR] required variable '$var' is missing in $TEST_ENV_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
COUCHDB_URI="${hostname%/}"
|
||||
DB_SUFFIX="$(date +%s)-$RANDOM"
|
||||
COUCHDB_DBNAME="${dbname}-${DB_SUFFIX}"
|
||||
|
||||
VAULT_ROOT="$CLI_DIR/.livesync"
|
||||
VAULT_A="$VAULT_ROOT/testvault_a"
|
||||
VAULT_B="$VAULT_ROOT/testvault_b"
|
||||
SETTINGS_A="$VAULT_ROOT/test-settings-a.json"
|
||||
SETTINGS_B="$VAULT_ROOT/test-settings-b.json"
|
||||
WORK_DIR="$(mktemp -d "${TMPDIR:-/tmp}/livesync-cli-e2e.XXXXXX")"
|
||||
|
||||
cleanup() {
|
||||
local exit_code=$?
|
||||
bash "$CLI_DIR/util/couchdb-stop.sh" >/dev/null 2>&1 || true
|
||||
if [[ "$KEEP_TEST_DATA" != "1" ]]; then
|
||||
rm -rf "$VAULT_A" "$VAULT_B" "$SETTINGS_A" "$SETTINGS_B" "$WORK_DIR"
|
||||
else
|
||||
echo "[INFO] KEEP_TEST_DATA=1, preserving test artefacts"
|
||||
echo " vault a: $VAULT_A"
|
||||
echo " vault b: $VAULT_B"
|
||||
echo " settings: $SETTINGS_A, $SETTINGS_B"
|
||||
echo " work dir: $WORK_DIR"
|
||||
fi
|
||||
exit "$exit_code"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
run_cli() {
|
||||
"${CLI_CMD[@]}" "$@"
|
||||
}
|
||||
|
||||
run_cli_a() {
|
||||
run_cli "$VAULT_A" --settings "$SETTINGS_A" "$@"
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
sanitise_cat_stdout() {
|
||||
sed '/^\[CLIWatchAdapter\] File watching is not enabled in CLI version$/d'
|
||||
}
|
||||
|
||||
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 "$@"
|
||||
}
|
||||
|
||||
init_settings() {
|
||||
local settings_file="$1"
|
||||
run_cli init-settings --force "$settings_file" >/dev/null
|
||||
SETTINGS_FILE="$settings_file" \
|
||||
COUCHDB_URI="$COUCHDB_URI" \
|
||||
COUCHDB_USER="$username" \
|
||||
COUCHDB_PASSWORD="$password" \
|
||||
COUCHDB_DBNAME="$COUCHDB_DBNAME" \
|
||||
node <<'NODE'
|
||||
const fs = require("node:fs");
|
||||
const settingsPath = process.env.SETTINGS_FILE;
|
||||
const data = JSON.parse(fs.readFileSync(settingsPath, "utf-8"));
|
||||
|
||||
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;
|
||||
data.liveSync = true;
|
||||
data.syncOnStart = false;
|
||||
data.syncOnSave = false;
|
||||
data.usePluginSync = false;
|
||||
data.isConfigured = true;
|
||||
|
||||
fs.writeFileSync(settingsPath, JSON.stringify(data, null, 2), "utf-8");
|
||||
NODE
|
||||
cat "$settings_file"
|
||||
}
|
||||
|
||||
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 "status"
|
||||
docker ps --filter "name=couchdb-test"
|
||||
|
||||
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
|
||||
|
||||
if [[ "$RUN_BUILD" == "1" ]]; then
|
||||
echo "[INFO] building CLI"
|
||||
npm run build
|
||||
fi
|
||||
|
||||
echo "[INFO] preparing vaults and settings"
|
||||
rm -rf "$VAULT_A" "$VAULT_B" "$SETTINGS_A" "$SETTINGS_B"
|
||||
mkdir -p "$VAULT_A" "$VAULT_B"
|
||||
init_settings "$SETTINGS_A"
|
||||
init_settings "$SETTINGS_B"
|
||||
|
||||
echo "[INFO] test DB: $COUCHDB_DBNAME"
|
||||
|
||||
TARGET_A_ONLY="e2e/a-only-info.md"
|
||||
TARGET_SYNC="e2e/sync-info.md"
|
||||
TARGET_PUSH="e2e/pushed-from-a.md"
|
||||
TARGET_PUT="e2e/put-from-a.md"
|
||||
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"
|
||||
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"
|
||||
echo "[PASS] sync A->B and B info"
|
||||
|
||||
echo "[CASE] A pushes and puts, both sync, and B can pull and cat"
|
||||
PUSH_SRC="$WORK_DIR/push-source.txt"
|
||||
PULL_DST="$WORK_DIR/pull-destination.txt"
|
||||
printf 'pushed-content-%s\n' "$DB_SUFFIX" > "$PUSH_SRC"
|
||||
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
|
||||
if ! cmp -s "$PUSH_SRC" "$PULL_DST"; then
|
||||
echo "[FAIL] B pull result does not match pushed source" >&2
|
||||
echo "--- source ---" >&2
|
||||
cat "$PUSH_SRC" >&2
|
||||
echo "--- pulled ---" >&2
|
||||
cat "$PULL_DST" >&2
|
||||
exit 1
|
||||
fi
|
||||
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"
|
||||
echo "[PASS] push/pull and put/cat 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"
|
||||
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"
|
||||
|
||||
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="$(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
|
||||
echo "[FAIL] conflict was expected but both A and B show Conflicts: N/A" >&2
|
||||
echo "--- A info ---" >&2
|
||||
echo "$INFO_A_CONFLICT" >&2
|
||||
echo "--- B info ---" >&2
|
||||
echo "$INFO_B_CONFLICT" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "[PASS] conflict detected by info"
|
||||
|
||||
echo "[PASS] all requested E2E scenarios completed"
|
||||
@@ -5,7 +5,7 @@ SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CLI_DIR="$(cd -- "$SCRIPT_DIR/.." && pwd)"
|
||||
cd "$CLI_DIR"
|
||||
|
||||
CLI_ENTRY="${CLI_ENTRY:-$CLI_DIR/dist/index.cjs}"
|
||||
CLI_CMD=(npm run cli --)
|
||||
RUN_BUILD="${RUN_BUILD:-1}"
|
||||
REMOTE_PATH="${REMOTE_PATH:-test/push-pull.txt}"
|
||||
|
||||
@@ -19,13 +19,12 @@ if [[ "$RUN_BUILD" == "1" ]]; then
|
||||
npm run build
|
||||
fi
|
||||
|
||||
if [[ ! -f "$CLI_ENTRY" ]]; then
|
||||
echo "[ERROR] CLI entry not found: $CLI_ENTRY" >&2
|
||||
exit 1
|
||||
fi
|
||||
run_cli() {
|
||||
"${CLI_CMD[@]}" "$@"
|
||||
}
|
||||
|
||||
echo "[INFO] generating settings from DEFAULT_SETTINGS -> $SETTINGS_FILE"
|
||||
node "$CLI_ENTRY" init-settings --force "$SETTINGS_FILE"
|
||||
run_cli init-settings --force "$SETTINGS_FILE"
|
||||
|
||||
if [[ -n "${COUCHDB_URI:-}" && -n "${COUCHDB_USER:-}" && -n "${COUCHDB_PASSWORD:-}" && -n "${COUCHDB_DBNAME:-}" ]]; then
|
||||
echo "[INFO] applying CouchDB env vars to generated settings"
|
||||
@@ -52,10 +51,10 @@ PULLED_FILE="$WORK_DIR/pull-result.txt"
|
||||
printf 'push-pull-test %s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > "$SRC_FILE"
|
||||
|
||||
echo "[INFO] push -> $REMOTE_PATH"
|
||||
node "$CLI_ENTRY" "$VAULT_DIR" --settings "$SETTINGS_FILE" push "$SRC_FILE" "$REMOTE_PATH"
|
||||
run_cli "$VAULT_DIR" --settings "$SETTINGS_FILE" push "$SRC_FILE" "$REMOTE_PATH"
|
||||
|
||||
echo "[INFO] pull <- $REMOTE_PATH"
|
||||
node "$CLI_ENTRY" "$VAULT_DIR" --settings "$SETTINGS_FILE" pull "$REMOTE_PATH" "$PULLED_FILE"
|
||||
run_cli "$VAULT_DIR" --settings "$SETTINGS_FILE" pull "$REMOTE_PATH" "$PULLED_FILE"
|
||||
|
||||
if cmp -s "$SRC_FILE" "$PULLED_FILE"; then
|
||||
echo "[PASS] push/pull roundtrip matched"
|
||||
|
||||
@@ -6,7 +6,7 @@ CLI_DIR="$(cd -- "$SCRIPT_DIR/.." && pwd)"
|
||||
REPO_ROOT="$(cd -- "$CLI_DIR/../../.." && pwd)"
|
||||
cd "$CLI_DIR"
|
||||
|
||||
CLI_ENTRY="${CLI_ENTRY:-$CLI_DIR/dist/index.cjs}"
|
||||
CLI_CMD=(npm run cli --)
|
||||
RUN_BUILD="${RUN_BUILD:-1}"
|
||||
REMOTE_PATH="${REMOTE_PATH:-test/setup-put-cat.txt}"
|
||||
SETUP_PASSPHRASE="${SETUP_PASSPHRASE:-setup-passphrase}"
|
||||
@@ -21,13 +21,12 @@ if [[ "$RUN_BUILD" == "1" ]]; then
|
||||
npm run build
|
||||
fi
|
||||
|
||||
if [[ ! -f "$CLI_ENTRY" ]]; then
|
||||
echo "[ERROR] CLI entry not found: $CLI_ENTRY" >&2
|
||||
exit 1
|
||||
fi
|
||||
run_cli() {
|
||||
"${CLI_CMD[@]}" "$@"
|
||||
}
|
||||
|
||||
echo "[INFO] generating settings from DEFAULT_SETTINGS -> $SETTINGS_FILE"
|
||||
node "$CLI_ENTRY" init-settings --force "$SETTINGS_FILE"
|
||||
run_cli init-settings --force "$SETTINGS_FILE"
|
||||
|
||||
echo "[INFO] creating setup URI from settings"
|
||||
SETUP_URI="$(
|
||||
@@ -57,7 +56,7 @@ mkdir -p "$VAULT_DIR/test"
|
||||
echo "[INFO] applying setup URI"
|
||||
SETUP_LOG="$WORK_DIR/setup-output.log"
|
||||
set +e
|
||||
printf '%s\n' "$SETUP_PASSPHRASE" | node "$CLI_ENTRY" "$VAULT_DIR" --settings "$SETTINGS_FILE" setup "$SETUP_URI" \
|
||||
printf '%s\n' "$SETUP_PASSPHRASE" | run_cli "$VAULT_DIR" --settings "$SETTINGS_FILE" setup "$SETUP_URI" \
|
||||
>"$SETUP_LOG" 2>&1
|
||||
SETUP_EXIT=$?
|
||||
set -e
|
||||
@@ -78,11 +77,11 @@ SRC_FILE="$WORK_DIR/put-source.txt"
|
||||
printf 'setup-put-cat-test %s\nline-2\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > "$SRC_FILE"
|
||||
|
||||
echo "[INFO] put -> $REMOTE_PATH"
|
||||
cat "$SRC_FILE" | node "$CLI_ENTRY" "$VAULT_DIR" --settings "$SETTINGS_FILE" put "$REMOTE_PATH"
|
||||
cat "$SRC_FILE" | run_cli "$VAULT_DIR" --settings "$SETTINGS_FILE" put "$REMOTE_PATH"
|
||||
|
||||
echo "[INFO] cat <- $REMOTE_PATH"
|
||||
CAT_OUTPUT="$WORK_DIR/cat-output.txt"
|
||||
node "$CLI_ENTRY" "$VAULT_DIR" --settings "$SETTINGS_FILE" cat "$REMOTE_PATH" > "$CAT_OUTPUT"
|
||||
run_cli "$VAULT_DIR" --settings "$SETTINGS_FILE" cat "$REMOTE_PATH" > "$CAT_OUTPUT"
|
||||
|
||||
CAT_OUTPUT_CLEAN="$WORK_DIR/cat-output-clean.txt"
|
||||
grep -v '^\[CLIWatchAdapter\] File watching is not enabled in CLI version$' "$CAT_OUTPUT" > "$CAT_OUTPUT_CLEAN" || true
|
||||
@@ -100,7 +99,7 @@ fi
|
||||
|
||||
echo "[INFO] ls $REMOTE_PATH"
|
||||
LS_OUTPUT="$WORK_DIR/ls-output.txt"
|
||||
node "$CLI_ENTRY" "$VAULT_DIR" --settings "$SETTINGS_FILE" ls "$REMOTE_PATH" > "$LS_OUTPUT"
|
||||
run_cli "$VAULT_DIR" --settings "$SETTINGS_FILE" ls "$REMOTE_PATH" > "$LS_OUTPUT"
|
||||
|
||||
LS_LINE="$(grep -F "$REMOTE_PATH" "$LS_OUTPUT" | head -n 1 || true)"
|
||||
if [[ -z "$LS_LINE" ]]; then
|
||||
@@ -129,12 +128,12 @@ fi
|
||||
echo "[PASS] ls output format matched"
|
||||
|
||||
echo "[INFO] adding more files for ls test cases"
|
||||
printf 'file-a\n' | node "$CLI_ENTRY" "$VAULT_DIR" --settings "$SETTINGS_FILE" put test/a-first.txt >/dev/null
|
||||
printf 'file-z\n' | node "$CLI_ENTRY" "$VAULT_DIR" --settings "$SETTINGS_FILE" put test/z-last.txt >/dev/null
|
||||
printf 'file-a\n' | run_cli "$VAULT_DIR" --settings "$SETTINGS_FILE" put test/a-first.txt >/dev/null
|
||||
printf 'file-z\n' | run_cli "$VAULT_DIR" --settings "$SETTINGS_FILE" put test/z-last.txt >/dev/null
|
||||
|
||||
echo "[INFO] ls test/ (prefix filter and sorting)"
|
||||
LS_PREFIX_OUTPUT="$WORK_DIR/ls-prefix-output.txt"
|
||||
node "$CLI_ENTRY" "$VAULT_DIR" --settings "$SETTINGS_FILE" ls test/ > "$LS_PREFIX_OUTPUT"
|
||||
run_cli "$VAULT_DIR" --settings "$SETTINGS_FILE" ls test/ > "$LS_PREFIX_OUTPUT"
|
||||
|
||||
if [[ "$(wc -l < "$LS_PREFIX_OUTPUT")" -lt 3 ]]; then
|
||||
echo "[FAIL] ls prefix output expected at least 3 rows" >&2
|
||||
@@ -164,7 +163,7 @@ echo "[PASS] ls prefix and sorting matched"
|
||||
|
||||
echo "[INFO] ls no-match prefix"
|
||||
LS_EMPTY_OUTPUT="$WORK_DIR/ls-empty-output.txt"
|
||||
node "$CLI_ENTRY" "$VAULT_DIR" --settings "$SETTINGS_FILE" ls no-such-prefix/ > "$LS_EMPTY_OUTPUT"
|
||||
run_cli "$VAULT_DIR" --settings "$SETTINGS_FILE" ls no-such-prefix/ > "$LS_EMPTY_OUTPUT"
|
||||
if [[ -s "$LS_EMPTY_OUTPUT" ]]; then
|
||||
echo "[FAIL] ls no-match prefix should produce empty output" >&2
|
||||
cat "$LS_EMPTY_OUTPUT" >&2
|
||||
@@ -174,7 +173,7 @@ echo "[PASS] ls no-match prefix matched"
|
||||
|
||||
echo "[INFO] info $REMOTE_PATH"
|
||||
INFO_OUTPUT="$WORK_DIR/info-output.txt"
|
||||
node "$CLI_ENTRY" "$VAULT_DIR" --settings "$SETTINGS_FILE" info "$REMOTE_PATH" > "$INFO_OUTPUT"
|
||||
run_cli "$VAULT_DIR" --settings "$SETTINGS_FILE" info "$REMOTE_PATH" > "$INFO_OUTPUT"
|
||||
|
||||
# Check required label lines
|
||||
for label in "ID:" "Revision:" "Conflicts:" "Filename:" "Path:" "Size:" "Chunks:"; do
|
||||
@@ -225,7 +224,7 @@ echo "[PASS] info output format matched"
|
||||
|
||||
echo "[INFO] info non-existent path"
|
||||
INFO_MISSING_EXIT=0
|
||||
node "$CLI_ENTRY" "$VAULT_DIR" --settings "$SETTINGS_FILE" info no-such-file.md > /dev/null || INFO_MISSING_EXIT=$?
|
||||
run_cli "$VAULT_DIR" --settings "$SETTINGS_FILE" info no-such-file.md > /dev/null || INFO_MISSING_EXIT=$?
|
||||
if [[ "$INFO_MISSING_EXIT" -eq 0 ]]; then
|
||||
echo "[FAIL] info on non-existent file should exit non-zero" >&2
|
||||
exit 1
|
||||
@@ -233,17 +232,17 @@ fi
|
||||
echo "[PASS] info non-existent path returns non-zero"
|
||||
|
||||
echo "[INFO] rm test/z-last.txt"
|
||||
node "$CLI_ENTRY" "$VAULT_DIR" --settings "$SETTINGS_FILE" rm test/z-last.txt > /dev/null
|
||||
run_cli "$VAULT_DIR" --settings "$SETTINGS_FILE" rm test/z-last.txt > /dev/null
|
||||
|
||||
RM_CAT_EXIT=0
|
||||
node "$CLI_ENTRY" "$VAULT_DIR" --settings "$SETTINGS_FILE" cat test/z-last.txt > /dev/null || RM_CAT_EXIT=$?
|
||||
run_cli "$VAULT_DIR" --settings "$SETTINGS_FILE" cat test/z-last.txt > /dev/null || RM_CAT_EXIT=$?
|
||||
if [[ "$RM_CAT_EXIT" -eq 0 ]]; then
|
||||
echo "[FAIL] rm target should not be readable by cat" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
LS_AFTER_RM="$WORK_DIR/ls-after-rm.txt"
|
||||
node "$CLI_ENTRY" "$VAULT_DIR" --settings "$SETTINGS_FILE" ls test/ > "$LS_AFTER_RM"
|
||||
run_cli "$VAULT_DIR" --settings "$SETTINGS_FILE" ls test/ > "$LS_AFTER_RM"
|
||||
if grep -Fq $'test/z-last.txt\t' "$LS_AFTER_RM"; then
|
||||
echo "[FAIL] rm target should not appear in ls output" >&2
|
||||
cat "$LS_AFTER_RM" >&2
|
||||
@@ -252,7 +251,7 @@ fi
|
||||
echo "[PASS] rm removed target from visible entries"
|
||||
|
||||
echo "[INFO] resolve test/a-first.txt using current revision"
|
||||
RESOLVE_LS_LINE="$(node "$CLI_ENTRY" "$VAULT_DIR" --settings "$SETTINGS_FILE" ls test/a-first.txt | head -n 1)"
|
||||
RESOLVE_LS_LINE="$(run_cli "$VAULT_DIR" --settings "$SETTINGS_FILE" ls test/a-first.txt | head -n 1)"
|
||||
if [[ -z "$RESOLVE_LS_LINE" ]]; then
|
||||
echo "[FAIL] could not fetch revision for resolve test" >&2
|
||||
exit 1
|
||||
@@ -263,12 +262,12 @@ if [[ -z "$RESOLVE_REV" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
node "$CLI_ENTRY" "$VAULT_DIR" --settings "$SETTINGS_FILE" resolve test/a-first.txt "$RESOLVE_REV" > /dev/null
|
||||
run_cli "$VAULT_DIR" --settings "$SETTINGS_FILE" resolve test/a-first.txt "$RESOLVE_REV" > /dev/null
|
||||
echo "[PASS] resolve accepted current revision"
|
||||
|
||||
echo "[INFO] resolve with non-existent revision"
|
||||
RESOLVE_BAD_EXIT=0
|
||||
node "$CLI_ENTRY" "$VAULT_DIR" --settings "$SETTINGS_FILE" resolve test/a-first.txt 9-no-such-rev > /dev/null || RESOLVE_BAD_EXIT=$?
|
||||
run_cli "$VAULT_DIR" --settings "$SETTINGS_FILE" resolve test/a-first.txt 9-no-such-rev > /dev/null || RESOLVE_BAD_EXIT=$?
|
||||
if [[ "$RESOLVE_BAD_EXIT" -eq 0 ]]; then
|
||||
echo "[FAIL] resolve with non-existent revision should exit non-zero" >&2
|
||||
exit 1
|
||||
@@ -285,13 +284,13 @@ printf 'revision-v1\n' > "$REV_V1_FILE"
|
||||
printf 'revision-v2\n' > "$REV_V2_FILE"
|
||||
printf 'revision-v3\n' > "$REV_V3_FILE"
|
||||
|
||||
cat "$REV_V1_FILE" | node "$CLI_ENTRY" "$VAULT_DIR" --settings "$SETTINGS_FILE" put "$REV_PATH" > /dev/null
|
||||
cat "$REV_V2_FILE" | node "$CLI_ENTRY" "$VAULT_DIR" --settings "$SETTINGS_FILE" put "$REV_PATH" > /dev/null
|
||||
cat "$REV_V3_FILE" | node "$CLI_ENTRY" "$VAULT_DIR" --settings "$SETTINGS_FILE" put "$REV_PATH" > /dev/null
|
||||
cat "$REV_V1_FILE" | run_cli "$VAULT_DIR" --settings "$SETTINGS_FILE" put "$REV_PATH" > /dev/null
|
||||
cat "$REV_V2_FILE" | run_cli "$VAULT_DIR" --settings "$SETTINGS_FILE" put "$REV_PATH" > /dev/null
|
||||
cat "$REV_V3_FILE" | run_cli "$VAULT_DIR" --settings "$SETTINGS_FILE" put "$REV_PATH" > /dev/null
|
||||
|
||||
echo "[INFO] info $REV_PATH (past revisions)"
|
||||
REV_INFO_OUTPUT="$WORK_DIR/rev-info-output.txt"
|
||||
node "$CLI_ENTRY" "$VAULT_DIR" --settings "$SETTINGS_FILE" info "$REV_PATH" > "$REV_INFO_OUTPUT"
|
||||
run_cli "$VAULT_DIR" --settings "$SETTINGS_FILE" info "$REV_PATH" > "$REV_INFO_OUTPUT"
|
||||
|
||||
PAST_REV="$(grep '^ rev: ' "$REV_INFO_OUTPUT" | head -n 1 | sed 's/^ rev: //')"
|
||||
if [[ -z "$PAST_REV" ]]; then
|
||||
@@ -302,7 +301,7 @@ fi
|
||||
|
||||
echo "[INFO] cat-rev $REV_PATH @ $PAST_REV"
|
||||
REV_CAT_OUTPUT="$WORK_DIR/rev-cat-output.txt"
|
||||
node "$CLI_ENTRY" "$VAULT_DIR" --settings "$SETTINGS_FILE" cat-rev "$REV_PATH" "$PAST_REV" > "$REV_CAT_OUTPUT"
|
||||
run_cli "$VAULT_DIR" --settings "$SETTINGS_FILE" cat-rev "$REV_PATH" "$PAST_REV" > "$REV_CAT_OUTPUT"
|
||||
|
||||
if cmp -s "$REV_CAT_OUTPUT" "$REV_V1_FILE" || cmp -s "$REV_CAT_OUTPUT" "$REV_V2_FILE"; then
|
||||
echo "[PASS] cat-rev matched one of the past revisions from info"
|
||||
@@ -321,7 +320,7 @@ fi
|
||||
|
||||
echo "[INFO] pull-rev $REV_PATH @ $PAST_REV"
|
||||
REV_PULL_OUTPUT="$WORK_DIR/rev-pull-output.txt"
|
||||
node "$CLI_ENTRY" "$VAULT_DIR" --settings "$SETTINGS_FILE" pull-rev "$REV_PATH" "$REV_PULL_OUTPUT" "$PAST_REV" > /dev/null
|
||||
run_cli "$VAULT_DIR" --settings "$SETTINGS_FILE" pull-rev "$REV_PATH" "$REV_PULL_OUTPUT" "$PAST_REV" > /dev/null
|
||||
|
||||
if cmp -s "$REV_PULL_OUTPUT" "$REV_V1_FILE" || cmp -s "$REV_PULL_OUTPUT" "$REV_V2_FILE"; then
|
||||
echo "[PASS] pull-rev matched one of the past revisions from info"
|
||||
|
||||
@@ -6,7 +6,7 @@ SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CLI_DIR="$(cd -- "$SCRIPT_DIR/.." && pwd)"
|
||||
cd "$CLI_DIR"
|
||||
|
||||
CLI_ENTRY="${CLI_ENTRY:-$CLI_DIR/dist/index.cjs}"
|
||||
CLI_CMD=(npm run cli --)
|
||||
RUN_BUILD="${RUN_BUILD:-1}"
|
||||
COUCHDB_URI="${COUCHDB_URI:-}"
|
||||
COUCHDB_USER="${COUCHDB_USER:-}"
|
||||
@@ -26,10 +26,9 @@ if [[ "$RUN_BUILD" == "1" ]]; then
|
||||
npm run build
|
||||
fi
|
||||
|
||||
if [[ ! -f "$CLI_ENTRY" ]]; then
|
||||
echo "[ERROR] CLI entry not found: $CLI_ENTRY" >&2
|
||||
exit 1
|
||||
fi
|
||||
run_cli() {
|
||||
"${CLI_CMD[@]}" "$@"
|
||||
}
|
||||
|
||||
DB_SUFFIX="$(date +%s)-$RANDOM"
|
||||
COUCHDB_DBNAME="${COUCHDB_DBNAME_BASE}-${DB_SUFFIX}"
|
||||
@@ -42,8 +41,8 @@ SETTINGS_A="$WORK_DIR/a-settings.json"
|
||||
SETTINGS_B="$WORK_DIR/b-settings.json"
|
||||
mkdir -p "$VAULT_A" "$VAULT_B"
|
||||
|
||||
node "$CLI_ENTRY" init-settings --force "$SETTINGS_A" >/dev/null
|
||||
node "$CLI_ENTRY" init-settings --force "$SETTINGS_B" >/dev/null
|
||||
run_cli init-settings --force "$SETTINGS_A" >/dev/null
|
||||
run_cli init-settings --force "$SETTINGS_B" >/dev/null
|
||||
|
||||
apply_settings() {
|
||||
local settings_file="$1"
|
||||
@@ -73,11 +72,11 @@ apply_settings "$SETTINGS_A"
|
||||
apply_settings "$SETTINGS_B"
|
||||
|
||||
run_cli_a() {
|
||||
node "$CLI_ENTRY" "$VAULT_A" --settings "$SETTINGS_A" "$@"
|
||||
run_cli "$VAULT_A" --settings "$SETTINGS_A" "$@"
|
||||
}
|
||||
|
||||
run_cli_b() {
|
||||
node "$CLI_ENTRY" "$VAULT_B" --settings "$SETTINGS_B" "$@"
|
||||
run_cli "$VAULT_B" --settings "$SETTINGS_B" "$@"
|
||||
}
|
||||
|
||||
sync_a() {
|
||||
|
||||
47
src/apps/cli/util/couchdb-init.sh
Executable file
47
src/apps/cli/util/couchdb-init.sh
Executable file
@@ -0,0 +1,47 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ -z "${hostname:-}" ]]; then
|
||||
echo "ERROR: Hostname missing"
|
||||
exit 1
|
||||
fi
|
||||
if [[ -z "${username:-}" ]]; then
|
||||
echo "ERROR: Username missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "${password:-}" ]]; then
|
||||
echo "ERROR: Password missing"
|
||||
exit 1
|
||||
fi
|
||||
if [[ -z "${node:-}" ]]; then
|
||||
echo "INFO: defaulting to _local"
|
||||
node=_local
|
||||
fi
|
||||
|
||||
hostname="${hostname%/}"
|
||||
# Podman environments often resolve localhost to ::1 while published ports are IPv4-only.
|
||||
hostname="${hostname/localhost/127.0.0.1}"
|
||||
|
||||
curl_json() {
|
||||
curl -4 -sS --fail --connect-timeout 3 --max-time 15 "$@"
|
||||
}
|
||||
|
||||
echo "-- Configuring CouchDB by REST APIs... -->"
|
||||
echo " Hostname: $hostname"
|
||||
echo " Username: $username"
|
||||
|
||||
until (curl_json -X POST "${hostname}/_cluster_setup" -H "Content-Type: application/json" -d "{\"action\":\"enable_single_node\",\"username\":\"${username}\",\"password\":\"${password}\",\"bind_address\":\"0.0.0.0\",\"port\":5984,\"singlenode\":true}" --user "${username}:${password}"); do sleep 5; done
|
||||
until (curl_json -X PUT "${hostname}/_node/${node}/_config/chttpd/require_valid_user" -H "Content-Type: application/json" -d '"true"' --user "${username}:${password}"); do sleep 5; done
|
||||
until (curl_json -X PUT "${hostname}/_node/${node}/_config/chttpd_auth/require_valid_user" -H "Content-Type: application/json" -d '"true"' --user "${username}:${password}"); do sleep 5; done
|
||||
until (curl_json -X PUT "${hostname}/_node/${node}/_config/httpd/WWW-Authenticate" -H "Content-Type: application/json" -d '"Basic realm=\"couchdb\""' --user "${username}:${password}"); do sleep 5; done
|
||||
until (curl_json -X PUT "${hostname}/_node/${node}/_config/httpd/enable_cors" -H "Content-Type: application/json" -d '"true"' --user "${username}:${password}"); do sleep 5; done
|
||||
until (curl_json -X PUT "${hostname}/_node/${node}/_config/chttpd/enable_cors" -H "Content-Type: application/json" -d '"true"' --user "${username}:${password}"); do sleep 5; done
|
||||
until (curl_json -X PUT "${hostname}/_node/${node}/_config/chttpd/max_http_request_size" -H "Content-Type: application/json" -d '"4294967296"' --user "${username}:${password}"); do sleep 5; done
|
||||
until (curl_json -X PUT "${hostname}/_node/${node}/_config/couchdb/max_document_size" -H "Content-Type: application/json" -d '"50000000"' --user "${username}:${password}"); do sleep 5; done
|
||||
until (curl_json -X PUT "${hostname}/_node/${node}/_config/cors/credentials" -H "Content-Type: application/json" -d '"true"' --user "${username}:${password}"); do sleep 5; done
|
||||
until (curl_json -X PUT "${hostname}/_node/${node}/_config/cors/origins" -H "Content-Type: application/json" -d '"*"' --user "${username}:${password}"); do sleep 5; done
|
||||
|
||||
# Create test database
|
||||
until (curl_json -X PUT --user "${username}:${password}" "${hostname}/${dbname}" >/dev/null); do sleep 5; done
|
||||
echo "<-- Configuring CouchDB by REST APIs Done!"
|
||||
4
src/apps/cli/util/couchdb-start.sh
Executable file
4
src/apps/cli/util/couchdb-start.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
echo "username: $username"
|
||||
docker run -d --name couchdb-test -p 5989:5984 -e COUCHDB_USER=$username -e COUCHDB_PASSWORD=$password -e COUCHDB_SINGLE_NODE=y couchdb:3.5.0
|
||||
3
src/apps/cli/util/couchdb-stop.sh
Executable file
3
src/apps/cli/util/couchdb-stop.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
docker stop couchdb-test
|
||||
docker rm couchdb-test
|
||||
47
src/apps/cli/util/minio-init.sh
Executable file
47
src/apps/cli/util/minio-init.sh
Executable file
@@ -0,0 +1,47 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
cat >/tmp/mybucket-rw.json <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": ["s3:GetBucketLocation","s3:ListBucket"],
|
||||
"Resource": ["arn:aws:s3:::$bucketName"]
|
||||
},
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": ["s3:GetObject","s3:PutObject","s3:DeleteObject"],
|
||||
"Resource": ["arn:aws:s3:::$bucketName/*"]
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
# echo "<CORSConfiguration>
|
||||
# <CORSRule>
|
||||
# <AllowedOrigin>http://localhost:63315</AllowedOrigin>
|
||||
# <AllowedOrigin>http://localhost:63316</AllowedOrigin>
|
||||
# <AllowedOrigin>http://localhost</AllowedOrigin>
|
||||
# <AllowedMethod>GET</AllowedMethod>
|
||||
# <AllowedMethod>PUT</AllowedMethod>
|
||||
# <AllowedMethod>POST</AllowedMethod>
|
||||
# <AllowedMethod>DELETE</AllowedMethod>
|
||||
# <AllowedMethod>HEAD</AllowedMethod>
|
||||
# <AllowedHeader>*</AllowedHeader>
|
||||
# </CORSRule>
|
||||
# </CORSConfiguration>" > /tmp/cors.xml
|
||||
# docker run --rm --network host -v /tmp/mybucket-rw.json:/tmp/mybucket-rw.json --entrypoint=/bin/sh minio/mc -c "
|
||||
# mc alias set myminio $minioEndpoint $username $password
|
||||
# mc mb --ignore-existing myminio/$bucketName
|
||||
# mc admin policy create myminio my-custom-policy /tmp/mybucket-rw.json
|
||||
# echo 'Creating service account for user $username with access key $accessKey'
|
||||
# mc admin user svcacct add --access-key '$accessKey' --secret-key '$secretKey' myminio '$username'
|
||||
# mc admin policy attach myminio my-custom-policy --user '$accessKey'
|
||||
# echo 'Verifying policy and user creation:'
|
||||
# mc admin user svcacct info myminio '$accessKey'
|
||||
# "
|
||||
|
||||
docker run --rm --network host -v /tmp/mybucket-rw.json:/tmp/mybucket-rw.json --entrypoint=/bin/sh minio/mc -c "
|
||||
mc alias set myminio $minioEndpoint $accessKey $secretKey
|
||||
mc mb --ignore-existing myminio/$bucketName
|
||||
"
|
||||
2
src/apps/cli/util/minio-start.sh
Executable file
2
src/apps/cli/util/minio-start.sh
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
docker run -d --name minio-test -p 9000:9000 -p 9001:9001 -e MINIO_ROOT_USER=$accessKey -e MINIO_ROOT_PASSWORD=$secretKey -e MINIO_SERVER_URL=$minioEndpoint minio/minio server /data --console-address ':9001'
|
||||
3
src/apps/cli/util/minio-stop.sh
Executable file
3
src/apps/cli/util/minio-stop.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
docker stop minio-test
|
||||
docker rm minio-test
|
||||
Reference in New Issue
Block a user