message: relocate from container
All checks were successful
Test / Create distribution (push) Successful in 35s
Test / Sandbox (push) Successful in 2m22s
Test / Hpkg (push) Successful in 4m2s
Test / Sandbox (race detector) (push) Successful in 4m28s
Test / Hakurei (race detector) (push) Successful in 5m21s
Test / Hakurei (push) Successful in 2m9s
Test / Flake checks (push) Successful in 1m29s
All checks were successful
Test / Create distribution (push) Successful in 35s
Test / Sandbox (push) Successful in 2m22s
Test / Hpkg (push) Successful in 4m2s
Test / Sandbox (race detector) (push) Successful in 4m28s
Test / Hakurei (race detector) (push) Successful in 5m21s
Test / Hakurei (push) Successful in 2m9s
Test / Flake checks (push) Successful in 1m29s
This package is quite useful. This change allows it to be imported without importing container. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
173
message/output_test.go
Normal file
173
message/output_test.go
Normal file
@@ -0,0 +1,173 @@
|
||||
package message_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"hakurei.app/container/stub"
|
||||
"hakurei.app/message"
|
||||
)
|
||||
|
||||
func TestSuspendable(t *testing.T) {
|
||||
// copied from output.go
|
||||
const suspendBufMax = 1 << 24
|
||||
|
||||
const (
|
||||
// equivalent to len(want.pt)
|
||||
nSpecialPtEquiv = -iota - 1
|
||||
// equivalent to len(want.w)
|
||||
nSpecialWEquiv
|
||||
// suspends writer before executing test case, implies nSpecialWEquiv
|
||||
nSpecialSuspend
|
||||
// offset: resume writer and measure against dump instead, implies nSpecialPtEquiv
|
||||
nSpecialDump
|
||||
)
|
||||
|
||||
// shares the same writer
|
||||
steps := []struct {
|
||||
name string
|
||||
w, pt []byte
|
||||
err error
|
||||
wantErr error
|
||||
n int
|
||||
}{
|
||||
{"simple", []byte{0xde, 0xad, 0xbe, 0xef}, []byte{0xde, 0xad, 0xbe, 0xef},
|
||||
nil, nil, nSpecialPtEquiv},
|
||||
|
||||
{"error", []byte{0xb, 0xad}, []byte{0xb, 0xad},
|
||||
stub.UniqueError(0), stub.UniqueError(0), nSpecialPtEquiv},
|
||||
|
||||
{"suspend short", []byte{0}, nil,
|
||||
nil, nil, nSpecialSuspend},
|
||||
{"sw short 0", []byte{0xca, 0xfe, 0xba, 0xbe}, nil,
|
||||
nil, nil, nSpecialWEquiv},
|
||||
{"sw short 1", []byte{0xff}, nil,
|
||||
nil, nil, nSpecialWEquiv},
|
||||
{"resume short", nil, []byte{0, 0xca, 0xfe, 0xba, 0xbe, 0xff}, nil, nil,
|
||||
nSpecialDump},
|
||||
|
||||
{"long pt", bytes.Repeat([]byte{0xff}, suspendBufMax+1), bytes.Repeat([]byte{0xff}, suspendBufMax+1),
|
||||
nil, nil, nSpecialPtEquiv},
|
||||
|
||||
{"suspend fill", bytes.Repeat([]byte{0xfe}, suspendBufMax), nil,
|
||||
nil, nil, nSpecialSuspend},
|
||||
{"drop", []byte{0}, nil,
|
||||
nil, syscall.ENOMEM, 0},
|
||||
{"drop error", []byte{0}, nil,
|
||||
stub.UniqueError(1), syscall.ENOMEM, 0},
|
||||
{"resume fill", nil, bytes.Repeat([]byte{0xfe}, suspendBufMax),
|
||||
nil, nil, nSpecialDump - 2},
|
||||
|
||||
{"suspend fill partial", bytes.Repeat([]byte{0xfd}, suspendBufMax-0xf), nil,
|
||||
nil, nil, nSpecialSuspend},
|
||||
{"partial write", bytes.Repeat([]byte{0xad}, 0x1f), nil,
|
||||
nil, syscall.ENOMEM, 0xf},
|
||||
{"full drop", []byte{0}, nil,
|
||||
nil, syscall.ENOMEM, 0},
|
||||
{"resume fill partial", nil, append(bytes.Repeat([]byte{0xfd}, suspendBufMax-0xf), bytes.Repeat([]byte{0xad}, 0xf)...),
|
||||
nil, nil, nSpecialDump - 0x10 - 1},
|
||||
}
|
||||
|
||||
var dw expectWriter
|
||||
|
||||
w := message.Suspendable{Downstream: &dw}
|
||||
for _, step := range steps {
|
||||
// these share the same writer, so cannot be subtests
|
||||
t.Logf("writing step %q", step.name)
|
||||
dw.expect, dw.err = step.pt, step.err
|
||||
|
||||
var (
|
||||
gotN int
|
||||
gotErr error
|
||||
)
|
||||
|
||||
wantN := step.n
|
||||
switch wantN {
|
||||
case nSpecialPtEquiv:
|
||||
wantN = len(step.pt)
|
||||
gotN, gotErr = w.Write(step.w)
|
||||
|
||||
case nSpecialWEquiv:
|
||||
wantN = len(step.w)
|
||||
gotN, gotErr = w.Write(step.w)
|
||||
|
||||
case nSpecialSuspend:
|
||||
s := w.IsSuspended()
|
||||
if ok := w.Suspend(); s && ok {
|
||||
t.Fatal("Suspend: unexpected success")
|
||||
}
|
||||
|
||||
wantN = len(step.w)
|
||||
gotN, gotErr = w.Write(step.w)
|
||||
|
||||
default:
|
||||
if wantN <= nSpecialDump {
|
||||
if !w.IsSuspended() {
|
||||
t.Fatal("IsSuspended unexpected false")
|
||||
}
|
||||
|
||||
resumed, dropped, n, err := w.Resume()
|
||||
if !resumed {
|
||||
t.Fatal("Resume: resumed = false")
|
||||
}
|
||||
if wantDropped := nSpecialDump - wantN; int(dropped) != wantDropped {
|
||||
t.Errorf("Resume: dropped = %d, want %d", dropped, wantDropped)
|
||||
}
|
||||
|
||||
wantN = len(step.pt)
|
||||
gotN, gotErr = int(n), err
|
||||
} else {
|
||||
gotN, gotErr = w.Write(step.w)
|
||||
}
|
||||
}
|
||||
|
||||
if gotN != wantN {
|
||||
t.Errorf("Write: n = %d, want %d", gotN, wantN)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(gotErr, step.wantErr) {
|
||||
t.Errorf("Write: %v", gotErr)
|
||||
}
|
||||
|
||||
if dw.expect != nil {
|
||||
t.Errorf("expect: %q", string(dw.expect))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// expectWriter compares Write calls to expect.
|
||||
type expectWriter struct {
|
||||
expect []byte
|
||||
err error
|
||||
|
||||
// optional consecutive write
|
||||
next []byte
|
||||
|
||||
// optional, calls Error on failure if not nil
|
||||
t *testing.T
|
||||
}
|
||||
|
||||
func (w *expectWriter) Write(p []byte) (n int, err error) {
|
||||
defer func() { w.expect = w.next; w.next = nil }()
|
||||
|
||||
n, err = len(p), w.err
|
||||
if w.expect == nil {
|
||||
n, err = 0, errors.New("unexpected call to Write: "+strconv.Quote(string(p)))
|
||||
if w.t != nil {
|
||||
w.t.Error(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
if string(p) != string(w.expect) {
|
||||
n, err = 0, errors.New("p = "+strconv.Quote(string(p))+", want "+strconv.Quote(string(w.expect)))
|
||||
if w.t != nil {
|
||||
w.t.Error(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user