|
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 |
|
@@ -224,6 +226,14 @@ jobs: |
224 | 226 | - example: networking-py |
225 | 227 | args: "--port 8080 -- /echo_server_test.py" |
226 | 228 | expect: "SUCCESS: bind\\+listen on port 8080 allowed" |
| 229 | + - example: go-http |
| 230 | + args: "--port 8080 -- /bin/server" |
| 231 | + expect: "Hello from Hyperlight-Unikraft!" |
| 232 | + http_port: "8080" |
| 233 | + - example: dotnet-http |
| 234 | + args: "--port 8080 -- /app/KestrelHyperlight" |
| 235 | + expect: "Hello from Kestrel on Hyperlight!" |
| 236 | + http_port: "8080" |
227 | 237 | steps: |
228 | 238 | - uses: actions/checkout@v4 |
229 | 239 |
|
@@ -345,9 +355,47 @@ jobs: |
345 | 355 | mkdir -p "$mount_dir" |
346 | 356 | mount_args="--mount $mount_dir:/host" |
347 | 357 | fi |
| 358 | + |
348 | 359 | tool_args="" |
349 | 360 | if [ "${{ matrix.needs_echo_tool }}" = "true" ]; then |
350 | 361 | tool_args="--tool echo=../echo-wasm-host-fxn/target/wasm32-wasip1/release/echo-wasm-host-fxn.wasm" |
| 362 | + fi |
| 363 | + |
| 364 | + # HTTP server examples: start in background, poll, curl, kill. |
| 365 | + http_port="${{ matrix.http_port }}" |
| 366 | + if [ -n "$http_port" ]; then |
| 367 | + mem_args="" |
| 368 | + if [ -n "$memory" ]; then |
| 369 | + mem_args="-m $memory" |
| 370 | + fi |
| 371 | + hyperlight-unikraft -q $mem_args "$kernel" --initrd "$cpio" ${{ matrix.args }} & |
| 372 | + server_pid=$! |
| 373 | + sleep 3 |
| 374 | + ready=0 |
| 375 | + for i in $(seq 1 30); do |
| 376 | + if curl -s --max-time 10 "http://127.0.0.1:${http_port}" >/dev/null 2>&1; then |
| 377 | + ready=1 |
| 378 | + break |
| 379 | + fi |
| 380 | + sleep 1 |
| 381 | + done |
| 382 | + if [ "$ready" -ne 1 ]; then |
| 383 | + echo "FAIL: server did not become ready within timeout" |
| 384 | + kill "$server_pid" 2>/dev/null || true |
| 385 | + exit 1 |
| 386 | + fi |
| 387 | + response=$(curl -s --max-time 10 "http://127.0.0.1:${http_port}") |
| 388 | + kill "$server_pid" 2>/dev/null || true |
| 389 | + wait "$server_pid" 2>/dev/null || true |
| 390 | + echo "=== HTTP response ===" |
| 391 | + echo "$response" |
| 392 | + if echo "$response" | grep -qF "$expect"; then |
| 393 | + echo "PASS: matched /$expect/" |
| 394 | + else |
| 395 | + echo "FAIL: did not match /$expect/" |
| 396 | + exit 1 |
| 397 | + fi |
| 398 | + exit 0 |
351 | 399 | fi |
352 | 400 | case "${{ matrix.driver }}" in |
353 | 401 | multifn-test) |
@@ -414,6 +462,8 @@ jobs: |
414 | 462 | - python-agent-driver |
415 | 463 | - powershell |
416 | 464 | - networking-py |
| 465 | + - go-http |
| 466 | + - dotnet-http |
417 | 467 | steps: |
418 | 468 | - uses: actions/checkout@v4 |
419 | 469 |
|
@@ -566,6 +616,14 @@ jobs: |
566 | 616 | - example: networking-py |
567 | 617 | args: "--port 8080 -- /echo_server_test.py" |
568 | 618 | expect: "SUCCESS: bind\\+listen on port 8080 allowed" |
| 619 | + - example: go-http |
| 620 | + args: "--port 8080 -- /bin/server" |
| 621 | + expect: "Hello from Hyperlight-Unikraft!" |
| 622 | + http_port: "8080" |
| 623 | + - example: dotnet-http |
| 624 | + args: "--port 8080 -- /app/KestrelHyperlight" |
| 625 | + expect: "Hello from Kestrel on Hyperlight!" |
| 626 | + http_port: "8080" |
569 | 627 | steps: |
570 | 628 | - uses: actions/checkout@v4 |
571 | 629 |
|
@@ -647,6 +705,54 @@ jobs: |
647 | 705 | $PSNativeCommandUseErrorActionPreference = $false |
648 | 706 | $ErrorActionPreference = 'Continue' |
649 | 707 |
|
| 708 | + # HTTP server examples: start in background, poll, curl, kill. |
| 709 | + $httpPort = '${{ matrix.http_port }}' |
| 710 | + if ($httpPort -ne '') { |
| 711 | + $argList = @() |
| 712 | + if ($runArgs -ne '') { |
| 713 | + $argList = $runArgs.Split(' ') | Where-Object { $_ -ne '' } |
| 714 | + } |
| 715 | + $memArgs = @() |
| 716 | + if ($memory -ne '') { |
| 717 | + $memArgs = @('-m', $memory) |
| 718 | + } |
| 719 | + $stderrLog = Join-Path $env:RUNNER_TEMP 'hl-stderr.log' |
| 720 | + $proc = Start-Process -FilePath 'hyperlight-unikraft' ` |
| 721 | + -ArgumentList (@('-q') + $memArgs + @($kernel, '--initrd', $cpio) + $argList) ` |
| 722 | + -PassThru -NoNewWindow -RedirectStandardError $stderrLog |
| 723 | + # Give the server time to boot the unikernel and start listening |
| 724 | + Start-Sleep -Seconds 5 |
| 725 | + $ready = $false |
| 726 | + for ($i = 0; $i -lt 30; $i++) { |
| 727 | + try { |
| 728 | + $null = Invoke-WebRequest -Uri "http://127.0.0.1:${httpPort}" -UseBasicParsing -TimeoutSec 10 -ErrorAction Stop |
| 729 | + $ready = $true |
| 730 | + break |
| 731 | + } catch { |
| 732 | + Start-Sleep -Seconds 1 |
| 733 | + } |
| 734 | + } |
| 735 | + if (-not $ready) { |
| 736 | + Write-Host "FAIL: server did not become ready within timeout" |
| 737 | + Write-Host "=== stderr (last 200 lines) ===" |
| 738 | + Get-Content $stderrLog -Tail 200 -ErrorAction SilentlyContinue |
| 739 | + Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue |
| 740 | + exit 1 |
| 741 | + } |
| 742 | + $raw = (Invoke-WebRequest -Uri "http://127.0.0.1:${httpPort}" -UseBasicParsing -TimeoutSec 10).Content |
| 743 | + if ($raw -is [byte[]]) { $resp = [System.Text.Encoding]::UTF8.GetString($raw) } else { $resp = $raw } |
| 744 | + Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue |
| 745 | + Write-Host "=== HTTP response ===" |
| 746 | + Write-Host $resp |
| 747 | + if ($resp -match [regex]::Escape($expect)) { |
| 748 | + Write-Host "PASS: matched /$expect/" |
| 749 | + exit 0 |
| 750 | + } else { |
| 751 | + Write-Host "FAIL: did not match /$expect/" |
| 752 | + exit 1 |
| 753 | + } |
| 754 | + } |
| 755 | +
|
650 | 756 | switch ($driver) { |
651 | 757 | 'multifn-test' { |
652 | 758 | $out = & multifn-test $kernel $cpio 2>&1 |
|
0 commit comments