github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/test/pseudo/svctool/svctool_test.go (about) 1 package svctool 2 3 import ( 4 "context" 5 "errors" 6 "os/exec" 7 "path/filepath" 8 "runtime" 9 "sync" 10 "testing" 11 "time" 12 ) 13 14 //go:generate go build -o ../cmd/svc/build/svc ../cmd/svc 15 //go:generate go build -o ../cmd/svc/build/tool ../cmd/tool 16 17 type logFunc func(...interface{}) 18 19 func (l logFunc) Write(p []byte) (int, error) { 20 l(string(p)) 21 return len(p), nil 22 } 23 24 func TestService(t *testing.T) { 25 t.SkipNow() // https://activestatef.atlassian.net/browse/DX-828 26 27 simultaneous := 2 28 iterations := 512 29 pause := time.Millisecond * 10 30 31 errs := make(chan error) 32 33 ctx, cancel := context.WithTimeout(context.Background(), time.Second*300) 34 defer cancel() 35 36 go func() { // load up command instances 37 defer close(errs) 38 39 wg := &sync.WaitGroup{} 40 var count int 41 42 for iter := 0; iter < iterations; iter++ { 43 start := make(chan struct{}) 44 wg.Add(simultaneous) 45 for i := 0; i < simultaneous; i++ { 46 count++ 47 t.Log("count", count) 48 var ext string 49 if runtime.GOOS == "windows" { 50 ext = ".exe" 51 } 52 c := exec.CommandContext(ctx, filepath.Clean("../cmd/svc/build/svc"+ext)) 53 c.Stdout = logFunc(t.Log) 54 c.Stderr = logFunc(t.Log) 55 56 go func(cmd *exec.Cmd) { 57 defer wg.Done() 58 59 select { // wait for common start time with fallback timeout 60 case <-start: 61 case <-time.After(time.Millisecond * 3): 62 t.Error("cmd start is not aligned") 63 } 64 65 t.Log("STARTING") 66 if err := cmd.Start(); err != nil { 67 t.Log("start error:", err) 68 errs <- err 69 } 70 71 if err := cmd.Wait(); err != nil { 72 t.Log("wait error:", err) 73 errs <- err 74 } 75 }(c) 76 } 77 78 close(start) // trip command instances executions 79 time.Sleep(pause) 80 } 81 wg.Wait() 82 }() 83 84 var saved error 85 var got int 86 want := (simultaneous * iterations) - 1 87 88 for err := range errs { 89 var eerr *exec.ExitError 90 if errors.As(err, &eerr) && eerr.ExitCode() < 0 { // ctx cancelled (ignore killed) 91 continue 92 } 93 94 if saved == nil && err != nil { // save first non-nil error for example output 95 saved = err 96 } 97 got++ 98 if got >= want { 99 cancel() 100 } 101 } 102 103 if got != want { 104 t.Errorf("error count: got %d, want %d: %v", got, want, saved) 105 } 106 }