test/e2e: optimize RunFrps/RunFrpc with process exit detection

Refactor Process to track subprocess lifecycle via a done channel,
replacing direct cmd.Wait() in Stop() to avoid double-Wait races.
RunFrps/RunFrpc now use select on the done channel instead of fixed
sleeps, allowing short-lived processes (verify, startup failures) to
return immediately while preserving existing timeout behavior for
long-running daemons.
This commit is contained in:
fatedier
2026-03-09 00:41:00 +08:00
parent bcd2424c24
commit f32bec9f4d
2 changed files with 30 additions and 4 deletions

View File

@@ -76,7 +76,10 @@ func (f *Framework) RunFrps(args ...string) (*process.Process, string, error) {
if err != nil { if err != nil {
return p, p.Output(), err return p, p.Output(), err
} }
time.Sleep(2 * time.Second) select {
case <-p.Done():
case <-time.After(2 * time.Second):
}
return p, p.Output(), nil return p, p.Output(), nil
} }
@@ -87,7 +90,10 @@ func (f *Framework) RunFrpc(args ...string) (*process.Process, string, error) {
if err != nil { if err != nil {
return p, p.Output(), err return p, p.Output(), err
} }
time.Sleep(1500 * time.Millisecond) select {
case <-p.Done():
case <-time.After(1500 * time.Millisecond):
}
return p, p.Output(), nil return p, p.Output(), nil
} }

View File

@@ -12,6 +12,9 @@ type Process struct {
errorOutput *bytes.Buffer errorOutput *bytes.Buffer
stdOutput *bytes.Buffer stdOutput *bytes.Buffer
done chan struct{}
waitErr error
beforeStopHandler func() beforeStopHandler func()
stopped bool stopped bool
} }
@@ -27,6 +30,7 @@ func NewWithEnvs(path string, params []string, envs []string) *Process {
p := &Process{ p := &Process{
cmd: cmd, cmd: cmd,
cancel: cancel, cancel: cancel,
done: make(chan struct{}),
} }
p.errorOutput = bytes.NewBufferString("") p.errorOutput = bytes.NewBufferString("")
p.stdOutput = bytes.NewBufferString("") p.stdOutput = bytes.NewBufferString("")
@@ -36,7 +40,22 @@ func NewWithEnvs(path string, params []string, envs []string) *Process {
} }
func (p *Process) Start() error { func (p *Process) Start() error {
return p.cmd.Start() err := p.cmd.Start()
if err != nil {
p.waitErr = err
close(p.done)
return err
}
go func() {
p.waitErr = p.cmd.Wait()
close(p.done)
}()
return nil
}
// Done returns a channel that is closed when the process exits.
func (p *Process) Done() <-chan struct{} {
return p.done
} }
func (p *Process) Stop() error { func (p *Process) Stop() error {
@@ -50,7 +69,8 @@ func (p *Process) Stop() error {
p.beforeStopHandler() p.beforeStopHandler()
} }
p.cancel() p.cancel()
return p.cmd.Wait() <-p.done
return p.waitErr
} }
func (p *Process) ErrorOutput() string { func (p *Process) ErrorOutput() string {