216 lines
7.4 KiB
Bash
216 lines
7.4 KiB
Bash
#!/usr/bin/env bats
|
|||
|
|
# tests/unit/rename.bats — Config-only rename tests (name/subfolder edits,
|
||
|
|
# validation, resumability field checks).
|
||
|
|
#
|
||
|
|
# No real git remote is touched here: `--subrepo-url` renames (which need a
|
||
|
|
# reachability check) and all actual state-branch migration behavior are
|
||
|
|
# covered by tests/unit/rename_e2e.bats instead. Every call below either
|
||
|
|
# omits --subrepo-url or passes assume_yes=true with no state branch present,
|
||
|
|
# so the concurrency/state-conflict checks run against a non-git tmpdir and
|
||
|
|
# harmlessly no-op (git commands fail closed, caught by `|| return 0`/`|| true`
|
||
|
|
# in lib/state.sh and lib/rename.sh).
|
||
|
|
|
||
|
|
setup() {
|
||
|
|
export JOSH_SYNC_ROOT="$(cd "$BATS_TEST_DIRNAME/../.." && pwd)"
|
||
|
|
source "$JOSH_SYNC_ROOT/lib/core.sh"
|
||
|
|
source "$JOSH_SYNC_ROOT/lib/config.sh"
|
||
|
|
source "$JOSH_SYNC_ROOT/lib/auth.sh"
|
||
|
|
source "$JOSH_SYNC_ROOT/lib/state.sh"
|
||
|
|
source "$JOSH_SYNC_ROOT/lib/rename.sh"
|
||
|
|
|
||
|
|
FIXTURES="$JOSH_SYNC_ROOT/tests/fixtures"
|
||
|
|
}
|
||
|
|
|
||
|
|
# ─── _rename_validate_name ─────────────────────────────────────────
|
||
|
|
|
||
|
|
@test "_rename_validate_name rejects a name with a slash" {
|
||
|
|
run _rename_validate_name "foo/bar"
|
||
|
|
[ "$status" -ne 0 ]
|
||
|
|
}
|
||
|
|
|
||
|
|
@test "_rename_validate_name rejects a name starting with a dot" {
|
||
|
|
run _rename_validate_name ".hidden"
|
||
|
|
[ "$status" -ne 0 ]
|
||
|
|
}
|
||
|
|
|
||
|
|
@test "_rename_validate_name rejects '..'" {
|
||
|
|
run _rename_validate_name ".."
|
||
|
|
[ "$status" -ne 0 ]
|
||
|
|
}
|
||
|
|
|
||
|
|
@test "_rename_validate_name accepts a normal name" {
|
||
|
|
run _rename_validate_name "payments-v2"
|
||
|
|
[ "$status" -eq 0 ]
|
||
|
|
}
|
||
|
|
|
||
|
|
# ─── josh_filter derivation ─────────────────────────────────────────
|
||
|
|
|
||
|
|
@test "_rename_auto_filter derives plain filter with no exclude" {
|
||
|
|
result=$(_rename_auto_filter "services/app" "[]")
|
||
|
|
[ "$result" = ":/services/app" ]
|
||
|
|
}
|
||
|
|
|
||
|
|
@test "_rename_auto_filter derives exclude filter" {
|
||
|
|
result=$(_rename_auto_filter "services/app" '[".monorepo/"]')
|
||
|
|
[ "$result" = ":/services/app:exclude[::.monorepo/]" ]
|
||
|
|
}
|
||
|
|
|
||
|
|
@test "_rename_derive_new_josh_filter tracks an auto-derived filter across a subfolder rename" {
|
||
|
|
result=$(_rename_derive_new_josh_filter "services/old" "services/new" "[]" ":/services/old")
|
||
|
|
[ "$result" = ":/services/new" ]
|
||
|
|
}
|
||
|
|
|
||
|
|
@test "_rename_derive_new_josh_filter leaves an explicit override alone" {
|
||
|
|
result=$(_rename_derive_new_josh_filter "services/old" "services/new" "[]" ":/custom/filter")
|
||
|
|
[ "$result" = ":/custom/filter" ]
|
||
|
|
}
|
||
|
|
|
||
|
|
# ─── rename_target: config edits ───────────────────────────────────
|
||
|
|
|
||
|
|
@test "rename_target --name updates only the matching target in a multi-target config" {
|
||
|
|
cd "$(mktemp -d)"
|
||
|
|
cp "$FIXTURES/multi-target.yml" .josh-sync.yml
|
||
|
|
parse_config ".josh-sync.yml"
|
||
|
|
|
||
|
|
rename_target "app-a" "app-a-renamed" "" "" ".josh-sync.yml" false true false
|
||
|
|
|
||
|
|
parse_config ".josh-sync.yml"
|
||
|
|
names=$(echo "$JOSH_SYNC_TARGETS" | jq -r '[.[].name] | sort | join(",")')
|
||
|
|
[ "$names" = "app-a-renamed,app-b" ]
|
||
|
|
|
||
|
|
app_b_subfolder=$(echo "$JOSH_SYNC_TARGETS" | jq -r '.[] | select(.name == "app-b") | .subfolder')
|
||
|
|
[ "$app_b_subfolder" = "services/app-b" ]
|
||
|
|
}
|
||
|
|
|
||
|
|
@test "rename_target --subfolder re-derives josh_filter" {
|
||
|
|
cd "$(mktemp -d)"
|
||
|
|
cp "$FIXTURES/minimal.yml" .josh-sync.yml
|
||
|
|
parse_config ".josh-sync.yml"
|
||
|
|
|
||
|
|
rename_target "example" "" "services/relocated" "" ".josh-sync.yml" false true false
|
||
|
|
|
||
|
|
parse_config ".josh-sync.yml"
|
||
|
|
filter=$(echo "$JOSH_SYNC_TARGETS" | jq -r '.[0].josh_filter')
|
||
|
|
[ "$filter" = ":/services/relocated" ]
|
||
|
|
subfolder=$(echo "$JOSH_SYNC_TARGETS" | jq -r '.[0].subfolder')
|
||
|
|
[ "$subfolder" = "services/relocated" ]
|
||
|
|
}
|
||
|
|
|
||
|
|
@test "rename_target combining --name and --subfolder updates both fields" {
|
||
|
|
cd "$(mktemp -d)"
|
||
|
|
cp "$FIXTURES/minimal.yml" .josh-sync.yml
|
||
|
|
parse_config ".josh-sync.yml"
|
||
|
|
|
||
|
|
rename_target "example" "relocated" "services/relocated" "" ".josh-sync.yml" false true false
|
||
|
|
|
||
|
|
parse_config ".josh-sync.yml"
|
||
|
|
name=$(echo "$JOSH_SYNC_TARGETS" | jq -r '.[0].name')
|
||
|
|
subfolder=$(echo "$JOSH_SYNC_TARGETS" | jq -r '.[0].subfolder')
|
||
|
|
filter=$(echo "$JOSH_SYNC_TARGETS" | jq -r '.[0].josh_filter')
|
||
|
|
[ "$name" = "relocated" ]
|
||
|
|
[ "$subfolder" = "services/relocated" ]
|
||
|
|
[ "$filter" = ":/services/relocated" ]
|
||
|
|
}
|
||
|
|
|
||
|
|
@test "rename_target rejects a new name colliding with an existing target" {
|
||
|
|
cd "$(mktemp -d)"
|
||
|
|
cp "$FIXTURES/multi-target.yml" .josh-sync.yml
|
||
|
|
parse_config ".josh-sync.yml"
|
||
|
|
|
||
|
|
run rename_target "app-a" "app-b" "" "" ".josh-sync.yml" false true false
|
||
|
|
[ "$status" -ne 0 ]
|
||
|
|
[[ "$output" == *"already exists"* ]]
|
||
|
|
}
|
||
|
|
|
||
|
|
@test "rename_target rejects an unsafe new name" {
|
||
|
|
cd "$(mktemp -d)"
|
||
|
|
cp "$FIXTURES/minimal.yml" .josh-sync.yml
|
||
|
|
parse_config ".josh-sync.yml"
|
||
|
|
|
||
|
|
run rename_target "example" "bad/name" "" "" ".josh-sync.yml" false true false
|
||
|
|
[ "$status" -ne 0 ]
|
||
|
|
}
|
||
|
|
|
||
|
|
@test "rename_target --dry-run leaves the config file byte-identical" {
|
||
|
|
cd "$(mktemp -d)"
|
||
|
|
cp "$FIXTURES/minimal.yml" .josh-sync.yml
|
||
|
|
parse_config ".josh-sync.yml"
|
||
|
|
|
||
|
|
before=$(cat .josh-sync.yml)
|
||
|
|
rename_target "example" "renamed" "" "" ".josh-sync.yml" true true false
|
||
|
|
after=$(cat .josh-sync.yml)
|
||
|
|
|
||
|
|
[ "$before" = "$after" ]
|
||
|
|
}
|
||
|
|
|
||
|
|
@test "rename_target edited config re-validates independently through parse_config" {
|
||
|
|
cd "$(mktemp -d)"
|
||
|
|
cp "$FIXTURES/minimal.yml" .josh-sync.yml
|
||
|
|
parse_config ".josh-sync.yml"
|
||
|
|
|
||
|
|
rename_target "example" "renamed" "" "" ".josh-sync.yml" false true false
|
||
|
|
|
||
|
|
run parse_config ".josh-sync.yml"
|
||
|
|
[ "$status" -eq 0 ]
|
||
|
|
}
|
||
|
|
|
||
|
|
@test "rename_target with nothing changed is a no-op" {
|
||
|
|
cd "$(mktemp -d)"
|
||
|
|
cp "$FIXTURES/minimal.yml" .josh-sync.yml
|
||
|
|
parse_config ".josh-sync.yml"
|
||
|
|
|
||
|
|
before=$(cat .josh-sync.yml)
|
||
|
|
rename_target "example" "" "" "" ".josh-sync.yml" false true false
|
||
|
|
after=$(cat .josh-sync.yml)
|
||
|
|
|
||
|
|
[ "$before" = "$after" ]
|
||
|
|
}
|
||
|
|
|
||
|
|
@test "rename_target dies for an unknown target" {
|
||
|
|
cd "$(mktemp -d)"
|
||
|
|
cp "$FIXTURES/minimal.yml" .josh-sync.yml
|
||
|
|
parse_config ".josh-sync.yml"
|
||
|
|
|
||
|
|
run rename_target "does-not-exist" "renamed" "" "" ".josh-sync.yml" false true false
|
||
|
|
[ "$status" -ne 0 ]
|
||
|
|
[[ "$output" == *"not found"* ]]
|
||
|
|
}
|
||
|
|
|
||
|
|
# ─── _rename_resolve_target: resumability ──────────────────────────
|
||
|
|
|
||
|
|
@test "_rename_resolve_target finds the target under its current name" {
|
||
|
|
cd "$(mktemp -d)"
|
||
|
|
cp "$FIXTURES/minimal.yml" .josh-sync.yml
|
||
|
|
parse_config ".josh-sync.yml"
|
||
|
|
|
||
|
|
result=$(_rename_resolve_target "example" "renamed" "" "")
|
||
|
|
already=$(echo "$result" | jq -r '.already_configured')
|
||
|
|
old=$(echo "$result" | jq -r '.old_name')
|
||
|
|
[ "$already" = "false" ]
|
||
|
|
[ "$old" = "example" ]
|
||
|
|
}
|
||
|
|
|
||
|
|
@test "_rename_resolve_target detects a resumed run (config already shows the new name)" {
|
||
|
|
cd "$(mktemp -d)"
|
||
|
|
cp "$FIXTURES/minimal.yml" .josh-sync.yml
|
||
|
|
yq -i '(.targets[] | select(.name == "example")).name = "renamed"' .josh-sync.yml
|
||
|
|
parse_config ".josh-sync.yml"
|
||
|
|
|
||
|
|
result=$(_rename_resolve_target "example" "renamed" "" "")
|
||
|
|
already=$(echo "$result" | jq -r '.already_configured')
|
||
|
|
old=$(echo "$result" | jq -r '.old_name')
|
||
|
|
new_name=$(echo "$result" | jq -r '.target_json.name')
|
||
|
|
[ "$already" = "true" ]
|
||
|
|
[ "$old" = "example" ]
|
||
|
|
[ "$new_name" = "renamed" ]
|
||
|
|
}
|
||
|
|
|
||
|
|
@test "_rename_resolve_target dies when neither the old nor new name exists" {
|
||
|
|
cd "$(mktemp -d)"
|
||
|
|
cp "$FIXTURES/minimal.yml" .josh-sync.yml
|
||
|
|
parse_config ".josh-sync.yml"
|
||
|
|
|
||
|
|
run _rename_resolve_target "does-not-exist" "also-missing" "" ""
|
||
|
|
[ "$status" -ne 0 ]
|
||
|
|
}
|