mirror of
https://github.com/OpenRouterTeam/spawn.git
synced 2026-05-07 09:10:55 +00:00
refactor: reduce complexity in test/mock.sh and test/record.sh (#1096)
Extract assertion tracking and fixture detection logic in mock.sh:
- New _run_assertions_and_track() helper consolidates 20 lines of repeated assertions
- New _has_missing_fixture() helper checks mock log for fixture errors
- run_test() now 30 lines shorter, focusing on orchestration rather than details
Extract cloud endpoints data in record.sh:
- Replace 132-line case statement with data-driven approach
- Each cloud's endpoints now live in _ENDPOINTS_{cloud} variable
- get_endpoints() function reduced to 3 lines, delegates to variable lookup
Benefits:
- Reduced cognitive load: test logic separated from data
- Easier to add new clouds: just add _ENDPOINTS_* variable
- Better maintainability: centralized endpoint definitions
Tests: All 80 tests pass with fixtures enabled.
Co-authored-by: Spawn Refactor Service <refactor@spawn.service>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
8981376274
commit
6647f7ca05
2 changed files with 167 additions and 157 deletions
61
test/mock.sh
61
test/mock.sh
|
|
@ -696,6 +696,37 @@ _categorize_failure() {
|
|||
fi
|
||||
}
|
||||
|
||||
# Run assertions for a script and track which categories failed.
|
||||
# Outputs: _exit_failed, _api_failed, _ssh_failed, _env_failed (as 0/1)
|
||||
_run_assertions_and_track() {
|
||||
local exit_code="$1" cloud="$2"
|
||||
local _ASSERT_DELTA=0
|
||||
|
||||
_tracked_assert assert_exit_code "${exit_code}" 0 "exits successfully"
|
||||
_exit_failed=$_ASSERT_DELTA
|
||||
|
||||
_tracked_assert assert_cloud_api_calls "$cloud"
|
||||
_api_failed=$_ASSERT_DELTA
|
||||
|
||||
_tracked_assert assert_log_contains "ssh " "uses SSH"
|
||||
_ssh_failed=$_ASSERT_DELTA
|
||||
|
||||
_tracked_assert assert_env_injected "OPENROUTER_API_KEY"
|
||||
_env_failed=$_ASSERT_DELTA
|
||||
|
||||
if [[ "${MOCK_VALIDATE_BODY:-}" == "1" ]]; then
|
||||
assert_no_body_errors
|
||||
fi
|
||||
if [[ "${MOCK_TRACK_STATE:-}" == "1" ]]; then
|
||||
assert_server_cleaned_up "$3"
|
||||
fi
|
||||
}
|
||||
|
||||
# Check for missing fixtures in the mock log.
|
||||
_has_missing_fixture() {
|
||||
grep -q "NO_FIXTURE:" "${MOCK_LOG}" 2>/dev/null && echo 1 || echo 0
|
||||
}
|
||||
|
||||
run_test() {
|
||||
local cloud="$1"
|
||||
local agent="$2"
|
||||
|
|
@ -731,37 +762,13 @@ run_test() {
|
|||
fi
|
||||
|
||||
# Normal mode: run standard assertions and track failures per category
|
||||
local _ASSERT_DELTA=0
|
||||
local _exit_failed _api_failed _ssh_failed _env_failed
|
||||
|
||||
_tracked_assert assert_exit_code "${exit_code}" 0 "exits successfully"
|
||||
_exit_failed=$_ASSERT_DELTA
|
||||
|
||||
_tracked_assert assert_cloud_api_calls "$cloud"
|
||||
_api_failed=$_ASSERT_DELTA
|
||||
|
||||
_tracked_assert assert_log_contains "ssh " "uses SSH"
|
||||
_ssh_failed=$_ASSERT_DELTA
|
||||
|
||||
_tracked_assert assert_env_injected "OPENROUTER_API_KEY"
|
||||
_env_failed=$_ASSERT_DELTA
|
||||
|
||||
if [[ "${MOCK_VALIDATE_BODY:-}" == "1" ]]; then
|
||||
assert_no_body_errors
|
||||
fi
|
||||
if [[ "${MOCK_TRACK_STATE:-}" == "1" ]]; then
|
||||
assert_server_cleaned_up "${state_file}"
|
||||
fi
|
||||
|
||||
# Check for missing fixtures
|
||||
local _has_no_fixture=0
|
||||
if grep -q "NO_FIXTURE:" "${MOCK_LOG}" 2>/dev/null; then
|
||||
_has_no_fixture=1
|
||||
fi
|
||||
_run_assertions_and_track "${exit_code}" "${cloud}" "${state_file}"
|
||||
|
||||
# Record result with failure category
|
||||
local pre_fail=$((FAILED - _pre_failed))
|
||||
if [[ "$pre_fail" -gt 0 ]]; then
|
||||
local _has_no_fixture
|
||||
_has_no_fixture=$(_has_missing_fixture)
|
||||
local _reason
|
||||
_reason=$(_categorize_failure "$_has_no_fixture" "$_exit_failed" "$_api_failed" "$_ssh_failed" "$_env_failed")
|
||||
record_test_result "${cloud}" "${agent}" "fail" "${_reason}"
|
||||
|
|
|
|||
263
test/record.sh
263
test/record.sh
|
|
@ -34,138 +34,141 @@ PROMPT_FOR_CREDS=true
|
|||
ALL_RECORDABLE_CLOUDS="hetzner digitalocean vultr linode lambda civo upcloud binarylane ovh scaleway genesiscloud kamatera latitude hyperstack atlanticnet hostkey cloudsigma webdock serverspace gcore"
|
||||
|
||||
# --- Endpoint registry ---
|
||||
# Format: "fixture_name:endpoint"
|
||||
# Declare endpoints as string literal for each cloud
|
||||
# Format: "fixture_name:endpoint" (one per line, indented)
|
||||
_ENDPOINTS_hetzner="
|
||||
server_types:/server_types?per_page=50
|
||||
locations:/locations
|
||||
ssh_keys:/ssh_keys
|
||||
servers:/servers
|
||||
"
|
||||
|
||||
_ENDPOINTS_digitalocean="
|
||||
account:/account
|
||||
ssh_keys:/account/keys
|
||||
droplets:/droplets
|
||||
sizes:/sizes
|
||||
regions:/regions
|
||||
"
|
||||
|
||||
_ENDPOINTS_vultr="
|
||||
account:/account
|
||||
ssh_keys:/ssh-keys
|
||||
instances:/instances
|
||||
plans:/plans
|
||||
regions:/regions
|
||||
"
|
||||
|
||||
_ENDPOINTS_linode="
|
||||
profile:/profile
|
||||
ssh_keys:/profile/sshkeys
|
||||
instances:/linode/instances
|
||||
types:/linode/types
|
||||
regions:/regions
|
||||
"
|
||||
|
||||
_ENDPOINTS_lambda="
|
||||
instances:/instances
|
||||
ssh_keys:/ssh-keys
|
||||
instance_types:/instance-types
|
||||
"
|
||||
|
||||
_ENDPOINTS_civo="
|
||||
regions:/regions
|
||||
instances:/instances
|
||||
sshkeys:/sshkeys
|
||||
networks:/networks
|
||||
disk_images:/disk_images
|
||||
"
|
||||
|
||||
_ENDPOINTS_upcloud="
|
||||
servers:/server
|
||||
server_sizes:/server_size
|
||||
"
|
||||
|
||||
_ENDPOINTS_binarylane="
|
||||
sizes:/sizes
|
||||
regions:/regions
|
||||
servers:/servers
|
||||
"
|
||||
|
||||
_ENDPOINTS_ovh="
|
||||
flavors:/cloud/project/\${OVH_PROJECT_ID:-MISSING}/flavor
|
||||
images:/cloud/project/\${OVH_PROJECT_ID:-MISSING}/image
|
||||
ssh_keys:/cloud/project/\${OVH_PROJECT_ID:-MISSING}/sshkey
|
||||
"
|
||||
|
||||
_ENDPOINTS_scaleway="
|
||||
servers:/servers
|
||||
images:/images?per_page=10
|
||||
"
|
||||
|
||||
_ENDPOINTS_genesiscloud="
|
||||
ssh_keys:/ssh-keys
|
||||
instances:/instances
|
||||
"
|
||||
|
||||
_ENDPOINTS_kamatera="
|
||||
server_options:/service/server
|
||||
"
|
||||
|
||||
_ENDPOINTS_latitude="
|
||||
ssh_keys:/ssh_keys
|
||||
plans:/plans
|
||||
regions:/regions
|
||||
"
|
||||
|
||||
_ENDPOINTS_hyperstack="
|
||||
flavors:/core/flavors
|
||||
ssh_keys:/core/keypairs
|
||||
"
|
||||
|
||||
_ENDPOINTS_atlanticnet="
|
||||
ssh_keys:list-sshkeys
|
||||
plans:describe-plan
|
||||
"
|
||||
|
||||
_ENDPOINTS_hostkey="
|
||||
services:/v1/services
|
||||
ssh_keys:/ssh_keys
|
||||
"
|
||||
|
||||
_ENDPOINTS_cloudsigma="
|
||||
balance:/balance/
|
||||
keypairs:/keypairs/
|
||||
servers:/servers/
|
||||
"
|
||||
|
||||
_ENDPOINTS_webdock="
|
||||
account:/account
|
||||
publicKeys:/account/publicKeys
|
||||
servers:/servers
|
||||
profiles:/profiles
|
||||
locations:/locations
|
||||
"
|
||||
|
||||
_ENDPOINTS_serverspace="
|
||||
project:/project
|
||||
servers:/servers
|
||||
ssh-keys:/ssh-keys
|
||||
locations:/locations
|
||||
images:/images
|
||||
"
|
||||
|
||||
_ENDPOINTS_gcore="
|
||||
projects:/cloud/v1/projects
|
||||
ssh_keys:/cloud/v1/ssh_keys/\${GCORE_PROJECT_ID:-MISSING}
|
||||
instances:/cloud/v1/instances/\${GCORE_PROJECT_ID:-MISSING}/\${GCORE_REGION:-ed-1}
|
||||
images:/cloud/v1/images/\${GCORE_PROJECT_ID:-MISSING}/\${GCORE_REGION:-ed-1}
|
||||
flavors:/cloud/v1/flavors/\${GCORE_PROJECT_ID:-MISSING}/\${GCORE_REGION:-ed-1}
|
||||
"
|
||||
|
||||
get_endpoints() {
|
||||
local cloud="$1"
|
||||
case "$cloud" in
|
||||
hetzner)
|
||||
printf '%s\n' \
|
||||
"server_types:/server_types?per_page=50" \
|
||||
"locations:/locations" \
|
||||
"ssh_keys:/ssh_keys" \
|
||||
"servers:/servers"
|
||||
;;
|
||||
digitalocean)
|
||||
printf '%s\n' \
|
||||
"account:/account" \
|
||||
"ssh_keys:/account/keys" \
|
||||
"droplets:/droplets" \
|
||||
"sizes:/sizes" \
|
||||
"regions:/regions"
|
||||
;;
|
||||
vultr)
|
||||
printf '%s\n' \
|
||||
"account:/account" \
|
||||
"ssh_keys:/ssh-keys" \
|
||||
"instances:/instances" \
|
||||
"plans:/plans" \
|
||||
"regions:/regions"
|
||||
;;
|
||||
linode)
|
||||
printf '%s\n' \
|
||||
"profile:/profile" \
|
||||
"ssh_keys:/profile/sshkeys" \
|
||||
"instances:/linode/instances" \
|
||||
"types:/linode/types" \
|
||||
"regions:/regions"
|
||||
;;
|
||||
lambda)
|
||||
printf '%s\n' \
|
||||
"instances:/instances" \
|
||||
"ssh_keys:/ssh-keys" \
|
||||
"instance_types:/instance-types"
|
||||
;;
|
||||
civo)
|
||||
printf '%s\n' \
|
||||
"regions:/regions" \
|
||||
"instances:/instances" \
|
||||
"sshkeys:/sshkeys" \
|
||||
"networks:/networks" \
|
||||
"disk_images:/disk_images"
|
||||
;;
|
||||
upcloud)
|
||||
printf '%s\n' \
|
||||
"servers:/server" \
|
||||
"server_sizes:/server_size"
|
||||
;;
|
||||
binarylane)
|
||||
printf '%s\n' \
|
||||
"sizes:/sizes" \
|
||||
"regions:/regions" \
|
||||
"servers:/servers"
|
||||
;;
|
||||
ovh)
|
||||
printf '%s\n' \
|
||||
"flavors:/cloud/project/${OVH_PROJECT_ID:-MISSING}/flavor" \
|
||||
"images:/cloud/project/${OVH_PROJECT_ID:-MISSING}/image" \
|
||||
"ssh_keys:/cloud/project/${OVH_PROJECT_ID:-MISSING}/sshkey"
|
||||
;;
|
||||
scaleway)
|
||||
printf '%s\n' \
|
||||
"servers:/servers" \
|
||||
"images:/images?per_page=10"
|
||||
;;
|
||||
genesiscloud)
|
||||
printf '%s\n' \
|
||||
"ssh_keys:/ssh-keys" \
|
||||
"instances:/instances"
|
||||
;;
|
||||
kamatera)
|
||||
printf '%s\n' \
|
||||
"server_options:/service/server"
|
||||
;;
|
||||
latitude)
|
||||
printf '%s\n' \
|
||||
"ssh_keys:/ssh_keys" \
|
||||
"plans:/plans" \
|
||||
"regions:/regions"
|
||||
;;
|
||||
hyperstack)
|
||||
printf '%s\n' \
|
||||
"flavors:/core/flavors" \
|
||||
"ssh_keys:/core/keypairs"
|
||||
;;
|
||||
atlanticnet)
|
||||
printf '%s\n' \
|
||||
"ssh_keys:list-sshkeys" \
|
||||
"plans:describe-plan"
|
||||
;;
|
||||
hostkey)
|
||||
printf '%s\n' \
|
||||
"services:/v1/services" \
|
||||
"ssh_keys:/ssh_keys"
|
||||
;;
|
||||
cloudsigma)
|
||||
printf '%s\n' \
|
||||
"balance:/balance/" \
|
||||
"keypairs:/keypairs/" \
|
||||
"servers:/servers/"
|
||||
;;
|
||||
webdock)
|
||||
printf '%s\n' \
|
||||
"account:/account" \
|
||||
"publicKeys:/account/publicKeys" \
|
||||
"servers:/servers" \
|
||||
"profiles:/profiles" \
|
||||
"locations:/locations"
|
||||
;;
|
||||
serverspace)
|
||||
printf '%s\n' \
|
||||
"project:/project" \
|
||||
"servers:/servers" \
|
||||
"ssh-keys:/ssh-keys" \
|
||||
"locations:/locations" \
|
||||
"images:/images"
|
||||
;;
|
||||
gcore)
|
||||
printf '%s\n' \
|
||||
"projects:/cloud/v1/projects" \
|
||||
"ssh_keys:/cloud/v1/ssh_keys/${GCORE_PROJECT_ID:-MISSING}" \
|
||||
"instances:/cloud/v1/instances/${GCORE_PROJECT_ID:-MISSING}/${GCORE_REGION:-ed-1}" \
|
||||
"images:/cloud/v1/images/${GCORE_PROJECT_ID:-MISSING}/${GCORE_REGION:-ed-1}" \
|
||||
"flavors:/cloud/v1/flavors/${GCORE_PROJECT_ID:-MISSING}/${GCORE_REGION:-ed-1}"
|
||||
;;
|
||||
esac
|
||||
local var_name="_ENDPOINTS_${cloud}"
|
||||
if [[ -n "${!var_name:-}" ]]; then
|
||||
printf '%s\n' "${!var_name}" | grep -v '^$'
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Multi-credential cloud specs ---
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue