internal/app/spcontainer: check params init behaviour
All checks were successful
Test / Create distribution (push) Successful in 34s
Test / Hakurei (push) Successful in 3m6s
Test / Hpkg (push) Successful in 4m4s
Test / Sandbox (push) Successful in 1m21s
Test / Hakurei (race detector) (push) Successful in 5m23s
Test / Sandbox (race detector) (push) Successful in 2m8s
Test / Flake checks (push) Successful in 1m31s
All checks were successful
Test / Create distribution (push) Successful in 34s
Test / Hakurei (push) Successful in 3m6s
Test / Hpkg (push) Successful in 4m4s
Test / Sandbox (push) Successful in 1m21s
Test / Hakurei (race detector) (push) Successful in 5m23s
Test / Sandbox (race detector) (push) Successful in 2m8s
Test / Flake checks (push) Successful in 1m31s
This change also significantly reduces duplicate information in test case. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
parent
9290748761
commit
9e3df0905b
@ -33,19 +33,17 @@ var checkExpectInstanceId = *(*state.ID)(bytes.Repeat([]byte{0xaa}, len(state.ID
|
||||
|
||||
type opBehaviourTestCase struct {
|
||||
name string
|
||||
newOp func() outcomeOp
|
||||
newOp func(isShim, clearUnexported bool) outcomeOp
|
||||
newConfig func() *hst.Config
|
||||
|
||||
pStateSys func(state *outcomeStateSys)
|
||||
toSystem []stub.Call
|
||||
wantOpSys outcomeOp
|
||||
wantSys *system.I
|
||||
extraCheckSys func(t *testing.T, state *outcomeStateSys)
|
||||
wantErrSystem error
|
||||
|
||||
pStateContainer func(state *outcomeStateParams)
|
||||
toContainer []stub.Call
|
||||
wantOpContainer outcomeOp
|
||||
wantParams *container.Params
|
||||
extraCheckParams func(t *testing.T, state *outcomeStateParams)
|
||||
wantErrContainer error
|
||||
@ -94,11 +92,11 @@ func checkOpBehaviour(t *testing.T, testCases []opBehaviourTestCase) {
|
||||
if err := s.populateLocal(k, k); err != nil {
|
||||
t.Fatalf("populateLocal: error = %v", err)
|
||||
}
|
||||
stateSys := s.newSys(config, system.New(panicMsgContext{}, panicMsgContext{}, checkExpectUid))
|
||||
stateSys := s.newSys(config, newI())
|
||||
if tc.pStateSys != nil {
|
||||
tc.pStateSys(stateSys)
|
||||
}
|
||||
op := tc.newOp()
|
||||
op := tc.newOp(false, true)
|
||||
|
||||
if err := op.toSystem(stateSys); !reflect.DeepEqual(err, tc.wantErrSystem) {
|
||||
t.Errorf("toSystem: error = %v, want %v", err, tc.wantErrSystem)
|
||||
@ -118,8 +116,8 @@ func checkOpBehaviour(t *testing.T, testCases []opBehaviourTestCase) {
|
||||
if tc.extraCheckSys != nil {
|
||||
tc.extraCheckSys(t, stateSys)
|
||||
}
|
||||
if !reflect.DeepEqual(op, tc.wantOpSys) {
|
||||
t.Errorf("toSystem: op = %#v, want %#v", op, tc.wantOpSys)
|
||||
if wantOpSys := tc.newOp(true, false); !reflect.DeepEqual(op, wantOpSys) {
|
||||
t.Errorf("toSystem: op = %#v, want %#v", op, wantOpSys)
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,7 +131,7 @@ func checkOpBehaviour(t *testing.T, testCases []opBehaviourTestCase) {
|
||||
if tc.pStateContainer != nil {
|
||||
tc.pStateContainer(stateParams)
|
||||
}
|
||||
op := tc.newOp()
|
||||
op := tc.newOp(true, true)
|
||||
|
||||
if err := op.toContainer(stateParams); !reflect.DeepEqual(err, tc.wantErrContainer) {
|
||||
t.Errorf("toContainer: error = %v, want %v", err, tc.wantErrContainer)
|
||||
@ -144,14 +142,11 @@ func checkOpBehaviour(t *testing.T, testCases []opBehaviourTestCase) {
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(stateParams.params, tc.wantParams) {
|
||||
t.Errorf("toContainer: %#v, want %#v", stateParams.params, tc.wantParams)
|
||||
t.Errorf("toContainer:\n%s\nwant\n%s", mustMarshal(stateParams.params), mustMarshal(tc.wantParams))
|
||||
}
|
||||
if tc.extraCheckParams != nil {
|
||||
tc.extraCheckParams(t, stateParams)
|
||||
}
|
||||
if !reflect.DeepEqual(op, tc.wantOpContainer) {
|
||||
t.Errorf("toContainer: op = %#v, want %#v", op, tc.wantOpContainer)
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
@ -167,6 +162,8 @@ func checkOpBehaviour(t *testing.T, testCases []opBehaviourTestCase) {
|
||||
}
|
||||
}
|
||||
|
||||
func newI() *system.I { return system.New(panicMsgContext{}, panicMsgContext{}, checkExpectUid) }
|
||||
|
||||
type kstub struct {
|
||||
panicDispatcher
|
||||
*stub.Stub[syscallDispatcher]
|
||||
|
@ -9,45 +9,43 @@ import (
|
||||
"hakurei.app/container"
|
||||
"hakurei.app/container/stub"
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/message"
|
||||
"hakurei.app/system"
|
||||
)
|
||||
|
||||
func TestSpAccountOp(t *testing.T) {
|
||||
config := hst.Template()
|
||||
|
||||
checkOpBehaviour(t, []opBehaviourTestCase{
|
||||
{"invalid state", func() outcomeOp { return spAccountOp{} }, func() *hst.Config {
|
||||
{"invalid state", func(bool, bool) outcomeOp { return spAccountOp{} }, func() *hst.Config {
|
||||
c := hst.Template()
|
||||
c.Container.Shell = nil
|
||||
return c
|
||||
}, nil, []stub.Call{
|
||||
// this op performs basic validation and does not make calls during toSystem
|
||||
}, spAccountOp{}, system.New(t.Context(), message.NewMsg(nil), checkExpectUid), nil, syscall.ENOTRECOVERABLE, nil, nil, nil, nil, nil, nil},
|
||||
}, nil, nil, syscall.ENOTRECOVERABLE, nil, nil, nil, nil, nil},
|
||||
|
||||
{"invalid user name", func() outcomeOp { return spAccountOp{} }, func() *hst.Config {
|
||||
{"invalid user name", func(bool, bool) outcomeOp { return spAccountOp{} }, func() *hst.Config {
|
||||
c := hst.Template()
|
||||
c.Container.Username = "9"
|
||||
return c
|
||||
}, nil, []stub.Call{
|
||||
// this op performs basic validation and does not make calls during toSystem
|
||||
}, spAccountOp{}, nil, nil, &hst.AppError{
|
||||
}, nil, nil, &hst.AppError{
|
||||
Step: "finalise",
|
||||
Err: os.ErrInvalid,
|
||||
Msg: `invalid user name "9"`,
|
||||
}, nil, nil, nil, nil, nil, nil},
|
||||
}, nil, nil, nil, nil, nil},
|
||||
|
||||
{"success fallback username", func() outcomeOp { return spAccountOp{} }, func() *hst.Config {
|
||||
{"success fallback username", func(bool, bool) outcomeOp { return spAccountOp{} }, func() *hst.Config {
|
||||
c := hst.Template()
|
||||
c.Container.Username = ""
|
||||
return c
|
||||
}, nil, []stub.Call{
|
||||
// this op performs basic validation and does not make calls during toSystem
|
||||
}, spAccountOp{}, system.New(t.Context(), message.NewMsg(nil), checkExpectUid), nil, nil, func(state *outcomeStateParams) {
|
||||
}, newI(), nil, nil, func(state *outcomeStateParams) {
|
||||
state.params.Ops = new(container.Ops)
|
||||
}, []stub.Call{
|
||||
// this op configures the container state and does not make calls during toContainer
|
||||
}, spAccountOp{}, &container.Params{
|
||||
}, &container.Params{
|
||||
Dir: config.Container.Home,
|
||||
Ops: new(container.Ops).
|
||||
Place(m("/etc/passwd"), []byte("chronos:x:1000:100:Hakurei:/data/data/org.chromium.Chromium:/run/current-system/sw/bin/zsh\n")).
|
||||
@ -64,13 +62,13 @@ func TestSpAccountOp(t *testing.T) {
|
||||
}
|
||||
}, nil},
|
||||
|
||||
{"success", func() outcomeOp { return spAccountOp{} }, hst.Template, nil, []stub.Call{
|
||||
{"success", func(bool, bool) outcomeOp { return spAccountOp{} }, hst.Template, nil, []stub.Call{
|
||||
// this op performs basic validation and does not make calls during toSystem
|
||||
}, spAccountOp{}, system.New(t.Context(), message.NewMsg(nil), checkExpectUid), nil, nil, func(state *outcomeStateParams) {
|
||||
}, newI(), nil, nil, func(state *outcomeStateParams) {
|
||||
state.params.Ops = new(container.Ops)
|
||||
}, []stub.Call{
|
||||
// this op configures the container state and does not make calls during toContainer
|
||||
}, spAccountOp{}, &container.Params{
|
||||
}, &container.Params{
|
||||
Dir: config.Container.Home,
|
||||
Ops: new(container.Ops).
|
||||
Place(m("/etc/passwd"), []byte("chronos:x:1000:100:Hakurei:/data/data/org.chromium.Chromium:/run/current-system/sw/bin/zsh\n")).
|
||||
|
140
internal/app/spcontainer_test.go
Normal file
140
internal/app/spcontainer_test.go
Normal file
@ -0,0 +1,140 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"maps"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"hakurei.app/container"
|
||||
"hakurei.app/container/bits"
|
||||
"hakurei.app/container/fhs"
|
||||
"hakurei.app/container/seccomp"
|
||||
"hakurei.app/container/stub"
|
||||
"hakurei.app/hst"
|
||||
)
|
||||
|
||||
func TestSpParamsOp(t *testing.T) {
|
||||
config := hst.Template()
|
||||
|
||||
checkOpBehaviour(t, []opBehaviourTestCase{
|
||||
{"invalid program path", func(isShim, _ bool) outcomeOp {
|
||||
if !isShim {
|
||||
return new(spParamsOp)
|
||||
}
|
||||
return &spParamsOp{Term: "xterm", TermSet: true}
|
||||
}, func() *hst.Config {
|
||||
c := hst.Template()
|
||||
c.Container.Path = nil
|
||||
return c
|
||||
}, nil, []stub.Call{
|
||||
call("lookupEnv", stub.ExpectArgs{"TERM"}, "xterm", nil),
|
||||
}, newI().
|
||||
Ensure(m(container.Nonexistent+"/tmp/hakurei.0"), 0711), nil, nil, nil, []stub.Call{
|
||||
// this op configures the container state and does not make calls during toContainer
|
||||
}, nil, nil, &hst.AppError{
|
||||
Step: "finalise",
|
||||
Err: os.ErrInvalid,
|
||||
Msg: "invalid program path",
|
||||
}},
|
||||
|
||||
{"success defaultargs secure", func(isShim, _ bool) outcomeOp {
|
||||
if !isShim {
|
||||
return new(spParamsOp)
|
||||
}
|
||||
return &spParamsOp{Term: "xterm", TermSet: true}
|
||||
}, func() *hst.Config {
|
||||
c := hst.Template()
|
||||
c.Container.Args = nil
|
||||
c.Container.Multiarch = false
|
||||
c.Container.SeccompCompat = false
|
||||
c.Container.Devel = false
|
||||
c.Container.Userns = false
|
||||
c.Container.Tty = false
|
||||
c.Container.Device = false
|
||||
return c
|
||||
}, nil, []stub.Call{
|
||||
call("lookupEnv", stub.ExpectArgs{"TERM"}, "xterm", nil),
|
||||
}, newI().
|
||||
Ensure(m(container.Nonexistent+"/tmp/hakurei.0"), 0711), nil, nil, nil, []stub.Call{
|
||||
// this op configures the container state and does not make calls during toContainer
|
||||
}, &container.Params{
|
||||
Hostname: config.Container.Hostname,
|
||||
HostNet: config.Container.HostNet,
|
||||
HostAbstract: config.Container.HostAbstract,
|
||||
Path: config.Container.Path,
|
||||
Args: []string{config.Container.Path.String()},
|
||||
SeccompPresets: bits.PresetExt | bits.PresetDenyDevel | bits.PresetDenyNS | bits.PresetDenyTTY,
|
||||
Uid: 1000,
|
||||
Gid: 100,
|
||||
Ops: new(container.Ops).
|
||||
Root(m("/var/lib/hakurei/base/org.debian"), bits.BindWritable).
|
||||
Proc(fhs.AbsProc).Tmpfs(hst.AbsTmp, 1<<12, 0755).
|
||||
DevWritable(fhs.AbsDev, true).
|
||||
Tmpfs(fhs.AbsDev.Append("shm"), 0, 01777),
|
||||
}, func(t *testing.T, state *outcomeStateParams) {
|
||||
wantEnv := map[string]string{
|
||||
"TERM": "xterm",
|
||||
}
|
||||
maps.Copy(wantEnv, config.Container.Env)
|
||||
if !maps.Equal(state.env, wantEnv) {
|
||||
t.Errorf("toContainer: env = %#v, want %#v", state.env, wantEnv)
|
||||
}
|
||||
|
||||
const wantAutoEtcPrefix = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
if state.as.AutoEtcPrefix != wantAutoEtcPrefix {
|
||||
t.Errorf("toContainer: as.AutoEtcPrefix = %q, want %q", state.as.AutoEtcPrefix, wantAutoEtcPrefix)
|
||||
}
|
||||
|
||||
wantFilesystems := config.Container.Filesystem[1:]
|
||||
if !reflect.DeepEqual(state.filesystem, wantFilesystems) {
|
||||
t.Errorf("toContainer: filesystem = %#v, want %#v", state.filesystem, wantFilesystems)
|
||||
}
|
||||
}, nil},
|
||||
|
||||
{"success", func(isShim, _ bool) outcomeOp {
|
||||
if !isShim {
|
||||
return new(spParamsOp)
|
||||
}
|
||||
return &spParamsOp{Term: "xterm", TermSet: true}
|
||||
}, hst.Template, nil, []stub.Call{
|
||||
call("lookupEnv", stub.ExpectArgs{"TERM"}, "xterm", nil),
|
||||
}, newI().
|
||||
Ensure(m(container.Nonexistent+"/tmp/hakurei.0"), 0711), nil, nil, nil, []stub.Call{
|
||||
// this op configures the container state and does not make calls during toContainer
|
||||
}, &container.Params{
|
||||
Hostname: config.Container.Hostname,
|
||||
RetainSession: config.Container.Tty,
|
||||
HostNet: config.Container.HostNet,
|
||||
HostAbstract: config.Container.HostAbstract,
|
||||
Path: config.Container.Path,
|
||||
Args: config.Container.Args,
|
||||
SeccompFlags: seccomp.AllowMultiarch,
|
||||
Uid: 1000,
|
||||
Gid: 100,
|
||||
Ops: new(container.Ops).
|
||||
Root(m("/var/lib/hakurei/base/org.debian"), bits.BindWritable).
|
||||
Proc(fhs.AbsProc).Tmpfs(hst.AbsTmp, 1<<12, 0755).
|
||||
Bind(fhs.AbsDev, fhs.AbsDev, bits.BindWritable|bits.BindDevice).
|
||||
Tmpfs(fhs.AbsDev.Append("shm"), 0, 01777),
|
||||
}, func(t *testing.T, state *outcomeStateParams) {
|
||||
wantEnv := map[string]string{
|
||||
"TERM": "xterm",
|
||||
}
|
||||
maps.Copy(wantEnv, config.Container.Env)
|
||||
if !maps.Equal(state.env, wantEnv) {
|
||||
t.Errorf("toContainer: env = %#v, want %#v", state.env, wantEnv)
|
||||
}
|
||||
|
||||
const wantAutoEtcPrefix = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
if state.as.AutoEtcPrefix != wantAutoEtcPrefix {
|
||||
t.Errorf("toContainer: as.AutoEtcPrefix = %q, want %q", state.as.AutoEtcPrefix, wantAutoEtcPrefix)
|
||||
}
|
||||
|
||||
wantFilesystems := config.Container.Filesystem[1:]
|
||||
if !reflect.DeepEqual(state.filesystem, wantFilesystems) {
|
||||
t.Errorf("toContainer: filesystem = %#v, want %#v", state.filesystem, wantFilesystems)
|
||||
}
|
||||
}, nil},
|
||||
})
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user