Files
3x-ui/internal/xray/process_race_test.go
T
MHSanaei 1c0b76c27a Use efficient APIs and simplify loops
Minor refactors across the codebase to improve readability and use more efficient APIs: replace fmt.Sprintf+base64 encoding with fmt.Appendf when building Shadowsocks userInfo; compute elapsed using max(now-prev.at, window) to simplify logic; use strings.SplitSeq for splitting in two places; simplify test and goroutine loops to range-based iterations and use errgroup's Go helper; and align/clean up struct field formatting and test map literals. Mostly stylistic/efficiency changes with no intended behavior changes.
2026-06-23 14:12:28 +02:00

57 lines
1.1 KiB
Go

package xray
import (
"errors"
"os/exec"
"sync"
"testing"
"time"
)
// TestProcessLifecycleFieldsRaceSafe drives the lifecycle fields (cmd, done,
// exitErr) the way Start/startCommand and the waitForCommand goroutine do, while
// the status getters read them concurrently. Run with -race: any unsynchronized
// access to those fields is reported as a data race.
func TestProcessLifecycleFieldsRaceSafe(t *testing.T) {
p := &process{logWriter: NewLogWriter()}
var wg sync.WaitGroup
stop := make(chan struct{})
// Writer: churn cmd/done/exitErr like Start + waitForCommand.
wg.Go(func() {
for {
select {
case <-stop:
return
default:
}
p.mu.Lock()
p.cmd = &exec.Cmd{}
p.done = make(chan struct{})
p.mu.Unlock()
p.setExitErr(errors.New("boom"))
}
})
// Readers: the concurrent status getters.
for range 4 {
wg.Go(func() {
for {
select {
case <-stop:
return
default:
}
_ = p.IsRunning()
_ = p.GetErr()
_ = p.GetResult()
}
})
}
time.Sleep(50 * time.Millisecond)
close(stop)
wg.Wait()
}