feat(\db-tool\): introduce unified db-tool package with postgres harness and tests (T0-T8)
This commit is contained in:
41
legacy/helper/posix-shell/change_namespace.sh
Normal file
41
legacy/helper/posix-shell/change_namespace.sh
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
: "${OLD_NAMESPACE:=}"
|
||||||
|
|
||||||
|
nl=$(printf '\nx')
|
||||||
|
nl=${nl%x}
|
||||||
|
|
||||||
|
___pop_namespace() {
|
||||||
|
v=${OLD_NAMESPACE%%"$nl"*}
|
||||||
|
|
||||||
|
case $OLD_NAMESPACE in
|
||||||
|
*"$nl"*)
|
||||||
|
OLD_NAMESPACE=${OLD_NAMESPACE#*"$nl"}
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
OLD_NAMESPACE=
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
printf '%s\n' "$v"
|
||||||
|
}
|
||||||
|
|
||||||
|
___peek_namespace() {
|
||||||
|
printf '%s\n' "${OLD_NAMESPACE%%"$nl"*}"
|
||||||
|
}
|
||||||
|
|
||||||
|
___push_namespace() {
|
||||||
|
if [ -n "$OLD_NAMESPACE" ]; then
|
||||||
|
OLD_NAMESPACE=$1"$nl$OLD_NAMESPACE"
|
||||||
|
else
|
||||||
|
OLD_NAMESPACE=$1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
change_namespace() {
|
||||||
|
___push_namespace "$HECTIC_NAMESPACE"
|
||||||
|
export HECTIC_NAMESPACE="$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
restore_namespace() {
|
||||||
|
HECTIC_NAMESPACE=$(___pop_namespace)
|
||||||
|
export HECTIC_NAMESPACE
|
||||||
|
}
|
||||||
@@ -12,4 +12,13 @@ in {
|
|||||||
colors = hectic.writeDash "colors.sh" ''
|
colors = hectic.writeDash "colors.sh" ''
|
||||||
${builtins.readFile ./colors.sh}
|
${builtins.readFile ./colors.sh}
|
||||||
'';
|
'';
|
||||||
|
change_namespace = hectic.writeDash "change_namespace.sh" ''
|
||||||
|
${builtins.readFile ./change_namespace.sh}
|
||||||
|
'';
|
||||||
|
quote = hectic.writeDash "quote.sh" ''
|
||||||
|
${builtins.readFile ./quote.sh}
|
||||||
|
'';
|
||||||
|
pager_or_cat = hectic.writeDash "pager_or_cat.sh" ''
|
||||||
|
${builtins.readFile ./pager_or_cat.sh}
|
||||||
|
'';
|
||||||
}
|
}
|
||||||
|
|||||||
8
legacy/helper/posix-shell/pager_or_cat.sh
Normal file
8
legacy/helper/posix-shell/pager_or_cat.sh
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
pager_or_cat_init() {
|
||||||
|
# Pipe to pager only if stdout is a terminal, otherwise output directly
|
||||||
|
if [ -t 1 ]; then
|
||||||
|
PAGER_OR_CAT="${PAGER:-less}"
|
||||||
|
else
|
||||||
|
PAGER_OR_CAT=cat
|
||||||
|
fi
|
||||||
|
}
|
||||||
1
legacy/helper/posix-shell/quote.sh
Normal file
1
legacy/helper/posix-shell/quote.sh
Normal file
@@ -0,0 +1 @@
|
|||||||
|
quote() { printf "'%s'" "$(printf %s "$1" | sed "s/'/'\\\\''/g")"; }
|
||||||
99
package/db-tool/README.md
Normal file
99
package/db-tool/README.md
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
# db-tool
|
||||||
|
|
||||||
|
PostgreSQL development database management tool. Drop-in replacement for per-project database.sh / postgres-init.sh / postgres-cleanup.sh scripts. Provides database, postgres-init, and postgres-cleanup binaries.
|
||||||
|
|
||||||
|
## Provided Binaries
|
||||||
|
|
||||||
|
| Binary | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `database` | Main script for managing migrations, deployments, and logs. |
|
||||||
|
| `postgres-init` | Ephemeral PostgreSQL cluster initialization and startup. |
|
||||||
|
| `postgres-cleanup` | Graceful shutdown and cleanup of the PostgreSQL cluster. |
|
||||||
|
|
||||||
|
## Required Environment Variables
|
||||||
|
|
||||||
|
These variables must be set for `db-tool` to function.
|
||||||
|
|
||||||
|
| Variable | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `LOCAL_DIR` | Absolute path to the project root directory. |
|
||||||
|
| `DB_URL` | Full PostgreSQL connection string (e.g., `postgresql://user@localhost/dbname?host=$PG_WORKING_DIR`). |
|
||||||
|
| `PG_WORKING_DIR` | Directory where the PostgreSQL cluster data and sockets are stored. |
|
||||||
|
|
||||||
|
## Optional Environment Variables
|
||||||
|
|
||||||
|
| Variable | Default Value | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `DATABASE_DIR` | `${LOCAL_DIR}/db` | Root directory for database-related files. |
|
||||||
|
| `MIGRATION_DIR` | `${DATABASE_DIR}/migration` | Directory containing SQL migration files. |
|
||||||
|
| `DATABASE_SOURCE` | `${DATABASE_DIR}/src` | Directory containing source SQL files for hydration. |
|
||||||
|
| `PG_URL_VAR` | `PGURL` | The name of the environment variable where the computed PG URL will be exported. |
|
||||||
|
| `PG_LOG_PATH` | (unset) | Path to redirect PostgreSQL server logs. |
|
||||||
|
| `PATCH_LOG` | (stdout) | Path to log the output of database patches. |
|
||||||
|
| `HYDRATE_LOG` | (stdout) | Path to log the output of database hydration. |
|
||||||
|
|
||||||
|
## pull_staging Contract
|
||||||
|
|
||||||
|
The `pull_staging` subcommand allows importing data from a remote staging environment into the local `test-data.sql` file. This functionality requires four specific environment variables to be defined:
|
||||||
|
|
||||||
|
1. `STAGING_SSH_HOST`: The SSH destination for the staging server.
|
||||||
|
2. `STAGING_DB_URL`: The PostgreSQL connection string for the remote staging database.
|
||||||
|
3. `STAGING_DUMP_TABLES`: A space-separated list of tables to include in the data dump.
|
||||||
|
4. `STAGING_DUMP_FLAGS`: Additional flags to pass to `pg_dump` (e.g., `--column-inserts`).
|
||||||
|
|
||||||
|
If any of these variables are missing when `pull_staging` is invoked, the tool will exit with code 3 and print the name of the missing variable to stderr.
|
||||||
|
|
||||||
|
## Subcommands
|
||||||
|
|
||||||
|
- `deploy`: Execute the full deployment flow (hydrate + patch). Supports `--cleanup` to teardown after success.
|
||||||
|
- `log`: Inspect database logs. Supports `list` and index-based selection.
|
||||||
|
- `test`: Execute database tests located in `${DATABASE_DIR}/test/test.sql`.
|
||||||
|
- `check`: Run a deployment validation in an isolated, temporary PostgreSQL cluster.
|
||||||
|
- `cleanup`: Stop the local database cluster and remove the `PG_WORKING_DIR`.
|
||||||
|
- `pull_staging`: Import data from the staging environment based on the env contract.
|
||||||
|
- `init`: Wrapper around `postgres-init` to start the cluster.
|
||||||
|
- `migrator`: Directly invoke the migration tool with the correct environment context.
|
||||||
|
|
||||||
|
## shellHook Example
|
||||||
|
|
||||||
|
To use `db-tool` in a Nix development shell, add the following to your `flake.nix` or `shell.nix`:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
# ...
|
||||||
|
devShells.default = pkgs.mkShell {
|
||||||
|
packages = [
|
||||||
|
pkgs.hectic.db-tool
|
||||||
|
pkgs.hectic.postgres-init
|
||||||
|
pkgs.hectic.postgres-cleanup
|
||||||
|
];
|
||||||
|
|
||||||
|
shellHook = ''
|
||||||
|
export LOCAL_DIR="$PWD"
|
||||||
|
export DATABASE_DIR="$LOCAL_DIR/db"
|
||||||
|
export MIGRATION_DIR="$DATABASE_DIR/migration"
|
||||||
|
export DATABASE_SOURCE="$DATABASE_DIR/src"
|
||||||
|
export PG_WORKING_DIR="$LOCAL_DIR/focus/postgresql"
|
||||||
|
export DB_URL="postgresql://user@localhost/dbname?host=$PG_WORKING_DIR&port=5432"
|
||||||
|
|
||||||
|
# for other non-db scripts (deploy.sh, task.sh, etc.):
|
||||||
|
export HECTIC_LIB="${pkgs.hectic.helpers.posix-shell.log}"
|
||||||
|
|
||||||
|
# Initialize and start the ephemeral database cluster
|
||||||
|
. ${pkgs.hectic.postgres-init}/bin/postgres-init
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Exit Codes
|
||||||
|
|
||||||
|
| Code | Meaning |
|
||||||
|
| --- | --- |
|
||||||
|
| 1 | Generic error. |
|
||||||
|
| 2 | Ambiguous arguments or state. |
|
||||||
|
| 3 | Missing required argument or environment variable. |
|
||||||
|
| 5 | Provided table does not exist. |
|
||||||
|
| 9 | Argument or command not found. |
|
||||||
|
| 13 | Program bug or unexpected system state. |
|
||||||
|
| 127 | Command not found (missing dependency). |
|
||||||
1539
package/db-tool/database.sh
Normal file
1539
package/db-tool/database.sh
Normal file
File diff suppressed because it is too large
Load Diff
62
package/db-tool/default.nix
Normal file
62
package/db-tool/default.nix
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
{ dash, hectic, postgresql_17, neovim, openssh, coreutils, gawk, lib }:
|
||||||
|
let
|
||||||
|
shell = "${dash}/bin/dash";
|
||||||
|
|
||||||
|
database = hectic.writeShellApplication {
|
||||||
|
inherit shell;
|
||||||
|
bashOptions = [
|
||||||
|
"errexit"
|
||||||
|
"nounset"
|
||||||
|
];
|
||||||
|
# SC2209: false positive — PAGER_OR_CAT=cat stores the string "cat" intentionally
|
||||||
|
excludeShellChecks = [ "SC2209" ];
|
||||||
|
name = "database";
|
||||||
|
runtimeInputs = [ hectic.migrator hectic.parse-uri postgresql_17 neovim openssh coreutils gawk ];
|
||||||
|
|
||||||
|
text = ''
|
||||||
|
${builtins.readFile hectic.helpers.posix-shell.log}
|
||||||
|
${builtins.readFile hectic.helpers.posix-shell.change_namespace}
|
||||||
|
${builtins.readFile hectic.helpers.posix-shell.quote}
|
||||||
|
${builtins.readFile hectic.helpers.posix-shell.pager_or_cat}
|
||||||
|
${builtins.readFile ./database.sh}
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
description = "PostgreSQL development database management";
|
||||||
|
mainProgram = "database";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
postgresInit = hectic.writeShellApplication {
|
||||||
|
inherit shell;
|
||||||
|
bashOptions = [ ];
|
||||||
|
name = "postgres-init";
|
||||||
|
runtimeInputs = [ postgresql_17 coreutils ];
|
||||||
|
|
||||||
|
text = builtins.readFile ./postgres-init.sh;
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
description = "Initialize local PostgreSQL instance";
|
||||||
|
mainProgram = "postgres-init";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
postgresCleanup = hectic.writeShellApplication {
|
||||||
|
inherit shell;
|
||||||
|
bashOptions = [ ];
|
||||||
|
name = "postgres-cleanup";
|
||||||
|
runtimeInputs = [ postgresql_17 coreutils ];
|
||||||
|
|
||||||
|
text = builtins.readFile ./postgres-cleanup.sh;
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
description = "Clean up local PostgreSQL instance";
|
||||||
|
mainProgram = "postgres-cleanup";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
"db-tool" = database;
|
||||||
|
"postgres-init" = postgresInit;
|
||||||
|
"postgres-cleanup" = postgresCleanup;
|
||||||
|
}
|
||||||
14
package/db-tool/postgres-cleanup.sh
Normal file
14
package/db-tool/postgres-cleanup.sh
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/dash
|
||||||
|
|
||||||
|
postgres_cleanup_main() {
|
||||||
|
if [ -z "${PG_WORKING_DIR:-}" ] && [ -z "${LOCAL_DIR:-}" ]; then return 0; fi
|
||||||
|
: "${PG_WORKING_DIR:=$LOCAL_DIR/focus/postgresql}"
|
||||||
|
if [ -f "${PG_WORKING_DIR}/data/postmaster.pid" ]; then
|
||||||
|
pg_ctl -D "${PG_WORKING_DIR}/data" -m fast -w stop || :
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$(basename "$0")" = 'postgres-cleanup' ]; then
|
||||||
|
postgres_cleanup_main "$@"
|
||||||
|
fi
|
||||||
49
package/db-tool/postgres-init.sh
Normal file
49
package/db-tool/postgres-init.sh
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#!/bin/dash
|
||||||
|
|
||||||
|
postgres_init_main() {
|
||||||
|
if [ -z "${PG_WORKING_DIR:-}" ] && [ -z "${LOCAL_DIR:-}" ]; then
|
||||||
|
printf '%s\n' 'postgres-init: PG_WORKING_DIR or LOCAL_DIR is required' >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
: "${PG_WORKING_DIR:=$LOCAL_DIR/focus/postgresql}"
|
||||||
|
: "${PG_PORT:=5432}"
|
||||||
|
: "${PG_DATABASE:=testdb}"
|
||||||
|
: "${PG_DISABLE_LOGGING:=0}"
|
||||||
|
[ "${PG_SHARED_PRELOAD_LIBRARIES+x}" ] || PG_SHARED_PRELOAD_LIBRARIES='pg_cron'
|
||||||
|
: "${PG_URL_VAR:=PGURL}"
|
||||||
|
|
||||||
|
mkdir -p "$PG_WORKING_DIR" || return 1
|
||||||
|
wd="$PG_WORKING_DIR"; data="$wd/data"; sockdir="$wd/sock"; db="$PG_DATABASE"
|
||||||
|
|
||||||
|
pg_ctl -D "$data" -m fast -w stop >/dev/null 2>&1 || :
|
||||||
|
mkdir -p "$sockdir" || return 1
|
||||||
|
|
||||||
|
if [ "${PG_REUSE+x}" ] && [ -f "$data/PG_VERSION" ]; then PG_REUSE=1; else PG_REUSE=0; fi
|
||||||
|
if [ "$PG_REUSE" -eq 0 ]; then
|
||||||
|
rm -rf "$data" "$sockdir" || return 1
|
||||||
|
mkdir -p "$sockdir" || return 1
|
||||||
|
initdb -D "$data" --no-locale -E UTF8 || return 1
|
||||||
|
{ printf '%s\n' "listen_addresses = ''"; [ "$PG_DISABLE_LOGGING" -eq 0 ] && { printf '%s\n' 'logging_collector = on'; printf '%s\n' "log_directory = 'log'"; }; [ -n "$PG_SHARED_PRELOAD_LIBRARIES" ] && { printf '%s\n' "shared_preload_libraries = '$PG_SHARED_PRELOAD_LIBRARIES'"; printf '%s\n' "cron.database_name = '$db'"; printf '%s\n' "cron.host = '$sockdir'"; }; :; } >> "$data/postgresql.conf" || return 1
|
||||||
|
sed -i "1ilocal all all trust" "$data/pg_hba.conf" || return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
sed -i '/^[[:space:]]*port[[:space:]]*=/d' "$data/postgresql.conf" || return 1
|
||||||
|
sed -i '/^[[:space:]]*unix_socket_directories[[:space:]]*=/d' "$data/postgresql.conf" || return 1
|
||||||
|
{ printf '%s\n' "port = $PG_PORT"; printf '%s\n' "unix_socket_directories = '$sockdir'"; } >> "$data/postgresql.conf" || return 1
|
||||||
|
pg_ctl -D "$data" -o "-F" -w start || return 2
|
||||||
|
|
||||||
|
user="$(id -un)" || return 1
|
||||||
|
if [ "$PG_REUSE" -eq 0 ]; then createdb -h "$sockdir" -U "$user" "$db" || return 1; fi
|
||||||
|
psql -h "$sockdir" -p "$PG_PORT" -d "$db" -v ON_ERROR_STOP=1 -c 'select 1;' || return 1
|
||||||
|
|
||||||
|
export POSTGRESQL_HOST="$sockdir" POSTGRESQL_PORT="$PG_PORT" POSTGRESQL_USER="$user" POSTGRESQL_DATABASE="$db"
|
||||||
|
_pg_url="postgresql://${POSTGRESQL_USER}@/${POSTGRESQL_DATABASE}?host=${POSTGRESQL_HOST}&port=${POSTGRESQL_PORT}"
|
||||||
|
case $PG_URL_VAR in ''|*[!ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_]* ) printf '%s\n' 'postgres-init: invalid PG_URL_VAR' >&2; return 1 ;; esac
|
||||||
|
export "${PG_URL_VAR}=${_pg_url}" || return 1
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$(basename "$0")" = 'postgres-init' ]; then
|
||||||
|
postgres_init_main "$@"
|
||||||
|
fi
|
||||||
@@ -107,6 +107,7 @@
|
|||||||
};
|
};
|
||||||
nativeBuildInputs = with pkgs; [pkg-config curl];
|
nativeBuildInputs = with pkgs; [pkg-config curl];
|
||||||
};
|
};
|
||||||
|
dbToolPkgs = pkgs.callPackage ./db-tool {};
|
||||||
in {
|
in {
|
||||||
py3-datetime = pkgs.callPackage ./py3-datetime.nix {};
|
py3-datetime = pkgs.callPackage ./py3-datetime.nix {};
|
||||||
py3-marzban = pkgs.callPackage ./py3-marzban.nix { inherit self; };
|
py3-marzban = pkgs.callPackage ./py3-marzban.nix { inherit self; };
|
||||||
@@ -140,6 +141,10 @@ in {
|
|||||||
shellplot = pkgs.callPackage ./shellplot {};
|
shellplot = pkgs.callPackage ./shellplot {};
|
||||||
onlinepubs2man = pkgs.callPackage ./onlinepubs2man {};
|
onlinepubs2man = pkgs.callPackage ./onlinepubs2man {};
|
||||||
migrator = pkgs.callPackage ./migrator {};
|
migrator = pkgs.callPackage ./migrator {};
|
||||||
|
"parse-uri" = pkgs.callPackage ./parse-uri {};
|
||||||
|
"db-tool" = dbToolPkgs."db-tool";
|
||||||
|
"postgres-init" = dbToolPkgs."postgres-init";
|
||||||
|
"postgres-cleanup" = dbToolPkgs."postgres-cleanup";
|
||||||
nbt2json = pkgs.callPackage ./nbt2json {};
|
nbt2json = pkgs.callPackage ./nbt2json {};
|
||||||
hemar-parser = pkgs.callPackage ./hemar/parser {};
|
hemar-parser = pkgs.callPackage ./hemar/parser {};
|
||||||
AstroTuxLauncher = pkgs.callPackage ./AstroTuxLauncher.nix {};
|
AstroTuxLauncher = pkgs.callPackage ./AstroTuxLauncher.nix {};
|
||||||
|
|||||||
29
package/parse-uri/default.nix
Normal file
29
package/parse-uri/default.nix
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{ stdenv, gcc, libpq, lib, bash }:
|
||||||
|
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
pname = "parse-uri";
|
||||||
|
version = "1.0";
|
||||||
|
|
||||||
|
src = ./.;
|
||||||
|
doCheck = false;
|
||||||
|
|
||||||
|
nativeBuildInputs = [ gcc ];
|
||||||
|
buildInputs = [ libpq ];
|
||||||
|
|
||||||
|
INCLUDES = "-I${libpq.dev}/include";
|
||||||
|
LDFLAGS = "-L${libpq.out}/lib -lpq";
|
||||||
|
|
||||||
|
buildPhase = ''
|
||||||
|
${bash}/bin/sh ./make.sh build
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p $out/bin
|
||||||
|
cp target/parse-uri $out/bin/
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
description = "parse-uri";
|
||||||
|
license = lib.licenses.mit;
|
||||||
|
};
|
||||||
|
}
|
||||||
32
package/parse-uri/main.c
Normal file
32
package/parse-uri/main.c
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <libpq-fe.h>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
if (argc != 2) {
|
||||||
|
printf("only 1 argument allow, please provide uri\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
const char *conninfo = argv[1];
|
||||||
|
char *errmsg = NULL;
|
||||||
|
|
||||||
|
PQconninfoOption *options = PQconninfoParse(conninfo, &errmsg);
|
||||||
|
if (!options) {
|
||||||
|
printf("Parse failed: %s\n", errmsg);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (PQconninfoOption *opt = options; opt->keyword != NULL; opt++) {
|
||||||
|
char upper[128];
|
||||||
|
size_t i = 0;
|
||||||
|
for (; opt->keyword[i] != '\0' && i < sizeof(upper)-1; i++)
|
||||||
|
upper[i] = toupper((unsigned char)opt->keyword[i]);
|
||||||
|
upper[i] = '\0';
|
||||||
|
|
||||||
|
printf("URI_%s=%s\n", upper, opt->val ? opt->val : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
PQconninfoFree(options);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
41
package/parse-uri/make.sh
Normal file
41
package/parse-uri/make.sh
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Usage: make.sh [build|check] [--norun] [--debug] [--color]
|
||||||
|
|
||||||
|
PACKAGE_NAME="parse-uri"
|
||||||
|
|
||||||
|
check_dependencies() {
|
||||||
|
for dep in cc; do
|
||||||
|
if ! command -v "$dep" >/dev/null 2>&1; then
|
||||||
|
echo "Error: Required dependency '$dep' not found." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
check_dependencies
|
||||||
|
|
||||||
|
# Default flags
|
||||||
|
OPTFLAGS="-O2"
|
||||||
|
CFLAGS="-Wall -Wextra -Werror -pedantic"
|
||||||
|
STD_FLAGS="-std=c99"
|
||||||
|
|
||||||
|
MODE="${1:-build}"
|
||||||
|
shift
|
||||||
|
|
||||||
|
build() {
|
||||||
|
mkdir -p target
|
||||||
|
echo "# Build $PACKAGE_NAME"
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
cc $CFLAGS $OPTFLAGS $STD_FLAGS main.c -o "target/$PACKAGE_NAME" $LDFLAGS $INCLUDES
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$MODE" in
|
||||||
|
build)
|
||||||
|
build
|
||||||
|
;;
|
||||||
|
check)
|
||||||
|
echo "No tests to run"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
82
test/package/db-tool/default.nix
Normal file
82
test/package/db-tool/default.nix
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
{ inputs, self, pkgs, system, ... }: let
|
||||||
|
lib = inputs.nixpkgs.lib;
|
||||||
|
|
||||||
|
# turn anything under test directory into a derivation that exposes $out/run.sh
|
||||||
|
mkTestDrv = folder: name: type:
|
||||||
|
if type == "directory" then
|
||||||
|
pkgs.runCommand "test-${name}" {} ''
|
||||||
|
if ! [ -f ${"${folder}/${name}/run.sh"} ]; then
|
||||||
|
echo no run.sh in test/${name}
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$out"
|
||||||
|
cp -r ${"${folder}/${name}"}/* "$out/"
|
||||||
|
chmod +x "$out/run.sh"
|
||||||
|
''
|
||||||
|
else if lib.hasSuffix ".sh" name then
|
||||||
|
pkgs.runCommand "test-${lib.removeSuffix ".sh" name}" {} ''
|
||||||
|
mkdir -p "$out"
|
||||||
|
install -Dm755 ${"${folder}/${name}"} "$out/run.sh"
|
||||||
|
''
|
||||||
|
else
|
||||||
|
null;
|
||||||
|
|
||||||
|
testDir = folder: builtins.readDir folder;
|
||||||
|
|
||||||
|
# attrset: testName -> drv with run.sh
|
||||||
|
testDrvs = folder:
|
||||||
|
lib.mapAttrs' (n: v:
|
||||||
|
lib.nameValuePair (lib.removeSuffix ".sh" n) v
|
||||||
|
) (lib.filterAttrs (_: v: v != null)
|
||||||
|
(lib.mapAttrs (n: t: mkTestDrv folder n t) (testDir folder)));
|
||||||
|
|
||||||
|
database = self.packages.${system}."db-tool";
|
||||||
|
postgresInit = self.packages.${system}."postgres-init";
|
||||||
|
postgresCleanup = self.packages.${system}."postgres-cleanup";
|
||||||
|
|
||||||
|
# Non-postgres tests: .sh files at ./test/ (excluding postgresql/ subdir)
|
||||||
|
nonPgTestDrvs =
|
||||||
|
lib.mapAttrs' (n: v: lib.nameValuePair (lib.removeSuffix ".sh" n) v)
|
||||||
|
(lib.filterAttrs (_: v: v != null)
|
||||||
|
(lib.mapAttrs (n: t: mkTestDrv ./test n t)
|
||||||
|
(lib.filterAttrs (n: _: n != "postgresql") (testDir ./test))));
|
||||||
|
|
||||||
|
# Postgres tests: subdirs at ./test/postgresql/
|
||||||
|
pgTestDrvs = testDrvs ./test/postgresql;
|
||||||
|
|
||||||
|
mkNonPgTest = testName: testDrv: pkgs.runCommand "db-tool-${testName}"
|
||||||
|
{
|
||||||
|
nativeBuildInputs = [ pkgs.coreutils pkgs.gnugrep pkgs.gnused ];
|
||||||
|
buildInputs = [ database postgresInit postgresCleanup pkgs.postgresql_17 pkgs.dash ];
|
||||||
|
} ''
|
||||||
|
${builtins.readFile self.legacyPackages.${system}.helpers.posix-shell.log}
|
||||||
|
test=${testDrv}
|
||||||
|
export HECTIC_LOG=trace
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
. "$test/run.sh"
|
||||||
|
|
||||||
|
mkdir -p "$out"
|
||||||
|
'';
|
||||||
|
|
||||||
|
mkPgTest = testName: testDrv: pkgs.runCommand "db-tool-${testName}"
|
||||||
|
{
|
||||||
|
nativeBuildInputs = [ pkgs.coreutils pkgs.gnugrep pkgs.gnused ];
|
||||||
|
buildInputs = [ database postgresInit postgresCleanup pkgs.postgresql_17 pkgs.dash pkgs.netcat-openbsd ];
|
||||||
|
} ''
|
||||||
|
${builtins.readFile self.legacyPackages.${system}.helpers.posix-shell.log}
|
||||||
|
test=${testDrv}
|
||||||
|
export HECTIC_LOG=trace
|
||||||
|
set -eu
|
||||||
|
${builtins.readFile ./postgresql/_lib.sh}
|
||||||
|
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
. "$test/run.sh"
|
||||||
|
|
||||||
|
mkdir -p "$out"
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
(lib.mapAttrs (name: drv: mkNonPgTest name drv) nonPgTestDrvs) //
|
||||||
|
(lib.mapAttrs (name: drv: mkPgTest name drv) pgTestDrvs)
|
||||||
147
test/package/db-tool/postgresql/_lib.sh
Normal file
147
test/package/db-tool/postgresql/_lib.sh
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
# shellcheck shell=dash
|
||||||
|
# Shared PostgreSQL harness for db-tool tests.
|
||||||
|
|
||||||
|
pg_harness__start_busy_socket() {
|
||||||
|
pg_harness_socket_dir="$1"
|
||||||
|
PG_HARNESS_BUSY_SOCKET_PATH="$pg_harness_socket_dir/.s.PGSQL.5432"
|
||||||
|
export PG_HARNESS_BUSY_SOCKET_PATH
|
||||||
|
|
||||||
|
rm -f "$PG_HARNESS_BUSY_SOCKET_PATH"
|
||||||
|
nc -l -U "$PG_HARNESS_BUSY_SOCKET_PATH" >/dev/null 2>&1 &
|
||||||
|
PG_HARNESS_BUSY_SOCKET_PID=$!
|
||||||
|
export PG_HARNESS_BUSY_SOCKET_PID
|
||||||
|
}
|
||||||
|
|
||||||
|
pg_harness_start() {
|
||||||
|
pg_harness_tmp_root="${TMPDIR:-/tmp}"
|
||||||
|
|
||||||
|
if [ "${PG_HARNESS_PGDATA_OVERRIDE+x}" ]; then
|
||||||
|
pgdata_dir="$PG_HARNESS_PGDATA_OVERRIDE"
|
||||||
|
else
|
||||||
|
pgdata_dir=$(mktemp -d "$pg_harness_tmp_root/pgdata_XXXXXX")
|
||||||
|
fi
|
||||||
|
|
||||||
|
PGDATA="$pgdata_dir"
|
||||||
|
export PGDATA
|
||||||
|
|
||||||
|
trap 'pg_harness_stop' EXIT INT TERM
|
||||||
|
|
||||||
|
if ! initdb -D "$pgdata_dir" --no-locale --encoding=UTF8 -U postgres >/dev/null 2>&1; then
|
||||||
|
pg_harness_stop
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${PG_HARNESS_INJECT_BUSY_SOCKET+x}" ] && ! [ "${PG_HARNESS_BUSY_SOCKET_PID+x}" ]; then
|
||||||
|
pg_harness__start_busy_socket "$pgdata_dir"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! pg_ctl start -D "$pgdata_dir" -o "-k $pgdata_dir -h ''" >/dev/null 2>&1; then
|
||||||
|
pg_harness_stop
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
PGHOST="$pgdata_dir"
|
||||||
|
PGPORT=""
|
||||||
|
PGUSER="postgres"
|
||||||
|
PGDATABASE="postgres"
|
||||||
|
export PGHOST PGPORT PGUSER PGDATABASE
|
||||||
|
|
||||||
|
POSTGRESQL_HOST="$PGHOST"
|
||||||
|
POSTGRESQL_PORT="$PGPORT"
|
||||||
|
POSTGRESQL_USER="$PGUSER"
|
||||||
|
POSTGRESQL_DATABASE="$PGDATABASE"
|
||||||
|
PGURL="postgresql://postgres@localhost/postgres?host=$pgdata_dir"
|
||||||
|
export POSTGRESQL_HOST POSTGRESQL_PORT POSTGRESQL_USER POSTGRESQL_DATABASE PGURL
|
||||||
|
|
||||||
|
pg_harness_ready=
|
||||||
|
pg_harness_attempt=0
|
||||||
|
while [ "$pg_harness_attempt" -lt 10 ]; do
|
||||||
|
if pg_isready -h "$pgdata_dir" >/dev/null 2>&1; then
|
||||||
|
pg_harness_ready=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
sleep 0.5
|
||||||
|
pg_harness_attempt=$((pg_harness_attempt + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
if ! [ "$pg_harness_ready" = 1 ]; then
|
||||||
|
pg_harness_stop
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
pg_harness_stop() {
|
||||||
|
trap - EXIT INT TERM
|
||||||
|
|
||||||
|
if [ "${PG_HARNESS_BUSY_SOCKET_PID+x}" ]; then
|
||||||
|
kill "$PG_HARNESS_BUSY_SOCKET_PID" >/dev/null 2>&1 || true
|
||||||
|
wait "$PG_HARNESS_BUSY_SOCKET_PID" >/dev/null 2>&1 || true
|
||||||
|
unset PG_HARNESS_BUSY_SOCKET_PID
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${PG_HARNESS_BUSY_SOCKET_PATH+x}" ] && [ -n "$PG_HARNESS_BUSY_SOCKET_PATH" ]; then
|
||||||
|
rm -f "$PG_HARNESS_BUSY_SOCKET_PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${PGDATA+x}" ] && [ -n "$PGDATA" ]; then
|
||||||
|
pg_ctl stop -D "$PGDATA" -m fast >/dev/null 2>&1 || true
|
||||||
|
rm -rf "$PGDATA"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${PG_HARNESS_PGDATA_OVERRIDE+x}" ] && [ -n "$PG_HARNESS_PGDATA_OVERRIDE" ]; then
|
||||||
|
if ! [ "${PGDATA+x}" ] || [ "$PG_HARNESS_PGDATA_OVERRIDE" != "$PGDATA" ]; then
|
||||||
|
rm -rf "$PG_HARNESS_PGDATA_OVERRIDE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${PG_HARNESS_CORRUPT_PATH+x}" ] && [ -n "$PG_HARNESS_CORRUPT_PATH" ]; then
|
||||||
|
rm -f "$PG_HARNESS_CORRUPT_PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
unset PG_HARNESS_BUSY_SOCKET_PATH
|
||||||
|
unset PG_HARNESS_CORRUPT_PATH
|
||||||
|
unset PG_HARNESS_INJECT_BUSY_SOCKET
|
||||||
|
unset PG_HARNESS_PGDATA_OVERRIDE
|
||||||
|
unset PGHOST PGPORT PGUSER PGDATABASE PGDATA
|
||||||
|
unset POSTGRESQL_HOST POSTGRESQL_PORT POSTGRESQL_USER POSTGRESQL_DATABASE PGURL
|
||||||
|
}
|
||||||
|
|
||||||
|
pg_harness_start_corrupt_dir() {
|
||||||
|
pg_harness_tmp_root="${TMPDIR:-/tmp}"
|
||||||
|
PG_HARNESS_PGDATA_OVERRIDE=$(mktemp "$pg_harness_tmp_root/pgdata_corrupt_XXXXXX")
|
||||||
|
: > "$PG_HARNESS_PGDATA_OVERRIDE"
|
||||||
|
PG_HARNESS_CORRUPT_PATH="$PG_HARNESS_PGDATA_OVERRIDE"
|
||||||
|
export PG_HARNESS_PGDATA_OVERRIDE PG_HARNESS_CORRUPT_PATH
|
||||||
|
}
|
||||||
|
|
||||||
|
pg_harness_busy_socket() {
|
||||||
|
pg_harness_tmp_root="${TMPDIR:-/tmp}"
|
||||||
|
PG_HARNESS_INJECT_BUSY_SOCKET=1
|
||||||
|
export PG_HARNESS_INJECT_BUSY_SOCKET
|
||||||
|
|
||||||
|
if [ "${PGDATA+x}" ] && [ -d "$PGDATA" ]; then
|
||||||
|
pg_harness_socket_dir="$PGDATA"
|
||||||
|
else
|
||||||
|
if [ "${PG_HARNESS_PGDATA_OVERRIDE+x}" ]; then
|
||||||
|
pg_harness_socket_dir="$PG_HARNESS_PGDATA_OVERRIDE"
|
||||||
|
else
|
||||||
|
pg_harness_socket_dir=$(mktemp -d "$pg_harness_tmp_root/pgdata_busy_XXXXXX")
|
||||||
|
PG_HARNESS_PGDATA_OVERRIDE="$pg_harness_socket_dir"
|
||||||
|
export PG_HARNESS_PGDATA_OVERRIDE
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${PGDATA+x}" ] && [ -d "$PGDATA" ] && ! [ "${PG_HARNESS_BUSY_SOCKET_PID+x}" ]; then
|
||||||
|
pg_harness__start_busy_socket "$pg_harness_socket_dir"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
pg_harness_kill_postmaster() {
|
||||||
|
if ! [ "${PGDATA+x}" ] || ! [ -f "$PGDATA/postmaster.pid" ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
IFS= read -r pg_harness_postmaster_pid < "$PGDATA/postmaster.pid" || return 1
|
||||||
|
kill -KILL "$pg_harness_postmaster_pid"
|
||||||
|
}
|
||||||
19
test/package/db-tool/test/help.sh
Normal file
19
test/package/db-tool/test/help.sh
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# shellcheck shell=dash
|
||||||
|
|
||||||
|
HECTIC_NAMESPACE=test-db-tool-help
|
||||||
|
|
||||||
|
log notice "test case: database --help exits 0"
|
||||||
|
if ! database --help > /tmp/help-out.txt 2>&1; then
|
||||||
|
log error "test failed: database --help exited non-zero"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
for tok in deploy pull_staging cleanup check log init migrator; do
|
||||||
|
if ! grep -qF "$tok" /tmp/help-out.txt; then
|
||||||
|
log error "test failed: --help output missing token: $tok"
|
||||||
|
cat /tmp/help-out.txt >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
log notice "test passed"
|
||||||
19
test/package/db-tool/test/missing-database-dir.sh
Normal file
19
test/package/db-tool/test/missing-database-dir.sh
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# shellcheck shell=dash
|
||||||
|
|
||||||
|
HECTIC_NAMESPACE=test-db-tool-missing-dir
|
||||||
|
|
||||||
|
export PGURL=""
|
||||||
|
unset LOCAL_DIR DATABASE_DIR DB_URL 2>/dev/null || true
|
||||||
|
|
||||||
|
log notice "test case: database deploy fails without LOCAL_DIR"
|
||||||
|
set +e
|
||||||
|
database deploy 2>/tmp/missing-err.txt
|
||||||
|
code=$?
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ "$code" = 0 ]; then
|
||||||
|
log error "test failed: database deploy exited 0 without LOCAL_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log notice "test passed: exited $code"
|
||||||
19
test/package/db-tool/test/postgresql/deploy-basic/run.sh
Normal file
19
test/package/db-tool/test/postgresql/deploy-basic/run.sh
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# shellcheck shell=dash
|
||||||
|
|
||||||
|
HECTIC_NAMESPACE=test-db-tool-deploy-basic
|
||||||
|
|
||||||
|
pg_harness_start
|
||||||
|
|
||||||
|
LOCAL_DIR=$(mktemp -d)
|
||||||
|
export LOCAL_DIR
|
||||||
|
mkdir -p "$LOCAL_DIR/devshell"
|
||||||
|
printf '#!/bin/dash\nexit 0\n' > "$LOCAL_DIR/devshell/postgres-init.sh"
|
||||||
|
chmod +x "$LOCAL_DIR/devshell/postgres-init.sh"
|
||||||
|
|
||||||
|
log notice "test case: database deploy --no-hydrate --no-patch exits 0"
|
||||||
|
if ! database deploy --no-hydrate --no-patch; then
|
||||||
|
log error "database deploy failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log notice "test passed"
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# shellcheck shell=dash
|
||||||
|
|
||||||
|
HECTIC_NAMESPACE=test-db-tool-deploy-cleanup-flag
|
||||||
|
|
||||||
|
pg_harness_start
|
||||||
|
|
||||||
|
LOCAL_DIR=$(mktemp -d)
|
||||||
|
export LOCAL_DIR
|
||||||
|
mkdir -p "$LOCAL_DIR/devshell"
|
||||||
|
printf '#!/bin/dash\nexit 0\n' > "$LOCAL_DIR/devshell/postgres-init.sh"
|
||||||
|
printf '#!/bin/dash\nexit 0\n' > "$LOCAL_DIR/devshell/postgres-cleanup.sh"
|
||||||
|
chmod +x "$LOCAL_DIR/devshell/postgres-init.sh" "$LOCAL_DIR/devshell/postgres-cleanup.sh"
|
||||||
|
|
||||||
|
log notice "test case: database deploy --no-hydrate --no-patch --cleanup exits 0"
|
||||||
|
if ! database deploy --no-hydrate --no-patch --cleanup; then
|
||||||
|
log error "database deploy --cleanup failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log notice "test passed"
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# shellcheck shell=dash
|
||||||
|
|
||||||
|
HECTIC_NAMESPACE=test-db-tool-init-cleanup-roundtrip
|
||||||
|
|
||||||
|
PG_WORKING_DIR=$(mktemp -d)
|
||||||
|
export PG_WORKING_DIR PG_DATABASE=testdb PG_PORT=5432 PG_SHARED_PRELOAD_LIBRARIES=''
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
postgres-cleanup
|
||||||
|
rm -rf "$PG_WORKING_DIR"
|
||||||
|
}
|
||||||
|
trap 'cleanup' EXIT INT TERM
|
||||||
|
|
||||||
|
log notice "test case: postgres-init starts cluster"
|
||||||
|
if ! postgres-init; then
|
||||||
|
log error "postgres-init failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
pgurl="postgresql://$(id -un)@/testdb?host=${PG_WORKING_DIR}/sock&port=5432"
|
||||||
|
log notice "verifying connection"
|
||||||
|
if ! psql "$pgurl" -c 'SELECT 1;' >/dev/null 2>&1; then
|
||||||
|
log error "connection failed after postgres-init"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log notice "test case: postgres-cleanup stops cluster"
|
||||||
|
postgres-cleanup
|
||||||
|
|
||||||
|
log notice "verifying cluster stopped"
|
||||||
|
if pg_isready -h "${PG_WORKING_DIR}/sock" -p 5432 >/dev/null 2>&1; then
|
||||||
|
log error "postgres still running after cleanup"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log notice "test passed"
|
||||||
18
test/package/db-tool/test/postgresql/log-subcommand/run.sh
Normal file
18
test/package/db-tool/test/postgresql/log-subcommand/run.sh
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# shellcheck shell=dash
|
||||||
|
|
||||||
|
HECTIC_NAMESPACE=test-db-tool-log-subcommand
|
||||||
|
|
||||||
|
PG_WORKING_DIR=$(mktemp -d)
|
||||||
|
LOCAL_DIR=$(mktemp -d)
|
||||||
|
export PG_WORKING_DIR LOCAL_DIR PGURL='postgresql://localhost/db'
|
||||||
|
mkdir -p "$PG_WORKING_DIR/data/log"
|
||||||
|
|
||||||
|
trap 'rm -rf "$PG_WORKING_DIR" "$LOCAL_DIR"' EXIT INT TERM
|
||||||
|
|
||||||
|
log notice "test case: database log list exits 0 with empty log dir"
|
||||||
|
if ! database log list; then
|
||||||
|
log error "database log list failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log notice "test passed"
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# shellcheck shell=dash
|
||||||
|
|
||||||
|
HECTIC_NAMESPACE=test-db-tool-postgres-cleanup-stale-pidfile
|
||||||
|
|
||||||
|
PG_WORKING_DIR=$(mktemp -d)
|
||||||
|
export PG_WORKING_DIR
|
||||||
|
|
||||||
|
mkdir -p "$PG_WORKING_DIR/data"
|
||||||
|
printf '99999999\n' > "$PG_WORKING_DIR/data/postmaster.pid"
|
||||||
|
|
||||||
|
trap 'rm -rf "$PG_WORKING_DIR"' EXIT INT TERM
|
||||||
|
|
||||||
|
log notice "test case: postgres-cleanup exits 0 with stale pidfile"
|
||||||
|
if ! postgres-cleanup; then
|
||||||
|
log error "postgres-cleanup failed with stale pidfile"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log notice "test passed"
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
# shellcheck shell=dash
|
||||||
|
|
||||||
|
HECTIC_NAMESPACE=test-db-tool-postgres-init-busy-socket
|
||||||
|
|
||||||
|
PG_WORKING_DIR=$(mktemp -d)
|
||||||
|
export PG_WORKING_DIR PG_DATABASE=testdb PG_PORT=5432 PG_SHARED_PRELOAD_LIBRARIES=''
|
||||||
|
|
||||||
|
trap 'pg_harness_stop; rm -rf "$PG_WORKING_DIR"' EXIT INT TERM
|
||||||
|
|
||||||
|
log notice "setup: creating initial postgres cluster"
|
||||||
|
if ! postgres-init; then
|
||||||
|
log error "setup failed: initial postgres-init failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log notice "setup: stopping postgres to free socket"
|
||||||
|
postgres-cleanup
|
||||||
|
|
||||||
|
log notice "setup: occupying socket with netcat"
|
||||||
|
pg_harness__start_busy_socket "$PG_WORKING_DIR/sock"
|
||||||
|
i=0
|
||||||
|
while [ "$i" -lt 50 ] && ! [ -S "$PG_HARNESS_BUSY_SOCKET_PATH" ]; do
|
||||||
|
sleep 0.1
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
[ -S "$PG_HARNESS_BUSY_SOCKET_PATH" ] || { log error "busy socket not ready"; exit 1; }
|
||||||
|
printf '%d\n' "$PG_HARNESS_BUSY_SOCKET_PID" > "${PG_HARNESS_BUSY_SOCKET_PATH}.lock"
|
||||||
|
|
||||||
|
log notice "test case: postgres-init fails when socket is pre-occupied"
|
||||||
|
PG_REUSE=1
|
||||||
|
export PG_REUSE
|
||||||
|
set +e
|
||||||
|
postgres-init
|
||||||
|
code=$?
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ "$code" = 0 ]; then
|
||||||
|
log error "test failed: postgres-init exited 0 with busy socket"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log notice "test passed: exited $code"
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# shellcheck shell=dash
|
||||||
|
|
||||||
|
HECTIC_NAMESPACE=test-db-tool-postgres-init-corrupt-pgdata
|
||||||
|
|
||||||
|
pg_harness_start_corrupt_dir
|
||||||
|
|
||||||
|
export PG_WORKING_DIR="$PG_HARNESS_PGDATA_OVERRIDE"
|
||||||
|
export PG_SHARED_PRELOAD_LIBRARIES=''
|
||||||
|
|
||||||
|
trap 'pg_harness_stop' EXIT INT TERM
|
||||||
|
|
||||||
|
log notice "test case: postgres-init fails when PG_WORKING_DIR is a regular file"
|
||||||
|
set +e
|
||||||
|
postgres-init
|
||||||
|
code=$?
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ "$code" = 0 ]; then
|
||||||
|
log error "test failed: postgres-init exited 0 with corrupt dir"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log notice "test passed: exited $code"
|
||||||
26
test/package/db-tool/test/pull-staging-no-env.sh
Normal file
26
test/package/db-tool/test/pull-staging-no-env.sh
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# shellcheck shell=dash
|
||||||
|
|
||||||
|
HECTIC_NAMESPACE=test-db-tool-pull-staging
|
||||||
|
|
||||||
|
export PGURL=""
|
||||||
|
unset STAGING_SSH_HOST STAGING_DB_URL STAGING_USER STAGING_HOST 2>/dev/null || true
|
||||||
|
|
||||||
|
log notice "test case: database pull_staging exits 3 without STAGING_SSH_HOST"
|
||||||
|
set +e
|
||||||
|
database pull_staging 2>/build/staging-err.txt
|
||||||
|
code=$?
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ "$code" != 3 ]; then
|
||||||
|
log error "test failed: expected exit 3, got $code"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! grep -q 'STAGING_SSH_HOST' /build/staging-err.txt; then
|
||||||
|
log error "test failed: stderr does not mention STAGING_SSH_HOST"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log notice "test passed"
|
||||||
|
|
||||||
|
log notice "test passed"
|
||||||
16
test/package/db-tool/test/unknown-subcommand.sh
Normal file
16
test/package/db-tool/test/unknown-subcommand.sh
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# shellcheck shell=dash
|
||||||
|
|
||||||
|
HECTIC_NAMESPACE=test-db-tool-unknown
|
||||||
|
|
||||||
|
log notice "test case: database nonsense exits non-zero (expected 1)"
|
||||||
|
set +e
|
||||||
|
database nonsense 2>/dev/null
|
||||||
|
code=$?
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ "$code" = 0 ]; then
|
||||||
|
log error "test failed: database nonsense exited 0 (should be non-zero)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log notice "test passed: exited $code"
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
{ system, inputs, self, pkgs }:
|
{ system, inputs, self, pkgs }:
|
||||||
(import ./migrator { inherit system inputs self pkgs; }) //
|
(import ./migrator { inherit system inputs self pkgs; }) //
|
||||||
(import ./hemar { inherit system inputs self pkgs; }) //
|
(import ./hemar { inherit system inputs self pkgs; }) //
|
||||||
(import (./. + "/sentinèlla") { inherit system inputs self pkgs; })
|
(import (./. + "/sentinèlla") { inherit system inputs self pkgs; }) //
|
||||||
|
(import ./db-tool { inherit system inputs self pkgs; })
|
||||||
|
|||||||
Reference in New Issue
Block a user