Skip to content

test(grpc): TypeScript wire-level contract suite + codecov integration coverage - #58

Merged
markovejnovic merged 13 commits into
mainfrom
test/grpc-ts
Jul 8, 2026
Merged

test(grpc): TypeScript wire-level contract suite + codecov integration coverage#58
markovejnovic merged 13 commits into
mainfrom
test/grpc-ts

Conversation

@markovejnovic

Copy link
Copy Markdown
Contributor

Summary

A TypeScript integration suite (test/grpc/) that exercises the public gRPC surface (hyper.grpc.v0.Hyper) over the real wire, from outside the BEAM — driven by an ExUnit :integration wrapper so the server-side Elixir coverage it produces flows to Codecov.

  • TS contract suite (@grpc/grpc-js + @grpc/proto-loader, vitest): loads the committed proto/hyper/grpc/v0/hyper.proto directly; generated TS types are gitignored and rebuilt by npm scripts (repo codegen rule).
    • errors.test.ts — 7 tests pinning the proto's documented status-code contracts (NOT_FOUND ×3, INVALID_ARGUMENT ×4).
    • lifecycle.test.ts — LoadImage → RESOURCE_EXHAUSTED probe (TERA) → CreateVm → GetVm → ListVms → GetVmUsage → StopVm → polls GetVm to NOT_FOUND.
  • ExUnit wrapper test/e2e/grpc_contract_test.exs starts the gRPC server on port 50061 under the booted app tree and shells out to npm test.
  • Two real server bugs found and fixed by the suite:
    1. fix(grpc): unrecognised enum ints (e.g. instance_type: 999 — only producible by an off-BEAM client) raised FunctionClauseError → INTERNAL; now INVALID_ARGUMENT per the proto contract.
    2. fix(grpc): StopVm never tore the VM down — it flipped the gen_statem to the stub :stopping state and nothing terminated the supervisor, leaving the guest running and GetVm resolving forever. New Hyper.stop_vm/1 resolves the VM's supervisor via the routing registry and terminates it on the owning node.
  • Codecov: the integration job previously uploaded no coverage; it now runs mix coveralls.json and uploads under a new integration flag, plus vitest JUnit → Test Analytics under grpc-ts.

Test plan

  • Live run on a provisioned KVM host: errors 7/7 + lifecycle 1/1 over the wire (real VM boot/stop), post-stop NOT_FOUND observed, no leaked firecracker
  • Unit gates: format / compile -Werror / credo --strict / dialyzer / 316 tests
  • CI integration job green with both Codecov uploads accepted (this PR run)

An off-BEAM client can send any integer in an enum field; protobuf
decodes it verbatim and instance_type/1 / arch/1 had no clause for it,
so the promised INVALID_ARGUMENT surfaced as an INTERNAL crash.
State.stop/1 only flipped the gen_statem to :stopping -- a stub state
whose teardown nobody performed, so the guest kept running and GetVm
resolved it forever. Route StopVm through a new Hyper.stop_vm/1 that
resolves the VM's supervisor from the routing registry and terminates
it on the owning node via Hyper.Node.stop_image_vm/1.
# Conflicts:
#	.github/workflows/ci.yml
#	codecov.yml
@codecov

codecov Bot commented Jul 7, 2026

Copy link
Copy Markdown

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
155 1 154 316
View the full list of 1 ❄️ flaky test(s)
Elixir.Hyper.E2e.VmLifecycleTest::test load -> create_vm -> exec -> stop reclaims the VM's dm volume

Flake rate in main: 33.33% (Passed 2 times, Failed 1 times)

Stack Traces | 61.7s run time
1) test load -> create_vm -> exec -> stop reclaims the VM's dm volume (Hyper.E2e.VmLifecycleTest)
     test/e2e/vm_lifecycle_test.exs:33
     no usage row after stop_image_vm — the teardown flush never landed
     code: assert poll_until(fn -> Usage.total(vm_id) != nil end, :timer.seconds(30)),
     stacktrace:
       test/e2e/vm_lifecycle_test.exs:66: (test)

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

Test Results

  4 files  + 1  163 suites  +4   2m 4s ⏱️ -28s
471 tests +11  470 ✅ +10    0 💤 ±0  1 ❌ +1 
798 runs  +14  470 ✅ +10  327 💤 +3  1 ❌ +1 

For more details on these failures, see this check.

Results for commit 53864ed. ± Comparison against base commit ef7243a.

♻️ This comment has been updated with latest results.

Final-review wave: the finally-block StopVm no longer masks the try
block's original failure when the VM is already gone; npm output
streams line-by-line instead of buffering until exit; the wrapper's
timeout reflects its real 25-minute ceiling and the CI job budget
gets headroom above the sum of its parts.
@markovejnovic

Copy link
Copy Markdown
Contributor Author

Status: branch is review-complete and ready to merge on its own scope. The integration job's remaining red is main's new metering assertion (vm_lifecycle_test.exs:66): a pre-existing Meter blind spot — a VM living under the 1s sample interval never writes a usage row because the first Accumulator observation only sets the baseline. This suite exposes it by warming the alpine image cache (the VM's whole lifecycle drops to ~1s). Being fixed separately per Marko. The integration coverage upload step (flag integration) is gated on a green job and will be exercised once that fix lands; the grpc-ts Test Analytics upload already works (verified in run 28905343125).

@markovejnovic
markovejnovic merged commit 5b5068f into main Jul 8, 2026
5 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant