All checks were successful
		
		
	
	Test / Create distribution (push) Successful in 25s
				
			Test / Sandbox (push) Successful in 39s
				
			Test / Sandbox (race detector) (push) Successful in 39s
				
			Test / Hakurei (push) Successful in 42s
				
			Test / Hpkg (push) Successful in 40s
				
			Test / Hakurei (race detector) (push) Successful in 44s
				
			Test / Flake checks (push) Successful in 1m23s
				
			Sharing and persisting these directories do not always make sense. Make it optional here. Closes #16. Signed-off-by: Ophestra <cat@gensokyo.uk>
		
			
				
	
	
		
			278 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			278 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,
 | 
						|
		"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)
 | 
						|
		}
 | 
						|
	})
 | 
						|
}
 |