Write stream implementation (#19)

Defines a WriteStream structure for buffering writes, similar to the existing ReadStream. WriteStreams can be created on OutEndpoints by using ep.NewStream().
This commit is contained in:
zagrodzki
2017-09-08 13:41:25 +02:00
committed by GitHub
parent 01840c1d23
commit 5c10dc8f4e
7 changed files with 368 additions and 84 deletions

View File

@@ -62,7 +62,7 @@ func (f *fakeStreamTransfer) wait() (int, error) {
return 0, errors.New("wait() called on a free()d transfer")
}
if !f.inFlight {
return 0, errors.New("wait() called without submit()")
return 0, nil
}
if len(f.res) == 0 {
return 0, errors.New("wait() called but fake result missing")
@@ -224,7 +224,8 @@ func TestTransferReadStream(t *testing.T) {
}
tt[i] = ftt[i]
}
s := ReadStream{newStream(tt, true)}
s := ReadStream{s: newStream(tt)}
s.s.submitAll()
buf := make([]byte, 400)
got := make([]readRes, len(tc.want))
for i := range tc.want {
@@ -250,3 +251,106 @@ func TestTransferReadStream(t *testing.T) {
})
}
}
func TestTransferWriteStream(t *testing.T) {
t.Parallel()
for _, tc := range []struct {
desc string
transfers [][]fakeStreamResult
writes []int
want []int
total int
err error
}{
{
desc: "successful two transfers",
transfers: [][]fakeStreamResult{
{{n: 1500}},
{{n: 1500}},
{{n: 1500}},
},
writes: []int{3000},
want: []int{3000},
total: 3000,
},
{
desc: "submit failed on second transfer",
transfers: [][]fakeStreamResult{
{{n: 1500}},
{{submitErr: errSentinel}},
{{n: 1500}},
},
writes: []int{3000},
want: []int{1500},
total: 1500,
err: errSentinel,
},
{
desc: "wait failed on second transfer",
transfers: [][]fakeStreamResult{
{{n: 1500}},
{{waitErr: errSentinel}},
{{n: 1500}},
},
writes: []int{3000, 1500},
want: []int{3000, 1500},
total: 1500,
err: errSentinel,
},
{
desc: "reused transfer",
transfers: [][]fakeStreamResult{
{{n: 1500}, {n: 1500}},
{{n: 1500}, {n: 1500}},
{{n: 1500}, {n: 500}},
},
writes: []int{3000, 3000, 2000},
want: []int{3000, 3000, 2000},
total: 8000,
},
{
desc: "wait failed on reused transfer",
transfers: [][]fakeStreamResult{
{{n: 1500}, {n: 1500}},
{{waitErr: errSentinel}, {n: 1500}},
{{n: 1500}, {n: 1500}},
},
writes: []int{1500, 1500, 1500, 1500, 1500},
want: []int{1500, 1500, 1500, 1500, 0},
total: 1500,
err: errSentinel,
},
} {
tc := tc
t.Run(tc.desc, func(t *testing.T) {
t.Parallel()
ftt := make([]*fakeStreamTransfer, len(tc.transfers))
tt := make([]transferIntf, len(tc.transfers))
for i := range tc.transfers {
ftt[i] = &fakeStreamTransfer{
res: tc.transfers[i],
}
tt[i] = ftt[i]
}
s := WriteStream{s: newStream(tt)}
for i, w := range tc.writes {
got, err := s.Write(make([]byte, w))
if want := tc.want[i]; got != want {
t.Errorf("WriteStream.Write #%d: got %d, want %d", i, got, want)
}
if err != nil && err != tc.err {
t.Errorf("WriteStream.Write: got error %v, want %v", err, tc.err)
}
}
if err := s.Close(); err != tc.err {
t.Fatalf("WriteStream.Close: got %v, want %v", err, tc.err)
}
if err := s.Close(); err != io.ErrClosedPipe {
t.Fatalf("second WriteStream.Close: got %v, want %v", err, io.ErrClosedPipe)
}
if got := s.Written(); got != tc.total {
t.Fatalf("WriteStream.Written: got %d, want %d", got, tc.total)
}
})
}
}