From 4cfb1fda8f07045f50a8e6d0f1c5469e3fa3e269 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Sun, 19 Oct 2025 00:30:56 +0900 Subject: [PATCH] internal/app/spwayland: check behaviour This op is quite clean. Might get slightly more complex at some point passing socket fd. Signed-off-by: Ophestra --- internal/app/spwayland.go | 1 + internal/app/spwayland_test.go | 104 +++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 internal/app/spwayland_test.go diff --git a/internal/app/spwayland.go b/internal/app/spwayland.go index 5355c32..d8c1838 100644 --- a/internal/app/spwayland.go +++ b/internal/app/spwayland.go @@ -12,6 +12,7 @@ import ( func init() { gob.Register(new(spWaylandOp)) } // spWaylandOp exports the Wayland display server to the container. +// Runs after spRuntimeOp. type spWaylandOp struct { // Path to host wayland socket. Populated during toSystem if DirectWayland is true. SocketPath *check.Absolute diff --git a/internal/app/spwayland_test.go b/internal/app/spwayland_test.go new file mode 100644 index 0000000..89c8147 --- /dev/null +++ b/internal/app/spwayland_test.go @@ -0,0 +1,104 @@ +package app + +import ( + "testing" + + "hakurei.app/container" + "hakurei.app/container/stub" + "hakurei.app/hst" + "hakurei.app/system" + "hakurei.app/system/acl" + "hakurei.app/system/wayland" +) + +func TestSpWaylandOp(t *testing.T) { + t.Parallel() + config := hst.Template() + + checkOpBehaviour(t, []opBehaviourTestCase{ + {"not enabled", func(bool, bool) outcomeOp { + return new(spWaylandOp) + }, func() *hst.Config { + c := hst.Template() + *c.Enablements = 0 + return c + }, nil, nil, nil, nil, errNotEnabled, nil, nil, nil, nil, nil}, + + {"success notAbs defaultAppId", func(bool, bool) outcomeOp { + return new(spWaylandOp) + }, func() *hst.Config { + c := hst.Template() + c.ID = "" + return c + }, nil, []stub.Call{ + call("lookupEnv", stub.ExpectArgs{"WAYLAND_DISPLAY"}, "wayland-1", nil), + }, newI(). + // state.instance + Ephemeral(system.Process, m(wantInstancePrefix), 0711). + // toSystem + Wayland( + m(wantInstancePrefix+"/wayland"), + m(wantRuntimePath+"/wayland-1"), + "app.hakurei."+wantAutoEtcPrefix, + wantAutoEtcPrefix, + ), sysUsesInstance(nil), nil, insertsOps(afterSpRuntimeOp(nil)), []stub.Call{ + // this op configures the container state and does not make calls during toContainer + }, &container.Params{ + Ops: new(container.Ops). + Bind(m(wantInstancePrefix+"/wayland"), m("/run/user/1000/wayland-0"), 0), + }, paramsWantEnv(config, map[string]string{ + wayland.WaylandDisplay: wayland.FallbackName, + }, nil), nil}, + + {"success direct", func(isShim, _ bool) outcomeOp { + if !isShim { + return new(spWaylandOp) + } + return &spWaylandOp{SocketPath: m("/proc/nonexistent/wayland")} + }, func() *hst.Config { + c := hst.Template() + c.DirectWayland = true + return c + }, nil, []stub.Call{ + call("lookupEnv", stub.ExpectArgs{"WAYLAND_DISPLAY"}, "/proc/nonexistent/wayland", nil), + call("verbose", stub.ExpectArgs{[]any{"direct wayland access, PROCEED WITH CAUTION"}}, nil, nil), + }, newI(). + // state.ensureRuntimeDir + Ensure(m(wantRunDirPath), 0700). + UpdatePermType(system.User, m(wantRunDirPath), acl.Execute). + Ensure(m(wantRuntimePath), 0700). + UpdatePermType(system.User, m(wantRuntimePath), acl.Execute). + // toSystem + UpdatePermType(hst.EWayland, m("/proc/nonexistent/wayland"), acl.Read, acl.Write, acl.Execute), nil, nil, insertsOps(afterSpRuntimeOp(nil)), []stub.Call{ + // this op configures the container state and does not make calls during toContainer + }, &container.Params{ + Ops: new(container.Ops). + Bind(m("/proc/nonexistent/wayland"), m("/run/user/1000/wayland-0"), 0), + }, paramsWantEnv(config, map[string]string{ + wayland.WaylandDisplay: wayland.FallbackName, + }, nil), nil}, + + {"success", func(bool, bool) outcomeOp { + return new(spWaylandOp) + }, hst.Template, nil, []stub.Call{ + call("lookupEnv", stub.ExpectArgs{"WAYLAND_DISPLAY"}, nil, nil), + call("verbose", stub.ExpectArgs{[]any{"WAYLAND_DISPLAY is not set, assuming wayland-0"}}, nil, nil), + }, newI(). + // state.instance + Ephemeral(system.Process, m(wantInstancePrefix), 0711). + // toSystem + Wayland( + m(wantInstancePrefix+"/wayland"), + m(wantRuntimePath+"/"+wayland.FallbackName), + "org.chromium.Chromium", + wantAutoEtcPrefix, + ), sysUsesInstance(nil), nil, insertsOps(afterSpRuntimeOp(nil)), []stub.Call{ + // this op configures the container state and does not make calls during toContainer + }, &container.Params{ + Ops: new(container.Ops). + Bind(m(wantInstancePrefix+"/wayland"), m("/run/user/1000/wayland-0"), 0), + }, paramsWantEnv(config, map[string]string{ + wayland.WaylandDisplay: wayland.FallbackName, + }, nil), nil}, + }) +}