# FuelLog API smoke test (UTF-8 with BOM) # Usage: powershell -ExecutionPolicy Bypass -File scripts/smoke.ps1 $ErrorActionPreference = 'Stop' $base = 'http://127.0.0.1:8080' function Step($name, $scriptBlock) { Write-Host '' Write-Host "=== $name ===" -ForegroundColor Cyan & $scriptBlock } function Hit($method, $path, $body) { $params = @{ Uri = "$base$path" Method = $method UseBasicParsing = $true ContentType = 'application/json' } if ($null -ne $body) { $params.Body = (ConvertTo-Json -InputObject $body -Depth 10) } try { $r = Invoke-WebRequest @params -TimeoutSec 10 return @{ Status = [int]$r.StatusCode; Body = $r.Content } } catch { $resp = $_.Exception.Response if ($resp) { $stream = $resp.GetResponseStream() $reader = New-Object System.IO.StreamReader($stream) return @{ Status = [int]$resp.StatusCode; Body = $reader.ReadToEnd() } } throw } } function Check($label, $actual, $expected) { if ($actual -eq $expected) { Write-Host " OK ${label} = $actual" -ForegroundColor Green } else { Write-Host " FAIL ${label}: expected $expected, got $actual" -ForegroundColor Red exit 1 } } # 1) health Step 'health' { $r = Hit GET '/health' $null Check 'status' $r.Status 200 Write-Host " body: $($r.Body)" } # 2) list (counted, not asserted empty -- DB may carry data from prior runs) Step 'list vehicles' { $r = Hit GET '/api/vehicles' $null Check 'status' $r.Status 200 $list = $r.Body | ConvertFrom-Json Write-Host " initial count = $($list.Count) (may be > 0 from prior runs)" } # 3) create vehicle $vehicle = $null Step 'create vehicle' { $body = @{ name = 'My Car' brand = 'BYD' model = 'Qin PLUS DM-i' plate_number = 'Jing-A12345' fuel_type = 'hybrid' tank_capacity = 48 current_odometer = 10000 default_vehicle = $true } $r = Hit POST '/api/vehicles' $body Check 'status' $r.Status 200 $v = $r.Body | ConvertFrom-Json $script:vehicle = $v Write-Host " id=$($v.id) name=$($v.name) default=$($v.default_vehicle)" } # 4) verify created vehicle shows up in list Step 'list contains new vehicle' { $r = Hit GET '/api/vehicles' $null Check 'status' $r.Status 200 $list = $r.Body | ConvertFrom-Json $found = $list | Where-Object { $_.id -eq $vehicle.id } if (-not $found) { Write-Host " FAIL: new vehicle not in list"; exit 1 } Write-Host " OK new vehicle id=$($vehicle.id) found in list of $($list.Count)" } # 5) refuel #1 (full) $refuel1 = $null Step 'refuel #1 (full)' { $body = @{ vehicle_id = $vehicle.id refuel_time = '2025-08-25T10:00:00+08:00' odometer = 10500 fuel_type = 'hybrid' liters = 40 total_amount = 320 station_name = 'Sinopec Wangjing' is_full = $true remark = 'first full' } $r = Hit POST '/api/refuels' $body Check 'status' $r.Status 200 $rec = $r.Body | ConvertFrom-Json $script:refuel1 = $rec Write-Host " price_per_liter = $($rec.price_per_liter) (expect 8.0)" if ([math]::Abs([double]$rec.price_per_liter - 8.0) -gt 0.001) { Write-Host 'FAIL price'; exit 1 } } # 6) refuel #2 (full) $refuel2 = $null Step 'refuel #2 (full)' { $body = @{ vehicle_id = $vehicle.id refuel_time = '2025-09-10T10:00:00+08:00' odometer = 11000 fuel_type = 'hybrid' liters = 32 total_amount = 256 station_name = 'Sinopec Wangjing' is_full = $true } $r = Hit POST '/api/refuels' $body Check 'status' $r.Status 200 $rec = $r.Body | ConvertFrom-Json $script:refuel2 = $rec Write-Host " price_per_liter = $($rec.price_per_liter) (expect 8.0)" } # 7) refuel #3 (half - should NOT affect avg consumption) Step 'refuel #3 (half)' { $body = @{ vehicle_id = $vehicle.id refuel_time = '2025-09-15T10:00:00+08:00' odometer = 11200 fuel_type = 'hybrid' liters = 10 total_amount = 80 station_name = 'Sinopec Wangjing' is_full = $false } $r = Hit POST '/api/refuels' $body Check 'status' $r.Status 200 } # 8) statistics Step 'statistics' { $r = Hit GET "/api/vehicles/$($vehicle.id)/statistics" $null Check 'status' $r.Status 200 $s = $r.Body | ConvertFrom-Json Write-Host " total_records = $($s.total_records) (expect 3)" Write-Host " total_liters = $($s.total_liters) (expect 82)" Write-Host " total_amount = $($s.total_amount) (expect 656)" Write-Host " avg_price = $($s.avg_price) (expect ~8.0)" Write-Host " avg_consumption = $($s.avg_consumption) (expect ~6.4 = 32/500*100)" Write-Host " cost_per_km = $($s.cost_per_km) (expect ~0.512 = 256/500)" if ($s.total_records -ne 3) { Write-Host 'FAIL count'; exit 1 } if ([math]::Abs([double]$s.total_liters - 82) -gt 0.5) { Write-Host 'FAIL liters'; exit 1 } if ([math]::Abs([double]$s.total_amount - 656) -gt 0.5) { Write-Host 'FAIL amount'; exit 1 } if ([math]::Abs([double]$s.avg_price - 8.0) -gt 0.1) { Write-Host 'FAIL avg_price'; exit 1 } if ([math]::Abs([double]$s.avg_consumption - 6.4) -gt 0.5) { Write-Host 'FAIL consumption'; exit 1 } if ([math]::Abs([double]$s.cost_per_km - 0.512) -gt 0.05) { Write-Host 'FAIL cost_per_km'; exit 1 } } # 9) list refuels Step 'list refuels' { $r = Hit GET "/api/refuels?vehicle_id=$($vehicle.id)" $null Check 'status' $r.Status 200 $list = $r.Body | ConvertFrom-Json Write-Host " count = $($list.Count) (expect 3)" if ($list.Count -ne 3) { Write-Host 'FAIL count'; exit 1 } } # 10) delete refuel Step 'delete refuel #1' { $r = Hit DELETE "/api/refuels/$($refuel1.id)" $null Check 'status' $r.Status 204 } # 11) statistics after delete Step 'statistics after delete' { $r = Hit GET "/api/vehicles/$($vehicle.id)/statistics" $null Check 'status' $r.Status 200 $s = $r.Body | ConvertFrom-Json Write-Host " total_records = $($s.total_records) (expect 2)" if ($s.total_records -ne 2) { Write-Host 'FAIL count'; exit 1 } } # 12) delete vehicle Step 'delete vehicle' { $r = Hit DELETE "/api/vehicles/$($vehicle.id)" $null Check 'status' $r.Status 204 } # 13) get deleted -> 404 Step 'get deleted vehicle' { $r = Hit GET "/api/vehicles/$($vehicle.id)" $null Check 'status' $r.Status 404 Write-Host " body: $($r.Body)" } Write-Host '' Write-Host 'ALL SMOKE TESTS PASSED' -ForegroundColor Green