mirror of
https://github.com/kellymichels/zscripts-token-savers
synced 2026-10-07 07:18:18 +00:00
* test: add bats suite for the bash port + fix underscore-key guard (phase 5) Part of #26. Closes #30. The bash port reimplements the exclude lists, config accessors and argument parsing, so it can drift from PowerShell independently. 50 bats tests mirror the Pester suites assertion-for-assertion where the two are meant to agree: z_archive_excludes (per-kind lists and the deploy-vs-backup gating), config accessors, z_path Windows->WSL translation, json_build_label, and argument handling (bare invocation, unknown key, 'all' expansion, --port override). Fixes #30 along the way, because the alternative was a test enshrining the bug: zproj_require accepted underscore comment keys. It only checked the key was non-null, and a comment is a non-null JSON string, so 'zkill _note' sailed through and exited 0 having done nothing - the silent-success failure mode. Now rejects any _-prefixed key and requires the value to be a JSON object. Both checks earn their place: the type check catches string comments, the prefix rule catches an object-valued _template key that PowerShell refuses and the type check alone would allow. Documents #31 rather than fixing it: a leading dash on a project key works in every PowerShell script but only in bash/zdeploy - the others reject -myapp as an unknown option. Stripping it everywhere would make a mistyped flag resolve as a project key, so the tests pin current behaviour and bash/README.md now states the difference instead of the README's blanket claim. Verified by mutation testing: all 9 mutations turn the suite red - removing the python and vite backup gates, reintroducing #23 in bash, unfiltering underscore keys in zproj_keys and zproj_require, breaking zremote_compose_dir fallback and z_path translation, and removing zkill's all-expansion and no-args guard. Both mutated files confirmed restored byte-for-byte. An early run also caught a bug in the tests themselves: the membership helper used 'grep -qx' (regex), so the needle '.env' matched 'venv' and several 'excludes .env' assertions were false passes. Now uses -qxF. * fix(gitattributes): keep .bats files LF so 'bats tests/bash' works on a Windows checkout The LF rule was scoped to 'bash/**', which does not match tests/bash/. With core.autocrlf a Windows working copy got CRLF .bats files, and bats fails on them - so the command the README documents would not run on the machine the suite was written on without stripping \r first. Adds tests/bash/** and *.bats to the same eol=lf rule and renormalises. Verified by running 'bats tests/bash' with no sed preprocessing: 50/50.
This commit is contained in:
parent
0ec4774740
commit
37a703ce19
6
.gitattributes
vendored
6
.gitattributes
vendored
@ -1,6 +1,12 @@
|
||||
# Bash scripts must stay LF — CRLF breaks the shebang on Linux/macOS/WSL.
|
||||
bash/** text eol=lf
|
||||
|
||||
# The bats suites are bash too, and they live outside bash/ — without this a
|
||||
# Windows checkout gets CRLF and `bats tests/bash` fails there (including when
|
||||
# run through WSL against the Windows working copy).
|
||||
tests/bash/** text eol=lf
|
||||
*.bats text eol=lf
|
||||
|
||||
# PowerShell/cmd are happiest with CRLF on Windows.
|
||||
*.ps1 text eol=crlf
|
||||
*.cmd text eol=crlf
|
||||
|
||||
@ -79,9 +79,29 @@ Where it's written, first match wins:
|
||||
Set `ZTOKENS_MODEL` to tag records with a specific model; it defaults to
|
||||
`est. chars/3.5`.
|
||||
|
||||
## Tests
|
||||
|
||||
The bash port has its own [bats](https://github.com/bats-core/bats-core) suite, mirroring the PowerShell Pester tests assertion-for-assertion where the two are meant to agree — the exclude lists, config accessors, `z_path` translation, and argument handling:
|
||||
|
||||
```bash
|
||||
bats tests/bash
|
||||
```
|
||||
|
||||
Install bats without root:
|
||||
|
||||
```bash
|
||||
git clone --depth 1 https://github.com/bats-core/bats-core.git /tmp/bats-core
|
||||
/tmp/bats-core/install.sh ~/.local # then ensure ~/.local/bin is on PATH
|
||||
```
|
||||
|
||||
A fixture config is injected through `ZCONFIG`, so the suite never reads your real `zconfig.json` and passes on a machine that has never been configured. Tests that run the scripts stay on paths that exit before doing any work; only `zkill` runs with a real target, against deliberately unused ports.
|
||||
|
||||
Why a separate suite: the bash port reimplements the exclude lists and argument parsing, so it can drift from the PowerShell side independently. Both suites assert the same deploy-vs-backup rule — **deploys drop `.env*` and `uploads/`, backups keep them** — because that one has broken in production.
|
||||
|
||||
## Differences from the PowerShell versions
|
||||
|
||||
- `zsync <viteproject>` mirrors `dist/` with `rsync -a --delete` (robocopy /MIR equivalent).
|
||||
- Scheduling uses cron (`setup_backup_schedule`) instead of Windows Task Scheduler.
|
||||
- The MOTD banner picks a random `motd/*.txt` instead of tracking a shuffle rotation.
|
||||
- Windows-only helpers (`.cmd` launchers) don't exist — scripts are directly executable.
|
||||
- **A leading dash on a project key is only tolerated by `zdeploy`.** PowerShell accepts `-myapp` anywhere; in bash every other script treats `-myapp` as an unknown option and exits 1. Tracked as a parity gap — use bare keys in the bash port.
|
||||
|
||||
@ -81,7 +81,14 @@ zproj() { jq -r --arg k "$1" ".projects[\$k]$2 // empty" "$ZCONFIG"; }
|
||||
# A project's local root, translated to the host's native path form.
|
||||
zproj_root() { z_path "$(zproj "$1" .localRoot)"; }
|
||||
zproj_require() {
|
||||
if [ "$(jq -r --arg k "$1" '(.projects[$k] != null)' "$ZCONFIG")" != "true" ]; then
|
||||
# Keys starting with "_" are comments, not projects (zproj_keys already skips
|
||||
# them). Reject them here too, or `zkill _comment` would sail past this guard
|
||||
# on the mere existence of the key and then act on a string as if it were a
|
||||
# project - PowerShell's Get-ZProject has always refused them.
|
||||
case "$1" in
|
||||
_*) err "Unknown project key '$1'. Available: $(zproj_csv)"; exit 1 ;;
|
||||
esac
|
||||
if [ "$(jq -r --arg k "$1" '(.projects[$k] | type) == "object"' "$ZCONFIG")" != "true" ]; then
|
||||
err "Unknown project key '$1'. Available: $(zproj_csv)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
232
tests/bash/args.bats
Normal file
232
tests/bash/args.bats
Normal file
@ -0,0 +1,232 @@
|
||||
#!/usr/bin/env bats
|
||||
# Evomedia.net Token Savers - https://github.com/kellymichels/zscripts-token-savers
|
||||
# Created by Kelly Michels - dev@evomedia.net
|
||||
# Licensed under the MIT License. See LICENSE.
|
||||
#
|
||||
# args.bats - how the bash scripts read their target arguments.
|
||||
#
|
||||
# bats tests/bash
|
||||
#
|
||||
# Mirrors tests/ArgumentParsing.Tests.ps1. Same safety rule as the PowerShell
|
||||
# side: these run the real scripts, so they stay on code paths that exit BEFORE
|
||||
# doing any work (no args, unknown key). Only zkill runs with a valid target,
|
||||
# and only because the fixture's dev ports are deliberately unused and its
|
||||
# localRoots do not exist - it finds no listeners and kills nothing. zdeploy,
|
||||
# zbackup_ec2, zec2, zec2online, zrepair, zstop, zstart and zbackup are never
|
||||
# invoked with a real target; that needs a disposable server.
|
||||
|
||||
setup() {
|
||||
REPO="$(cd "$(dirname "$BATS_TEST_FILENAME")/../.." && pwd)"
|
||||
BASHDIR="$REPO/bash"
|
||||
export ZCONFIG="$BATS_TEST_TMPDIR/zconfig.json"
|
||||
cat > "$ZCONFIG" <<'JSON'
|
||||
{
|
||||
"ec2": { "ip": "203.0.113.10", "user": "testuser", "pemKey": "/fixtures/test.pem", "stackRoot": "/home/testuser/stack" },
|
||||
"paths": { "temp": "/fixtures/temp", "backupsLocal": "/fixtures/backups", "backupsEc2": "/fixtures/backups-ec2", "scriptsRoot": "/fixtures/zscripts", "oneDriveBackups": "" },
|
||||
"projects": {
|
||||
"_note": "comment key - must never be treated as a project",
|
||||
"pyapp": {
|
||||
"label": "Fixture Python App", "kind": "python", "localRoot": "/fixtures/nonexistent-pyapp",
|
||||
"startModule": "pyapp.main", "ports": { "dev": 59990 },
|
||||
"remote": { "path": "/home/testuser/stack/pyapp" }
|
||||
},
|
||||
"viteapp": {
|
||||
"label": "Fixture Vite Site", "kind": "vite", "localRoot": "/fixtures/nonexistent-viteapp",
|
||||
"ports": { "dev": 59991 }, "remote": { "path": "/home/testuser/stack/viteapp" }
|
||||
},
|
||||
"edgeproxy": {
|
||||
"label": "Fixture Edge", "kind": "edge", "localRoot": "/fixtures/nonexistent-edge",
|
||||
"remote": { "path": "/home/testuser/stack/edge" }
|
||||
}
|
||||
}
|
||||
}
|
||||
JSON
|
||||
}
|
||||
|
||||
# ---- no arguments -----------------------------------------------------------
|
||||
# Running bare must never mean "do it to everything".
|
||||
|
||||
@test "zkill with no args shows usage and exits 1" {
|
||||
run "$BASHDIR/zkill"
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"Usage"* ]]
|
||||
}
|
||||
|
||||
@test "zstart with no args shows usage and exits non-zero" {
|
||||
run "$BASHDIR/zstart"
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"Usage"* ]]
|
||||
}
|
||||
|
||||
@test "zdeploy with no args shows usage and exits non-zero" {
|
||||
run "$BASHDIR/zdeploy"
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"Usage"* ]]
|
||||
}
|
||||
|
||||
@test "zbackup with no args shows usage and exits non-zero" {
|
||||
run "$BASHDIR/zbackup"
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"Usage"* ]]
|
||||
}
|
||||
|
||||
@test "usage lists the configured project keys" {
|
||||
run "$BASHDIR/zkill"
|
||||
[[ "$output" == *"pyapp"* ]]
|
||||
[[ "$output" == *"viteapp"* ]]
|
||||
}
|
||||
|
||||
@test "usage never advertises the underscore comment key" {
|
||||
run "$BASHDIR/zkill"
|
||||
[[ "$output" != *"_note"* ]]
|
||||
}
|
||||
|
||||
# ---- unknown key ------------------------------------------------------------
|
||||
# Exiting 0 having selected nothing is the dangerous outcome.
|
||||
|
||||
@test "zkill rejects an unknown project key" {
|
||||
run "$BASHDIR/zkill" definitelynotaproject
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"Unknown project key"* ]]
|
||||
}
|
||||
|
||||
@test "zstart rejects an unknown project key" {
|
||||
run "$BASHDIR/zstart" definitelynotaproject
|
||||
[ "$status" -ne 0 ]
|
||||
}
|
||||
|
||||
@test "zdeploy rejects an unknown project key" {
|
||||
run "$BASHDIR/zdeploy" definitelynotaproject
|
||||
[ "$status" -ne 0 ]
|
||||
}
|
||||
|
||||
@test "the unknown-key error names both the bad key and the valid ones" {
|
||||
run "$BASHDIR/zkill" definitelynotaproject
|
||||
[[ "$output" == *"definitelynotaproject"* ]]
|
||||
[[ "$output" == *"pyapp"* ]]
|
||||
}
|
||||
|
||||
@test "the underscore comment key is not addressable as a project" {
|
||||
run "$BASHDIR/zkill" _note
|
||||
[ "$status" -ne 0 ]
|
||||
}
|
||||
|
||||
# The convention is that ANY "_"-prefixed key is a comment, not a project -
|
||||
# PowerShell's Get-ZProject refuses them outright. A string-valued comment is
|
||||
# also caught by the "is it an object?" check, so this uses an OBJECT-valued
|
||||
# underscore key (e.g. someone keeping a "_template" block to copy from) to
|
||||
# prove the prefix rule itself is enforced.
|
||||
@test "an object-valued underscore key is still not addressable" {
|
||||
cat > "$BATS_TEST_TMPDIR/objkey.json" <<'JSON'
|
||||
{
|
||||
"ec2": { "ip": "203.0.113.10", "user": "testuser", "pemKey": "/f/t.pem", "stackRoot": "/s" },
|
||||
"paths": { "temp": "/f/t", "backupsLocal": "/f/b", "backupsEc2": "/f/be", "scriptsRoot": "/f/z", "oneDriveBackups": "" },
|
||||
"projects": {
|
||||
"_template": {
|
||||
"label": "Template To Copy", "kind": "python", "localRoot": "/fixtures/none",
|
||||
"ports": { "dev": 59993 }, "remote": { "path": "/s/t" }
|
||||
},
|
||||
"pyapp": {
|
||||
"label": "Fixture Python App", "kind": "python", "localRoot": "/fixtures/nonexistent-pyapp",
|
||||
"ports": { "dev": 59990 }, "remote": { "path": "/s/py" }
|
||||
}
|
||||
}
|
||||
}
|
||||
JSON
|
||||
ZCONFIG="$BATS_TEST_TMPDIR/objkey.json" run "$BASHDIR/zkill" _template
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"Unknown project key"* ]]
|
||||
}
|
||||
|
||||
@test "an object-valued underscore key is excluded from 'all'" {
|
||||
cat > "$BATS_TEST_TMPDIR/objkey2.json" <<'JSON'
|
||||
{
|
||||
"ec2": { "ip": "203.0.113.10", "user": "testuser", "pemKey": "/f/t.pem", "stackRoot": "/s" },
|
||||
"paths": { "temp": "/f/t", "backupsLocal": "/f/b", "backupsEc2": "/f/be", "scriptsRoot": "/f/z", "oneDriveBackups": "" },
|
||||
"projects": {
|
||||
"_template": {
|
||||
"label": "Template To Copy", "kind": "python", "localRoot": "/fixtures/none",
|
||||
"ports": { "dev": 59993 }, "remote": { "path": "/s/t" }
|
||||
},
|
||||
"pyapp": {
|
||||
"label": "Fixture Python App", "kind": "python", "localRoot": "/fixtures/nonexistent-pyapp",
|
||||
"ports": { "dev": 59990 }, "remote": { "path": "/s/py" }
|
||||
}
|
||||
}
|
||||
}
|
||||
JSON
|
||||
ZCONFIG="$BATS_TEST_TMPDIR/objkey2.json" run "$BASHDIR/zkill" all
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"Fixture Python App"* ]]
|
||||
[[ "$output" != *"Template To Copy"* ]]
|
||||
}
|
||||
|
||||
# ---- leading dash: CURRENT bash behaviour ------------------------------------
|
||||
# NOTE: this is a known divergence from the PowerShell port, pinned here as it
|
||||
# actually behaves rather than as it ideally would. PowerShell tolerates a
|
||||
# leading dash on any project key (zdeploy -myapp == zdeploy myapp). In bash,
|
||||
# only zdeploy strips it ("${1#-}"); every other script treats -myapp as an
|
||||
# unknown option and exits 1. These tests document today's behaviour so a fix
|
||||
# is a deliberate change with a failing test to update, not a silent surprise.
|
||||
|
||||
@test "bash zdeploy strips a leading dash from a project key" {
|
||||
# Unknown key keeps this on the no-work path; the error must name the key
|
||||
# without its dash, proving the strip happened.
|
||||
run "$BASHDIR/zdeploy" -definitelynotaproject
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"definitelynotaproject"* ]]
|
||||
[[ "$output" != *"-definitelynotaproject"* ]]
|
||||
}
|
||||
|
||||
@test "bash zkill rejects a dashed key as an unknown option (diverges from PowerShell)" {
|
||||
run "$BASHDIR/zkill" -pyapp
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"Unknown option"* ]]
|
||||
}
|
||||
|
||||
@test "bash zstart rejects a dashed key as an unknown option (diverges from PowerShell)" {
|
||||
run "$BASHDIR/zstart" -pyapp
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"Unknown option"* ]]
|
||||
}
|
||||
|
||||
# ---- zkill target resolution (safe: fixture ports are unused) ----------------
|
||||
|
||||
@test "zkill accepts a bare project key" {
|
||||
run "$BASHDIR/zkill" pyapp
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"Fixture Python App"* ]]
|
||||
[[ "$output" == *"59990"* ]]
|
||||
}
|
||||
|
||||
@test "zkill accepts several keys at once" {
|
||||
run "$BASHDIR/zkill" pyapp viteapp
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"Fixture Python App"* ]]
|
||||
[[ "$output" == *"Fixture Vite Site"* ]]
|
||||
}
|
||||
|
||||
@test "zkill 'all' expands to every project with a dev port" {
|
||||
run "$BASHDIR/zkill" all
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"Fixture Python App"* ]]
|
||||
[[ "$output" == *"Fixture Vite Site"* ]]
|
||||
}
|
||||
|
||||
@test "zkill 'all' skips projects with no dev port (edge/docker stacks)" {
|
||||
run "$BASHDIR/zkill" all
|
||||
[[ "$output" != *"Fixture Edge"* ]]
|
||||
}
|
||||
|
||||
@test "zkill --port overrides the configured dev port" {
|
||||
run "$BASHDIR/zkill" pyapp --port 59999
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"59999"* ]]
|
||||
[[ "$output" != *"59990"* ]]
|
||||
}
|
||||
|
||||
@test "zkill announces that --kill-all is not implemented rather than silently ignoring it" {
|
||||
run "$BASHDIR/zkill" pyapp --kill-all
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"kill-all"* ]]
|
||||
}
|
||||
237
tests/bash/helpers.bats
Normal file
237
tests/bash/helpers.bats
Normal file
@ -0,0 +1,237 @@
|
||||
#!/usr/bin/env bats
|
||||
# Evomedia.net Token Savers - https://github.com/kellymichels/zscripts-token-savers
|
||||
# Created by Kelly Michels - dev@evomedia.net
|
||||
# Licensed under the MIT License. See LICENSE.
|
||||
#
|
||||
# helpers.bats - coverage for the pure/config functions in bash/zhelpers.sh.
|
||||
#
|
||||
# bats tests/bash
|
||||
#
|
||||
# The bash port has its own implementation of the exclude lists and config
|
||||
# accessors, so it can drift from the PowerShell side independently. These
|
||||
# mirror tests/ZHelpers.Tests.ps1 assertion-for-assertion where the two are
|
||||
# meant to agree.
|
||||
#
|
||||
# A fixture config is injected through ZCONFIG (zhelpers.sh has always honored
|
||||
# it), so no real zconfig.json is read.
|
||||
|
||||
setup() {
|
||||
REPO="$(cd "$(dirname "$BATS_TEST_FILENAME")/../.." && pwd)"
|
||||
export ZCONFIG="$BATS_TEST_TMPDIR/zconfig.json"
|
||||
cat > "$ZCONFIG" <<'JSON'
|
||||
{
|
||||
"ec2": { "ip": "203.0.113.10", "user": "testuser", "pemKey": "/fixtures/test.pem", "stackRoot": "/home/testuser/stack" },
|
||||
"paths": { "temp": "/fixtures/temp", "backupsLocal": "/fixtures/backups", "backupsEc2": "/fixtures/backups-ec2", "scriptsRoot": "/fixtures/zscripts", "oneDriveBackups": "" },
|
||||
"projects": {
|
||||
"_note": "comment key - must never be treated as a project",
|
||||
"pyapp": {
|
||||
"label": "Fixture Python App", "kind": "python", "localRoot": "/fixtures/pyapp",
|
||||
"startModule": "pyapp.main", "ports": { "dev": 59990 }, "domain": "pyapp.example.com",
|
||||
"remote": { "path": "/home/testuser/stack/pyapp", "composeDir": "/home/testuser/stack/pyapp/docker", "appService": "app" },
|
||||
"deploy": { "zipName": "PyAppDeploy.zip", "exclude": ["docs", "fixtures-extra"] }
|
||||
},
|
||||
"viteapp": {
|
||||
"label": "Fixture Vite Site", "kind": "vite", "localRoot": "/fixtures/viteapp",
|
||||
"ports": { "dev": 59991 }, "domain": "www.example.com",
|
||||
"remote": { "path": "/home/testuser/stack/viteapp" }
|
||||
},
|
||||
"nextapp": {
|
||||
"label": "Fixture Next App", "kind": "nextjs", "localRoot": "/fixtures/nextapp",
|
||||
"ports": { "dev": 59992 }, "remote": { "path": "/home/testuser/stack/nextapp" }
|
||||
},
|
||||
"edgeproxy": {
|
||||
"label": "Fixture Edge", "kind": "edge", "localRoot": "/fixtures/edge",
|
||||
"proxyContainer": "edge_proxy", "remote": { "path": "/home/testuser/stack/edge" }
|
||||
},
|
||||
"noports": {
|
||||
"label": "Fixture No Dev Port", "kind": "python", "localRoot": "/fixtures/noports",
|
||||
"remote": { "path": "/home/testuser/stack/noports" }
|
||||
}
|
||||
}
|
||||
}
|
||||
JSON
|
||||
# shellcheck disable=SC1090
|
||||
source "$REPO/bash/zhelpers.sh"
|
||||
}
|
||||
|
||||
# Emit the exclude list for a project; $2=1 means "for backup".
|
||||
excludes() { z_archive_excludes "$1" "${2:-0}"; }
|
||||
|
||||
# Fixed-string, whole-line match. -F matters: without it grep treats the needle
|
||||
# as a regex, and '.env' would match 'venv' (leading '.' = any char) - which
|
||||
# silently turns every ".env is excluded" assertion into a false pass.
|
||||
has() { printf '%s\n' "$1" | grep -qxF "$2"; }
|
||||
|
||||
# ---- config accessors -------------------------------------------------------
|
||||
|
||||
@test "zproj_keys returns every project in config order" {
|
||||
run bash -c "source '$REPO/bash/zhelpers.sh'; zproj_keys | paste -sd, -"
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" = "pyapp,viteapp,nextapp,edgeproxy,noports" ]
|
||||
}
|
||||
|
||||
@test "zproj_keys omits underscore comment keys" {
|
||||
run bash -c "source '$REPO/bash/zhelpers.sh'; zproj_keys"
|
||||
[ "$status" -eq 0 ]
|
||||
! has "$output" "_note"
|
||||
}
|
||||
|
||||
@test "zproj reads a project field" {
|
||||
run bash -c "source '$REPO/bash/zhelpers.sh'; zproj pyapp .label"
|
||||
[ "$output" = "Fixture Python App" ]
|
||||
}
|
||||
|
||||
@test "zproj returns empty for a missing field rather than the string null" {
|
||||
run bash -c "source '$REPO/bash/zhelpers.sh'; zproj viteapp .startModule"
|
||||
[ "$output" = "" ]
|
||||
}
|
||||
|
||||
@test "zec2_target composes user@ip" {
|
||||
run bash -c "source '$REPO/bash/zhelpers.sh'; zec2_target"
|
||||
[ "$output" = "testuser@203.0.113.10" ]
|
||||
}
|
||||
|
||||
@test "zremote_compose_dir prefers composeDir" {
|
||||
run bash -c "source '$REPO/bash/zhelpers.sh'; zremote_compose_dir pyapp"
|
||||
[ "$output" = "/home/testuser/stack/pyapp/docker" ]
|
||||
}
|
||||
|
||||
@test "zremote_compose_dir falls back to remote.path" {
|
||||
run bash -c "source '$REPO/bash/zhelpers.sh'; zremote_compose_dir viteapp"
|
||||
[ "$output" = "/home/testuser/stack/viteapp" ]
|
||||
}
|
||||
|
||||
@test "zedge_key finds the first edge-kind project" {
|
||||
run bash -c "source '$REPO/bash/zhelpers.sh'; zedge_key"
|
||||
[ "$output" = "edgeproxy" ]
|
||||
}
|
||||
|
||||
@test "zproj_keys_with_domain lists only projects that have a domain" {
|
||||
run bash -c "source '$REPO/bash/zhelpers.sh'; zproj_keys_with_domain | paste -sd, -"
|
||||
[ "$output" = "pyapp,viteapp" ]
|
||||
}
|
||||
|
||||
# ---- z_path (Windows -> host path translation) ------------------------------
|
||||
# A shared zconfig.json may carry Windows paths when the same file is used from
|
||||
# a Windows checkout and from WSL.
|
||||
|
||||
@test "z_path translates a Windows drive path to /mnt form" {
|
||||
run bash -c "source '$REPO/bash/zhelpers.sh'; z_path 'F:\\evomedia.net\\app'"
|
||||
[ "$output" = "/mnt/f/evomedia.net/app" ]
|
||||
}
|
||||
|
||||
@test "z_path lowercases the drive letter" {
|
||||
run bash -c "source '$REPO/bash/zhelpers.sh'; z_path 'C:\\Users\\Someone'"
|
||||
[ "$output" = "/mnt/c/Users/Someone" ]
|
||||
}
|
||||
|
||||
@test "z_path leaves a unix path untouched (no-op on native Linux/macOS)" {
|
||||
run bash -c "source '$REPO/bash/zhelpers.sh'; z_path '/home/kelly/project'"
|
||||
[ "$output" = "/home/kelly/project" ]
|
||||
}
|
||||
|
||||
@test "z_path leaves an empty string empty" {
|
||||
run bash -c "source '$REPO/bash/zhelpers.sh'; z_path ''"
|
||||
[ "$output" = "" ]
|
||||
}
|
||||
|
||||
# ---- z_archive_excludes -----------------------------------------------------
|
||||
# Parity target: tests/ZHelpers.Tests.ps1 "Get-ArchiveExcludes".
|
||||
|
||||
@test "excludes: common junk applies to every kind" {
|
||||
run excludes pyapp
|
||||
for n in .git .idea .vscode .claude tmp nul .DS_Store backups; do
|
||||
has "$output" "$n" || { echo "missing common exclude: $n"; return 1; }
|
||||
done
|
||||
}
|
||||
|
||||
@test "excludes: python build/venv cruft" {
|
||||
run excludes pyapp
|
||||
for n in .venv venv __pycache__ .pytest_cache .nicegui archive dist build htmlcov; do
|
||||
has "$output" "$n" || { echo "missing python exclude: $n"; return 1; }
|
||||
done
|
||||
}
|
||||
|
||||
@test "excludes: vite drops node_modules and dist" {
|
||||
run excludes viteapp
|
||||
has "$output" "node_modules"
|
||||
has "$output" "dist"
|
||||
}
|
||||
|
||||
@test "excludes: nextjs drops .next and .vercel" {
|
||||
run excludes nextapp
|
||||
has "$output" ".next"
|
||||
has "$output" ".vercel"
|
||||
has "$output" "next-env.d.ts"
|
||||
}
|
||||
|
||||
# The regression this suite exists for: a dev .env shipped to production in a
|
||||
# deploy zip. Deploys drop secrets and uploads; backups must keep them or the
|
||||
# backup is not a restore point.
|
||||
@test "excludes: python DEPLOY drops .env, .env.local, .env.production and uploads" {
|
||||
run excludes pyapp 0
|
||||
for n in .env .env.local .env.production uploads; do
|
||||
has "$output" "$n" || { echo "deploy should exclude: $n"; return 1; }
|
||||
done
|
||||
}
|
||||
|
||||
@test "excludes: python BACKUP keeps .env, .env.local, .env.production and uploads" {
|
||||
run excludes pyapp 1
|
||||
for n in .env .env.local .env.production uploads; do
|
||||
if has "$output" "$n"; then echo "backup must NOT exclude: $n"; return 1; fi
|
||||
done
|
||||
}
|
||||
|
||||
@test "excludes: python BACKUP still drops the virtualenv (bulk, not a secret)" {
|
||||
run excludes pyapp 1
|
||||
has "$output" ".venv"
|
||||
}
|
||||
|
||||
@test "excludes: vite DEPLOY drops .env files" {
|
||||
run excludes viteapp 0
|
||||
for n in .env .env.local .env.production; do
|
||||
has "$output" "$n" || { echo "deploy should exclude: $n"; return 1; }
|
||||
done
|
||||
}
|
||||
|
||||
@test "excludes: vite BACKUP keeps .env files" {
|
||||
run excludes viteapp 1
|
||||
for n in .env .env.local .env.production; do
|
||||
if has "$output" "$n"; then echo "backup must NOT exclude: $n"; return 1; fi
|
||||
done
|
||||
}
|
||||
|
||||
@test "excludes: vite BACKUP still drops node_modules" {
|
||||
run excludes viteapp 1
|
||||
has "$output" "node_modules"
|
||||
}
|
||||
|
||||
# nextjs has no backup gate on the PowerShell side either - both agree.
|
||||
@test "excludes: nextjs drops .env in a backup too (no gate, matches PowerShell)" {
|
||||
run excludes nextapp 1
|
||||
has "$output" ".env"
|
||||
}
|
||||
|
||||
@test "excludes: the project's own deploy.exclude entries are merged in" {
|
||||
run excludes pyapp
|
||||
has "$output" "docs"
|
||||
has "$output" "fixtures-extra"
|
||||
}
|
||||
|
||||
@test "excludes: a kind with no specific list still gets the common entries" {
|
||||
run excludes edgeproxy
|
||||
has "$output" ".git"
|
||||
}
|
||||
|
||||
# ---- json_build_label -------------------------------------------------------
|
||||
|
||||
@test "json_build_label formats v<productVersion>.<buildNumber>" {
|
||||
printf '{ "productVersion": "1.0", "buildNumber": 42 }' > "$BATS_TEST_TMPDIR/bv.json"
|
||||
run bash -c "source '$REPO/bash/zhelpers.sh'; json_build_label '$BATS_TEST_TMPDIR/bv.json'"
|
||||
[ "$output" = "v1.0.42" ]
|
||||
}
|
||||
|
||||
@test "json_build_label reports unknown for a missing file" {
|
||||
run bash -c "source '$REPO/bash/zhelpers.sh'; json_build_label '$BATS_TEST_TMPDIR/nope.json'"
|
||||
[ "$output" = "unknown" ]
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user