aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-10-12 18:14:01 +0900
committerOphestra <cat@gensokyo.uk>2026-10-12 18:14:01 +0900
commit11e395a1a7453b93c695e849bd93d8c2c0af6aef (patch)
tree8f874f9ce4371ae59ac7738bdfa2f028efc00ff6
parent39726881f528afbbf8f8b49d6f0921d1f330acd8 (diff)
cmd/hakurei/testsuite: extra exercise parameters
This also removes the interval and fixes the mustStart search criteria. Signed-off-by: Ophestra <cat@gensokyo.uk>
-rw-r--r--cmd/hakurei/testsuite/sandbox/main.go110
-rw-r--r--internal/testsuite/testsuite.go9
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
}