Source file
src/io/pipe_test.go
1
2
3
4
5 package io_test
6
7 import (
8 "bytes"
9 "fmt"
10 . "io"
11 "sort"
12 "strings"
13 "testing"
14 "time"
15 )
16
17 func checkWrite(t *testing.T, w Writer, data []byte, c chan int) {
18 n, err := w.Write(data)
19 if err != nil {
20 t.Errorf("write: %v", err)
21 }
22 if n != len(data) {
23 t.Errorf("short write: %d != %d", n, len(data))
24 }
25 c <- 0
26 }
27
28
29 func TestPipe1(t *testing.T) {
30 c := make(chan int)
31 r, w := Pipe()
32 var buf = make([]byte, 64)
33 go checkWrite(t, w, []byte("hello, world"), c)
34 n, err := r.Read(buf)
35 if err != nil {
36 t.Errorf("read: %v", err)
37 } else if n != 12 || string(buf[0:12]) != "hello, world" {
38 t.Errorf("bad read: got %q", buf[0:n])
39 }
40 <-c
41 r.Close()
42 w.Close()
43 }
44
45 func reader(t *testing.T, r Reader, c chan int) {
46 var buf = make([]byte, 64)
47 for {
48 n, err := r.Read(buf)
49 if err == EOF {
50 c <- 0
51 break
52 }
53 if err != nil {
54 t.Errorf("read: %v", err)
55 }
56 c <- n
57 }
58 }
59
60
61 func TestPipe2(t *testing.T) {
62 c := make(chan int)
63 r, w := Pipe()
64 go reader(t, r, c)
65 var buf = make([]byte, 64)
66 for i := 0; i < 5; i++ {
67 p := buf[0 : 5+i*10]
68 n, err := w.Write(p)
69 if n != len(p) {
70 t.Errorf("wrote %d, got %d", len(p), n)
71 }
72 if err != nil {
73 t.Errorf("write: %v", err)
74 }
75 nn := <-c
76 if nn != n {
77 t.Errorf("wrote %d, read got %d", n, nn)
78 }
79 }
80 w.Close()
81 nn := <-c
82 if nn != 0 {
83 t.Errorf("final read got %d", nn)
84 }
85 }
86
87 type pipeReturn struct {
88 n int
89 err error
90 }
91
92
93 func writer(w WriteCloser, buf []byte, c chan pipeReturn) {
94 n, err := w.Write(buf)
95 w.Close()
96 c <- pipeReturn{n, err}
97 }
98
99 func TestPipe3(t *testing.T) {
100 c := make(chan pipeReturn)
101 r, w := Pipe()
102 var wdat = make([]byte, 128)
103 for i := 0; i < len(wdat); i++ {
104 wdat[i] = byte(i)
105 }
106 go writer(w, wdat, c)
107 var rdat = make([]byte, 1024)
108 tot := 0
109 for n := 1; n <= 256; n *= 2 {
110 nn, err := r.Read(rdat[tot : tot+n])
111 if err != nil && err != EOF {
112 t.Fatalf("read: %v", err)
113 }
114
115
116 expect := n
117 if n == 128 {
118 expect = 1
119 } else if n == 256 {
120 expect = 0
121 if err != EOF {
122 t.Fatalf("read at end: %v", err)
123 }
124 }
125 if nn != expect {
126 t.Fatalf("read %d, expected %d, got %d", n, expect, nn)
127 }
128 tot += nn
129 }
130 pr := <-c
131 if pr.n != 128 || pr.err != nil {
132 t.Fatalf("write 128: %d, %v", pr.n, pr.err)
133 }
134 if tot != 128 {
135 t.Fatalf("total read %d != 128", tot)
136 }
137 for i := 0; i < 128; i++ {
138 if rdat[i] != byte(i) {
139 t.Fatalf("rdat[%d] = %d", i, rdat[i])
140 }
141 }
142 }
143
144
145
146 type closer interface {
147 CloseWithError(error) error
148 Close() error
149 }
150
151 type pipeTest struct {
152 async bool
153 err error
154 closeWithError bool
155 }
156
157 func (p pipeTest) String() string {
158 return fmt.Sprintf("async=%v err=%v closeWithError=%v", p.async, p.err, p.closeWithError)
159 }
160
161 var pipeTests = []pipeTest{
162 {true, nil, false},
163 {true, nil, true},
164 {true, ErrShortWrite, true},
165 {false, nil, false},
166 {false, nil, true},
167 {false, ErrShortWrite, true},
168 }
169
170 func delayClose(t *testing.T, cl closer, ch chan int, tt pipeTest) {
171 time.Sleep(1 * time.Millisecond)
172 var err error
173 if tt.closeWithError {
174 err = cl.CloseWithError(tt.err)
175 } else {
176 err = cl.Close()
177 }
178 if err != nil {
179 t.Errorf("delayClose: %v", err)
180 }
181 ch <- 0
182 }
183
184 func TestPipeReadClose(t *testing.T) {
185 for _, tt := range pipeTests {
186 c := make(chan int, 1)
187 r, w := Pipe()
188 if tt.async {
189 go delayClose(t, w, c, tt)
190 } else {
191 delayClose(t, w, c, tt)
192 }
193 var buf = make([]byte, 64)
194 n, err := r.Read(buf)
195 <-c
196 want := tt.err
197 if want == nil {
198 want = EOF
199 }
200 if err != want {
201 t.Errorf("read from closed pipe: %v want %v", err, want)
202 }
203 if n != 0 {
204 t.Errorf("read on closed pipe returned %d", n)
205 }
206 if err = r.Close(); err != nil {
207 t.Errorf("r.Close: %v", err)
208 }
209 }
210 }
211
212
213 func TestPipeReadClose2(t *testing.T) {
214 c := make(chan int, 1)
215 r, _ := Pipe()
216 go delayClose(t, r, c, pipeTest{})
217 n, err := r.Read(make([]byte, 64))
218 <-c
219 if n != 0 || err != ErrClosedPipe {
220 t.Errorf("read from closed pipe: %v, %v want %v, %v", n, err, 0, ErrClosedPipe)
221 }
222 }
223
224
225
226 func TestPipeWriteClose(t *testing.T) {
227 for _, tt := range pipeTests {
228 c := make(chan int, 1)
229 r, w := Pipe()
230 if tt.async {
231 go delayClose(t, r, c, tt)
232 } else {
233 delayClose(t, r, c, tt)
234 }
235 n, err := WriteString(w, "hello, world")
236 <-c
237 expect := tt.err
238 if expect == nil {
239 expect = ErrClosedPipe
240 }
241 if err != expect {
242 t.Errorf("write on closed pipe: %v want %v", err, expect)
243 }
244 if n != 0 {
245 t.Errorf("write on closed pipe returned %d", n)
246 }
247 if err = w.Close(); err != nil {
248 t.Errorf("w.Close: %v", err)
249 }
250 }
251 }
252
253
254 func TestPipeWriteClose2(t *testing.T) {
255 c := make(chan int, 1)
256 _, w := Pipe()
257 go delayClose(t, w, c, pipeTest{})
258 n, err := w.Write(make([]byte, 64))
259 <-c
260 if n != 0 || err != ErrClosedPipe {
261 t.Errorf("write to closed pipe: %v, %v want %v, %v", n, err, 0, ErrClosedPipe)
262 }
263 }
264
265 func TestWriteEmpty(t *testing.T) {
266 r, w := Pipe()
267 go func() {
268 w.Write([]byte{})
269 w.Close()
270 }()
271 var b [2]byte
272 ReadFull(r, b[0:2])
273 r.Close()
274 }
275
276 func TestWriteNil(t *testing.T) {
277 r, w := Pipe()
278 go func() {
279 w.Write(nil)
280 w.Close()
281 }()
282 var b [2]byte
283 ReadFull(r, b[0:2])
284 r.Close()
285 }
286
287 func TestWriteAfterWriterClose(t *testing.T) {
288 r, w := Pipe()
289
290 done := make(chan bool)
291 var writeErr error
292 go func() {
293 _, err := w.Write([]byte("hello"))
294 if err != nil {
295 t.Errorf("got error: %q; expected none", err)
296 }
297 w.Close()
298 _, writeErr = w.Write([]byte("world"))
299 done <- true
300 }()
301
302 buf := make([]byte, 100)
303 var result string
304 n, err := ReadFull(r, buf)
305 if err != nil && err != ErrUnexpectedEOF {
306 t.Fatalf("got: %q; want: %q", err, ErrUnexpectedEOF)
307 }
308 result = string(buf[0:n])
309 <-done
310
311 if result != "hello" {
312 t.Errorf("got: %q; want: %q", result, "hello")
313 }
314 if writeErr != ErrClosedPipe {
315 t.Errorf("got: %q; want: %q", writeErr, ErrClosedPipe)
316 }
317 }
318
319 func TestPipeCloseError(t *testing.T) {
320 type testError1 struct{ error }
321 type testError2 struct{ error }
322
323 r, w := Pipe()
324 r.CloseWithError(testError1{})
325 if _, err := w.Write(nil); err != (testError1{}) {
326 t.Errorf("Write error: got %T, want testError1", err)
327 }
328 r.CloseWithError(testError2{})
329 if _, err := w.Write(nil); err != (testError1{}) {
330 t.Errorf("Write error: got %T, want testError1", err)
331 }
332
333 r, w = Pipe()
334 w.CloseWithError(testError1{})
335 if _, err := r.Read(nil); err != (testError1{}) {
336 t.Errorf("Read error: got %T, want testError1", err)
337 }
338 w.CloseWithError(testError2{})
339 if _, err := r.Read(nil); err != (testError1{}) {
340 t.Errorf("Read error: got %T, want testError1", err)
341 }
342 }
343
344 func TestPipeConcurrent(t *testing.T) {
345 const (
346 input = "0123456789abcdef"
347 count = 8
348 readSize = 2
349 )
350
351 t.Run("Write", func(t *testing.T) {
352 r, w := Pipe()
353
354 for i := 0; i < count; i++ {
355 go func() {
356 time.Sleep(time.Millisecond)
357 if n, err := w.Write([]byte(input)); n != len(input) || err != nil {
358 t.Errorf("Write() = (%d, %v); want (%d, nil)", n, err, len(input))
359 }
360 }()
361 }
362
363 buf := make([]byte, count*len(input))
364 for i := 0; i < len(buf); i += readSize {
365 if n, err := r.Read(buf[i : i+readSize]); n != readSize || err != nil {
366 t.Errorf("Read() = (%d, %v); want (%d, nil)", n, err, readSize)
367 }
368 }
369
370
371
372 got := string(buf)
373 want := strings.Repeat(input, count)
374 if got != want {
375 t.Errorf("got: %q; want: %q", got, want)
376 }
377 })
378
379 t.Run("Read", func(t *testing.T) {
380 r, w := Pipe()
381
382 c := make(chan []byte, count*len(input)/readSize)
383 for i := 0; i < cap(c); i++ {
384 go func() {
385 time.Sleep(time.Millisecond)
386 buf := make([]byte, readSize)
387 if n, err := r.Read(buf); n != readSize || err != nil {
388 t.Errorf("Read() = (%d, %v); want (%d, nil)", n, err, readSize)
389 }
390 c <- buf
391 }()
392 }
393
394 for i := 0; i < count; i++ {
395 if n, err := w.Write([]byte(input)); n != len(input) || err != nil {
396 t.Errorf("Write() = (%d, %v); want (%d, nil)", n, err, len(input))
397 }
398 }
399
400
401
402 got := make([]byte, 0, count*len(input))
403 for i := 0; i < cap(c); i++ {
404 got = append(got, (<-c)...)
405 }
406 got = sortBytesInGroups(got, readSize)
407 want := bytes.Repeat([]byte(input), count)
408 want = sortBytesInGroups(want, readSize)
409 if string(got) != string(want) {
410 t.Errorf("got: %q; want: %q", got, want)
411 }
412 })
413 }
414
415 func sortBytesInGroups(b []byte, n int) []byte {
416 var groups [][]byte
417 for len(b) > 0 {
418 groups = append(groups, b[:n])
419 b = b[n:]
420 }
421 sort.Slice(groups, func(i, j int) bool { return bytes.Compare(groups[i], groups[j]) < 0 })
422 return bytes.Join(groups, nil)
423 }
424
View as plain text