mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-08-27 13:57:07 +00:00
test(obsidian): cover Adaptive PostgREST remotes
This commit is contained in:
@@ -71,6 +71,8 @@
|
||||
"test:e2e:obsidian:couchdb-manual-setup-workflow": "tsx test/e2e-obsidian/scripts/couchdb-manual-setup-workflow.ts",
|
||||
"test:e2e:obsidian:cli-to-obsidian-sync": "tsx test/e2e-obsidian/scripts/cli-to-obsidian-sync.ts",
|
||||
"test:e2e:obsidian:minio-upload": "tsx test/e2e-obsidian/scripts/minio-upload.ts",
|
||||
"test:e2e:obsidian:adaptive-postgrest": "tsx test/e2e-obsidian/scripts/adaptive-postgrest.ts",
|
||||
"test:e2e:obsidian:adaptive-postgrest:services": "tsx test/e2e-obsidian/scripts/adaptive-postgrest.ts --manage-postgrest",
|
||||
"test:e2e:obsidian:object-storage-setup-uri-workflow": "tsx test/e2e-obsidian/scripts/object-storage-setup-uri-workflow.ts",
|
||||
"test:e2e:obsidian:p2p-setup-uri-workflow": "tsx test/e2e-obsidian/scripts/p2p-setup-uri-workflow.ts",
|
||||
"pretest:e2e:obsidian:p2p-connection-check": "npm run build && npm run build --workspace webpeer",
|
||||
|
||||
@@ -76,9 +76,10 @@ After changing plug-in source, use the focused wrapper rather than invoking a sc
|
||||
npm run test:e2e:obsidian:focused -- settings-ui
|
||||
npm run test:e2e:obsidian:focused -- two-vault-sync
|
||||
npm run test:e2e:obsidian:focused -- security-seed-reconnect
|
||||
npm run test:e2e:obsidian:focused -- adaptive-postgrest --manage-postgrest
|
||||
```
|
||||
|
||||
The wrapper accepts only maintained real-Obsidian scenario names; run it with `--help` for the current list. It deliberately does not manage CouchDB, Object Storage, or the P2P signalling relay. Start the required fixture first, or use the complete service-managed suite.
|
||||
The wrapper accepts only maintained real-Obsidian scenario names; run it with `--help` for the current list. It deliberately does not manage CouchDB, Object Storage, PostgREST, or the P2P signalling relay unless a focused scenario exposes its own explicit service-management argument. Start the required fixture first, pass `--manage-postgrest` to the Adaptive PostgREST scenario, or use the complete service-managed suite.
|
||||
|
||||
The principal entry points are:
|
||||
|
||||
@@ -147,6 +148,7 @@ LIVESYNC_CLI_COMMAND="docker run --rm --network host --user $(id -u):$(id -g) --
|
||||
|
||||
`test:e2e:obsidian:minio-upload` reuses the Object Storage variables from `.test.env` or the process environment. It expects a reachable S3-compatible service and starts with isolated Object Storage settings and the device-local compatibility acknowledgement already in place, keeping the scenario focused on upload rather than unconfigured start-up or setup. It confirms those settings through `obsidian-cli eval`, creates a note in real Obsidian, runs one-shot Journal Sync, and verifies through the AWS SDK that objects were written under a unique bucket prefix. Adapter tests separately observe an in-progress SDK command, while this real-runtime workflow verifies the resulting request counters advance and rebalance.
|
||||
|
||||
`test:e2e:obsidian:adaptive-postgrest` applies the two-device real-Obsidian workflow to the Adaptive-only PostgREST provider. Visible manual onboarding must withhold continuation until the packaged RPC and binary-semantics check succeeds, and it must not expose Opaque or Pack retrieval choices. The first device retains its profile across a real Obsidian restart, generates a Setup URI for the second device, and completes Fast Fetch and a text and binary return journey. This representative native-store journey verifies Host composition and user-observable Vault reflection. Commonlib integration tests own the RPC failure matrix, SQL transaction semantics, repository binding, and remote layout. Rebuild resets all Adaptive data for the supplied Vault ID, so external settings must identify a disposable test Vault. Run `test:e2e:obsidian:adaptive-postgrest:services`, or pass `--manage-postgrest` through the focused wrapper, to start and stop the shared PostgreSQL and PostgREST fixture around this scenario.
|
||||
`test:e2e:obsidian:object-storage-setup-uri-workflow` uses the public Commonlib-backed tool to generate the initial Setup URI for a unique MinIO prefix, completes visible initialisation on the first device, and then asks that working real Obsidian device to create a new Setup URI through the registered command. A second real Obsidian device imports only the device-generated URI. The workflow verifies A-to-B and B-to-A notes, captures the documented onboarding choices, and removes the Object Storage prefix only after both sessions have stopped.
|
||||
|
||||
`test:e2e:obsidian:p2p-setup-uri-workflow` runs two concurrent isolated real Obsidian sessions against the local Compose Nostr relay fixture. The first device imports a generated initial Setup URI and completes its signalling test with zero peers, creates a Setup URI for the second device through the registered command, and remains online while the second device imports it. The second device must select the expected online source before Fetch can rebuild its local database. The workflow accepts each connection request visibly on the receiving device, verifies the initial A-to-B fetch, checks that the menu for the three persistent per-peer actions remains within the viewport, reconnects both P2P sessions in join order, and verifies the B-to-A return journey. Every started session remains tracked until teardown completes.
|
||||
|
||||
@@ -21,6 +21,7 @@ export type SetupState = {
|
||||
p2pEnabled: boolean;
|
||||
p2pRelays: string;
|
||||
p2pRoomId: string;
|
||||
postgrestActiveConnectionURI: string;
|
||||
};
|
||||
|
||||
export type SetupCaptureNames = {
|
||||
@@ -345,6 +346,7 @@ export async function readSetupState(cliBinary: string, environment: NodeJS.Proc
|
||||
"p2pEnabled:settings.P2P_Enabled===true,",
|
||||
"p2pRelays:settings.P2P_relays||'',",
|
||||
"p2pRoomId:settings.P2P_roomID||'',",
|
||||
"postgrestActiveConnectionURI:settings.postgrestActiveConnectionURI||'',",
|
||||
"});",
|
||||
"})()",
|
||||
].join(""),
|
||||
|
||||
@@ -0,0 +1,279 @@
|
||||
/**
|
||||
* Exercises the Adaptive-only PostgREST Journal provider through visible,
|
||||
* safety-gated onboarding. The shared Adaptive Journal runner owns restart
|
||||
* persistence, device-generated Setup URI transfer, Fast Fetch, and a
|
||||
* two-device text and binary return journey.
|
||||
*/
|
||||
import { parsePostgRESTConnectionURI } from "@vrtmrz/livesync-commonlib/journal-storage";
|
||||
import { runAdaptiveJournalObsidianRoundTrip, runNpmScript } from "../runner/adaptiveJournal.ts";
|
||||
import { assertEqual } from "../runner/liveSyncWorkflow.ts";
|
||||
import { captureGuideDialogue, modalByTitle, selectRadioOption, type SetupState } from "../runner/setupUri.ts";
|
||||
import { withObsidianPage } from "../runner/ui.ts";
|
||||
|
||||
type PostgRESTConfig = {
|
||||
apiKey: string;
|
||||
endpoint: string;
|
||||
schema: string;
|
||||
vaultCredential: string;
|
||||
vaultId: string;
|
||||
};
|
||||
|
||||
const supportedArguments = new Set(["--keep-postgrest", "--manage-postgrest"]);
|
||||
const unsupportedArguments = process.argv.slice(2).filter((argument) => !supportedArguments.has(argument));
|
||||
if (unsupportedArguments.length > 0) {
|
||||
throw new Error(`Unsupported Adaptive PostgREST argument: ${unsupportedArguments.join(", ")}`);
|
||||
}
|
||||
|
||||
const managePostgREST = process.argv.includes("--manage-postgrest");
|
||||
const keepPostgRESTFixture = process.argv.includes("--keep-postgrest");
|
||||
const uiTimeoutMs = Number(process.env.E2E_OBSIDIAN_SETUP_URI_TIMEOUT_MS ?? 30000);
|
||||
const remoteTimeoutMs = Number(process.env.E2E_OBSIDIAN_POSTGREST_TIMEOUT_MS ?? 30000);
|
||||
|
||||
function environmentValue(primary: string, legacy: string, fallback: string): string {
|
||||
return process.env[primary] ?? process.env[legacy] ?? fallback;
|
||||
}
|
||||
|
||||
function loadPostgRESTConfig(): PostgRESTConfig {
|
||||
const endpoint = environmentValue("POSTGREST_ENDPOINT", "postgrestEndpoint", "http://127.0.0.1:3001").replace(
|
||||
/\/+$/u,
|
||||
""
|
||||
);
|
||||
const endpointUrl = new URL(endpoint);
|
||||
if (
|
||||
(endpointUrl.protocol !== "http:" && endpointUrl.protocol !== "https:") ||
|
||||
endpointUrl.username !== "" ||
|
||||
endpointUrl.password !== "" ||
|
||||
endpointUrl.search !== "" ||
|
||||
endpointUrl.hash !== ""
|
||||
) {
|
||||
throw new Error("Adaptive PostgREST requires a complete HTTP or HTTPS endpoint without embedded credentials.");
|
||||
}
|
||||
const config = {
|
||||
apiKey: environmentValue("POSTGREST_API_KEY", "postgrestApiKey", ""),
|
||||
endpoint,
|
||||
schema: environmentValue("POSTGREST_SCHEMA", "postgrestSchema", "livesync_api"),
|
||||
vaultCredential: environmentValue(
|
||||
"POSTGREST_VAULT_CREDENTIAL",
|
||||
"postgrestVaultCredential",
|
||||
"adaptive-cli-vault-credential-0000000000001"
|
||||
),
|
||||
vaultId: environmentValue("POSTGREST_VAULT_ID", "postgrestVaultId", "adaptive-cli-vault-01"),
|
||||
};
|
||||
if (!/^[A-Za-z_][A-Za-z0-9_]*$/u.test(config.schema)) {
|
||||
throw new Error("Adaptive PostgREST requires a valid exposed schema identifier.");
|
||||
}
|
||||
if (!/^[A-Za-z0-9_-]{16,128}$/u.test(config.vaultId) || config.vaultCredential.length === 0) {
|
||||
throw new Error("Adaptive PostgREST requires a provisioned Vault ID and Vault credential.");
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
function postgRESTHeaders(config: PostgRESTConfig): Headers {
|
||||
const headers = new Headers({
|
||||
Accept: "application/json",
|
||||
"Accept-Profile": config.schema,
|
||||
"Content-Profile": config.schema,
|
||||
"X-LiveSync-Vault-Credential": config.vaultCredential,
|
||||
"X-LiveSync-Vault-ID": config.vaultId,
|
||||
});
|
||||
if (config.apiKey) headers.set("apikey", config.apiKey);
|
||||
return headers;
|
||||
}
|
||||
|
||||
async function readEstimatedSize(config: PostgRESTConfig): Promise<number> {
|
||||
const response = await fetch(`${config.endpoint}/rpc/livesync_adaptive_status`, {
|
||||
headers: postgRESTHeaders(config),
|
||||
method: "GET",
|
||||
signal: AbortSignal.timeout(5000),
|
||||
});
|
||||
if (!response.ok) {
|
||||
await response.body?.cancel().catch(() => undefined);
|
||||
throw new Error(`Adaptive PostgREST status failed with HTTP ${response.status}.`);
|
||||
}
|
||||
const value = (await response.json()) as unknown;
|
||||
const body = Array.isArray(value) && value.length === 1 ? value[0] : value;
|
||||
const estimatedSize = Number(
|
||||
body && typeof body === "object" && !Array.isArray(body)
|
||||
? (body as { estimated_size?: unknown }).estimated_size
|
||||
: Number.NaN
|
||||
);
|
||||
if (!Number.isFinite(estimatedSize) || estimatedSize < 0) {
|
||||
throw new Error("Adaptive PostgREST status returned an invalid estimated size.");
|
||||
}
|
||||
return estimatedSize;
|
||||
}
|
||||
|
||||
async function assertPostgRESTReachable(config: PostgRESTConfig): Promise<void> {
|
||||
await readEstimatedSize(config);
|
||||
}
|
||||
|
||||
async function enterManualAdaptivePostgRESTSettings(
|
||||
port: number,
|
||||
config: PostgRESTConfig,
|
||||
vaultPassphrase: string
|
||||
): Promise<string[]> {
|
||||
const screenshots: string[] = [];
|
||||
await withObsidianPage(port, async (page) => {
|
||||
const invitation = page.locator(".notice").filter({ hasText: "Welcome to Self-hosted LiveSync" });
|
||||
await invitation.waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
await invitation.locator(".sls-onboarding-invitation-action").click({ timeout: uiTimeoutMs });
|
||||
|
||||
const intro = modalByTitle(page, "Welcome to Self-hosted LiveSync");
|
||||
await intro.waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
await selectRadioOption(intro, "I am setting this up for the first time");
|
||||
await intro
|
||||
.getByRole("button", { name: "Yes, I want to set up a new synchronisation" })
|
||||
.click({ timeout: uiTimeoutMs });
|
||||
|
||||
const method = modalByTitle(page, "Connection Method");
|
||||
await method.waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
await selectRadioOption(method, "Configure a remote manually");
|
||||
await method.getByRole("button", { name: "Proceed with manual configuration" }).click({ timeout: uiTimeoutMs });
|
||||
|
||||
const encryption = modalByTitle(page, "End-to-End Encryption");
|
||||
await encryption.waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
await encryption
|
||||
.locator("label.row")
|
||||
.filter({ hasText: "End-to-End Encryption" })
|
||||
.locator('input[type="checkbox"]')
|
||||
.first()
|
||||
.check({ timeout: uiTimeoutMs });
|
||||
await encryption.locator('input[name="e2ee-passphrase"]').fill(vaultPassphrase);
|
||||
});
|
||||
screenshots.push(
|
||||
await captureGuideDialogue(port, "guide-adaptive-postgrest-encryption.png", "End-to-End Encryption")
|
||||
);
|
||||
|
||||
await withObsidianPage(port, async (page) => {
|
||||
await modalByTitle(page, "End-to-End Encryption")
|
||||
.getByRole("button", { name: "Proceed", exact: true })
|
||||
.click({ timeout: uiTimeoutMs });
|
||||
|
||||
const remoteSelection = modalByTitle(page, "Choose a synchronisation remote");
|
||||
await remoteSelection.waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
await selectRadioOption(remoteSelection, "PostgREST Journal");
|
||||
await remoteSelection
|
||||
.getByRole("button", { name: "Continue to PostgREST setup", exact: true })
|
||||
.click({ timeout: uiTimeoutMs });
|
||||
|
||||
const postgRESTModal = modalByTitle(page, "PostgREST Journal Configuration");
|
||||
await postgRESTModal.waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
await postgRESTModal.locator('input[name="postgrest-endpoint"]').fill(config.endpoint);
|
||||
await postgRESTModal.locator('input[name="postgrest-vault-id"]').fill(config.vaultId);
|
||||
await postgRESTModal.locator('input[name="postgrest-vault-credential"]').fill(config.vaultCredential);
|
||||
await postgRESTModal.locator('input[name="postgrest-schema"]').fill(config.schema);
|
||||
if (config.apiKey) await postgRESTModal.locator('input[name="postgrest-api-key"]').fill(config.apiKey);
|
||||
await postgRESTModal.locator('input[name="postgrest-use-internal-api"]').check({ timeout: uiTimeoutMs });
|
||||
|
||||
if (
|
||||
(await postgRESTModal.locator('select[name="postgrest-journal-format"]').count()) !== 0 ||
|
||||
(await postgRESTModal.locator('select[name="postgrest-pack-read-policy"]').count()) !== 0
|
||||
) {
|
||||
throw new Error("Adaptive-only PostgREST onboarding exposed an Opaque or Pack retrieval choice.");
|
||||
}
|
||||
if (
|
||||
(await postgRESTModal
|
||||
.getByRole("button", { name: "Continue with verified settings", exact: true })
|
||||
.count()) !== 0
|
||||
) {
|
||||
throw new Error("Adaptive PostgREST could continue before its server safety check completed.");
|
||||
}
|
||||
await postgRESTModal
|
||||
.getByRole("button", { name: "Check PostgREST server", exact: true })
|
||||
.click({ timeout: uiTimeoutMs });
|
||||
await postgRESTModal
|
||||
.getByText("The required PostgREST RPC operations and binary semantics were verified.", { exact: false })
|
||||
.waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
await postgRESTModal
|
||||
.getByRole("button", { name: "Continue with verified settings", exact: true })
|
||||
.waitFor({ state: "visible", timeout: uiTimeoutMs });
|
||||
if (
|
||||
(await postgRESTModal.getByRole("button", { name: "Save without connecting", exact: true }).count()) !== 0
|
||||
) {
|
||||
throw new Error("Adaptive PostgREST onboarding exposed the unverified Settings-only save action.");
|
||||
}
|
||||
});
|
||||
screenshots.push(
|
||||
await captureGuideDialogue(port, "guide-adaptive-postgrest-safety-check.png", "PostgREST Journal Configuration")
|
||||
);
|
||||
await withObsidianPage(port, async (page) => {
|
||||
const postgRESTModal = modalByTitle(page, "PostgREST Journal Configuration");
|
||||
await postgRESTModal
|
||||
.getByRole("button", { name: "Continue with verified settings", exact: true })
|
||||
.click({ timeout: uiTimeoutMs });
|
||||
await modalByTitle(page, "Setup Complete: Preparing to Initialise Server").waitFor({
|
||||
state: "visible",
|
||||
timeout: uiTimeoutMs,
|
||||
});
|
||||
});
|
||||
return screenshots;
|
||||
}
|
||||
|
||||
function assertAdaptivePostgRESTSettings(state: SetupState, config: PostgRESTConfig, label: string): void {
|
||||
assertEqual(state.remoteType, "POSTGREST", `${label} did not retain PostgREST as its active remote.`);
|
||||
assertEqual(state.journalFormat, "adaptive-v1", `${label} did not retain the Adaptive Journal format.`);
|
||||
assertEqual(state.packReadPolicy, "whole-pack", `${label} did not retain complete Pack retrieval.`);
|
||||
assertEqual(state.remoteConfigurationCount, 1, `${label} did not retain exactly one remote profile.`);
|
||||
const connection = parsePostgRESTConnectionURI(state.postgrestActiveConnectionURI);
|
||||
assertEqual(connection.endpoint, config.endpoint, `${label} retained a different PostgREST endpoint.`);
|
||||
assertEqual(connection.schema, config.schema, `${label} retained a different PostgREST schema.`);
|
||||
if (connection.vaultId !== config.vaultId || connection.vaultCredential !== config.vaultCredential) {
|
||||
throw new Error(`${label} did not retain the provisioned PostgREST Vault ID and Vault credential.`);
|
||||
}
|
||||
if (connection.apiKey !== config.apiKey) {
|
||||
throw new Error(`${label} did not retain the configured PostgREST client API key.`);
|
||||
}
|
||||
assertEqual(
|
||||
connection.useCustomRequestHandler,
|
||||
true,
|
||||
`${label} did not retain the Obsidian internal request API selection.`
|
||||
);
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const config = loadPostgRESTConfig();
|
||||
let shouldStopPostgREST = false;
|
||||
let observedEstimatedSize = 0;
|
||||
|
||||
try {
|
||||
if (managePostgREST) {
|
||||
await runNpmScript("test:docker-postgrest:start");
|
||||
shouldStopPostgREST = !keepPostgRESTFixture;
|
||||
}
|
||||
await assertPostgRESTReachable(config);
|
||||
await runAdaptiveJournalObsidianRoundTrip({
|
||||
label: "Adaptive PostgREST",
|
||||
slug: "adaptive-postgrest",
|
||||
targetDescription: `Temporary PostgREST target: ${config.endpoint}`,
|
||||
enterManualSettings: async (port, vaultPassphrase) =>
|
||||
await enterManualAdaptivePostgRESTSettings(port, config, vaultPassphrase),
|
||||
assertSettings: (state, label) => assertAdaptivePostgRESTSettings(state, config, label),
|
||||
assertPublished: async (minimumWriters, minimumCommits) => {
|
||||
const deadline = Date.now() + remoteTimeoutMs;
|
||||
let lastSize = 0;
|
||||
while (Date.now() < deadline) {
|
||||
lastSize = await readEstimatedSize(config);
|
||||
if (lastSize > observedEstimatedSize && lastSize > 0) {
|
||||
observedEstimatedSize = lastSize;
|
||||
return;
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
}
|
||||
throw new Error(
|
||||
`Timed out waiting for Adaptive PostgREST publication stage ${minimumWriters}/${minimumCommits}; last estimated size was ${lastSize}.`
|
||||
);
|
||||
},
|
||||
});
|
||||
} finally {
|
||||
if (shouldStopPostgREST) {
|
||||
await runNpmScript("test:docker-postgrest:stop").catch((error: unknown) => {
|
||||
console.warn(error instanceof Error ? error.message : error);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((error: unknown) => {
|
||||
console.error(error instanceof Error ? error.stack : error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -31,6 +31,7 @@ const testSteps: Step[] = [
|
||||
args: ["run", "test:e2e:obsidian:cli-to-obsidian-sync"],
|
||||
},
|
||||
{ name: "Object Storage upload", args: ["run", "test:e2e:obsidian:minio-upload"] },
|
||||
{ name: "Adaptive PostgREST workflow", args: ["run", "test:e2e:obsidian:adaptive-postgrest"] },
|
||||
{
|
||||
name: "Object Storage Setup URI workflow",
|
||||
args: ["run", "test:e2e:obsidian:object-storage-setup-uri-workflow"],
|
||||
@@ -47,10 +48,12 @@ const testSteps: Step[] = [
|
||||
const manageCouchDb = process.argv.includes("--manage-couchdb") || process.argv.includes("--manage-services");
|
||||
const manageMinio = process.argv.includes("--manage-minio") || process.argv.includes("--manage-services");
|
||||
const manageP2P = process.argv.includes("--manage-p2p") || process.argv.includes("--manage-services");
|
||||
const managePostgREST = process.argv.includes("--manage-postgrest") || process.argv.includes("--manage-services");
|
||||
const keepServices = process.argv.includes("--keep-services");
|
||||
const keepCouchDb = keepServices || process.argv.includes("--keep-couchdb");
|
||||
const keepMinio = keepServices || process.argv.includes("--keep-minio");
|
||||
const keepP2P = keepServices || process.argv.includes("--keep-p2p");
|
||||
const keepPostgREST = keepServices || process.argv.includes("--keep-postgrest");
|
||||
|
||||
function npmBinary(): string {
|
||||
return process.platform === "win32" ? "npm.cmd" : "npm";
|
||||
@@ -105,10 +108,18 @@ async function stopManagedP2P(): Promise<void> {
|
||||
});
|
||||
}
|
||||
|
||||
async function stopManagedPostgREST(): Promise<void> {
|
||||
await runStep({
|
||||
name: "stop PostgREST fixture",
|
||||
args: ["run", "test:docker-postgrest:stop"],
|
||||
optional: true,
|
||||
});
|
||||
}
|
||||
async function main(): Promise<void> {
|
||||
let shouldStopCouchDb = false;
|
||||
let shouldStopMinio = false;
|
||||
let shouldStopP2P = false;
|
||||
let shouldStopPostgREST = false;
|
||||
try {
|
||||
if (manageCouchDb) {
|
||||
await stopManagedCouchDb();
|
||||
@@ -125,11 +136,19 @@ async function main(): Promise<void> {
|
||||
await runStep({ name: "start P2P relay fixture", args: ["run", "test:docker-p2p:start"] });
|
||||
shouldStopP2P = !keepP2P;
|
||||
}
|
||||
if (managePostgREST) {
|
||||
await stopManagedPostgREST();
|
||||
await runStep({ name: "start PostgREST fixture", args: ["run", "test:docker-postgrest:start"] });
|
||||
shouldStopPostgREST = !keepPostgREST;
|
||||
}
|
||||
|
||||
for (const step of testSteps) {
|
||||
await runStep(step);
|
||||
}
|
||||
} finally {
|
||||
if (shouldStopPostgREST) {
|
||||
await stopManagedPostgREST();
|
||||
}
|
||||
if (shouldStopP2P) {
|
||||
await stopManagedP2P();
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ const focusedScenarios = new Set([
|
||||
"couchdb-manual-setup-workflow",
|
||||
"cli-to-obsidian-sync",
|
||||
"minio-upload",
|
||||
"adaptive-postgrest",
|
||||
"object-storage-setup-uri-workflow",
|
||||
"p2p-setup-uri-workflow",
|
||||
"startup-scan",
|
||||
@@ -39,7 +40,7 @@ real-Obsidian scenario. Supported scenarios:
|
||||
|
||||
${[...focusedScenarios].map((scenario) => ` ${scenario}`).join("\n")}
|
||||
|
||||
This wrapper does not start CouchDB, Object Storage, or the P2P signalling
|
||||
This wrapper does not start CouchDB, Object Storage, PostgREST, or the P2P signalling
|
||||
relay. Use the documented service commands or the complete
|
||||
local-suite:services wrapper when required.`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user