238 lines
7 KiB
Text
238 lines
7 KiB
Text
|
|
#!/usr/bin/env nu
|
||
|
|
|
||
|
|
# Hetzner provider API client integration tests (with mocks)
|
||
|
|
|
||
|
|
# Load mock responses
|
||
|
|
def load-mock-responses []: nothing -> record {
|
||
|
|
let mocks = (open ../../tests/mocks/mock_api_responses.json)
|
||
|
|
$mocks
|
||
|
|
}
|
||
|
|
|
||
|
|
# Mock HTTP response handler
|
||
|
|
def mock-http-response [endpoint: string]: nothing -> record {
|
||
|
|
let mocks = (load-mock-responses)
|
||
|
|
|
||
|
|
match $endpoint {
|
||
|
|
"/servers" => {
|
||
|
|
$mocks.servers_list
|
||
|
|
}
|
||
|
|
"/servers/12345" => {
|
||
|
|
$mocks.server_info
|
||
|
|
}
|
||
|
|
"/volumes" => {
|
||
|
|
$mocks.volumes_list
|
||
|
|
}
|
||
|
|
"/networks" => {
|
||
|
|
$mocks.networks_list
|
||
|
|
}
|
||
|
|
"/floating_ips" => {
|
||
|
|
$mocks.floating_ips_list
|
||
|
|
}
|
||
|
|
"/server_types" => {
|
||
|
|
$mocks.server_types_list
|
||
|
|
}
|
||
|
|
"/error/401" => {
|
||
|
|
$mocks.error_401
|
||
|
|
}
|
||
|
|
"/error/404" => {
|
||
|
|
$mocks.error_404
|
||
|
|
}
|
||
|
|
_ => {
|
||
|
|
error make {msg: $"Unknown endpoint: ($endpoint)"}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test framework
|
||
|
|
def test-result [name: string, passed: bool]: nothing -> record {
|
||
|
|
if $passed {
|
||
|
|
print $"✓ ($name)"
|
||
|
|
} else {
|
||
|
|
print $"✗ ($name)"
|
||
|
|
}
|
||
|
|
{name: $name, passed: $passed}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test: GET request response structure
|
||
|
|
def test_get_request_servers []: nothing -> record {
|
||
|
|
let result = (do {
|
||
|
|
let response = (mock-http-response "/servers")
|
||
|
|
($response | has servers)
|
||
|
|
} | complete)
|
||
|
|
|
||
|
|
let passed = ($result.exit_code == 0 and $result.stdout)
|
||
|
|
test-result "GET /servers: response structure" $passed
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test: GET request returns list
|
||
|
|
def test_get_request_list []: nothing -> record {
|
||
|
|
let result = (do {
|
||
|
|
let response = (mock-http-response "/servers")
|
||
|
|
($response.servers | describe) =~ "list"
|
||
|
|
} | complete)
|
||
|
|
|
||
|
|
let passed = ($result.exit_code == 0 and $result.stdout)
|
||
|
|
test-result "GET /servers: returns list" $passed
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test: GET single server
|
||
|
|
def test_get_single_server []: nothing -> record {
|
||
|
|
let result = (do {
|
||
|
|
let response = (mock-http-response "/servers/12345")
|
||
|
|
($response | has server) and (not ($response.server | is-empty))
|
||
|
|
} | complete)
|
||
|
|
|
||
|
|
let passed = ($result.exit_code == 0 and $result.stdout)
|
||
|
|
test-result "GET /servers/{id}: single server response" $passed
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test: GET volumes list
|
||
|
|
def test_get_volumes_list []: nothing -> record {
|
||
|
|
let result = (do {
|
||
|
|
let response = (mock-http-response "/volumes")
|
||
|
|
($response | has volumes) and (($response.volumes | describe) =~ "list")
|
||
|
|
} | complete)
|
||
|
|
|
||
|
|
let passed = ($result.exit_code == 0 and $result.stdout)
|
||
|
|
test-result "GET /volumes: returns list" $passed
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test: GET networks list
|
||
|
|
def test_get_networks_list []: nothing -> record {
|
||
|
|
let result = (do {
|
||
|
|
let response = (mock-http-response "/networks")
|
||
|
|
($response | has networks)
|
||
|
|
} | complete)
|
||
|
|
|
||
|
|
let passed = ($result.exit_code == 0 and $result.stdout)
|
||
|
|
test-result "GET /networks: returns list" $passed
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test: GET floating IPs list
|
||
|
|
def test_get_floating_ips_list []: nothing -> record {
|
||
|
|
let result = (do {
|
||
|
|
let response = (mock-http-response "/floating_ips")
|
||
|
|
($response | has floating_ips)
|
||
|
|
} | complete)
|
||
|
|
|
||
|
|
let passed = ($result.exit_code == 0 and $result.stdout)
|
||
|
|
test-result "GET /floating_ips: returns list" $passed
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test: GET server types list
|
||
|
|
def test_get_server_types_list []: nothing -> record {
|
||
|
|
let result = (do {
|
||
|
|
let response = (mock-http-response "/server_types")
|
||
|
|
($response | has server_types) and (($response.server_types | length) > 0)
|
||
|
|
} | complete)
|
||
|
|
|
||
|
|
let passed = ($result.exit_code == 0 and $result.stdout)
|
||
|
|
test-result "GET /server_types: returns list" $passed
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test: Server type pricing structure
|
||
|
|
def test_server_type_pricing []: nothing -> record {
|
||
|
|
let result = (do {
|
||
|
|
let response = (mock-http-response "/server_types")
|
||
|
|
let st = ($response.server_types | first)
|
||
|
|
{
|
||
|
|
has_name: ($st | has name)
|
||
|
|
has_cores: ($st | has cores)
|
||
|
|
has_prices: ($st | has prices)
|
||
|
|
}
|
||
|
|
} | complete)
|
||
|
|
|
||
|
|
let passed = ($result.exit_code == 0 and
|
||
|
|
$result.stdout.has_name and
|
||
|
|
$result.stdout.has_cores and
|
||
|
|
$result.stdout.has_prices)
|
||
|
|
test-result "server_types: pricing structure" $passed
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test: Error response format (401)
|
||
|
|
def test_error_401_response []: nothing -> record {
|
||
|
|
let result = (do {
|
||
|
|
let response = (mock-http-response "/error/401")
|
||
|
|
($response | has error) and ($response.error | has message)
|
||
|
|
} | complete)
|
||
|
|
|
||
|
|
let passed = ($result.exit_code == 0 and $result.stdout)
|
||
|
|
test-result "error_response: 401 Unauthorized format" $passed
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test: Error response format (404)
|
||
|
|
def test_error_404_response []: nothing -> record {
|
||
|
|
let result = (do {
|
||
|
|
let response = (mock-http-response "/error/404")
|
||
|
|
($response | has error) and ($response.error.code == "not_found")
|
||
|
|
} | complete)
|
||
|
|
|
||
|
|
let passed = ($result.exit_code == 0 and $result.stdout)
|
||
|
|
test-result "error_response: 404 Not Found format" $passed
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test: Server pagination fields (if present)
|
||
|
|
def test_response_server_count []: nothing -> record {
|
||
|
|
let result = (do {
|
||
|
|
let response = (mock-http-response "/servers")
|
||
|
|
($response.servers | length)
|
||
|
|
} | complete)
|
||
|
|
|
||
|
|
let passed = ($result.exit_code == 0 and $result.stdout > 0)
|
||
|
|
test-result "response: contains servers" $passed
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test: Unknown endpoint error
|
||
|
|
def test_unknown_endpoint_error []: nothing -> record {
|
||
|
|
let result = (do { mock-http-response "/unknown" } | complete)
|
||
|
|
let passed = ($result.exit_code != 0)
|
||
|
|
test-result "error_handling: unknown endpoint fails" $passed
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test: Server ID type
|
||
|
|
def test_server_id_type []: nothing -> record {
|
||
|
|
let result = (do {
|
||
|
|
let response = (mock-http-response "/servers")
|
||
|
|
let server = ($response.servers | first)
|
||
|
|
($server.id | describe) =~ "int"
|
||
|
|
} | complete)
|
||
|
|
|
||
|
|
let passed = ($result.exit_code == 0 and $result.stdout)
|
||
|
|
test-result "response: server ID is integer" $passed
|
||
|
|
}
|
||
|
|
|
||
|
|
# Main test runner
|
||
|
|
def main []: nothing -> record {
|
||
|
|
print "=== Hetzner API Client Integration Tests (Mock Mode) ==="
|
||
|
|
print ""
|
||
|
|
|
||
|
|
let results = [
|
||
|
|
(test_get_request_servers)
|
||
|
|
(test_get_request_list)
|
||
|
|
(test_get_single_server)
|
||
|
|
(test_get_volumes_list)
|
||
|
|
(test_get_networks_list)
|
||
|
|
(test_get_floating_ips_list)
|
||
|
|
(test_get_server_types_list)
|
||
|
|
(test_server_type_pricing)
|
||
|
|
(test_error_401_response)
|
||
|
|
(test_error_404_response)
|
||
|
|
(test_response_server_count)
|
||
|
|
(test_unknown_endpoint_error)
|
||
|
|
(test_server_id_type)
|
||
|
|
]
|
||
|
|
|
||
|
|
print ""
|
||
|
|
print "Test Summary:"
|
||
|
|
print "============="
|
||
|
|
|
||
|
|
let passed = ($results | where {|r| $r.passed} | length)
|
||
|
|
let failed = ($results | where {|r| not $r.passed} | length)
|
||
|
|
let total = ($results | length)
|
||
|
|
|
||
|
|
print $"Passed: ($passed)/$total"
|
||
|
|
print $"Failed: ($failed)/$total"
|
||
|
|
|
||
|
|
{passed: $passed, failed: $failed, total: $total}
|
||
|
|
}
|