|
61 | 61 | - python-agent-driver |
62 | 62 | - powershell |
63 | 63 | - networking-py |
| 64 | + - go-http |
| 65 | + - dotnet-http |
64 | 66 | steps: |
65 | 67 | - uses: actions/checkout@v4 |
66 | 68 |
|
@@ -223,6 +225,14 @@ jobs: |
223 | 225 | - example: networking-py |
224 | 226 | args: "--port 8080 -- /echo_server_test.py" |
225 | 227 | expect: "SUCCESS: bind\\+listen on port 8080 allowed" |
| 228 | + - example: go-http |
| 229 | + args: "--port 8080 -- /bin/server" |
| 230 | + expect: "Hello from Hyperlight-Unikraft!" |
| 231 | + http_port: "8080" |
| 232 | + - example: dotnet-http |
| 233 | + args: "--port 8080 -- /app/KestrelHyperlight" |
| 234 | + expect: "Hello from Kestrel on Hyperlight!" |
| 235 | + http_port: "8080" |
226 | 236 | steps: |
227 | 237 | - uses: actions/checkout@v4 |
228 | 238 |
|
@@ -338,6 +348,42 @@ jobs: |
338 | 348 | mkdir -p "$mount_dir" |
339 | 349 | mount_args="--mount $mount_dir:/host" |
340 | 350 | fi |
| 351 | + # HTTP server examples: start in background, poll, curl, kill. |
| 352 | + http_port="${{ matrix.http_port }}" |
| 353 | + if [ -n "$http_port" ]; then |
| 354 | + mem_args="" |
| 355 | + if [ -n "$memory" ]; then |
| 356 | + mem_args="-m $memory" |
| 357 | + fi |
| 358 | + hyperlight-unikraft -q $mem_args "$kernel" --initrd "$cpio" ${{ matrix.args }} & |
| 359 | + server_pid=$! |
| 360 | + sleep 3 |
| 361 | + ready=0 |
| 362 | + for i in $(seq 1 30); do |
| 363 | + if curl -s --max-time 10 "http://127.0.0.1:${http_port}" >/dev/null 2>&1; then |
| 364 | + ready=1 |
| 365 | + break |
| 366 | + fi |
| 367 | + sleep 1 |
| 368 | + done |
| 369 | + if [ "$ready" -ne 1 ]; then |
| 370 | + echo "FAIL: server did not become ready within timeout" |
| 371 | + kill "$server_pid" 2>/dev/null || true |
| 372 | + exit 1 |
| 373 | + fi |
| 374 | + response=$(curl -s --max-time 10 "http://127.0.0.1:${http_port}") |
| 375 | + kill "$server_pid" 2>/dev/null || true |
| 376 | + wait "$server_pid" 2>/dev/null || true |
| 377 | + echo "=== HTTP response ===" |
| 378 | + echo "$response" |
| 379 | + if echo "$response" | grep -qF "$expect"; then |
| 380 | + echo "PASS: matched /$expect/" |
| 381 | + else |
| 382 | + echo "FAIL: did not match /$expect/" |
| 383 | + exit 1 |
| 384 | + fi |
| 385 | + exit 0 |
| 386 | + fi |
341 | 387 | case "${{ matrix.driver }}" in |
342 | 388 | multifn-test) |
343 | 389 | cmd=(timeout 60 /home/runner/work/hyperlight-unikraft/hyperlight-unikraft/host/target/release/multifn-test "$kernel" "$cpio") |
@@ -403,6 +449,8 @@ jobs: |
403 | 449 | - python-agent-driver |
404 | 450 | - powershell |
405 | 451 | - networking-py |
| 452 | + - go-http |
| 453 | + - dotnet-http |
406 | 454 | steps: |
407 | 455 | - uses: actions/checkout@v4 |
408 | 456 |
|
@@ -554,6 +602,14 @@ jobs: |
554 | 602 | - example: networking-py |
555 | 603 | args: "--port 8080 -- /echo_server_test.py" |
556 | 604 | expect: "SUCCESS: bind\\+listen on port 8080 allowed" |
| 605 | + - example: go-http |
| 606 | + args: "--port 8080 -- /bin/server" |
| 607 | + expect: "Hello from Hyperlight-Unikraft!" |
| 608 | + http_port: "8080" |
| 609 | + - example: dotnet-http |
| 610 | + args: "--port 8080 -- /app/KestrelHyperlight" |
| 611 | + expect: "Hello from Kestrel on Hyperlight!" |
| 612 | + http_port: "8080" |
557 | 613 | steps: |
558 | 614 | - uses: actions/checkout@v4 |
559 | 615 |
|
@@ -622,6 +678,54 @@ jobs: |
622 | 678 | $PSNativeCommandUseErrorActionPreference = $false |
623 | 679 | $ErrorActionPreference = 'Continue' |
624 | 680 |
|
| 681 | + # HTTP server examples: start in background, poll, curl, kill. |
| 682 | + $httpPort = '${{ matrix.http_port }}' |
| 683 | + if ($httpPort -ne '') { |
| 684 | + $argList = @() |
| 685 | + if ($runArgs -ne '') { |
| 686 | + $argList = $runArgs.Split(' ') | Where-Object { $_ -ne '' } |
| 687 | + } |
| 688 | + $memArgs = @() |
| 689 | + if ($memory -ne '') { |
| 690 | + $memArgs = @('-m', $memory) |
| 691 | + } |
| 692 | + $stderrLog = Join-Path $env:RUNNER_TEMP 'hl-stderr.log' |
| 693 | + $proc = Start-Process -FilePath 'hyperlight-unikraft' ` |
| 694 | + -ArgumentList (@('-q') + $memArgs + @($kernel, '--initrd', $cpio) + $argList) ` |
| 695 | + -PassThru -NoNewWindow -RedirectStandardError $stderrLog |
| 696 | + # Give the server time to boot the unikernel and start listening |
| 697 | + Start-Sleep -Seconds 5 |
| 698 | + $ready = $false |
| 699 | + for ($i = 0; $i -lt 30; $i++) { |
| 700 | + try { |
| 701 | + $null = Invoke-WebRequest -Uri "http://127.0.0.1:${httpPort}" -UseBasicParsing -TimeoutSec 10 -ErrorAction Stop |
| 702 | + $ready = $true |
| 703 | + break |
| 704 | + } catch { |
| 705 | + Start-Sleep -Seconds 1 |
| 706 | + } |
| 707 | + } |
| 708 | + if (-not $ready) { |
| 709 | + Write-Host "FAIL: server did not become ready within timeout" |
| 710 | + Write-Host "=== stderr (last 200 lines) ===" |
| 711 | + Get-Content $stderrLog -Tail 200 -ErrorAction SilentlyContinue |
| 712 | + Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue |
| 713 | + exit 1 |
| 714 | + } |
| 715 | + $raw = (Invoke-WebRequest -Uri "http://127.0.0.1:${httpPort}" -UseBasicParsing -TimeoutSec 10).Content |
| 716 | + if ($raw -is [byte[]]) { $resp = [System.Text.Encoding]::UTF8.GetString($raw) } else { $resp = $raw } |
| 717 | + Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue |
| 718 | + Write-Host "=== HTTP response ===" |
| 719 | + Write-Host $resp |
| 720 | + if ($resp -match [regex]::Escape($expect)) { |
| 721 | + Write-Host "PASS: matched /$expect/" |
| 722 | + exit 0 |
| 723 | + } else { |
| 724 | + Write-Host "FAIL: did not match /$expect/" |
| 725 | + exit 1 |
| 726 | + } |
| 727 | + } |
| 728 | +
|
625 | 729 | switch ($driver) { |
626 | 730 | 'multifn-test' { |
627 | 731 | $out = & multifn-test $kernel $cpio 2>&1 |
|
0 commit comments