All checks were successful
Test / Create distribution (push) Successful in 36s
Test / Sandbox (push) Successful in 2m36s
Test / Sandbox (race detector) (push) Successful in 4m47s
Test / Hpkg (push) Successful in 4m55s
Test / Hakurei (push) Successful in 4m59s
Test / Hakurei (race detector) (push) Successful in 6m26s
Test / Flake checks (push) Successful in 1m31s
These are for #26. None of them are implemented yet. This fixes up test cases for the change to happen. Existing source code and JSON configuration continue to have the same effect. Existing flags get its EPulse bit replaced by EPipeWire. Signed-off-by: Ophestra <cat@gensokyo.uk>
279 lines
6.7 KiB
Go
279 lines
6.7 KiB
Go
package hst_test
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"net"
|
|
"os"
|
|
"reflect"
|
|
"syscall"
|
|
"testing"
|
|
|
|
"hakurei.app/container/stub"
|
|
"hakurei.app/hst"
|
|
"hakurei.app/message"
|
|
)
|
|
|
|
func TestAppError(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
testCases := []struct {
|
|
name string
|
|
err error
|
|
s string
|
|
message string
|
|
is, isF error
|
|
}{
|
|
{"message", &hst.AppError{Step: "obtain uid from hsu", Err: stub.UniqueError(0),
|
|
Msg: "the setuid helper is missing: /run/wrappers/bin/hsu"},
|
|
"unique error 0 injected by the test suite",
|
|
"the setuid helper is missing: /run/wrappers/bin/hsu",
|
|
stub.UniqueError(0), os.ErrNotExist},
|
|
|
|
{"os.PathError", &hst.AppError{Step: "passthrough os.PathError",
|
|
Err: &os.PathError{Op: "stat", Path: "/proc/nonexistent", Err: os.ErrNotExist}},
|
|
"stat /proc/nonexistent: file does not exist",
|
|
"cannot stat /proc/nonexistent: file does not exist",
|
|
os.ErrNotExist, stub.UniqueError(0xdeadbeef)},
|
|
|
|
{"os.LinkError", &hst.AppError{Step: "passthrough os.LinkError",
|
|
Err: &os.LinkError{Op: "link", Old: "/proc/self", New: "/proc/nonexistent", Err: os.ErrNotExist}},
|
|
"link /proc/self /proc/nonexistent: file does not exist",
|
|
"cannot link /proc/self /proc/nonexistent: file does not exist",
|
|
os.ErrNotExist, stub.UniqueError(0xdeadbeef)},
|
|
|
|
{"os.SyscallError", &hst.AppError{Step: "passthrough os.SyscallError",
|
|
Err: &os.SyscallError{Syscall: "meow", Err: syscall.ENOSYS}},
|
|
"meow: function not implemented",
|
|
"cannot meow: function not implemented",
|
|
syscall.ENOSYS, syscall.ENOTRECOVERABLE},
|
|
|
|
{"net.OpError", &hst.AppError{Step: "passthrough net.OpError",
|
|
Err: &net.OpError{Op: "dial", Net: "cat", Err: net.UnknownNetworkError("cat")}},
|
|
"dial cat: unknown network cat",
|
|
"cannot dial cat: unknown network cat",
|
|
net.UnknownNetworkError("cat"), syscall.ENOTRECOVERABLE},
|
|
|
|
{"default", &hst.AppError{Step: "initialise container configuration", Err: stub.UniqueError(1)},
|
|
"unique error 1 injected by the test suite",
|
|
"cannot initialise container configuration: unique error 1 injected by the test suite",
|
|
stub.UniqueError(1), os.ErrInvalid},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("error", func(t *testing.T) {
|
|
t.Parallel()
|
|
if got := tc.err.Error(); got != tc.s {
|
|
t.Errorf("Error: %s, want %s", got, tc.s)
|
|
}
|
|
})
|
|
|
|
t.Run("message", func(t *testing.T) {
|
|
t.Parallel()
|
|
gotMessage, gotMessageOk := message.GetMessage(tc.err)
|
|
if want := tc.message != "\x00"; gotMessageOk != want {
|
|
t.Errorf("GetMessage: ok = %v, want %v", gotMessage, want)
|
|
}
|
|
|
|
if gotMessageOk {
|
|
if gotMessage != tc.message {
|
|
t.Errorf("GetMessage: %s, want %s", gotMessage, tc.message)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("is", func(t *testing.T) {
|
|
t.Parallel()
|
|
if !errors.Is(tc.err, tc.is) {
|
|
t.Errorf("Is: unexpected false for %v", tc.is)
|
|
}
|
|
if errors.Is(tc.err, tc.isF) {
|
|
t.Errorf("Is: unexpected true for %v", tc.isF)
|
|
}
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTemplate(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const want = `{
|
|
"id": "org.chromium.Chromium",
|
|
"enablements": {
|
|
"wayland": true,
|
|
"dbus": true,
|
|
"pipewire": true,
|
|
"pulse": true
|
|
},
|
|
"session_bus": {
|
|
"see": null,
|
|
"talk": [
|
|
"org.freedesktop.Notifications",
|
|
"org.freedesktop.FileManager1",
|
|
"org.freedesktop.ScreenSaver",
|
|
"org.freedesktop.secrets",
|
|
"org.kde.kwalletd5",
|
|
"org.kde.kwalletd6",
|
|
"org.gnome.SessionManager"
|
|
],
|
|
"own": [
|
|
"org.chromium.Chromium.*",
|
|
"org.mpris.MediaPlayer2.org.chromium.Chromium.*",
|
|
"org.mpris.MediaPlayer2.chromium.*"
|
|
],
|
|
"call": {
|
|
"org.freedesktop.portal.*": "*"
|
|
},
|
|
"broadcast": {
|
|
"org.freedesktop.portal.*": "@/org/freedesktop/portal/*"
|
|
},
|
|
"filter": true
|
|
},
|
|
"system_bus": {
|
|
"see": null,
|
|
"talk": [
|
|
"org.bluez",
|
|
"org.freedesktop.Avahi",
|
|
"org.freedesktop.UPower"
|
|
],
|
|
"own": null,
|
|
"call": null,
|
|
"broadcast": null,
|
|
"filter": true
|
|
},
|
|
"extra_perms": [
|
|
{
|
|
"ensure": true,
|
|
"path": "/var/lib/hakurei/u0",
|
|
"x": true
|
|
},
|
|
{
|
|
"path": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
|
"r": true,
|
|
"w": true,
|
|
"x": true
|
|
}
|
|
],
|
|
"identity": 9,
|
|
"groups": [
|
|
"video",
|
|
"dialout",
|
|
"plugdev"
|
|
],
|
|
"container": {
|
|
"hostname": "localhost",
|
|
"wait_delay": -1,
|
|
"env": {
|
|
"GOOGLE_API_KEY": "AIzaSyBHDrl33hwRp4rMQY0ziRbj8K9LPA6vUCY",
|
|
"GOOGLE_DEFAULT_CLIENT_ID": "77185425430.apps.googleusercontent.com",
|
|
"GOOGLE_DEFAULT_CLIENT_SECRET": "OTJgUOQcT7lO7GsGZq2G4IlT"
|
|
},
|
|
"filesystem": [
|
|
{
|
|
"type": "bind",
|
|
"dst": "/",
|
|
"src": "/var/lib/hakurei/base/org.debian",
|
|
"write": true,
|
|
"special": true
|
|
},
|
|
{
|
|
"type": "bind",
|
|
"dst": "/etc/",
|
|
"src": "/etc/",
|
|
"special": true
|
|
},
|
|
{
|
|
"type": "ephemeral",
|
|
"dst": "/tmp/",
|
|
"write": true,
|
|
"perm": 493
|
|
},
|
|
{
|
|
"type": "overlay",
|
|
"dst": "/nix/store",
|
|
"lower": [
|
|
"/var/lib/hakurei/base/org.nixos/ro-store"
|
|
],
|
|
"upper": "/var/lib/hakurei/nix/u0/org.chromium.Chromium/rw-store/upper",
|
|
"work": "/var/lib/hakurei/nix/u0/org.chromium.Chromium/rw-store/work"
|
|
},
|
|
{
|
|
"type": "link",
|
|
"dst": "/run/current-system",
|
|
"linkname": "/run/current-system",
|
|
"dereference": true
|
|
},
|
|
{
|
|
"type": "link",
|
|
"dst": "/run/opengl-driver",
|
|
"linkname": "/run/opengl-driver",
|
|
"dereference": true
|
|
},
|
|
{
|
|
"type": "bind",
|
|
"dst": "/data/data/org.chromium.Chromium",
|
|
"src": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
|
"write": true,
|
|
"ensure": true
|
|
},
|
|
{
|
|
"type": "bind",
|
|
"src": "/dev/dri",
|
|
"dev": true,
|
|
"optional": true
|
|
}
|
|
],
|
|
"username": "chronos",
|
|
"shell": "/run/current-system/sw/bin/zsh",
|
|
"home": "/data/data/org.chromium.Chromium",
|
|
"path": "/run/current-system/sw/bin/chromium",
|
|
"args": [
|
|
"chromium",
|
|
"--ignore-gpu-blocklist",
|
|
"--disable-smooth-scrolling",
|
|
"--enable-features=UseOzonePlatform",
|
|
"--ozone-platform=wayland"
|
|
],
|
|
"seccomp_compat": true,
|
|
"devel": true,
|
|
"userns": true,
|
|
"host_net": true,
|
|
"host_abstract": true,
|
|
"tty": true,
|
|
"multiarch": true,
|
|
"map_real_uid": true,
|
|
"device": true,
|
|
"share_runtime": true,
|
|
"share_tmpdir": true
|
|
}
|
|
}`
|
|
|
|
t.Run("marshal", func(t *testing.T) {
|
|
t.Parallel()
|
|
if p, err := json.MarshalIndent(hst.Template(), "", "\t"); err != nil {
|
|
t.Fatalf("cannot marshal: %v", err)
|
|
} else if s := string(p); s != want {
|
|
t.Fatalf("Template:\n%s\nwant:\n%s",
|
|
s, want)
|
|
}
|
|
})
|
|
|
|
t.Run("unmarshal", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var got *hst.Config
|
|
if err := json.Unmarshal([]byte(want), &got); err != nil {
|
|
t.Fatalf("Unmarshal: error = %v", err)
|
|
}
|
|
|
|
wantVal := hst.Template()
|
|
wantVal.Container.Flags = hst.FAll
|
|
if !reflect.DeepEqual(got, wantVal) {
|
|
t.Fatalf("Unmarshal: %#v, want %#v", got, wantVal)
|
|
}
|
|
})
|
|
}
|