pkg/ioutils: some cleanups in tests

- remove gotest.tools dependency as it was only used in one test,
  and only for a trivial check
- use t.TempDir()
- rename vars that collided with package types
- don't use un-keyed structs
- explicitly ignore some errors to please linters
- use iotest.ErrReader
- TestReadCloserWrapperClose: verify reading works before closing :)

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2023-07-13 00:26:11 +02:00
parent 3b77e38b8e
commit 3cfc1ffb0a
No known key found for this signature in database
GPG key ID: 76698F39D527CE8C
5 changed files with 70 additions and 78 deletions

View file

@ -17,7 +17,7 @@ func TestFixedBufferCap(t *testing.T) {
func TestFixedBufferLen(t *testing.T) {
buf := &fixedBuffer{buf: make([]byte, 0, 10)}
buf.Write([]byte("hello"))
_, _ = buf.Write([]byte("hello"))
l := buf.Len()
if l != 5 {
t.Fatalf("expected buffer length to be 5 bytes, got %d", l)
@ -31,7 +31,7 @@ func TestFixedBufferLen(t *testing.T) {
// read 5 bytes
b := make([]byte, 5)
buf.Read(b)
_, _ = buf.Read(b)
l = buf.Len()
if l != 5 {
@ -61,8 +61,8 @@ func TestFixedBufferLen(t *testing.T) {
func TestFixedBufferString(t *testing.T) {
buf := &fixedBuffer{buf: make([]byte, 0, 10)}
buf.Write([]byte("hello"))
buf.Write([]byte("world"))
_, _ = buf.Write([]byte("hello"))
_, _ = buf.Write([]byte("world"))
out := buf.String()
if out != "helloworld" {
@ -71,7 +71,7 @@ func TestFixedBufferString(t *testing.T) {
// read 5 bytes
b := make([]byte, 5)
buf.Read(b)
_, _ = buf.Read(b)
// test that fixedBuffer.String() only returns the part that hasn't been read
out = buf.String()

View file

@ -10,11 +10,11 @@ import (
func TestBytesPipeRead(t *testing.T) {
buf := NewBytesPipe()
buf.Write([]byte("12"))
buf.Write([]byte("34"))
buf.Write([]byte("56"))
buf.Write([]byte("78"))
buf.Write([]byte("90"))
_, _ = buf.Write([]byte("12"))
_, _ = buf.Write([]byte("34"))
_, _ = buf.Write([]byte("56"))
_, _ = buf.Write([]byte("78"))
_, _ = buf.Write([]byte("90"))
rd := make([]byte, 4)
n, err := buf.Read(rd)
if err != nil {
@ -50,11 +50,11 @@ func TestBytesPipeRead(t *testing.T) {
func TestBytesPipeWrite(t *testing.T) {
buf := NewBytesPipe()
buf.Write([]byte("12"))
buf.Write([]byte("34"))
buf.Write([]byte("56"))
buf.Write([]byte("78"))
buf.Write([]byte("90"))
_, _ = buf.Write([]byte("12"))
_, _ = buf.Write([]byte("34"))
_, _ = buf.Write([]byte("56"))
_, _ = buf.Write([]byte("78"))
_, _ = buf.Write([]byte("90"))
if buf.buf[0].String() != "1234567890" {
t.Fatalf("Buffer %q, must be %q", buf.buf[0].String(), "1234567890")
}
@ -121,12 +121,12 @@ func TestBytesPipeDeadlock(t *testing.T) {
// Write and read in different speeds/chunk sizes and check valid data is read.
func TestBytesPipeWriteRandomChunks(t *testing.T) {
cases := []struct{ iterations, writesPerLoop, readsPerLoop int }{
{100, 10, 1},
{1000, 10, 5},
{1000, 100, 0},
{1000, 5, 6},
{10000, 50, 25},
tests := []struct{ iterations, writesPerLoop, readsPerLoop int }{
{iterations: 100, writesPerLoop: 10, readsPerLoop: 1},
{iterations: 1000, writesPerLoop: 10, readsPerLoop: 5},
{iterations: 1000, writesPerLoop: 100},
{iterations: 1000, writesPerLoop: 5, readsPerLoop: 6},
{iterations: 10000, writesPerLoop: 50, readsPerLoop: 25},
}
testMessage := []byte("this is a random string for testing")
@ -134,10 +134,10 @@ func TestBytesPipeWriteRandomChunks(t *testing.T) {
writeChunks := []int{25, 35, 15, 20}
readChunks := []int{5, 45, 20, 25}
for _, c := range cases {
for _, tc := range tests {
// first pass: write directly to hash
hash := sha256.New()
for i := 0; i < c.iterations*c.writesPerLoop; i++ {
for i := 0; i < tc.iterations*tc.writesPerLoop; i++ {
if _, err := hash.Write(testMessage[:writeChunks[i%len(writeChunks)]]); err != nil {
t.Fatal(err)
}
@ -154,7 +154,7 @@ func TestBytesPipeWriteRandomChunks(t *testing.T) {
// random delay before read starts
<-time.After(time.Duration(rand.Intn(10)) * time.Millisecond)
for i := 0; ; i++ {
p := make([]byte, readChunks[(c.iterations*c.readsPerLoop+i)%len(readChunks)])
p := make([]byte, readChunks[(tc.iterations*tc.readsPerLoop+i)%len(readChunks)])
n, _ := buf.Read(p)
if n == 0 {
break
@ -165,12 +165,12 @@ func TestBytesPipeWriteRandomChunks(t *testing.T) {
close(done)
}()
for i := 0; i < c.iterations; i++ {
for w := 0; w < c.writesPerLoop; w++ {
buf.Write(testMessage[:writeChunks[(i*c.writesPerLoop+w)%len(writeChunks)]])
for i := 0; i < tc.iterations; i++ {
for w := 0; w < tc.writesPerLoop; w++ {
buf.Write(testMessage[:writeChunks[(i*tc.writesPerLoop+w)%len(writeChunks)]])
}
}
buf.Close()
_ = buf.Close()
<-done
actual := hex.EncodeToString(hash.Sum(nil))
@ -182,6 +182,7 @@ func TestBytesPipeWriteRandomChunks(t *testing.T) {
}
func BenchmarkBytesPipeWrite(b *testing.B) {
b.ReportAllocs()
testData := []byte("pretty short line, because why not?")
for i := 0; i < b.N; i++ {
readBuf := make([]byte, 1024)
@ -193,19 +194,20 @@ func BenchmarkBytesPipeWrite(b *testing.B) {
}
}()
for j := 0; j < 1000; j++ {
buf.Write(testData)
_, _ = buf.Write(testData)
}
buf.Close()
_ = buf.Close()
}
}
func BenchmarkBytesPipeRead(b *testing.B) {
b.ReportAllocs()
rd := make([]byte, 512)
for i := 0; i < b.N; i++ {
b.StopTimer()
buf := NewBytesPipe()
for j := 0; j < 500; j++ {
buf.Write(make([]byte, 1024))
_, _ = buf.Write(make([]byte, 1024))
}
b.StartTimer()
for j := 0; j < 1000; j++ {

View file

@ -18,11 +18,7 @@ func init() {
}
func TestAtomicWriteToFile(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "atomic-writers-test")
if err != nil {
t.Fatalf("Error when creating temporary directory: %s", err)
}
defer os.RemoveAll(tmpDir)
tmpDir := t.TempDir()
expected := []byte("barbaz")
if err := AtomicWriteFile(filepath.Join(tmpDir, "foo"), expected, testMode); err != nil {
@ -48,11 +44,7 @@ func TestAtomicWriteToFile(t *testing.T) {
}
func TestAtomicWriteSetCommit(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "atomic-writerset-test")
if err != nil {
t.Fatalf("Error when creating temporary directory: %s", err)
}
defer os.RemoveAll(tmpDir)
tmpDir := t.TempDir()
if err := os.Mkdir(filepath.Join(tmpDir, "tmp"), 0o700); err != nil {
t.Fatalf("Error creating tmp directory: %s", err)
@ -96,11 +88,7 @@ func TestAtomicWriteSetCommit(t *testing.T) {
}
func TestAtomicWriteSetCancel(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "atomic-writerset-test")
if err != nil {
t.Fatalf("Error when creating temporary directory: %s", err)
}
defer os.RemoveAll(tmpDir)
tmpDir := t.TempDir()
if err := os.Mkdir(filepath.Join(tmpDir, "tmp"), 0o700); err != nil {
t.Fatalf("Error creating tmp directory: %s", err)

View file

@ -2,59 +2,61 @@ package ioutils // import "github.com/docker/docker/pkg/ioutils"
import (
"context"
"fmt"
"errors"
"io"
"strings"
"testing"
"testing/iotest"
"time"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
// Implement io.Reader
type errorReader struct{}
func (r *errorReader) Read(p []byte) (int, error) {
return 0, fmt.Errorf("error reader always fail")
}
func TestReadCloserWrapperClose(t *testing.T) {
reader := strings.NewReader("A string reader")
wrapper := NewReadCloserWrapper(reader, func() error {
return fmt.Errorf("This will be called when closing")
const text = "hello world"
testErr := errors.New("this will be called when closing")
wrapper := NewReadCloserWrapper(strings.NewReader(text), func() error {
return testErr
})
err := wrapper.Close()
if err == nil || !strings.Contains(err.Error(), "This will be called when closing") {
t.Fatalf("readCloserWrapper should have call the anonymous func and thus, fail.")
buf, err := io.ReadAll(wrapper)
if err != nil {
t.Errorf("io.ReadAll(wrapper) err = %v", err)
}
if string(buf) != text {
t.Errorf("expected %v, got: %v", text, string(buf))
}
err = wrapper.Close()
if !errors.Is(err, testErr) {
// readCloserWrapper should have called the anonymous func and thus, fail
t.Errorf("expected %v, got: %v", testErr, err)
}
}
func TestReaderErrWrapperReadOnError(t *testing.T) {
called := false
reader := &errorReader{}
wrapper := NewReaderErrWrapper(reader, func() {
expectedErr := errors.New("error reader always fail")
wrapper := NewReaderErrWrapper(iotest.ErrReader(expectedErr), func() {
called = true
})
_, err := wrapper.Read([]byte{})
assert.Check(t, is.Error(err, "error reader always fail"))
if !errors.Is(err, expectedErr) {
t.Errorf("expected %v, got: %v", expectedErr, err)
}
if !called {
t.Fatalf("readErrWrapper should have call the anonymous function on failure")
t.Fatalf("readErrWrapper should have called the anonymous function on failure")
}
}
func TestReaderErrWrapperRead(t *testing.T) {
reader := strings.NewReader("a string reader.")
wrapper := NewReaderErrWrapper(reader, func() {
const text = "hello world"
wrapper := NewReaderErrWrapper(strings.NewReader(text), func() {
t.Fatalf("readErrWrapper should not have called the anonymous function")
})
// Read 20 byte (should be ok with the string above)
num, err := wrapper.Read(make([]byte, 20))
num, err := wrapper.Read(make([]byte, len(text)+10))
if err != nil {
t.Fatal(err)
t.Error(err)
}
if num != 16 {
t.Fatalf("readerErrWrapper should have read 16 byte, but read %d", num)
if expected := len(text); num != expected {
t.Errorf("readerErrWrapper should have read %d byte, but read %d", expected, num)
}
}
@ -70,10 +72,10 @@ func (p *perpetualReader) Read(buf []byte) (n int, err error) {
func TestCancelReadCloser(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
cancelReadCloser := NewCancelReadCloser(ctx, io.NopCloser(&perpetualReader{}))
crc := NewCancelReadCloser(ctx, io.NopCloser(&perpetualReader{}))
for {
var buf [128]byte
_, err := cancelReadCloser.Read(buf[:])
_, err := crc.Read(buf[:])
if err == context.DeadlineExceeded {
break
} else if err != nil {

View file

@ -51,8 +51,8 @@ func TestWriteCounter(t *testing.T) {
var buffer bytes.Buffer
wc := NewWriteCounter(&buffer)
reader1.WriteTo(wc)
reader2.WriteTo(wc)
_, _ = reader1.WriteTo(wc)
_, _ = reader2.WriteTo(wc)
if wc.Count != totalLength {
t.Errorf("Wrong count: %d vs. %d", wc.Count, totalLength)