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  }