internal/outcome/shim: check full behaviour
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				Test / Create distribution (push) Successful in 24s
				
			
		
			
				
	
				Test / Hakurei (push) Successful in 42s
				
			
		
			
				
	
				Test / Sandbox (push) Successful in 38s
				
			
		
			
				
	
				Test / Hakurei (race detector) (push) Successful in 42s
				
			
		
			
				
	
				Test / Sandbox (race detector) (push) Successful in 38s
				
			
		
			
				
	
				Test / Hpkg (push) Successful in 39s
				
			
		
			
				
	
				Test / Flake checks (push) Successful in 1m21s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	Test / Create distribution (push) Successful in 24s
				
			Test / Hakurei (push) Successful in 42s
				
			Test / Sandbox (push) Successful in 38s
				
			Test / Hakurei (race detector) (push) Successful in 42s
				
			Test / Sandbox (race detector) (push) Successful in 38s
				
			Test / Hpkg (push) Successful in 39s
				
			Test / Flake checks (push) Successful in 1m21s
				
			This took significant effort to stub out, and achieves full coverage after c5aefe5e9d. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
		
							parent
							
								
									36f8064905
								
							
						
					
					
						commit
						46c5ce4936
					
				| @ -4,6 +4,7 @@ import ( | |||||||
| 	"bytes" | 	"bytes" | ||||||
| 	"context" | 	"context" | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
|  | 	"errors" | ||||||
| 	"io" | 	"io" | ||||||
| 	"io/fs" | 	"io/fs" | ||||||
| 	"log" | 	"log" | ||||||
| @ -193,8 +194,8 @@ func checkOpBehaviour(t *testing.T, testCases []opBehaviourTestCase) { | |||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			wantConfig := tc.newConfig() | 			wantConfig := tc.newConfig() | ||||||
| 			k := &kstub{panicDispatcher{}, stub.New(t, | 			k := &kstub{nil, nil, panicDispatcher{}, stub.New(t, | ||||||
| 				func(s *stub.Stub[syscallDispatcher]) syscallDispatcher { return &kstub{panicDispatcher{}, s} }, | 				func(s *stub.Stub[syscallDispatcher]) syscallDispatcher { return &kstub{nil, nil, panicDispatcher{}, s} }, | ||||||
| 				stub.Expect{Calls: wantCallsFull}, | 				stub.Expect{Calls: wantCallsFull}, | ||||||
| 			)} | 			)} | ||||||
| 			defer stub.HandleExit(t) | 			defer stub.HandleExit(t) | ||||||
| @ -297,7 +298,12 @@ func checkSimple(t *testing.T, fname string, testCases []simpleTestCase) { | |||||||
| 			t.Parallel() | 			t.Parallel() | ||||||
| 
 | 
 | ||||||
| 			defer stub.HandleExit(t) | 			defer stub.HandleExit(t) | ||||||
| 			k := &kstub{panicDispatcher{}, stub.New(t, func(s *stub.Stub[syscallDispatcher]) syscallDispatcher { return &kstub{panicDispatcher{}, s} }, tc.want)} | 
 | ||||||
|  | 			uNotifyContext, uShimReader := make(chan struct{}), make(chan struct{}) | ||||||
|  | 			k := &kstub{uNotifyContext, uShimReader, panicDispatcher{}, | ||||||
|  | 				stub.New(t, func(s *stub.Stub[syscallDispatcher]) syscallDispatcher { | ||||||
|  | 					return &kstub{uNotifyContext, uShimReader, panicDispatcher{}, s} | ||||||
|  | 				}, tc.want)} | ||||||
| 			if err := tc.f(k); !reflect.DeepEqual(err, tc.wantErr) { | 			if err := tc.f(k); !reflect.DeepEqual(err, tc.wantErr) { | ||||||
| 				t.Errorf("%s: error = %#v, want %#v", fname, err, tc.wantErr) | 				t.Errorf("%s: error = %#v, want %#v", fname, err, tc.wantErr) | ||||||
| 			} | 			} | ||||||
| @ -312,6 +318,11 @@ func checkSimple(t *testing.T, fname string, testCases []simpleTestCase) { | |||||||
| 
 | 
 | ||||||
| // kstub partially implements syscallDispatcher via [stub.Stub]. | // kstub partially implements syscallDispatcher via [stub.Stub]. | ||||||
| type kstub struct { | type kstub struct { | ||||||
|  | 	// notifyContext blocks on unblockNotifyContext if provided with a kstub.Stub track. | ||||||
|  | 	unblockNotifyContext chan struct{} | ||||||
|  | 	// stubTrackReader blocks on unblockShimReader if unblocking notifyContext. | ||||||
|  | 	unblockShimReader chan struct{} | ||||||
|  | 
 | ||||||
| 	panicDispatcher | 	panicDispatcher | ||||||
| 	*stub.Stub[syscallDispatcher] | 	*stub.Stub[syscallDispatcher] | ||||||
| } | } | ||||||
| @ -354,6 +365,19 @@ func (k *kstub) readdir(name string) ([]os.DirEntry, error) { | |||||||
| 		stub.CheckArg(k.Stub, "name", name, 0)) | 		stub.CheckArg(k.Stub, "name", name, 0)) | ||||||
| } | } | ||||||
| func (k *kstub) tempdir() string { k.Helper(); return k.Expects("tempdir").Ret.(string) } | func (k *kstub) tempdir() string { k.Helper(); return k.Expects("tempdir").Ret.(string) } | ||||||
|  | func (k *kstub) exit(code int) { | ||||||
|  | 	k.Helper() | ||||||
|  | 	expect := k.Expects("exit") | ||||||
|  | 
 | ||||||
|  | 	if errors.Is(expect.Err, unblockNotifyContext) { | ||||||
|  | 		close(k.unblockNotifyContext) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if !stub.CheckArg(k.Stub, "code", code, 0) { | ||||||
|  | 		k.FailNow() | ||||||
|  | 	} | ||||||
|  | 	panic(expect.Ret.(int)) | ||||||
|  | } | ||||||
| func (k *kstub) evalSymlinks(path string) (string, error) { | func (k *kstub) evalSymlinks(path string) (string, error) { | ||||||
| 	k.Helper() | 	k.Helper() | ||||||
| 	expect := k.Expects("evalSymlinks") | 	expect := k.Expects("evalSymlinks") | ||||||
| @ -388,16 +412,17 @@ func (k *kstub) receive(key string, e any, fdp *uintptr) (closeFunc func() error | |||||||
| 
 | 
 | ||||||
| func (k *kstub) expectCheckContainer(expect *stub.Call, z *container.Container) error { | func (k *kstub) expectCheckContainer(expect *stub.Call, z *container.Container) error { | ||||||
| 	k.Helper() | 	k.Helper() | ||||||
| 	err := expect.Error( | 	if !stub.CheckArgReflect(k.Stub, "params", &z.Params, 0) { | ||||||
| 		stub.CheckArgReflect(k.Stub, "params", &z.Params, 0)) |  | ||||||
| 	if err != nil { |  | ||||||
| 		k.Errorf("params:\n%s\n%s", mustMarshal(&z.Params), mustMarshal(expect.Args[0])) | 		k.Errorf("params:\n%s\n%s", mustMarshal(&z.Params), mustMarshal(expect.Args[0])) | ||||||
| 	} | 	} | ||||||
| 	return err | 	return expect.Err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (k *kstub) containerStart(z *container.Container) error { | func (k *kstub) containerStart(z *container.Container) error { | ||||||
| 	k.Helper() | 	k.Helper() | ||||||
|  | 	if k.unblockShimReader != nil { | ||||||
|  | 		close(k.unblockShimReader) | ||||||
|  | 	} | ||||||
| 	return k.expectCheckContainer(k.Expects("containerStart"), z) | 	return k.expectCheckContainer(k.Expects("containerStart"), z) | ||||||
| } | } | ||||||
| func (k *kstub) containerServe(z *container.Container) error { | func (k *kstub) containerServe(z *container.Container) error { | ||||||
| @ -428,12 +453,25 @@ func (k *kstub) cmdOutput(cmd *exec.Cmd) ([]byte, error) { | |||||||
| 
 | 
 | ||||||
| func (k *kstub) notifyContext(parent context.Context, signals ...os.Signal) (ctx context.Context, stop context.CancelFunc) { | func (k *kstub) notifyContext(parent context.Context, signals ...os.Signal) (ctx context.Context, stop context.CancelFunc) { | ||||||
| 	k.Helper() | 	k.Helper() | ||||||
| 	if k.Expects("notifyContext").Error( | 	expect := k.Expects("notifyContext") | ||||||
|  | 
 | ||||||
|  | 	if expect.Error( | ||||||
| 		stub.CheckArgReflect(k.Stub, "parent", parent, 0), | 		stub.CheckArgReflect(k.Stub, "parent", parent, 0), | ||||||
| 		stub.CheckArgReflect(k.Stub, "signals", signals, 1)) != nil { | 		stub.CheckArgReflect(k.Stub, "signals", signals, 1)) != nil { | ||||||
| 		k.FailNow() | 		k.FailNow() | ||||||
| 	} | 	} | ||||||
| 	return k.Context(), func() { k.Helper(); k.Expects("notifyContextStop") } | 
 | ||||||
|  | 	if sub, ok := expect.Ret.(int); ok && sub >= 0 { | ||||||
|  | 		subVal := reflect.ValueOf(k.Stub).Elem().FieldByName("sub") | ||||||
|  | 		ks := &kstub{nil, nil, panicDispatcher{}, reflect. | ||||||
|  | 			NewAt(subVal.Type(), unsafe.Pointer(subVal.UnsafeAddr())).Elem(). | ||||||
|  | 			Interface().([]*stub.Stub[syscallDispatcher])[sub]} | ||||||
|  | 
 | ||||||
|  | 		<-k.unblockNotifyContext | ||||||
|  | 		return k.Context(), func() { k.Helper(); ks.Expects("notifyContextStop") } | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return k.Context(), func() { panic("unexpected call to stop") } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (k *kstub) mustHsuPath() *check.Absolute { | func (k *kstub) mustHsuPath() *check.Absolute { | ||||||
| @ -457,26 +495,51 @@ type stubTrackReader struct { | |||||||
| 	*kstub | 	*kstub | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // unblockNotifyContext is passed via call and must be handled by stubTrackReader.Read | ||||||
|  | var unblockNotifyContext = errors.New("this error unblocks notifyContext and must not be returned") | ||||||
|  | 
 | ||||||
| func (r *stubTrackReader) Read(p []byte) (n int, err error) { | func (r *stubTrackReader) Read(p []byte) (n int, err error) { | ||||||
| 	r.subOnce.Do(func() { | 	r.subOnce.Do(func() { | ||||||
| 		subVal := reflect.ValueOf(r.kstub.Stub).Elem().FieldByName("sub") | 		subVal := reflect.ValueOf(r.kstub.Stub).Elem().FieldByName("sub") | ||||||
| 		r.kstub = &kstub{panicDispatcher{}, reflect. | 		r.kstub = &kstub{r.kstub.unblockNotifyContext, r.kstub.unblockShimReader, panicDispatcher{}, reflect. | ||||||
| 			NewAt(subVal.Type(), unsafe.Pointer(subVal.UnsafeAddr())).Elem(). | 			NewAt(subVal.Type(), unsafe.Pointer(subVal.UnsafeAddr())).Elem(). | ||||||
| 			Interface().([]*stub.Stub[syscallDispatcher])[r.sub]} | 			Interface().([]*stub.Stub[syscallDispatcher])[r.sub]} | ||||||
| 	}) | 	}) | ||||||
| 
 | 
 | ||||||
| 	return r.kstub.Read(p) | 	n, err = r.kstub.Read(p) | ||||||
|  | 	if errors.Is(err, unblockNotifyContext) { | ||||||
|  | 		err = nil | ||||||
|  | 		close(r.unblockNotifyContext) | ||||||
|  | 		<-r.unblockShimReader | ||||||
|  | 	} | ||||||
|  | 	return n, err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (k *kstub) setupContSignal(pid int) (io.ReadCloser, func(), error) { | func (k *kstub) setupContSignal(pid int) (io.ReadCloser, func(), error) { | ||||||
| 	k.Helper() | 	k.Helper() | ||||||
| 	expect := k.Expects("setupContSignal") | 	expect := k.Expects("setupContSignal") | ||||||
| 	return &stubTrackReader{sub: expect.Ret.(int), kstub: k}, func() { k.Expects("wKeepAlive") }, expect.Error( | 	return &stubTrackReader{sub: expect.Ret.(int), kstub: k}, func() { k.Helper(); k.Expects("wKeepAlive") }, expect.Error( | ||||||
| 		stub.CheckArg(k.Stub, "pid", pid, 0)) | 		stub.CheckArg(k.Stub, "pid", pid, 0)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (k *kstub) getMsg() message.Msg { k.Helper(); k.Expects("getMsg"); return k } | func (k *kstub) getMsg() message.Msg { k.Helper(); k.Expects("getMsg"); return k } | ||||||
| 
 | 
 | ||||||
|  | func (k *kstub) fatal(v ...any) { | ||||||
|  | 	if k.Expects("fatal").Error( | ||||||
|  | 		stub.CheckArgReflect(k.Stub, "v", v, 0)) != nil { | ||||||
|  | 		k.FailNow() | ||||||
|  | 	} | ||||||
|  | 	panic(stub.PanicExit) | ||||||
|  | } | ||||||
|  | func (k *kstub) fatalf(format string, v ...any) { | ||||||
|  | 	if k.Expects("fatalf").Error( | ||||||
|  | 		stub.CheckArg(k.Stub, "format", format, 0), | ||||||
|  | 		stub.CheckArgReflect(k.Stub, "v", v, 1)) != nil { | ||||||
|  | 		k.FailNow() | ||||||
|  | 	} | ||||||
|  | 	panic(stub.PanicExit) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (k *kstub) Close() error { k.Helper(); return k.Expects("rcClose").Err } | func (k *kstub) Close() error { k.Helper(); return k.Expects("rcClose").Err } | ||||||
| func (k *kstub) Read(p []byte) (n int, err error) { | func (k *kstub) Read(p []byte) (n int, err error) { | ||||||
| 	k.Helper() | 	k.Helper() | ||||||
|  | |||||||
| @ -93,7 +93,7 @@ func shimEntrypoint(k syscallDispatcher) { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if err := k.setDumpable(container.SUID_DUMP_DISABLE); err != nil { | 	if err := k.setDumpable(container.SUID_DUMP_DISABLE); err != nil { | ||||||
| 		k.fatalf("cannot set SUID_DUMP_DISABLE: %s", err) | 		k.fatalf("cannot set SUID_DUMP_DISABLE: %v", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	var ( | 	var ( | ||||||
| @ -114,11 +114,8 @@ func shimEntrypoint(k syscallDispatcher) { | |||||||
| 		closeSetup = f | 		closeSetup = f | ||||||
| 
 | 
 | ||||||
| 		if err = state.populateLocal(k, msg); err != nil { | 		if err = state.populateLocal(k, msg); err != nil { | ||||||
| 			if m, ok := message.GetMessage(err); ok { | 			printMessageError(func(v ...any) { k.fatal(fmt.Sprintln(v...)) }, | ||||||
| 				k.fatal(m) | 				"cannot populate local state:", err) | ||||||
| 			} else { |  | ||||||
| 				k.fatalf("cannot populate local state: %v", err) |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -138,7 +135,6 @@ func shimEntrypoint(k syscallDispatcher) { | |||||||
| 			k.fatalf("cannot set up exit request: %v", err) | 			k.fatalf("cannot set up exit request: %v", err) | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 
 |  | ||||||
| 	} else { | 	} else { | ||||||
| 		defer wKeepAlive() | 		defer wKeepAlive() | ||||||
| 		signalPipe = r | 		signalPipe = r | ||||||
| @ -152,15 +148,12 @@ func shimEntrypoint(k syscallDispatcher) { | |||||||
| 	stateParams := state.newParams() | 	stateParams := state.newParams() | ||||||
| 	for _, op := range state.Shim.Ops { | 	for _, op := range state.Shim.Ops { | ||||||
| 		if err := op.toContainer(stateParams); err != nil { | 		if err := op.toContainer(stateParams); err != nil { | ||||||
| 			if m, ok := message.GetMessage(err); ok { | 			printMessageError(func(v ...any) { k.fatal(fmt.Sprintln(v...)) }, | ||||||
| 				k.fatal(m) | 				"cannot create container state:", err) | ||||||
| 			} else { |  | ||||||
| 				k.fatalf("cannot create container state: %v", err) |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	if stateParams.params.Ops == nil { // unreachable | 	if stateParams.params.Ops == nil { // only reachable with corrupted outcomeState | ||||||
| 		k.fatal("invalid container params") | 		k.fatal("invalid container state") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// shim exit outcomes | 	// shim exit outcomes | ||||||
| @ -226,7 +219,8 @@ func shimEntrypoint(k syscallDispatcher) { | |||||||
| 		k.exit(hst.ExitFailure) | 		k.exit(hst.ExitFailure) | ||||||
| 	} | 	} | ||||||
| 	if err := k.containerServe(z); err != nil { | 	if err := k.containerServe(z); err != nil { | ||||||
| 		printMessageError(func(v ...any) { k.fatal(fmt.Sprintln(v...)) }, "cannot configure container:", err) | 		printMessageError(func(v ...any) { k.fatal(fmt.Sprintln(v...)) }, | ||||||
|  | 			"cannot configure container:", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if err := k.seccompLoad( | 	if err := k.seccompLoad( | ||||||
|  | |||||||
| @ -106,8 +106,8 @@ func TestShimEntrypoint(t *testing.T) { | |||||||
| 			Remount(fhs.AbsRoot, syscall.MS_RDONLY), | 			Remount(fhs.AbsRoot, syscall.MS_RDONLY), | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	templateState := outcomeState{ | 	newShimParams := func() *shimParams { | ||||||
| 		Shim: &shimParams{PrivPID: 0xbad, WaitDelay: 0xf, Verbose: true, Ops: []outcomeOp{ | 		return &shimParams{PrivPID: 0xbad, WaitDelay: 0xf, Verbose: true, Ops: []outcomeOp{ | ||||||
| 			&spParamsOp{"xterm-256color", true}, | 			&spParamsOp{"xterm-256color", true}, | ||||||
| 			&spRuntimeOp{sessionTypeWayland}, | 			&spRuntimeOp{sessionTypeWayland}, | ||||||
| 			spTmpdirOp{}, | 			spTmpdirOp{}, | ||||||
| @ -116,8 +116,11 @@ func TestShimEntrypoint(t *testing.T) { | |||||||
| 			&spPulseOp{(*[pulseCookieSizeMax]byte)(bytes.Repeat([]byte{0}, pulseCookieSizeMax)), pulseCookieSizeMax}, | 			&spPulseOp{(*[pulseCookieSizeMax]byte)(bytes.Repeat([]byte{0}, pulseCookieSizeMax)), pulseCookieSizeMax}, | ||||||
| 			&spDBusOp{true}, | 			&spDBusOp{true}, | ||||||
| 			&spFilesystemOp{}, | 			&spFilesystemOp{}, | ||||||
| 		}}, | 		}} | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
|  | 	templateState := outcomeState{ | ||||||
|  | 		Shim:      newShimParams(), | ||||||
| 		ID:        &checkExpectInstanceId, | 		ID:        &checkExpectInstanceId, | ||||||
| 		Identity:  hst.IdentityMax, | 		Identity:  hst.IdentityMax, | ||||||
| 		UserID:    10, | 		UserID:    10, | ||||||
| @ -128,6 +131,333 @@ func TestShimEntrypoint(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	checkSimple(t, "shimEntrypoint", []simpleTestCase{ | 	checkSimple(t, "shimEntrypoint", []simpleTestCase{ | ||||||
|  | 		{"dumpable", func(k *kstub) error { shimEntrypoint(k); return nil }, stub.Expect{Calls: []stub.Call{ | ||||||
|  | 			call("getMsg", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("getLogger", stub.ExpectArgs{}, new(log.Logger), nil), | ||||||
|  | 			call("setDumpable", stub.ExpectArgs{uintptr(container.SUID_DUMP_DISABLE)}, nil, stub.UniqueError(11)), | ||||||
|  | 			call("fatalf", stub.ExpectArgs{"cannot set SUID_DUMP_DISABLE: %v", []any{stub.UniqueError(11)}}, nil, nil), | ||||||
|  | 		}}, nil}, | ||||||
|  | 
 | ||||||
|  | 		{"receive fd", func(k *kstub) error { shimEntrypoint(k); return nil }, stub.Expect{Calls: []stub.Call{ | ||||||
|  | 			call("getMsg", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("getLogger", stub.ExpectArgs{}, (*log.Logger)(nil), nil), | ||||||
|  | 			call("setDumpable", stub.ExpectArgs{uintptr(container.SUID_DUMP_DISABLE)}, nil, nil), | ||||||
|  | 			call("receive", stub.ExpectArgs{"HAKUREI_SHIM", outcomeState{}, nil}, nil, syscall.EBADF), | ||||||
|  | 			call("fatal", stub.ExpectArgs{[]any{"invalid config descriptor"}}, nil, nil), | ||||||
|  | 		}}, nil}, | ||||||
|  | 
 | ||||||
|  | 		{"receive env", func(k *kstub) error { shimEntrypoint(k); return nil }, stub.Expect{Calls: []stub.Call{ | ||||||
|  | 			call("getMsg", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("getLogger", stub.ExpectArgs{}, (*log.Logger)(nil), nil), | ||||||
|  | 			call("setDumpable", stub.ExpectArgs{uintptr(container.SUID_DUMP_DISABLE)}, nil, nil), | ||||||
|  | 			call("receive", stub.ExpectArgs{"HAKUREI_SHIM", outcomeState{}, nil}, nil, container.ErrReceiveEnv), | ||||||
|  | 			call("fatal", stub.ExpectArgs{[]any{"HAKUREI_SHIM not set"}}, nil, nil), | ||||||
|  | 		}}, nil}, | ||||||
|  | 
 | ||||||
|  | 		{"receive strange", func(k *kstub) error { shimEntrypoint(k); return nil }, stub.Expect{Calls: []stub.Call{ | ||||||
|  | 			call("getMsg", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("getLogger", stub.ExpectArgs{}, (*log.Logger)(nil), nil), | ||||||
|  | 			call("setDumpable", stub.ExpectArgs{uintptr(container.SUID_DUMP_DISABLE)}, nil, nil), | ||||||
|  | 			call("receive", stub.ExpectArgs{"HAKUREI_SHIM", outcomeState{}, nil}, nil, stub.UniqueError(10)), | ||||||
|  | 			call("fatalf", stub.ExpectArgs{"cannot receive shim setup params: %v", []any{stub.UniqueError(10)}}, nil, nil), | ||||||
|  | 		}}, nil}, | ||||||
|  | 
 | ||||||
|  | 		{"invalid state", func(k *kstub) error { shimEntrypoint(k); return nil }, stub.Expect{Calls: []stub.Call{ | ||||||
|  | 			call("getMsg", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("getLogger", stub.ExpectArgs{}, (*log.Logger)(nil), nil), | ||||||
|  | 			call("setDumpable", stub.ExpectArgs{uintptr(container.SUID_DUMP_DISABLE)}, nil, nil), | ||||||
|  | 			call("receive", stub.ExpectArgs{"HAKUREI_SHIM", func() outcomeState { | ||||||
|  | 				state := templateState | ||||||
|  | 				state.Shim = newShimParams() | ||||||
|  | 				state.Shim.PrivPID = 0 | ||||||
|  | 				return state | ||||||
|  | 			}(), nil}, nil, nil), | ||||||
|  | 			call("swapVerbose", stub.ExpectArgs{true}, false, nil), | ||||||
|  | 			call("fatal", stub.ExpectArgs{[]any{"impossible outcome state reached\n"}}, nil, nil), | ||||||
|  | 		}}, nil}, | ||||||
|  | 
 | ||||||
|  | 		{"sigaction pipe", func(k *kstub) error { shimEntrypoint(k); return nil }, stub.Expect{Calls: []stub.Call{ | ||||||
|  | 			call("getMsg", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("getLogger", stub.ExpectArgs{}, (*log.Logger)(nil), nil), | ||||||
|  | 			call("setDumpable", stub.ExpectArgs{uintptr(container.SUID_DUMP_DISABLE)}, nil, nil), | ||||||
|  | 			call("receive", stub.ExpectArgs{"HAKUREI_SHIM", templateState, nil}, nil, nil), | ||||||
|  | 			call("swapVerbose", stub.ExpectArgs{true}, false, nil), | ||||||
|  | 			call("verbosef", stub.ExpectArgs{"process share directory at %q, runtime directory at %q", []any{m("/tmp/hakurei.10"), m("/run/user/1000/hakurei")}}, nil, nil), | ||||||
|  | 			call("setupContSignal", stub.ExpectArgs{0xbad}, 0, &os.SyscallError{Syscall: "pipe2", Err: stub.UniqueError(9)}), | ||||||
|  | 			call("fatal", stub.ExpectArgs{[]any{"pipe2: unique error 9 injected by the test suite"}}, nil, nil), | ||||||
|  | 		}}, nil}, | ||||||
|  | 
 | ||||||
|  | 		{"sigaction cgo", func(k *kstub) error { shimEntrypoint(k); return nil }, stub.Expect{Calls: []stub.Call{ | ||||||
|  | 			call("getMsg", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("getLogger", stub.ExpectArgs{}, (*log.Logger)(nil), nil), | ||||||
|  | 			call("setDumpable", stub.ExpectArgs{uintptr(container.SUID_DUMP_DISABLE)}, nil, nil), | ||||||
|  | 			call("receive", stub.ExpectArgs{"HAKUREI_SHIM", templateState, nil}, nil, nil), | ||||||
|  | 			call("swapVerbose", stub.ExpectArgs{true}, false, nil), | ||||||
|  | 			call("verbosef", stub.ExpectArgs{"process share directory at %q, runtime directory at %q", []any{m("/tmp/hakurei.10"), m("/run/user/1000/hakurei")}}, nil, nil), | ||||||
|  | 			call("setupContSignal", stub.ExpectArgs{0xbad}, 0, syscall.ENOTRECOVERABLE), | ||||||
|  | 			call("fatalf", stub.ExpectArgs{"cannot install SIGCONT handler: %v", []any{syscall.ENOTRECOVERABLE}}, nil, nil), | ||||||
|  | 		}}, nil}, | ||||||
|  | 
 | ||||||
|  | 		{"sigaction strange", func(k *kstub) error { shimEntrypoint(k); return nil }, stub.Expect{Calls: []stub.Call{ | ||||||
|  | 			call("getMsg", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("getLogger", stub.ExpectArgs{}, (*log.Logger)(nil), nil), | ||||||
|  | 			call("setDumpable", stub.ExpectArgs{uintptr(container.SUID_DUMP_DISABLE)}, nil, nil), | ||||||
|  | 			call("receive", stub.ExpectArgs{"HAKUREI_SHIM", templateState, nil}, nil, nil), | ||||||
|  | 			call("swapVerbose", stub.ExpectArgs{true}, false, nil), | ||||||
|  | 			call("verbosef", stub.ExpectArgs{"process share directory at %q, runtime directory at %q", []any{m("/tmp/hakurei.10"), m("/run/user/1000/hakurei")}}, nil, nil), | ||||||
|  | 			call("setupContSignal", stub.ExpectArgs{0xbad}, 0, stub.UniqueError(8)), | ||||||
|  | 			call("fatalf", stub.ExpectArgs{"cannot set up exit request: %v", []any{stub.UniqueError(8)}}, nil, nil), | ||||||
|  | 		}}, nil}, | ||||||
|  | 
 | ||||||
|  | 		{"prctl", func(k *kstub) error { shimEntrypoint(k); return nil }, stub.Expect{Calls: []stub.Call{ | ||||||
|  | 			call("getMsg", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("getLogger", stub.ExpectArgs{}, (*log.Logger)(nil), nil), | ||||||
|  | 			call("setDumpable", stub.ExpectArgs{uintptr(container.SUID_DUMP_DISABLE)}, nil, nil), | ||||||
|  | 			call("receive", stub.ExpectArgs{"HAKUREI_SHIM", templateState, nil}, nil, nil), | ||||||
|  | 			call("swapVerbose", stub.ExpectArgs{true}, false, nil), | ||||||
|  | 			call("verbosef", stub.ExpectArgs{"process share directory at %q, runtime directory at %q", []any{m("/tmp/hakurei.10"), m("/run/user/1000/hakurei")}}, nil, nil), | ||||||
|  | 			call("setupContSignal", stub.ExpectArgs{0xbad}, 0, nil), | ||||||
|  | 			call("prctl", stub.ExpectArgs{uintptr(syscall.PR_SET_PDEATHSIG), uintptr(syscall.SIGCONT), uintptr(0)}, nil, stub.UniqueError(7)), | ||||||
|  | 			call("fatalf", stub.ExpectArgs{"cannot set parent-death signal: %v", []any{stub.UniqueError(7)}}, nil, nil), | ||||||
|  | 
 | ||||||
|  | 			// deferred | ||||||
|  | 			call("wKeepAlive", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 		}}, nil}, | ||||||
|  | 
 | ||||||
|  | 		{"toContainer", func(k *kstub) error { shimEntrypoint(k); return nil }, stub.Expect{Calls: []stub.Call{ | ||||||
|  | 			call("getMsg", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("getLogger", stub.ExpectArgs{}, (*log.Logger)(nil), nil), | ||||||
|  | 			call("setDumpable", stub.ExpectArgs{uintptr(container.SUID_DUMP_DISABLE)}, nil, nil), | ||||||
|  | 			call("receive", stub.ExpectArgs{"HAKUREI_SHIM", func() outcomeState { | ||||||
|  | 				state := templateState | ||||||
|  | 				state.Shim = newShimParams() | ||||||
|  | 				state.Shim.Ops = []outcomeOp{errorOp(6)} | ||||||
|  | 				return state | ||||||
|  | 			}(), nil}, nil, nil), | ||||||
|  | 			call("swapVerbose", stub.ExpectArgs{true}, false, nil), | ||||||
|  | 			call("verbosef", stub.ExpectArgs{"process share directory at %q, runtime directory at %q", []any{m("/tmp/hakurei.10"), m("/run/user/1000/hakurei")}}, nil, nil), | ||||||
|  | 			call("setupContSignal", stub.ExpectArgs{0xbad}, 0, nil), | ||||||
|  | 			call("prctl", stub.ExpectArgs{uintptr(syscall.PR_SET_PDEATHSIG), uintptr(syscall.SIGCONT), uintptr(0)}, nil, nil), | ||||||
|  | 			call("fatal", stub.ExpectArgs{[]any{"cannot create container state: unique error 6 injected by the test suite\n"}}, nil, nil), | ||||||
|  | 
 | ||||||
|  | 			// deferred | ||||||
|  | 			call("wKeepAlive", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 		}}, nil}, | ||||||
|  | 
 | ||||||
|  | 		{"bad ops", func(k *kstub) error { shimEntrypoint(k); return nil }, stub.Expect{Calls: []stub.Call{ | ||||||
|  | 			call("getMsg", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("getLogger", stub.ExpectArgs{}, (*log.Logger)(nil), nil), | ||||||
|  | 			call("setDumpable", stub.ExpectArgs{uintptr(container.SUID_DUMP_DISABLE)}, nil, nil), | ||||||
|  | 			call("receive", stub.ExpectArgs{"HAKUREI_SHIM", func() outcomeState { | ||||||
|  | 				state := templateState | ||||||
|  | 				state.Shim = newShimParams() | ||||||
|  | 				state.Shim.Ops = nil | ||||||
|  | 				return state | ||||||
|  | 			}(), nil}, nil, nil), | ||||||
|  | 			call("swapVerbose", stub.ExpectArgs{true}, false, nil), | ||||||
|  | 			call("verbosef", stub.ExpectArgs{"process share directory at %q, runtime directory at %q", []any{m("/tmp/hakurei.10"), m("/run/user/1000/hakurei")}}, nil, nil), | ||||||
|  | 			call("setupContSignal", stub.ExpectArgs{0xbad}, 0, nil), | ||||||
|  | 			call("prctl", stub.ExpectArgs{uintptr(syscall.PR_SET_PDEATHSIG), uintptr(syscall.SIGCONT), uintptr(0)}, nil, nil), | ||||||
|  | 			call("fatal", stub.ExpectArgs{[]any{"invalid container state"}}, nil, nil), | ||||||
|  | 
 | ||||||
|  | 			// deferred | ||||||
|  | 			call("wKeepAlive", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 		}}, nil}, | ||||||
|  | 
 | ||||||
|  | 		{"start", func(k *kstub) error { shimEntrypoint(k); return nil }, stub.Expect{Calls: []stub.Call{ | ||||||
|  | 			call("getMsg", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("getLogger", stub.ExpectArgs{}, (*log.Logger)(nil), nil), | ||||||
|  | 			call("setDumpable", stub.ExpectArgs{uintptr(container.SUID_DUMP_DISABLE)}, nil, nil), | ||||||
|  | 			call("receive", stub.ExpectArgs{"HAKUREI_SHIM", templateState, nil}, nil, nil), | ||||||
|  | 			call("swapVerbose", stub.ExpectArgs{true}, false, nil), | ||||||
|  | 			call("verbosef", stub.ExpectArgs{"process share directory at %q, runtime directory at %q", []any{m("/tmp/hakurei.10"), m("/run/user/1000/hakurei")}}, nil, nil), | ||||||
|  | 			call("setupContSignal", stub.ExpectArgs{0xbad}, 0, nil), | ||||||
|  | 			call("prctl", stub.ExpectArgs{uintptr(syscall.PR_SET_PDEATHSIG), uintptr(syscall.SIGCONT), uintptr(0)}, nil, nil), | ||||||
|  | 			call("New", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("closeReceive", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("notifyContext", stub.ExpectArgs{context.Background(), []os.Signal{os.Interrupt, syscall.SIGTERM}}, -1, nil), | ||||||
|  | 			call("containerStart", stub.ExpectArgs{templateParams}, nil, stub.UniqueError(5)), | ||||||
|  | 			call("getLogger", stub.ExpectArgs{}, (*log.Logger)(nil), nil), | ||||||
|  | 			call("verbose", stub.ExpectArgs{[]any{"cannot start container: unique error 5 injected by the test suite\n"}}, nil, nil), | ||||||
|  | 			call("exit", stub.ExpectArgs{hst.ExitFailure}, stub.PanicExit, nil), | ||||||
|  | 
 | ||||||
|  | 			// deferred | ||||||
|  | 			call("wKeepAlive", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 		}, Tracks: []stub.Expect{{Calls: []stub.Call{ | ||||||
|  | 			call("rcRead", stub.ExpectArgs{}, nil, nil), // stub terminates this goroutine | ||||||
|  | 		}}}}, nil}, | ||||||
|  | 
 | ||||||
|  | 		{"start logger signalread", func(k *kstub) error { shimEntrypoint(k); return nil }, stub.Expect{Calls: []stub.Call{ | ||||||
|  | 			call("getMsg", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("getLogger", stub.ExpectArgs{}, (*log.Logger)(nil), nil), | ||||||
|  | 			call("setDumpable", stub.ExpectArgs{uintptr(container.SUID_DUMP_DISABLE)}, nil, nil), | ||||||
|  | 			call("receive", stub.ExpectArgs{"HAKUREI_SHIM", templateState, nil}, nil, nil), | ||||||
|  | 			call("swapVerbose", stub.ExpectArgs{true}, false, nil), | ||||||
|  | 			call("verbosef", stub.ExpectArgs{"process share directory at %q, runtime directory at %q", []any{m("/tmp/hakurei.10"), m("/run/user/1000/hakurei")}}, nil, nil), | ||||||
|  | 			call("setupContSignal", stub.ExpectArgs{0xbad}, 0, nil), | ||||||
|  | 			call("prctl", stub.ExpectArgs{uintptr(syscall.PR_SET_PDEATHSIG), uintptr(syscall.SIGCONT), uintptr(0)}, nil, nil), | ||||||
|  | 			call("New", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("closeReceive", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("notifyContext", stub.ExpectArgs{context.Background(), []os.Signal{os.Interrupt, syscall.SIGTERM}}, -1, nil), | ||||||
|  | 			call("containerStart", stub.ExpectArgs{templateParams}, nil, stub.UniqueError(5)), | ||||||
|  | 			call("getLogger", stub.ExpectArgs{}, log.Default(), nil), | ||||||
|  | 			call("exit", stub.ExpectArgs{hst.ExitFailure}, stub.PanicExit, nil), | ||||||
|  | 
 | ||||||
|  | 			// deferred | ||||||
|  | 			call("wKeepAlive", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 		}, Tracks: []stub.Expect{{Calls: []stub.Call{ | ||||||
|  | 			call("rcRead", stub.ExpectArgs{}, []byte{}, stub.UniqueError(4)), | ||||||
|  | 			call("fatalf", stub.ExpectArgs{"cannot read from signal pipe: %v", []any{stub.UniqueError(4)}}, nil, nil), | ||||||
|  | 		}}}}, nil}, | ||||||
|  | 
 | ||||||
|  | 		{"serve", func(k *kstub) error { shimEntrypoint(k); return nil }, stub.Expect{Calls: []stub.Call{ | ||||||
|  | 			call("getMsg", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("getLogger", stub.ExpectArgs{}, (*log.Logger)(nil), nil), | ||||||
|  | 			call("setDumpable", stub.ExpectArgs{uintptr(container.SUID_DUMP_DISABLE)}, nil, nil), | ||||||
|  | 			call("receive", stub.ExpectArgs{"HAKUREI_SHIM", templateState, nil}, nil, nil), | ||||||
|  | 			call("swapVerbose", stub.ExpectArgs{true}, false, nil), | ||||||
|  | 			call("verbosef", stub.ExpectArgs{"process share directory at %q, runtime directory at %q", []any{m("/tmp/hakurei.10"), m("/run/user/1000/hakurei")}}, nil, nil), | ||||||
|  | 			call("setupContSignal", stub.ExpectArgs{0xbad}, 0, nil), | ||||||
|  | 			call("prctl", stub.ExpectArgs{uintptr(syscall.PR_SET_PDEATHSIG), uintptr(syscall.SIGCONT), uintptr(0)}, nil, nil), | ||||||
|  | 			call("New", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("closeReceive", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("notifyContext", stub.ExpectArgs{context.Background(), []os.Signal{os.Interrupt, syscall.SIGTERM}}, -1, nil), | ||||||
|  | 			call("containerStart", stub.ExpectArgs{templateParams}, nil, nil), | ||||||
|  | 			call("containerServe", stub.ExpectArgs{templateParams}, nil, stub.UniqueError(3)), | ||||||
|  | 			call("fatal", stub.ExpectArgs{[]any{"cannot configure container: unique error 3 injected by the test suite\n"}}, nil, nil), | ||||||
|  | 
 | ||||||
|  | 			// deferred | ||||||
|  | 			call("wKeepAlive", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 		}, Tracks: []stub.Expect{{Calls: []stub.Call{ | ||||||
|  | 			call("rcRead", stub.ExpectArgs{}, nil, nil), // stub terminates this goroutine | ||||||
|  | 		}}}}, nil}, | ||||||
|  | 
 | ||||||
|  | 		{"seccomp", func(k *kstub) error { shimEntrypoint(k); return nil }, stub.Expect{Calls: []stub.Call{ | ||||||
|  | 			call("getMsg", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("getLogger", stub.ExpectArgs{}, (*log.Logger)(nil), nil), | ||||||
|  | 			call("setDumpable", stub.ExpectArgs{uintptr(container.SUID_DUMP_DISABLE)}, nil, nil), | ||||||
|  | 			call("receive", stub.ExpectArgs{"HAKUREI_SHIM", templateState, nil}, nil, nil), | ||||||
|  | 			call("swapVerbose", stub.ExpectArgs{true}, false, nil), | ||||||
|  | 			call("verbosef", stub.ExpectArgs{"process share directory at %q, runtime directory at %q", []any{m("/tmp/hakurei.10"), m("/run/user/1000/hakurei")}}, nil, nil), | ||||||
|  | 			call("setupContSignal", stub.ExpectArgs{0xbad}, 0, nil), | ||||||
|  | 			call("prctl", stub.ExpectArgs{uintptr(syscall.PR_SET_PDEATHSIG), uintptr(syscall.SIGCONT), uintptr(0)}, nil, nil), | ||||||
|  | 			call("New", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("closeReceive", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("notifyContext", stub.ExpectArgs{context.Background(), []os.Signal{os.Interrupt, syscall.SIGTERM}}, -1, nil), | ||||||
|  | 			call("containerStart", stub.ExpectArgs{templateParams}, nil, nil), | ||||||
|  | 			call("containerServe", stub.ExpectArgs{templateParams}, nil, nil), | ||||||
|  | 			call("seccompLoad", stub.ExpectArgs{shimPreset, seccomp.AllowMultiarch}, nil, stub.UniqueError(2)), | ||||||
|  | 			call("fatalf", stub.ExpectArgs{"cannot load syscall filter: %v", []any{stub.UniqueError(2)}}, nil, nil), | ||||||
|  | 
 | ||||||
|  | 			// deferred | ||||||
|  | 			call("wKeepAlive", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 		}, Tracks: []stub.Expect{{Calls: []stub.Call{ | ||||||
|  | 			call("rcRead", stub.ExpectArgs{}, nil, nil), // stub terminates this goroutine | ||||||
|  | 		}}}}, nil}, | ||||||
|  | 
 | ||||||
|  | 		{"exited closesetup earlyrequested", func(k *kstub) error { shimEntrypoint(k); return nil }, stub.Expect{Calls: []stub.Call{ | ||||||
|  | 			call("getMsg", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("getLogger", stub.ExpectArgs{}, (*log.Logger)(nil), nil), | ||||||
|  | 			call("setDumpable", stub.ExpectArgs{uintptr(container.SUID_DUMP_DISABLE)}, nil, nil), | ||||||
|  | 			call("receive", stub.ExpectArgs{"HAKUREI_SHIM", templateState, nil}, nil, nil), | ||||||
|  | 			call("swapVerbose", stub.ExpectArgs{true}, false, nil), | ||||||
|  | 			call("verbosef", stub.ExpectArgs{"process share directory at %q, runtime directory at %q", []any{m("/tmp/hakurei.10"), m("/run/user/1000/hakurei")}}, nil, nil), | ||||||
|  | 			call("setupContSignal", stub.ExpectArgs{0xbad}, 0, nil), | ||||||
|  | 			call("prctl", stub.ExpectArgs{uintptr(syscall.PR_SET_PDEATHSIG), uintptr(syscall.SIGCONT), uintptr(0)}, nil, nil), | ||||||
|  | 			call("New", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("closeReceive", stub.ExpectArgs{}, nil, stub.UniqueError(1)), | ||||||
|  | 			call("verbosef", stub.ExpectArgs{"cannot close setup pipe: %v", []any{stub.UniqueError(1)}}, nil, nil), | ||||||
|  | 			call("notifyContext", stub.ExpectArgs{context.Background(), []os.Signal{os.Interrupt, syscall.SIGTERM}}, 0, nil), | ||||||
|  | 			call("containerStart", stub.ExpectArgs{templateParams}, nil, nil), | ||||||
|  | 			call("containerServe", stub.ExpectArgs{templateParams}, nil, nil), | ||||||
|  | 			call("seccompLoad", stub.ExpectArgs{shimPreset, seccomp.AllowMultiarch}, nil, nil), | ||||||
|  | 			call("containerWait", stub.ExpectArgs{templateParams}, nil, makeExitError(1<<8)), | ||||||
|  | 			call("exit", stub.ExpectArgs{1}, stub.PanicExit, nil), | ||||||
|  | 
 | ||||||
|  | 			// deferred | ||||||
|  | 			call("wKeepAlive", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 		}, Tracks: []stub.Expect{{Calls: []stub.Call{ | ||||||
|  | 			call("rcRead", stub.ExpectArgs{}, []byte{shimMsgExitRequested}, nil), | ||||||
|  | 			call("exit", stub.ExpectArgs{hst.ExitRequest}, stub.PanicExit, unblockNotifyContext), | ||||||
|  | 		}}}}, nil}, | ||||||
|  | 
 | ||||||
|  | 		{"exited requested", func(k *kstub) error { shimEntrypoint(k); return nil }, stub.Expect{Calls: []stub.Call{ | ||||||
|  | 			call("getMsg", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("getLogger", stub.ExpectArgs{}, (*log.Logger)(nil), nil), | ||||||
|  | 			call("setDumpable", stub.ExpectArgs{uintptr(container.SUID_DUMP_DISABLE)}, nil, nil), | ||||||
|  | 			call("receive", stub.ExpectArgs{"HAKUREI_SHIM", templateState, nil}, nil, nil), | ||||||
|  | 			call("swapVerbose", stub.ExpectArgs{true}, false, nil), | ||||||
|  | 			call("verbosef", stub.ExpectArgs{"process share directory at %q, runtime directory at %q", []any{m("/tmp/hakurei.10"), m("/run/user/1000/hakurei")}}, nil, nil), | ||||||
|  | 			call("setupContSignal", stub.ExpectArgs{0xbad}, 0, nil), | ||||||
|  | 			call("prctl", stub.ExpectArgs{uintptr(syscall.PR_SET_PDEATHSIG), uintptr(syscall.SIGCONT), uintptr(0)}, nil, nil), | ||||||
|  | 			call("New", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("closeReceive", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("notifyContext", stub.ExpectArgs{context.Background(), []os.Signal{os.Interrupt, syscall.SIGTERM}}, 0, nil), | ||||||
|  | 			call("containerStart", stub.ExpectArgs{templateParams}, nil, nil), | ||||||
|  | 			call("containerServe", stub.ExpectArgs{templateParams}, nil, nil), | ||||||
|  | 			call("seccompLoad", stub.ExpectArgs{shimPreset, seccomp.AllowMultiarch}, nil, nil), | ||||||
|  | 			call("containerWait", stub.ExpectArgs{templateParams}, nil, makeExitError(1<<8)), | ||||||
|  | 			call("exit", stub.ExpectArgs{1}, stub.PanicExit, nil), | ||||||
|  | 
 | ||||||
|  | 			// deferred | ||||||
|  | 			call("wKeepAlive", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 		}, Tracks: []stub.Expect{{Calls: []stub.Call{ | ||||||
|  | 			call("rcRead", stub.ExpectArgs{}, []byte{shimMsgExitRequested}, unblockNotifyContext), | ||||||
|  | 			call("notifyContextStop", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("rcRead", stub.ExpectArgs{}, nil, nil), // stub terminates this goroutine | ||||||
|  | 		}}}}, nil}, | ||||||
|  | 
 | ||||||
|  | 		{"canceled orphaned", func(k *kstub) error { shimEntrypoint(k); return nil }, stub.Expect{Calls: []stub.Call{ | ||||||
|  | 			call("getMsg", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("getLogger", stub.ExpectArgs{}, (*log.Logger)(nil), nil), | ||||||
|  | 			call("setDumpable", stub.ExpectArgs{uintptr(container.SUID_DUMP_DISABLE)}, nil, nil), | ||||||
|  | 			call("receive", stub.ExpectArgs{"HAKUREI_SHIM", templateState, nil}, nil, nil), | ||||||
|  | 			call("swapVerbose", stub.ExpectArgs{true}, false, nil), | ||||||
|  | 			call("verbosef", stub.ExpectArgs{"process share directory at %q, runtime directory at %q", []any{m("/tmp/hakurei.10"), m("/run/user/1000/hakurei")}}, nil, nil), | ||||||
|  | 			call("setupContSignal", stub.ExpectArgs{0xbad}, 0, nil), | ||||||
|  | 			call("prctl", stub.ExpectArgs{uintptr(syscall.PR_SET_PDEATHSIG), uintptr(syscall.SIGCONT), uintptr(0)}, nil, nil), | ||||||
|  | 			call("New", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("closeReceive", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("notifyContext", stub.ExpectArgs{context.Background(), []os.Signal{os.Interrupt, syscall.SIGTERM}}, -1, nil), | ||||||
|  | 			call("containerStart", stub.ExpectArgs{templateParams}, nil, nil), | ||||||
|  | 			call("containerServe", stub.ExpectArgs{templateParams}, nil, nil), | ||||||
|  | 			call("seccompLoad", stub.ExpectArgs{shimPreset, seccomp.AllowMultiarch}, nil, nil), | ||||||
|  | 			call("containerWait", stub.ExpectArgs{templateParams}, nil, context.Canceled), | ||||||
|  | 			call("exit", stub.ExpectArgs{hst.ExitCancel}, stub.PanicExit, nil), | ||||||
|  | 
 | ||||||
|  | 			// deferred | ||||||
|  | 			call("wKeepAlive", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 		}, Tracks: []stub.Expect{{Calls: []stub.Call{ | ||||||
|  | 			call("rcRead", stub.ExpectArgs{}, []byte{shimMsgOrphaned}, nil), | ||||||
|  | 			call("exit", stub.ExpectArgs{hst.ExitOrphan}, stub.PanicExit, nil), | ||||||
|  | 		}}}}, nil}, | ||||||
|  | 
 | ||||||
|  | 		{"strangewait invalidmsg", func(k *kstub) error { shimEntrypoint(k); return nil }, stub.Expect{Calls: []stub.Call{ | ||||||
|  | 			call("getMsg", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("getLogger", stub.ExpectArgs{}, (*log.Logger)(nil), nil), | ||||||
|  | 			call("setDumpable", stub.ExpectArgs{uintptr(container.SUID_DUMP_DISABLE)}, nil, nil), | ||||||
|  | 			call("receive", stub.ExpectArgs{"HAKUREI_SHIM", templateState, nil}, nil, nil), | ||||||
|  | 			call("swapVerbose", stub.ExpectArgs{true}, false, nil), | ||||||
|  | 			call("verbosef", stub.ExpectArgs{"process share directory at %q, runtime directory at %q", []any{m("/tmp/hakurei.10"), m("/run/user/1000/hakurei")}}, nil, nil), | ||||||
|  | 			call("setupContSignal", stub.ExpectArgs{0xbad}, 0, nil), | ||||||
|  | 			call("prctl", stub.ExpectArgs{uintptr(syscall.PR_SET_PDEATHSIG), uintptr(syscall.SIGCONT), uintptr(0)}, nil, nil), | ||||||
|  | 			call("New", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("closeReceive", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 			call("notifyContext", stub.ExpectArgs{context.Background(), []os.Signal{os.Interrupt, syscall.SIGTERM}}, -1, nil), | ||||||
|  | 			call("containerStart", stub.ExpectArgs{templateParams}, nil, nil), | ||||||
|  | 			call("containerServe", stub.ExpectArgs{templateParams}, nil, nil), | ||||||
|  | 			call("seccompLoad", stub.ExpectArgs{shimPreset, seccomp.AllowMultiarch}, nil, nil), | ||||||
|  | 			call("containerWait", stub.ExpectArgs{templateParams}, nil, stub.UniqueError(0)), | ||||||
|  | 			call("verbosef", stub.ExpectArgs{"cannot wait: %v", []any{stub.UniqueError(0)}}, nil, nil), | ||||||
|  | 			call("exit", stub.ExpectArgs{127}, stub.PanicExit, nil), | ||||||
|  | 
 | ||||||
|  | 			// deferred | ||||||
|  | 			call("wKeepAlive", stub.ExpectArgs{}, nil, nil), | ||||||
|  | 		}, Tracks: []stub.Expect{{Calls: []stub.Call{ | ||||||
|  | 			call("rcRead", stub.ExpectArgs{}, []byte{0xff}, nil), | ||||||
|  | 			call("fatalf", stub.ExpectArgs{"got invalid message %d from signal handler", []any{byte(0xff)}}, nil, nil), | ||||||
|  | 		}}}}, nil}, | ||||||
|  | 
 | ||||||
| 		{"success", func(k *kstub) error { shimEntrypoint(k); return nil }, stub.Expect{Calls: []stub.Call{ | 		{"success", func(k *kstub) error { shimEntrypoint(k); return nil }, stub.Expect{Calls: []stub.Call{ | ||||||
| 			call("getMsg", stub.ExpectArgs{}, nil, nil), | 			call("getMsg", stub.ExpectArgs{}, nil, nil), | ||||||
| 			call("getLogger", stub.ExpectArgs{}, (*log.Logger)(nil), nil), | 			call("getLogger", stub.ExpectArgs{}, (*log.Logger)(nil), nil), | ||||||
| @ -139,7 +469,7 @@ func TestShimEntrypoint(t *testing.T) { | |||||||
| 			call("prctl", stub.ExpectArgs{uintptr(syscall.PR_SET_PDEATHSIG), uintptr(syscall.SIGCONT), uintptr(0)}, nil, nil), | 			call("prctl", stub.ExpectArgs{uintptr(syscall.PR_SET_PDEATHSIG), uintptr(syscall.SIGCONT), uintptr(0)}, nil, nil), | ||||||
| 			call("New", stub.ExpectArgs{}, nil, nil), | 			call("New", stub.ExpectArgs{}, nil, nil), | ||||||
| 			call("closeReceive", stub.ExpectArgs{}, nil, nil), | 			call("closeReceive", stub.ExpectArgs{}, nil, nil), | ||||||
| 			call("notifyContext", stub.ExpectArgs{context.Background(), []os.Signal{os.Interrupt, syscall.SIGTERM}}, nil, nil), | 			call("notifyContext", stub.ExpectArgs{context.Background(), []os.Signal{os.Interrupt, syscall.SIGTERM}}, -1, nil), | ||||||
| 			call("containerStart", stub.ExpectArgs{templateParams}, nil, nil), | 			call("containerStart", stub.ExpectArgs{templateParams}, nil, nil), | ||||||
| 			call("containerServe", stub.ExpectArgs{templateParams}, nil, nil), | 			call("containerServe", stub.ExpectArgs{templateParams}, nil, nil), | ||||||
| 			call("seccompLoad", stub.ExpectArgs{shimPreset, seccomp.AllowMultiarch}, nil, nil), | 			call("seccompLoad", stub.ExpectArgs{shimPreset, seccomp.AllowMultiarch}, nil, nil), | ||||||
| @ -156,3 +486,9 @@ func TestShimEntrypoint(t *testing.T) { | |||||||
| 		}}}}, nil}, | 		}}}}, nil}, | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // errorOp implements a noop outcomeOp that unconditionally returns [stub.UniqueError]. | ||||||
|  | type errorOp stub.UniqueError | ||||||
|  | 
 | ||||||
|  | func (e errorOp) toSystem(*outcomeStateSys) error       { return stub.UniqueError(e) } | ||||||
|  | func (e errorOp) toContainer(*outcomeStateParams) error { return stub.UniqueError(e) } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user