Skip to content

Commit ce50989

Browse files
jingdi.zhuxiantang
jingdi.zhu
authored andcommitted
Add exiter to test os.Exit case
1 parent 0811477 commit ce50989

File tree

3 files changed

+109
-4
lines changed

3 files changed

+109
-4
lines changed

runner/engine.go

+12-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ import (
1717

1818
// Engine ...
1919
type Engine struct {
20-
config *Config
20+
config *Config
21+
22+
exiter exiter
2123
proxy *Proxy
2224
logger *logger
2325
watcher filenotify.FileWatcher
@@ -50,6 +52,7 @@ func NewEngineWithConfig(cfg *Config, debugMode bool) (*Engine, error) {
5052
}
5153
e := Engine{
5254
config: cfg,
55+
exiter: defaultExiter{},
5356
proxy: NewProxy(&cfg.Proxy),
5457
logger: logger,
5558
watcher: watcher,
@@ -655,8 +658,14 @@ func (e *Engine) stopBin() {
655658
close(exitCode)
656659
}
657660
})
658-
if ret := <-exitCode; ret != 0 {
659-
os.Exit(ret)
661+
662+
select {
663+
case ret := <-exitCode:
664+
if ret != 0 {
665+
e.exiter.Exit(ret) // Use exiter instead of direct os.Exit, it's for tests purpose.
666+
}
667+
case <-time.After(5 * time.Second):
668+
e.mainDebug("timed out waiting for process exit")
660669
}
661670
}
662671

runner/engine_test.go

+84-1
Original file line numberDiff line numberDiff line change
@@ -1044,7 +1044,7 @@ include_file = ["main.sh"]
10441044

10451045
t.Logf("start change main.sh")
10461046
go func() {
1047-
err := os.WriteFile("main.sh", []byte("#!/bin/sh\nprintf modified > output"), 0o755)
1047+
err = os.WriteFile("main.sh", []byte("#!/bin/sh\nprintf modified > output"), 0o755)
10481048
if err != nil {
10491049
log.Fatalf("Error updating file: %s.", err)
10501050
}
@@ -1058,3 +1058,86 @@ include_file = ["main.sh"]
10581058
}
10591059
assert.Equal(t, []byte("modified"), bytes)
10601060
}
1061+
1062+
type testExiter struct {
1063+
t *testing.T
1064+
called bool
1065+
expectCode int
1066+
}
1067+
1068+
func (te *testExiter) Exit(code int) {
1069+
te.called = true
1070+
if code != te.expectCode {
1071+
te.t.Fatalf("expected exit code %d, got %d", te.expectCode, code)
1072+
}
1073+
}
1074+
1075+
func TestEngineExit(t *testing.T) {
1076+
tests := []struct {
1077+
name string
1078+
setup func(*Engine, chan<- int)
1079+
expectCode int
1080+
wantCalled bool
1081+
}{
1082+
{
1083+
name: "normal exit - no error",
1084+
setup: func(_ *Engine, exitCode chan<- int) {
1085+
go func() {
1086+
exitCode <- 0
1087+
}()
1088+
},
1089+
expectCode: 0,
1090+
wantCalled: false,
1091+
},
1092+
{
1093+
name: "error exit - non-zero code",
1094+
setup: func(_ *Engine, exitCode chan<- int) {
1095+
go func() {
1096+
exitCode <- 1
1097+
}()
1098+
},
1099+
expectCode: 1,
1100+
wantCalled: true,
1101+
},
1102+
{
1103+
name: "process timeout",
1104+
setup: func(_ *Engine, _ chan<- int) {
1105+
},
1106+
expectCode: 0,
1107+
wantCalled: false,
1108+
},
1109+
}
1110+
1111+
for _, tt := range tests {
1112+
t.Run(tt.name, func(t *testing.T) {
1113+
e, err := NewEngine("", true)
1114+
if err != nil {
1115+
t.Fatal(err)
1116+
}
1117+
1118+
exiter := &testExiter{
1119+
t: t,
1120+
expectCode: tt.expectCode,
1121+
}
1122+
e.exiter = exiter
1123+
1124+
exitCode := make(chan int)
1125+
1126+
if tt.setup != nil {
1127+
tt.setup(e, exitCode)
1128+
}
1129+
select {
1130+
case ret := <-exitCode:
1131+
if ret != 0 {
1132+
e.exiter.Exit(ret)
1133+
}
1134+
case <-time.After(1 * time.Millisecond):
1135+
// timeout case
1136+
}
1137+
1138+
if tt.wantCalled != exiter.called {
1139+
t.Errorf("Exit() called = %v, want %v", exiter.called, tt.wantCalled)
1140+
}
1141+
})
1142+
}
1143+
}

runner/exiter.go

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package runner
2+
3+
import "os"
4+
5+
type exiter interface {
6+
Exit(code int)
7+
}
8+
9+
type defaultExiter struct{}
10+
11+
func (d defaultExiter) Exit(code int) {
12+
os.Exit(code)
13+
}

0 commit comments

Comments
 (0)