Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { expect } from "vitest";

import {
postgresConfigLiveFlags,
removePostgresConfigLiveOverride,
requireLiveSuccess,
test,
throwWithCleanup,
} from "../../../../../tests/helpers/live.ts";

// Seeds its own override and proves it landed before deleting, so the absence
// assertion cannot be satisfied by the pre-seed state. Teardown removes the
// seeded key only when the test did not already prove it gone.
test("removes the test-seeded override and get proves it is gone", async ({ cli, project }) => {
const flags = postgresConfigLiveFlags(project);
let targetError: unknown;
const cleanupErrors: Array<unknown> = [];
let cleanupNeeded = true;
try {
const seeded = await cli([
"postgres-config",
"update",
"--config",
"maintenance_work_mem=16MB",
...flags,
"--no-restart",
]);
requireLiveSuccess(seeded, "postgres-config update setup for postgres-config delete");
const before = await cli(["postgres-config", "get", ...flags, "-o", "json"]);
requireLiveSuccess(before, "postgres-config get seed proof for postgres-config delete");
expect(before.stdout, before.stderr).not.toBe("");
const seededConfig = JSON.parse(before.stdout) as Record<string, unknown>;
expect(seededConfig["maintenance_work_mem"], before.stdout).toBe("16MB");

const removed = await cli([
"postgres-config",
"delete",
"--config",
"maintenance_work_mem",
...flags,
"--no-restart",
"-o",
"json",
]);
expect(removed.exitCode, removed.stderr).toBe(0);
expect(removed.stdout, removed.stderr).not.toBe("");
const remaining = JSON.parse(removed.stdout) as Record<string, unknown>;
expect(remaining["maintenance_work_mem"], removed.stdout).toBeUndefined();

const proof = await cli(["postgres-config", "get", ...flags, "-o", "json"]);
requireLiveSuccess(proof, "postgres-config get proof for postgres-config delete");
expect(proof.stdout, proof.stderr).not.toBe("");
const config = JSON.parse(proof.stdout) as Record<string, unknown>;
expect(config["maintenance_work_mem"], proof.stdout).toBeUndefined();
cleanupNeeded = false;
} catch (error) {
targetError = error;
} finally {
if (cleanupNeeded) {
try {
await removePostgresConfigLiveOverride(cli, project, "maintenance_work_mem");
} catch (error) {
cleanupErrors.push(error);
}
}
}
throwWithCleanup(targetError, cleanupErrors);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { expect } from "vitest";

import { postgresConfigLiveFlags, test } from "../../../../../tests/helpers/live.ts";

// A freshly provisioned project can have zero overrides, so the golden path
// pins the payload shape rather than any key: exit 0 and a JSON object on
// payload-only stdout.
test("reads the current config of the target project", async ({ cli, project }) => {
const result = await cli([
"postgres-config",
"get",
...postgresConfigLiveFlags(project),
"-o",
"json",
]);
expect(result.exitCode, result.stderr).toBe(0);
expect(result.stdout, result.stderr).not.toBe("");
const config: unknown = JSON.parse(result.stdout);
expect(config, result.stdout).toBeTypeOf("object");
expect(config, result.stdout).not.toBeNull();
expect(Array.isArray(config), result.stdout).toBe(false);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { expect } from "vitest";

import {
postgresConfigLiveFlags,
removePostgresConfigLiveOverride,
requireLiveSuccess,
test,
throwWithCleanup,
} from "../../../../../tests/helpers/live.ts";

// --no-restart skips the database restart; work_mem is a dynamic parameter, so
// the override still takes effect.
test("applies an override with --no-restart and get proves it", async ({ cli, project }) => {
const flags = postgresConfigLiveFlags(project);
let targetError: unknown;
const cleanupErrors: Array<unknown> = [];
try {
const updated = await cli([
"postgres-config",
"update",
"--config",
"work_mem=7MB",
...flags,
"--no-restart",
"-o",
"json",
]);
expect(updated.exitCode, updated.stderr).toBe(0);
expect(updated.stdout, updated.stderr).not.toBe("");
const applied = JSON.parse(updated.stdout) as Record<string, unknown>;
expect(applied["work_mem"], updated.stdout).toBe("7MB");

const proof = await cli(["postgres-config", "get", ...flags, "-o", "json"]);
requireLiveSuccess(proof, "postgres-config get proof for postgres-config update");
expect(proof.stdout, proof.stderr).not.toBe("");
const config = JSON.parse(proof.stdout) as Record<string, unknown>;
expect(config["work_mem"], proof.stdout).toBe("7MB");
} catch (error) {
targetError = error;
} finally {
try {
await removePostgresConfigLiveOverride(cli, project, "work_mem");
} catch (error) {
cleanupErrors.push(error);
}
}
throwWithCleanup(targetError, cleanupErrors);
});
27 changes: 27 additions & 0 deletions apps/cli/tests/helpers/live.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,33 @@ export async function removeStorageLiveObject(
}
}

/** Flags every postgres-config live test passes: the family is
* experimental-gated and addresses the shared project by ref. */
export function postgresConfigLiveFlags(project: LiveProject): ReadonlyArray<string> {
return ["--project-ref", project.ref, "--experimental"];
}

/**
* Exact-key cleanup for postgres-config live tests: removes one owned override
* without a database restart. Deleting an absent key is a no-op PUT, so the
* teardown stays idempotent.
*/
export async function removePostgresConfigLiveOverride(
cli: (args: string[]) => Promise<{ exitCode: number; stdout: string; stderr: string }>,
project: LiveProject,
key: string,
): Promise<void> {
const removed = await cli([
"postgres-config",
"delete",
"--config",
key,
...postgresConfigLiveFlags(project),
"--no-restart",
]);
requireLiveSuccess(removed, `postgres-config delete cleanup for ${key}`);
}

/**
* Unique migration version for a live test: a sortable `YYYYMMDDHHMMSS` UTC
* stamp plus four random digits, so it always orders after any conventional
Expand Down
Loading