#!/usr/bin/env bash set -u -o pipefail TEST_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" source "${TEST_ROOT}/tests/testlib.sh" source "${TEST_ROOT}/inc/deploy-pulse-lxc.sh" assert_success "stable Pulse release" TAPM_PULSE_VALID_RELEASE v6.1.1 assert_success "prerelease Pulse release" TAPM_PULSE_VALID_RELEASE v6.2.0-rc.1 assert_failure "Pulse release requires v prefix" TAPM_PULSE_VALID_RELEASE 6.1.1 assert_failure "Pulse release rejects URL content" \ TAPM_PULSE_VALID_RELEASE 'v6.1.1/../../latest' assert_equal amd64 "$(TAPM_PULSE_ARCH x86_64)" "x86 architecture mapping" assert_equal arm64 "$(TAPM_PULSE_ARCH aarch64)" "ARM architecture mapping" assert_failure "unsupported Pulse architecture" TAPM_PULSE_ARCH riscv64 test_bridge_selection_assignment() { local bridge='' TAPM_PULSE_SET_BRIDGE_FROM_SELECTION bridge 'bridge:vmbr0' || return 1 assert_equal vmbr0 "$bridge" "selected Pulse bridge assigned to caller" } assert_success "Pulse bridge selection assignment" test_bridge_selection_assignment assert_failure "empty Pulse bridge selection rejected" \ TAPM_PULSE_SET_BRIDGE_FROM_SELECTION selected_bridge 'bridge:' bootstrap_token='0123456789abcdef0123456789abcdef0123456789abcdef' bootstrap_output="║ Token: ${bootstrap_token} ║" assert_equal "$bootstrap_token" \ "$(TAPM_PULSE_BOOTSTRAP_TOKEN_FROM_OUTPUT "$bootstrap_output")" \ "Pulse bootstrap token parsed" assert_failure "malformed Pulse bootstrap output rejected" \ TAPM_PULSE_BOOTSTRAP_TOKEN_FROM_OUTPUT 'Token: not-a-token' agent_token='0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef' assert_equal "$agent_token" \ "$(TAPM_PULSE_TOKEN_FROM_RESPONSE "{\"token\":\"${agent_token}\"}")" \ "Pulse agent token parsed" assert_failure "missing Pulse agent token rejected" \ TAPM_PULSE_TOKEN_FROM_RESPONSE '{"command":"install"}' assert_failure "Pulse agent token containing whitespace rejected" \ TAPM_PULSE_TOKEN_FROM_RESPONSE '{"token":"invalid token"}' assert_failure "non-hex Pulse agent token rejected" \ TAPM_PULSE_TOKEN_FROM_RESPONSE '{"token":"not-a-token"}' assert_success "registered Pulse agent response accepted" \ TAPM_PULSE_AGENT_REGISTERED_FROM_RESPONSE \ '{"agent":{"id":"agent-123","hostname":"pve1"}}' assert_failure "missing Pulse agent ID rejected" \ TAPM_PULSE_AGENT_REGISTERED_FROM_RESPONSE '{"agent":{"hostname":"pve1"}}' assert_equal '{"type":"pve","enableCommands":false}' \ "$(TAPM_PULSE_AGENT_TOKEN_REQUEST_JSON)" \ "Proxmox-specific agent enrollment requested with commands disabled" setup_token='0123456789abcdef0123456789abcdef' setup_host='https://pve1.example.test:8006' setup_old_url='https://pulse.example.test/api/setup-script?backup_perms=true' setup_response="$( SETUP_TOKEN="$setup_token" SETUP_HOST="$setup_host" SETUP_OLD_URL="$setup_old_url" \ python3 -c ' import json, os, sys, time old_url = os.environ["SETUP_OLD_URL"] token = os.environ["SETUP_TOKEN"] json.dump({ "type": "pve", "host": os.environ["SETUP_HOST"], "url": old_url, "downloadURL": old_url + "&setup_token=" + token, "scriptFileName": "pulse-setup-pve.sh", "command": old_url + " PULSE_SETUP_TOKEN=" + token + " if", "commandWithEnv": old_url + " PULSE_SETUP_TOKEN=" + token + " if", "commandWithoutEnv": old_url + " if", "expires": int(time.time()) + 300, "setupToken": token, "tokenHint": token[:3] + "..." + token[-3:], }, sys.stdout) ' )" normalized_setup="$( TAPM_PULSE_NORMALIZE_V611_SETUP_ARTIFACT \ "$setup_response" 'http://10.10.2.30:7655' )" assert_equal "$setup_token" \ "$(SETUP_RESPONSE="$normalized_setup" python3 -c 'import json, os; print(json.loads(os.environ["SETUP_RESPONSE"])["setupToken"])')" \ "Pulse v6.1.1 compatibility preserves server-issued setup token" assert_equal \ 'http://10.10.2.30:7655/api/setup-script?host=https%3A%2F%2Fpve1.example.test%3A8006&pulse_url=http%3A%2F%2F10.10.2.30%3A7655&type=pve' \ "$(SETUP_RESPONSE="$normalized_setup" python3 -c 'import json, os; print(json.loads(os.environ["SETUP_RESPONSE"])["url"])')" \ "Pulse v6.1.1 compatibility normalizes setup artifact URL" assert_failure "Pulse v6.1.1 compatibility rejects missing setup token" \ TAPM_PULSE_NORMALIZE_V611_SETUP_ARTIFACT \ '{"type":"pve","host":"https://pve1:8006"}' 'http://10.10.2.30:7655' test_pve_token_output_assignment() { local token_output='' local token_status=99 pveum() { printf '%s\n' \ '{"full-tokenid":"pulse-monitor@pve!pulse-test","value":"secret-value"}' } TAPM_PULSE_CREATE_PVE_AUTO_REGISTER_TOKEN \ 'pulse-test' token_output token_status || return 1 unset -f pveum assert_equal \ '{"full-tokenid":"pulse-monitor@pve!pulse-test","value":"secret-value"}' \ "$token_output" \ "Pulse receives pveum token output" assert_equal 0 "$token_status" "Pulse receives pveum token status" } assert_success "Pulse v6.1.1 pveum output-shadowing workaround" \ test_pve_token_output_assignment nodes_json='[ {"node":"pve3","status":"offline"}, {"node":"pve2","status":"online"}, {"node":"pve1","status":"online"} ]' assert_equal $'pve1\npve2' \ "$(TAPM_PULSE_ONLINE_NODES_FROM_JSON "$nodes_json")" \ "online Pulse nodes selected and sorted" assert_equal 'pve3' \ "$(TAPM_PULSE_OFFLINE_NODES_FROM_JSON "$nodes_json")" \ "offline Pulse nodes reported" assert_success "valid Pulse CTID" TAPM_PULSE_VALID_CTID 210 assert_failure "invalid Pulse CTID" TAPM_PULSE_VALID_CTID 99 assert_success "valid Pulse hostname" TAPM_PULSE_VALID_HOSTNAME pulse-monitor assert_failure "invalid Pulse hostname" TAPM_PULSE_VALID_HOSTNAME 'pulse monitor' assert_success "valid positive integer" TAPM_PULSE_VALID_POSITIVE_INTEGER 1024 assert_failure "zero is not positive" TAPM_PULSE_VALID_POSITIVE_INTEGER 0 assert_success "zero is a valid nonnegative integer" \ TAPM_PULSE_VALID_NONNEGATIVE_INTEGER 0 assert_failure "negative integer rejected" TAPM_PULSE_VALID_NONNEGATIVE_INTEGER -1 assert_success "valid Pulse port" TAPM_PULSE_VALID_PORT 7655 assert_failure "Pulse port too high" TAPM_PULSE_VALID_PORT 65536 assert_success "valid Pulse IPv4 CIDR" TAPM_PULSE_VALID_IPV4_CIDR 10.10.1.50/24 assert_failure "invalid Pulse IPv4 CIDR" TAPM_PULSE_VALID_IPV4_CIDR 10.10.1.500/24 assert_success "valid Pulse gateway" TAPM_PULSE_VALID_IPV4 10.10.0.1 assert_failure "gateway CIDR rejected" TAPM_PULSE_VALID_IPV4 10.10.0.1/16 assert_success "blank optional Pulse address accepted" \ TAPM_PULSE_VALID_OPTIONAL_IPV4_CIDR '' assert_success "valid Pulse VLAN" TAPM_PULSE_VALID_OPTIONAL_VLAN 4094 assert_failure "Pulse VLAN zero rejected" TAPM_PULSE_VALID_OPTIONAL_VLAN 0 assert_success "blank Pulse VLAN accepted" TAPM_PULSE_VALID_OPTIONAL_VLAN '' resources='[ {"type":"lxc","name":"pulse-a","tags":"tapm;pulse"}, {"type":"qemu","name":"unrelated"} ]' assert_success "tagged Pulse LXC detected" TAPM_PULSE_RESOURCE_INSTALLED "$resources" assert_success "legacy Pulse hostname detected" \ TAPM_PULSE_RESOURCE_INSTALLED '[{"type":"lxc","name":"Pulse"}]' assert_success "untagged default Pulse hostname detected" \ TAPM_PULSE_RESOURCE_INSTALLED '[{"type":"lxc","name":"Pulse-Monitor"}]' assert_failure "unrelated resource not detected" \ TAPM_PULSE_RESOURCE_INSTALLED '[{"type":"qemu","name":"pulse"}]' ha_status=$'quorum OK\nmaster pve1 (active, Sat Jul 25 12:00:00 2026)\nlrm pve1 (active, Sat Jul 25 12:00:00 2026)' assert_success "active Proxmox HA detected" TAPM_PULSE_HA_STATUS_ENABLED "$ha_status" assert_failure "inactive Proxmox HA rejected" \ TAPM_PULSE_HA_STATUS_ENABLED $'quorum OK\nmaster pve1 (idle)' finish_tests