#!/usr/bin/env nu # Hetzner provider pricing and cache integration tests (with mocks) # Load mock responses def load-mock-responses []: nothing -> record { let mocks = (open ../../tests/mocks/mock_api_responses.json) $mocks } # Mock: get pricing data def mock-get-pricing []: nothing -> record { let mocks = (load-mock-responses) {server_types: $mocks.server_types_list.server_types} } # Mock: cache operations def mock-create-cache-entry [server: string]: nothing -> record { { server: $server timestamp: (now) cached_at: (date now | date to-record) } } def mock-read-cache-entry [server: string]: nothing -> record { { server: $server timestamp: (now) cached_at: (date now | date to-record) } } # Test framework def test-result [name: string, passed: bool]: nothing -> record { if $passed { print $"✓ ($name)" } else { print $"✗ ($name)" } {name: $name, passed: $passed} } # Test: Get pricing data def test_get_pricing_data []: nothing -> record { let result = (do { let pricing = (mock-get-pricing) ($pricing | has server_types) } | complete) let passed = ($result.exit_code == 0 and $result.stdout) test-result "get_pricing: returns pricing data" $passed } # Test: Server type pricing structure def test_server_type_pricing_structure []: nothing -> record { let result = (do { let pricing = (mock-get-pricing) let st = ($pricing.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 "pricing: server type structure" $passed } # Test: Pricing hourly rate exists def test_pricing_hourly_rate []: nothing -> record { let result = (do { let pricing = (mock-get-pricing) let st = ($pricing.server_types | first) let price = ($st.prices | first) ($price | has price_hourly) } | complete) let passed = ($result.exit_code == 0 and $result.stdout) test-result "pricing: hourly rate field" $passed } # Test: Pricing monthly rate exists def test_pricing_monthly_rate []: nothing -> record { let result = (do { let pricing = (mock-get-pricing) let st = ($pricing.server_types | first) let price = ($st.prices | first) ($price | has price_monthly) } | complete) let passed = ($result.exit_code == 0 and $result.stdout) test-result "pricing: monthly rate field" $passed } # Test: Create cache entry def test_create_cache_entry []: nothing -> record { let result = (do { let cache = (mock-create-cache-entry "test-server") { has_server: ($cache | has server) has_timestamp: ($cache | has timestamp) } } | complete) let passed = ($result.exit_code == 0 and $result.stdout.has_server and $result.stdout.has_timestamp) test-result "cache: create entry structure" $passed } # Test: Read cache entry def test_read_cache_entry []: nothing -> record { let result = (do { let cache = (mock-read-cache-entry "test-server") $cache.server } | complete) let passed = ($result.exit_code == 0 and $result.stdout == "test-server") test-result "cache: read entry" $passed } # Test: Cache timestamp is valid def test_cache_timestamp_valid []: nothing -> record { let result = (do { let cache = (mock-create-cache-entry "test-server") ($cache.timestamp | describe) =~ "int" } | complete) let passed = ($result.exit_code == 0 and $result.stdout) test-result "cache: timestamp is integer" $passed } # Test: Price with net and gross def test_price_net_and_gross []: nothing -> record { let result = (do { let pricing = (mock-get-pricing) let st = ($pricing.server_types | first) let price = ($st.prices | first) let hourly = $price.price_hourly { has_net: ($hourly | has net) has_gross: ($hourly | has gross) } } | complete) let passed = ($result.exit_code == 0 and $result.stdout.has_net and $result.stdout.has_gross) test-result "pricing: net and gross prices" $passed } # Test: Multiple server types pricing def test_multiple_server_types []: nothing -> record { let result = (do { let pricing = (mock-get-pricing) ($pricing.server_types | length) } | complete) let passed = ($result.exit_code == 0 and $result.stdout > 1) test-result "pricing: multiple server types" $passed } # Test: Cache entry contains server name def test_cache_server_name []: nothing -> record { let result = (do { let cache = (mock-create-cache-entry "my-production-server") $cache.server == "my-production-server" } | complete) let passed = ($result.exit_code == 0 and $result.stdout) test-result "cache: preserves server name" $passed } # Test: Calculate pricing per GB def test_pricing_per_gb []: nothing -> record { let result = (do { # Volume pricing: 0.085 EUR per GB per month let volume_gb = 100 let volume_price = $volume_gb * 0.085 $volume_price > 0 } | complete) let passed = ($result.exit_code == 0 and $result.stdout) test-result "pricing: volume per GB calculation" $passed } # Test: Server type names available def test_server_type_names []: nothing -> record { let result = (do { let pricing = (mock-get-pricing) let names = ($pricing.server_types | map {|st| $st.name}) ("cx11" in $names) and ("cx21" in $names) } | complete) let passed = ($result.exit_code == 0 and $result.stdout) test-result "pricing: standard server types available" $passed } # Main test runner def main []: nothing -> record { print "=== Hetzner Pricing & Cache Integration Tests (Mock Mode) ===" print "" let results = [ (test_get_pricing_data) (test_server_type_pricing_structure) (test_pricing_hourly_rate) (test_pricing_monthly_rate) (test_create_cache_entry) (test_read_cache_entry) (test_cache_timestamp_valid) (test_price_net_and_gross) (test_multiple_server_types) (test_cache_server_name) (test_pricing_per_gb) (test_server_type_names) ] 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} }