Skip to content

test(hypervisors): cover Qemu.BuildExecCmd#597

Merged
cmainas merged 1 commit into
urunc-dev:main-pr597from
parthdagia05:test/hypervisors-qemu-buildexeccmd
Jun 9, 2026
Merged

test(hypervisors): cover Qemu.BuildExecCmd#597
cmainas merged 1 commit into
urunc-dev:main-pr597from
parthdagia05:test/hypervisors-qemu-buildexeccmd

Conversation

@parthdagia05

Copy link
Copy Markdown
Contributor

Description

Qemu.BuildExecCmd in pkg/unikontainers/hypervisors/qemu.go didn't have any direct unit-test coverage, so this PR adds qemu_test.go that walks through the main branches the function actually exercises:

  • Static flags that should always be present
  • Memory default fallback and custom values
  • vCPU handling (omits -smp when zero, sets it correctly otherwise)
  • Seccomp on / off
  • Architecture-specific machine type (-M virt on arm64)
  • Networking: empty TapDev, generic tap setup, custom MonitorNetCli, and vhost on/off
  • Initrd present / absent
  • Sharedfs: 9pfs, virtiofs, and none
  • Block devices: no blocks, generic, and ExactArgs verbatim path
  • MonitorCli extras (ExtraInitrd, OtherArgs)
  • vsock with VAccelType set
  • The -append rule for the kernel command line

A small fakeUnikernel stub keeps the tests focused on BuildExecCmd itself rather than pulling in any real unikernel implementation.

Related issues

  • Fixes #

How was this tested?

  • go test ./pkg/unikontainers/hypervisors/... passes locally
  • go build ./... passes
  • All sub-tests use t.Parallel() and assert against the joined command string

LLM usage

Used Anthropic's Claude Opus 4.6 to help research the function's branches and shape the test cases around the actual code paths.

Checklist

  • I have read the contribution guide.
  • The linter passes locally (make lint).
  • The e2e tests of at least one tool pass locally (make test_ctr, make test_nerdctl, make test_docker, make test_crictl).
  • If LLMs were used: I have read the llm policy.

@netlify

netlify Bot commented May 1, 2026

Copy link
Copy Markdown

Deploy Preview for urunc canceled.

Name Link
🔨 Latest commit 4aee235
🔍 Latest deploy log https://app.netlify.com/projects/urunc/deploys/6a1ec166c226730008d0e913

@cmainas cmainas left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @parthdagia05 ,

thank you for this PR. Please do not use multiple test functions for the same test and:

@parthdagia05

Copy link
Copy Markdown
Contributor Author

@cmainas the per-feature test functions are now collapsed into a single TestQemuBuildExecCmd, the coverage is same as before

@cmainas cmainas left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @parthdagia05 ,

the new version is very complex without any reason. We want to test one function, which takes a struct as an argument. The struct which we pass as an argument controls the result. However, not all the fields of the struct affect the result. Therefore, we can focus only in the fields that affect the result.

Also, there are some specific values, like the qemu binary name or the argument of -kernel. These can be tested in a single test.


// withArgs returns defaultArgs() after applying the given modifier, so that
// each table case can declare only the fields it cares about.
func withArgs(modify func(*types.ExecArgs)) types.ExecArgs {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no need to pass a function to change the value of a struct.

mustContain: []string{"-smp 1"},
},
{
name: "VCPUs=4 emits -smp 4",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the same test as the above.

mustContain: []string{"-smp 4"},
},
{
name: "VCPUs=16 emits -smp 16",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the same test as the above.

@parthdagia05

Copy link
Copy Markdown
Contributor Author

Hi @cmainas, thanks for your feedback, I think I jumped into writing tests before fully understanding the patterns. Let me take a proper look through rest of the existing tests and update accordingly. I'd rather slow down and get the structure right than ship another iteration that misses something obvious.

@parthdagia05

Copy link
Copy Markdown
Contributor Author

@cmainas done with the changes.

@cmainas cmainas left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @parthdagia05 for the changes.

I believe we can remove the "extra" check defined in two tests and perform the same tests either directly in the test loop or with mustContain.

} else {
assert.NotContains(t, strings.Join(out, " "), archFlag)
}
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No reason for this to be an "extra" check. We can check it in the subtest loop instead.

Comment on lines +277 to +280
extra: func(t *testing.T, out []string) {
assert.GreaterOrEqual(t, len(out), 2)
assert.Equal(t, "-append", out[len(out)-2])
assert.Equal(t, "init=/bin/sh root=/dev/vda console=ttyS0", out[len(out)-1])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not need an "extra test for this". If we include the whole command in mustContain, then we can be sure that it is a single argument.

@parthdagia05

Copy link
Copy Markdown
Contributor Author

@cmainas removed the extra check

@cmainas cmainas left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @parthdagia05 ,

I have one more question. Sorry for not checking this earlier.


// Invariants that hold for every call to BuildExecCmd.
assert.Equal(t, testQemuBinary, out[0], "binary path must be the first element")
joined := strings.Join(out, " ")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason for joining the string, instead of check if out contains the respective strings?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because BuildExecCmd does strings.Split(cmdString, " ") (qemu.go-140th line), multi-word flags like -m 256M end up as two separate slice elements, so assert.Contains(out, "-m 256M") wouldn't match so i thought joining back is the simplest way to substring-check them as one piece.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this makes sense. We need to come up with a better scheme for the construction of the cli args.

@cmainas

cmainas commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Thank you @parthdagia05 for the changes. Can you rebase over main and squash your commits so we can merge?

Adds a table-driven test that covers the main branches of BuildExecCmd:
static flags, memory default and custom value, vCPUs, seccomp, the
architecture machine flag, networking (no-net, generic tap, custom
MonitorNetCli, vhost), initrd, sharedfs (9pfs / virtiofs), block devices
(generic and ExactArgs), MonitorCli extras, vsock, and the kernel
command append rule. A small fakeUnikernel stub keeps the tests
focused on BuildExecCmd itself.

Signed-off-by: Parth Dagia <parth.24bcs10414@sst.scaler.com>
@parthdagia05 parthdagia05 force-pushed the test/hypervisors-qemu-buildexeccmd branch from 8396e65 to 4aee235 Compare June 2, 2026 11:41
@parthdagia05

Copy link
Copy Markdown
Contributor Author

Done @cmainas

@urunc-bot urunc-bot Bot changed the base branch from main to main-pr597 June 9, 2026 12:42

@cmainas cmainas left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @parthdagia05 for the tests.

@cmainas cmainas merged commit 3a88a70 into urunc-dev:main-pr597 Jun 9, 2026
53 of 55 checks passed
github-actions Bot pushed a commit that referenced this pull request Jun 9, 2026
Adds a table-driven test that covers the main branches of BuildExecCmd:
static flags, memory default and custom value, vCPUs, seccomp, the
architecture machine flag, networking (no-net, generic tap, custom
MonitorNetCli, vhost), initrd, sharedfs (9pfs / virtiofs), block devices
(generic and ExactArgs), MonitorCli extras, vsock, and the kernel
command append rule. A small fakeUnikernel stub keeps the tests
focused on BuildExecCmd itself.

PR: #597
Signed-off-by: Parth Dagia <parth.24bcs10414@sst.scaler.com>
Reviewed-by: Charalampos Mainas <cmainas@nubificus.co.uk>
Approved-by: Charalampos Mainas <cmainas@nubificus.co.uk>
urunc-bot Bot pushed a commit that referenced this pull request Jun 9, 2026
Adds a table-driven test that covers the main branches of BuildExecCmd:
static flags, memory default and custom value, vCPUs, seccomp, the
architecture machine flag, networking (no-net, generic tap, custom
MonitorNetCli, vhost), initrd, sharedfs (9pfs / virtiofs), block devices
(generic and ExactArgs), MonitorCli extras, vsock, and the kernel
command append rule. A small fakeUnikernel stub keeps the tests
focused on BuildExecCmd itself.

PR: #597
Signed-off-by: Parth Dagia <parth.24bcs10414@sst.scaler.com>
Reviewed-by: Charalampos Mainas <cmainas@nubificus.co.uk>
Approved-by: Charalampos Mainas <cmainas@nubificus.co.uk>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants