1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
|
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package io
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"syscall"
"testing"
)
func writeToPipe(namedPipe string, flaky bool, i int) {
pipe, err := os.OpenFile(namedPipe, os.O_WRONLY, 0600)
if err != nil {
return
}
// The first two reads should never be consistent but all
// subsequent reads should be
outstr := fmt.Sprintf("Foobar %t", (i <= 0))
if flaky {
outstr = fmt.Sprintf("Foobar %d", i)
}
pipe.Write([]byte(outstr))
pipe.Close()
}
func makePipe(t *testing.T) string {
tmp, err := ioutil.TempDir("", "pipe-test")
if err != nil {
t.Fatal(err)
}
pipe := filepath.Join(tmp, "pipe")
syscall.Mkfifo(pipe, 0600)
return pipe
}
func writer(namedPipe string, flaky bool, c <-chan int, d <-chan bool) {
// Make sure something is in the fifo otherwise the first iteration of
// ConsistentRead will block forever
writeToPipe(namedPipe, flaky, -1)
for {
select {
case i := <-c:
writeToPipe(namedPipe, flaky, i)
case <-d:
os.RemoveAll(namedPipe)
return
}
}
}
func TestConsistentRead(t *testing.T) {
pipe := makePipe(t)
prog, done := make(chan int), make(chan bool)
go writer(pipe, false, prog, done)
if _, err := consistentReadSync(pipe, 3, func(i int) { prog <- i }); err != nil {
t.Fatal(err)
}
done <- true
}
func TestConsistentReadFlakyReader(t *testing.T) {
pipe := makePipe(t)
prog, done := make(chan int), make(chan bool)
go writer(pipe, true, prog, done)
var err error
if _, err = consistentReadSync(pipe, 3, func(i int) { prog <- i }); err == nil {
t.Fatal("flaky reader returned consistent results")
}
if !IsInconsistentReadError(err) {
t.Errorf("Unexpected error returned, expected InconsistentReadError, got: %T / %q", err, err)
}
}
func TestReadAtMost(t *testing.T) {
testCases := []struct {
limit int64
data string
errMsg string
}{
{4, "hell", "the read limit is reached"},
{5, "hello", "the read limit is reached"},
{6, "hello", ""},
}
for _, tc := range testCases {
r := strings.NewReader("hello")
data, err := ReadAtMost(r, tc.limit)
if string(data) != tc.data {
t.Errorf("Read limit %d: expected \"%s\", got \"%s\"", tc.limit, tc.data, string(data))
}
if err == nil && tc.errMsg != "" {
t.Errorf("Read limit %d: expected error with message \"%s\", got no error", tc.limit, tc.errMsg)
}
if err != nil && err.Error() != tc.errMsg {
t.Errorf("Read limit %d: expected error with message \"%s\", got error with message \"%s\"", tc.limit, tc.errMsg, err.Error())
}
}
}
|