From 658e507f4684cb3cbc50484862e113a4dfb9afa2 Mon Sep 17 00:00:00 2001 From: r0hansaxena Date: Mon, 4 May 2026 17:01:30 +0530 Subject: [PATCH 1/2] test(hypervisors): add unit tests for HVT Signed-off-by: r0hansaxena --- pkg/unikontainers/hypervisors/hvt_test.go | 165 ++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 pkg/unikontainers/hypervisors/hvt_test.go diff --git a/pkg/unikontainers/hypervisors/hvt_test.go b/pkg/unikontainers/hypervisors/hvt_test.go new file mode 100644 index 000000000..8252f06bb --- /dev/null +++ b/pkg/unikontainers/hypervisors/hvt_test.go @@ -0,0 +1,165 @@ +// Copyright (c) 2023-2026, Nubificus LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package hypervisors + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/urunc-dev/urunc/pkg/unikontainers/types" +) + +func newTestHVT() *HVT { + return &HVT{ + binary: HvtBinary, + binaryPath: "/usr/bin/solo5-hvt", + } +} + +func TestHVTUsesKVM(t *testing.T) { + t.Parallel() + assert.True(t, newTestHVT().UsesKVM()) +} + +func TestHVTSupportsSharedfs(t *testing.T) { + t.Parallel() + h := newTestHVT() + assert.False(t, h.SupportsSharedfs("virtio")) + assert.False(t, h.SupportsSharedfs("9p")) + assert.False(t, h.SupportsSharedfs("")) +} + +func TestHVTPath(t *testing.T) { + t.Parallel() + assert.Equal(t, "/usr/bin/solo5-hvt", newTestHVT().Path()) +} + +func TestHVTOkBinaryNotFound(t *testing.T) { + t.Parallel() + assert.ErrorIs(t, newTestHVT().Ok(), ErrVMMNotInstalled) +} + +func TestHVTPreExecNoSeccomp(t *testing.T) { + t.Parallel() + assert.NoError(t, newTestHVT().PreExec(types.ExecArgs{Seccomp: false})) +} + +func TestHVTBuildExecCmd(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + args types.ExecArgs + unikernel *mockUnikernel + wantContain []string + wantAbsent []string + }{ + { + name: "binary path is first element", + args: types.ExecArgs{ + UnikernelPath: "/unikernel.bin", + }, + unikernel: &mockUnikernel{}, + wantContain: []string{"/usr/bin/solo5-hvt"}, + }, + { + name: "default memory when MemSizeB is zero", + args: types.ExecArgs{ + UnikernelPath: "/unikernel.bin", + }, + unikernel: &mockUnikernel{}, + wantContain: []string{"--mem=256"}, + }, + { + name: "memory set from MemSizeB", + args: types.ExecArgs{ + UnikernelPath: "/unikernel.bin", + MemSizeB: 512 * 1000 * 1000, + }, + unikernel: &mockUnikernel{}, + wantContain: []string{"--mem=512"}, + }, + { + name: "net cli from unikernel when TapDev set", + args: types.ExecArgs{ + UnikernelPath: "/unikernel.bin", + Net: types.NetDevParams{ + TapDev: "tap0", + MAC: "aa:bb:cc:dd:ee:ff", + }, + }, + unikernel: &mockUnikernel{netCli: "--net:service0=tap0"}, + wantContain: []string{"--net:service0=tap0"}, + }, + { + name: "no net args when TapDev is empty", + args: types.ExecArgs{ + UnikernelPath: "/unikernel.bin", + }, + unikernel: &mockUnikernel{}, + wantAbsent: []string{"--net"}, + }, + { + name: "block device appended", + args: types.ExecArgs{ + UnikernelPath: "/unikernel.bin", + }, + unikernel: &mockUnikernel{ + blockCli: []types.MonitorBlockArgs{ + {ID: "storage0", Path: "/dev/vda"}, + }, + }, + wantContain: []string{"--block:storage0=/dev/vda"}, + }, + { + name: "extra args from MonitorCli appended", + args: types.ExecArgs{ + UnikernelPath: "/unikernel.bin", + }, + unikernel: &mockUnikernel{ + monCli: types.MonitorCliArgs{OtherArgs: "--dumpcore"}, + }, + wantContain: []string{"--dumpcore"}, + }, + { + name: "unikernel path and command are last", + args: types.ExecArgs{ + UnikernelPath: "/unikernel.bin", + Command: "console=ttyS0", + }, + unikernel: &mockUnikernel{}, + wantContain: []string{"/unikernel.bin", "console=ttyS0"}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + h := newTestHVT() + got, err := h.BuildExecCmd(tc.args, tc.unikernel) + assert.NoError(t, err) + assert.Equal(t, "/usr/bin/solo5-hvt", got[0]) + + joined := strings.Join(got, " ") + for _, want := range tc.wantContain { + assert.Contains(t, joined, want) + } + for _, absent := range tc.wantAbsent { + assert.NotContains(t, joined, absent) + } + }) + } +} From 828b58e19651fc904635e194bcefee41de5c7921 Mon Sep 17 00:00:00 2001 From: r0hansaxena Date: Sat, 23 May 2026 08:28:56 +0530 Subject: [PATCH 2/2] update HVT tests Signed-off-by: r0hansaxena --- pkg/unikontainers/hypervisors/hvt_test.go | 72 +++++++++-------------- 1 file changed, 27 insertions(+), 45 deletions(-) diff --git a/pkg/unikontainers/hypervisors/hvt_test.go b/pkg/unikontainers/hypervisors/hvt_test.go index 8252f06bb..9d116f553 100644 --- a/pkg/unikontainers/hypervisors/hvt_test.go +++ b/pkg/unikontainers/hypervisors/hvt_test.go @@ -22,6 +22,20 @@ import ( "github.com/urunc-dev/urunc/pkg/unikontainers/types" ) +type mockUnikernel struct { + netCli string + blockCli []types.MonitorBlockArgs + monCli types.MonitorCliArgs +} + +func (m *mockUnikernel) Init(_ types.UnikernelParams) error { return nil } +func (m *mockUnikernel) CommandString() (string, error) { return "", nil } +func (m *mockUnikernel) SupportsBlock() bool { return false } +func (m *mockUnikernel) SupportsFS(_ string) bool { return false } +func (m *mockUnikernel) MonitorNetCli(_, _ string) string { return m.netCli } +func (m *mockUnikernel) MonitorBlockCli() []types.MonitorBlockArgs { return m.blockCli } +func (m *mockUnikernel) MonitorCli() types.MonitorCliArgs { return m.monCli } + func newTestHVT() *HVT { return &HVT{ binary: HvtBinary, @@ -29,34 +43,6 @@ func newTestHVT() *HVT { } } -func TestHVTUsesKVM(t *testing.T) { - t.Parallel() - assert.True(t, newTestHVT().UsesKVM()) -} - -func TestHVTSupportsSharedfs(t *testing.T) { - t.Parallel() - h := newTestHVT() - assert.False(t, h.SupportsSharedfs("virtio")) - assert.False(t, h.SupportsSharedfs("9p")) - assert.False(t, h.SupportsSharedfs("")) -} - -func TestHVTPath(t *testing.T) { - t.Parallel() - assert.Equal(t, "/usr/bin/solo5-hvt", newTestHVT().Path()) -} - -func TestHVTOkBinaryNotFound(t *testing.T) { - t.Parallel() - assert.ErrorIs(t, newTestHVT().Ok(), ErrVMMNotInstalled) -} - -func TestHVTPreExecNoSeccomp(t *testing.T) { - t.Parallel() - assert.NoError(t, newTestHVT().PreExec(types.ExecArgs{Seccomp: false})) -} - func TestHVTBuildExecCmd(t *testing.T) { t.Parallel() @@ -67,14 +53,6 @@ func TestHVTBuildExecCmd(t *testing.T) { wantContain []string wantAbsent []string }{ - { - name: "binary path is first element", - args: types.ExecArgs{ - UnikernelPath: "/unikernel.bin", - }, - unikernel: &mockUnikernel{}, - wantContain: []string{"/usr/bin/solo5-hvt"}, - }, { name: "default memory when MemSizeB is zero", args: types.ExecArgs{ @@ -134,15 +112,6 @@ func TestHVTBuildExecCmd(t *testing.T) { }, wantContain: []string{"--dumpcore"}, }, - { - name: "unikernel path and command are last", - args: types.ExecArgs{ - UnikernelPath: "/unikernel.bin", - Command: "console=ttyS0", - }, - unikernel: &mockUnikernel{}, - wantContain: []string{"/unikernel.bin", "console=ttyS0"}, - }, } for _, tc := range tests { @@ -163,3 +132,16 @@ func TestHVTBuildExecCmd(t *testing.T) { }) } } + +func TestHVTBuildExecCmdOrdering(t *testing.T) { + t.Parallel() + h := newTestHVT() + got, err := h.BuildExecCmd(types.ExecArgs{ + UnikernelPath: "/unikernel.bin", + Command: "console=ttyS0", + }, &mockUnikernel{}) + assert.NoError(t, err) + assert.Equal(t, "/usr/bin/solo5-hvt", got[0]) + assert.Equal(t, "/unikernel.bin", got[len(got)-2]) + assert.Equal(t, "console=ttyS0", got[len(got)-1]) +}