From 11e395a1a7453b93c695e849bd93d8c2c0af6aef Mon Sep 17 00:00:00 2001 From: Ophestra Date: Mon, 12 Oct 2026 18:14:01 +0900 Subject: cmd/hakurei/testsuite: extra exercise parameters This also removes the interval and fixes the mustStart search criteria. Signed-off-by: Ophestra --- cmd/hakurei/testsuite/sandbox/main.go | 110 +++++++++++++++++++--------------- internal/testsuite/testsuite.go | 9 ++- 2 files changed, 69 insertions(+), 50 deletions(-) diff --git a/cmd/hakurei/testsuite/sandbox/main.go b/cmd/hakurei/testsuite/sandbox/main.go index a2d1cb5e..88e028e1 100644 --- a/cmd/hakurei/testsuite/sandbox/main.go +++ b/cmd/hakurei/testsuite/sandbox/main.go @@ -8,6 +8,7 @@ import ( "bytes" "context" "encoding/json" + "fmt" "io" "log" "os" @@ -18,9 +19,7 @@ import ( "strconv" "strings" "sync" - "sync/atomic" "syscall" - "time" "hakurei.app/check" "hakurei.app/fhs" @@ -99,7 +98,7 @@ func mustStart( log.Fatal(err) } - id := hst.ToUser[uint32](0, 0) + id := hst.ToUser[uint32](0, uint32(identity)) if stat.Uid != id || stat.Gid != id { return false } @@ -109,11 +108,50 @@ func mustStart( return } -// serial is the previous value returned by newSerial. -var serial atomic.Uint64 +// exercise exercises internal/outcome container setup and teardown. +func exercise( + ctx context.Context, + cred *syscall.Credential, + n, count int, + f func(identity, pid int), +) { -// newSerial returns a unique number. -func newSerial() uint64 { defer serial.Add(1); return serial.Load() } + var wg sync.WaitGroup + in := count + var identity int + + wg.Add(n) + for range n { + in-- + if in < 0 { + identity++ + in = count + } + go func(identity int) { + defer wg.Done() + + for ctx.Err() == nil { + pid, done := mustStart( + ctx, + testsuite.NewSerial(), + identity, + cred, + ) + + if _err := syscall.Kill(pid, syscall.SIGTERM); _err != nil { + log.Fatal(_err) + } + if _err := testsuite.FilterTerminated(<-done); _err != nil { + log.Fatal(_err) + } + if f != nil { + f(identity, pid) + } + } + }(identity) + } + wg.Wait() +} func main() { cred := syscall.Credential{Uid: 1000, Gid: 100} @@ -124,52 +162,26 @@ func main() { log.Fatalf("invalid stress concurrency %q", p) } + count := n + if p, ok = os.LookupEnv("HAKUREI_TESTSUITE_EXERCISE_COUNT"); ok { + count, err = strconv.Atoi(p) + if err != nil { + log.Fatalf("invalid stress instance count %q", p) + } + } + ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM, ) defer stop() - - const identCount = 8 - - var wg sync.WaitGroup - in := identCount - var identity int - - wg.Add(n) - for range n { - in-- - if in < 0 { - identity++ - in = identCount - } - go func(identity int) { - defer wg.Done() - - t := time.NewTicker(500 * time.Millisecond) - start: - pid, done := mustStart(ctx, newSerial(), identity, &cred) - select { - case <-t.C: - if _err := syscall.Kill(pid, syscall.SIGTERM); _err != nil { - log.Fatal(_err) - } - - case <-ctx.Done(): - if _err := syscall.Kill(pid, syscall.SIGTERM); _err != nil { - log.Fatal(_err) - } - } - if _err := testsuite.FilterTerminated(<-done); _err != nil { - log.Fatal(_err) - } - if ctx.Err() == nil { - goto start - } - }(identity) - } log.Printf("exercising cmd/hakurei with %d concurrent instances", n) - wg.Wait() + var mu sync.Mutex + exercise(ctx, &cred, n, count, func(identity, pid int) { + mu.Lock() + fmt.Print(strconv.Itoa(identity) + "\t" + strconv.Itoa(pid) + "\r") + mu.Unlock() + }) } go testsuite.ReceiveSignals() @@ -227,7 +239,7 @@ func main() { c, cancel := context.WithCancel(ctx) defer cancel() - pid, done := mustStart(c, newSerial(), 0, &cred) + pid, done := mustStart(c, testsuite.NewSerial(), 0, &cred) testsuite.MustCheckFilter(pid, testdata.SumPD) if err := testsuite.FilterTerminated(<-done); err != nil { log.Fatal(err) @@ -240,7 +252,7 @@ func main() { c, cancel := context.WithCancel(ctx) defer cancel() - pid, done := mustStart(c, newSerial(), 0, &cred, os.Stdin, os.Stdout, os.Stderr) + pid, done := mustStart(c, testsuite.NewSerial(), 0, &cred, os.Stdin, os.Stdout, os.Stderr) prefix := filepath.Join(fhs.Proc, strconv.Itoa(pid), "fd") var fail bool diff --git a/internal/testsuite/testsuite.go b/internal/testsuite/testsuite.go index 6e48eca1..2c82e1e9 100644 --- a/internal/testsuite/testsuite.go +++ b/internal/testsuite/testsuite.go @@ -17,10 +17,17 @@ import ( "strconv" "strings" "sync" + "sync/atomic" "syscall" "time" ) +// serial is the next value returned by [NewSerial]. +var serial atomic.Uint64 + +// NewSerial returns a serial number. +func NewSerial() uint64 { defer serial.Add(1); return serial.Load() } + // ReceiveSignals blocks until a termination signal arrives, and terminates. func ReceiveSignals() { s := make(chan os.Signal, 3) @@ -116,7 +123,7 @@ func MustStart(cmd *exec.Cmd) (done <-chan error) { if err := cmd.Start(); err != nil { log.Fatal(err) } - d := make(chan error) + d := make(chan error, 1) go func() { d <- cmd.Wait() }() return d } -- cgit v1.3.1