From b70e91f201168cd948d2d0ef4efecb2cb0842fa3 Mon Sep 17 00:00:00 2001 From: Md Raiyan Date: Mon, 25 May 2026 07:38:06 +0000 Subject: [PATCH] test(unikontainers): add unit tests for pure functions Signed-off-by: Md Raiyan --- pkg/unikontainers/ipc_message_test.go | 105 ++++++++++++++++++++++++++ pkg/unikontainers/mount_test.go | 54 +++++++++++++ pkg/unikontainers/shared_fs_test.go | 66 ++++++++++++++++ 3 files changed, 225 insertions(+) create mode 100644 pkg/unikontainers/ipc_message_test.go create mode 100644 pkg/unikontainers/mount_test.go create mode 100644 pkg/unikontainers/shared_fs_test.go diff --git a/pkg/unikontainers/ipc_message_test.go b/pkg/unikontainers/ipc_message_test.go new file mode 100644 index 00000000..bc3ea2c0 --- /dev/null +++ b/pkg/unikontainers/ipc_message_test.go @@ -0,0 +1,105 @@ +// 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 unikontainers + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/vishvananda/netlink/nl" + "golang.org/x/sys/unix" +) + +func TestInt32msgSerialize(t *testing.T) { + native := nl.NativeEndian() + tests := []struct { + name string + msgType uint16 + value uint32 + }{ + { + name: "clone flags attribute with typical value", + msgType: cloneFlagsAttr, + value: unix.CLONE_NEWNET | unix.CLONE_NEWPID, + }, + { + name: "zero value", + msgType: cloneFlagsAttr, + value: 0, + }, + { + name: "max uint32 value", + msgType: oomScoreAdjAttr, + value: ^uint32(0), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + msg := &int32msg{Type: tt.msgType, Value: tt.value} + got := msg.Serialize() + assert.Equal(t, 8, len(got)) + assert.Equal(t, uint16(8), native.Uint16(got[0:2])) + assert.Equal(t, tt.msgType, native.Uint16(got[2:4])) + assert.Equal(t, tt.value, native.Uint32(got[4:8])) + }) + } +} + +func TestBytemsgSerialize(t *testing.T) { + native := nl.NativeEndian() + tests := []struct { + name string + msgType uint16 + value []byte + wantPanic bool + }{ + { + name: "empty value produces aligned buffer", + msgType: nsPathsAttr, + value: []byte{}, + }, + { + name: "non-empty value encodes correctly", + msgType: nsPathsAttr, + value: []byte("net:/tmp/netns"), + }, + { + name: "oversized value panics with netlinkError", + msgType: nsPathsAttr, + value: make([]byte, 65532), + wantPanic: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + msg := &bytemsg{Type: tt.msgType, Value: tt.value} + if tt.wantPanic { + assert.Panics(t, func() { msg.Serialize() }) + return + } + got := msg.Serialize() + l := msg.Len() + expectedLen := (l + unix.NLA_ALIGNTO - 1) &^ (unix.NLA_ALIGNTO - 1) + assert.Equal(t, expectedLen, len(got)) + assert.Equal(t, uint16(l), native.Uint16(got[0:2])) //nolint: gosec + assert.Equal(t, tt.msgType, native.Uint16(got[2:4])) + if len(tt.value) > 0 { + assert.Equal(t, tt.value, got[unix.NLA_HDRLEN:unix.NLA_HDRLEN+len(tt.value)]) + } + }) + } +} diff --git a/pkg/unikontainers/mount_test.go b/pkg/unikontainers/mount_test.go new file mode 100644 index 00000000..bdd810db --- /dev/null +++ b/pkg/unikontainers/mount_test.go @@ -0,0 +1,54 @@ +// 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 unikontainers + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "golang.org/x/sys/unix" +) + +func TestMapRootfsPropagationFlag(t *testing.T) { + tests := []struct { + name string + input string + expected int + wantErr bool + }{ + {name: "rprivate", input: "rprivate", expected: unix.MS_PRIVATE | unix.MS_REC}, + {name: "private", input: "private", expected: unix.MS_PRIVATE}, + {name: "rslave", input: "rslave", expected: unix.MS_SLAVE | unix.MS_REC}, + {name: "slave", input: "slave", expected: unix.MS_SLAVE}, + {name: "rshared", input: "rshared", expected: unix.MS_SHARED | unix.MS_REC}, + {name: "shared", input: "shared", expected: unix.MS_SHARED}, + {name: "runbindable", input: "runbindable", expected: unix.MS_UNBINDABLE | unix.MS_REC}, + {name: "unbindable", input: "unbindable", expected: unix.MS_UNBINDABLE}, + {name: "unknown value returns error", input: "unknown", wantErr: true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got, err := mapRootfsPropagationFlag(tt.input) + if tt.wantErr { + assert.Error(t, err) + assert.Equal(t, 0, got) + return + } + assert.NoError(t, err) + assert.Equal(t, tt.expected, got) + }) + } +} diff --git a/pkg/unikontainers/shared_fs_test.go b/pkg/unikontainers/shared_fs_test.go new file mode 100644 index 00000000..935497f7 --- /dev/null +++ b/pkg/unikontainers/shared_fs_test.go @@ -0,0 +1,66 @@ +// 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 unikontainers + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestChooseTmpfsSize(t *testing.T) { + const ( + mem256MB uint64 = 256 * 1024 * 1024 + mem512MB uint64 = 512 * 1024 * 1024 + ) + tests := []struct { + name string + sfsType string + mem uint64 + expected string + }{ + { + name: "9pfs returns constant regardless of memory", + sfsType: "9pfs", + mem: mem256MB, + expected: tmpfsSizeFor9pfsRootfs, + }, + { + name: "virtiofs 256 MB adds 1 MiB overhead", + sfsType: "virtiofs", + mem: mem256MB, + expected: "269m", + }, + { + name: "virtiofs 512 MB adds 1 MiB overhead", + sfsType: "virtiofs", + mem: mem512MB, + expected: "537m", + }, + { + name: "virtiofs zero memory uses 1 MiB overhead only", + sfsType: "virtiofs", + mem: 0, + expected: "1m", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got := chooseTmpfsSize(tt.sfsType, tt.mem) + assert.Equal(t, tt.expected, got) + }) + } +}