75 lines
2.2 KiB
Go
75 lines
2.2 KiB
Go
package stdio
|
|
|
|
import (
|
|
"io"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// A bus function called before Serve waits for Serve and proceeds (issue 1966): a module that starts a goroutine
|
|
// before stdio.Serve and calls the bus there is no longer refused. It is refused only when the process never serves.
|
|
// The test drives the wait itself: serveWait is the test's own timer channel, no row sleeps on a clock.
|
|
func TestBusFunctionsWaitForServe(t *testing.T) {
|
|
const refusal = "before Serve: a bundle reaches the bus through the runtime that launched it"
|
|
for _, tc := range []struct {
|
|
name string
|
|
serve string // "first": before the call; "during": while the call waits; "never"
|
|
wantOK bool
|
|
}{
|
|
{"a call before Serve completes after Serve", "during", true},
|
|
{"a call whose wait ends before Serve is refused", "never", false},
|
|
{"a call after Serve is as before", "first", true},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
servesAlone(t)
|
|
expire := make(chan time.Time)
|
|
oldAfter := serveTimer
|
|
serveTimer = func() (<-chan time.Time, func()) { return expire, func() {} }
|
|
t.Cleanup(func() { serveTimer = oldAfter })
|
|
|
|
inR, inW := io.Pipe()
|
|
outR, outW := io.Pipe()
|
|
stopped := make(chan struct{})
|
|
serve := func() {
|
|
go func() { _ = ServeOn("m", nil, inR, outW); close(stopped) }()
|
|
}
|
|
t.Cleanup(func() { _ = inW.Close(); go func() { _, _ = io.Copy(io.Discard, outR) }() })
|
|
|
|
type result struct {
|
|
c *channel
|
|
err error
|
|
}
|
|
done := make(chan result, 1)
|
|
if tc.serve == "first" {
|
|
serve()
|
|
<-Served()
|
|
c, err := live()
|
|
done <- result{c, err}
|
|
} else {
|
|
go func() { c, err := live(); done <- result{c, err} }()
|
|
select {
|
|
case r := <-done:
|
|
t.Fatalf("live() returned before Serve and before its wait ended: %v", r.err)
|
|
default:
|
|
}
|
|
if tc.serve == "during" {
|
|
serve()
|
|
} else {
|
|
expire <- time.Time{}
|
|
}
|
|
}
|
|
r := <-done
|
|
if tc.wantOK != (r.err == nil && r.c != nil) {
|
|
t.Fatalf("live() = %v, %v; want ok=%v", r.c, r.err, tc.wantOK)
|
|
}
|
|
if !tc.wantOK && r.err.Error() != refusal {
|
|
t.Fatalf("refusal words changed: %v", r.err)
|
|
}
|
|
if tc.serve != "never" {
|
|
_ = inW.Close()
|
|
<-stopped
|
|
}
|
|
})
|
|
}
|
|
}
|