Ctrl K
ComunidadGuías…

test/scripts/database-snapshot-options.test.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { expect } from "@std/expect";
import { join } from "@std/path";
import { describe, it as test } from "@std/testing/bdd";
import {
  parseSnapshotArgs,
  readSnapshotRequest,
  readSnapshotRequestFromEnvFile,
  SNAPSHOT_USAGE,
} from "#scripts/database-snapshot-lib.ts";
import { withEnv } from "#test-utils/env.ts";
import { withTempDir } from "#test-utils/files.ts";

const envReader =
  (values: Record<string, string | undefined>) =>
  (key: string): string | undefined =>
    values[key];

describe("database snapshot options", () => {
  test("accepts one output path", () => {
    expect(parseSnapshotArgs(["--out", "backups/site.sqlite"])).toEqual({
      outputPath: "backups/site.sqlite",
    });
  });

  test("returns help without an output path", () => {
    expect(parseSnapshotArgs(["--help"])).toBeNull();
    expect(parseSnapshotArgs(["-h"])).toBeNull();
  });

  test("rejects missing, blank, duplicate, and extra output arguments", () => {
    const invalidArguments = [
      [],
      ["--out"],
      ["--out", " "],
      ["--out", "one.sqlite", "--out", "two.sqlite"],
      ["--out", "site.sqlite", "extra"],
      ["--out", "site.sqlite", "--unknown"],
      ["--help", "--out", "site.sqlite"],
    ];

    for (const args of invalidArguments) {
      expect(() => parseSnapshotArgs(args)).toThrow(SNAPSHOT_USAGE);
    }
  });

  test("reads remote database credentials", () => {
    using _env = withEnv({
      DB_TOKEN: "secret-token",
      DB_URL: "libsql://site.example.com",
    });
    expect(readSnapshotRequest({ outputPath: "site.sqlite" })).toEqual({
      dbToken: "secret-token",
      dbUrl: "libsql://site.example.com",
      outputPath: "site.sqlite",
    });
  });

  test("prefers database credentials from .env over shell values", () =>
    withTempDir(async (dir) => {
      const envPath = join(dir, ".env");
      await Deno.writeTextFile(
        envPath,
        'DB_URL="libsql://file.example.com"\nDB_TOKEN="file-token"\n',
      );

      await expect(
        readSnapshotRequestFromEnvFile(
          { outputPath: "site.sqlite" },
          envPath,
          envReader({ DB_TOKEN: "shell-token", DB_URL: ":memory:" }),
        ),
      ).resolves.toEqual({
        dbToken: "file-token",
        dbUrl: "libsql://file.example.com",
        outputPath: "site.sqlite",
      });
    }));

  test("uses shell credentials when .env is absent", () =>
    withTempDir(
      async (dir) =>
        await expect(
          readSnapshotRequestFromEnvFile(
            { outputPath: "site.sqlite" },
            join(dir, ".env"),
            envReader({
              DB_TOKEN: "shell-token",
              DB_URL: "libsql://shell.example.com",
            }),
          ),
        ).resolves.toEqual({
          dbToken: "shell-token",
          dbUrl: "libsql://shell.example.com",
          outputPath: "site.sqlite",
        }),
    ));

  test("rejects missing database credentials", () => {
    expect(() =>
      readSnapshotRequest(
        { outputPath: "site.sqlite" },
        envReader({ DB_TOKEN: "token" }),
      ),
    ).toThrow("DB_URL environment variable is required");
    expect(() =>
      readSnapshotRequest(
        { outputPath: "site.sqlite" },
        envReader({ DB_URL: "libsql://site.example.com" }),
      ),
    ).toThrow("DB_TOKEN environment variable is required");
    expect(() =>
      readSnapshotRequest(
        { outputPath: "site.sqlite" },
        envReader({ DB_TOKEN: " ", DB_URL: "libsql://site.example.com" }),
      ),
    ).toThrow("DB_TOKEN environment variable is required");
  });

  test("rejects local, insecure, and malformed database URLs", () => {
    for (const dbUrl of [
      ":memory:",
      "file:site.sqlite",
      "http://site.example.com",
      "http://localhost.example.com",
      "libsql://site.example.com:8080?tls=0",
      "libsql://site.example.com:8080?tls=1&tls=0",
      "not a URL",
    ]) {
      expect(() =>
        readSnapshotRequest(
          { outputPath: "site.sqlite" },
          envReader({ DB_TOKEN: "token", DB_URL: dbUrl }),
        ),
      ).toThrow(
        "DB_URL must use TLS. Plain connections are allowed only for loopback.",
      );
    }
  });

  test("accepts each supported remote database protocol", () => {
    for (const dbUrl of [
      "libsql://site.example.com",
      "libsql://site.example.com:8080?tls=0&tls=1",
      "https://site.example.com",
      "http://localhost:8080",
      "http://127.0.0.1:8080",
      "http://[::1]:8080",
      "libsql://localhost:8080?tls=0",
      "libsql://127.0.0.1:8080?tls=0",
      "libsql://[::1]:8080?tls=0",
    ]) {
      expect(
        readSnapshotRequest(
          { outputPath: "site.sqlite" },
          envReader({ DB_TOKEN: "token", DB_URL: dbUrl }),
        ).dbUrl,
      ).toBe(dbUrl);
    }
  });
});