Documentation
¶
Overview ¶
Package pidonetest provides a simple way for running go tests in an isolated system. It requires QEMU to be present on the system.
Depending on the presence of GOARCH or the runtime arch, the correct qemu-system binary and machine type is used. KVM is enabled if present and accessible. Those things can be overridden by flags. See "pidonetest -help" for all flags.
Default mode ¶
The easiest way to use this package is to use the default mode. This does not need any special support by your test package. The downside is, that it can only be used if the target architecture matches the pidonetest binary architecture. See "Library" if you want to test for different architectures.
If the kernel used does not have support for Virtio-MMIO compiled in, use flag "-transport 0" in order to use legacy isa-pci serial consoles for IO.
Set absolute path to the kernel to use by environment variable:
$ export QEMU_KERNEL=/boot/vmlinuz-linux
If you have it installed with go install in your PATH:
$ go test -exec "pidonetest" .
Or build and run on the fly with "go run":
$ go test -exec 'go run github.com/aibor/pidonetest/cmd/pidonetest' .
There is also support for coverage profiles. Just specify it as usual:
$ go test -exec "pidonetest" -cover -coverprofile cover.out .
Standalone mode ¶
In Standalone mode, the test binary can be used as init binary directly. For this to work, the init steps need to be compiled in. this is done by defining your own TestMain function using the provided package as library.
The library part is a wrapper for testing.M.Run. Before running the tests some special system file systems are mounted, like /dev, /sys, /proc, /tmp, /run, /sys/fs/bpf/, /sys/kernel/tracing/.
In a test package, define your custom TestMain function and call pidonetest.RunTests. You may keep this in a separate test file and use build constraints in order to have an easy way of separating such test from normal go tests that can run on the same system:
//go:build pidonetest
package some_test
import (
"testing"
"github.com/aibor/pidonetest"
)
func TestMain(m *testing.M) {
pidonetest.RunTests(m)
}
See the selftest directory for a working example.
Instead of using pidonetest.RunTests you can use call the various parts individually, of course, and just mount the file systems you need or additional ones. See pidonetest.RunTests for the steps it does.
With the TestMain function in place, run the test and specify the pidonetest binary in one of the following ways. If the test binary is dynamically linked libraries are resolved. However, if you run into errors try again with "CGO_ENABLED=0", if you don't need cgo. In any case, make sure the QEMU binary used has the same architecture as the test binary.
If you have it installed with go install in your PATH:
$ go test -tags pidonetest -exec 'pidonetest -standalone' .
Or build and run on the fly with "go run":
$ go test -tags pidonetest -exec 'go run github.com/aibor/pidonetest/cmd/pidonetest -standalone' .
There is also support for coverage profiles. Just specify it as usual:
$ go test -tags pidonetest -exec 'pidonetest -standalone' -cover -coverprofile cover.out .
Other architectures work as well. You need a kernel for the target architecture.
$ GOARCH=arm64 go test -exec "pidonetest -kernel $(realpath kernel/vmlinuz.arm64) -standalone" .
Index ¶
- Variables
- func Exec(path string, args []string, outWriter, errWriter io.Writer) error
- func ExecParallel(paths []string, args []string, outW, errW io.Writer) error
- func IsPidOne() bool
- func IsPidOneChild() bool
- func MountAll() error
- func MountFs(path string, fstype FSType) error
- func Poweroff(err *error)
- func PrintRC(ret int)
- func Run(fn func() (int, error)) error
- func RunTests(m *testing.M)
- type FSType
- type MountPoint
- type MountPoints
Constants ¶
This section is empty.
Variables ¶
var ErrNotPidOne = errors.New("process does not have ID 1")
var MountPointPresets = map[string]MountPoints{ "amd64": { {"/proc", FSTypeProc}, {"/sys", FSTypeSys}, {"/sys/fs/bpf", FSTypeBpf}, {"/sys/kernel/tracing", FSTypeTracing}, {"/dev", FSTypeDevTmp}, {"/run", FSTypeTmp}, {"/tmp", FSTypeTmp}, }, "arm64": { {"/proc", FSTypeProc}, {"/sys", FSTypeSys}, {"/sys/fs/bpf", FSTypeBpf}, {"/dev", FSTypeDevTmp}, {"/run", FSTypeTmp}, {"/tmp", FSTypeTmp}, }, }
MountPointPresets defines architecture specific mount points.
Functions ¶
func Exec ¶ added in v0.6.0
Exec executes the given file wit the given arguments. Output and errors are written to the given writers immediately. Might return exec.ExitError.
func ExecParallel ¶ added in v0.6.0
ExecParallel executes the given files in parallel. Each is called with the given args. Output of the commands is written to the given out and err writers once the command exited. If there is only a single path given, output is printed unbuffered. It respects runtime.GOMAXPROCS and does run max the number set in parallel. Might return exec.ExitError.
func IsPidOneChild ¶
func IsPidOneChild() bool
IsPidOneChild returns true if the running process is a child of the process with PID 1.
func MountAll ¶
func MountAll() error
MountAll mounts all known essential special file systems at the usual paths.
All special file systems required for usual operations, like accessing kernel variables, modifying kernel knobs or accessing devices are mounted.
func MountFs ¶
MountFs mounts the special file system with type FsType at the given path.
If path does not exist, it is created. An error is returned if this or the mount syscall fails.
func Poweroff ¶
func Poweroff(err *error)
Poweroff shuts down the system.
Call when done, or deferred right at the beginning of your `TestMain` function. If the given error pointer and error are not nil, print it before shutting down.
func PrintRC ¶ added in v0.6.0
func PrintRC(ret int)
PrintRC prints the magic string communicating the return code of the tests.
func Run ¶
Run is the entry point for an actual init system. It prepares the system to be used. Preparing steps are: - Guarding itself to be actually PID 1. - Setup system poweroff on its exit. - Mount all known virtual system file systems.
Once this is done, the given function is run. The function must not call os.Exit itself since the program would not be able to ensure a correct system termination.
After that, a return code is sent to stdout for consumption by the host process. The return code returnded by the function is used, unless it returned with an error. If the error is an exec.ExitError, it is parsed and its return code is used. Otherwise the return code is 99.
func RunTests ¶ added in v0.6.0
RunTests sets up the system, runs the tests and shuts down the system.
Call it from your `TestMain` function. It wraps testing.M.Run and returns only in case of failure. It is an error if the process does not run with PID 1, since the intention of this library is to run test binaries in an isolated system.
Types ¶
type MountPoint ¶ added in v0.6.0
MountPoint is a single mount point for a virtual system FS.
type MountPoints ¶ added in v0.6.0
type MountPoints []MountPoint
MountPoints is a collection of MountPoints.