github.com/sijibomii/docker@v0.0.0-20231230191044-5cf6ca554647/pkg/ioutils/bytespipe_test.go (about) 1 package ioutils 2 3 import ( 4 "crypto/sha1" 5 "encoding/hex" 6 "math/rand" 7 "testing" 8 "time" 9 ) 10 11 func TestBytesPipeRead(t *testing.T) { 12 buf := NewBytesPipe() 13 buf.Write([]byte("12")) 14 buf.Write([]byte("34")) 15 buf.Write([]byte("56")) 16 buf.Write([]byte("78")) 17 buf.Write([]byte("90")) 18 rd := make([]byte, 4) 19 n, err := buf.Read(rd) 20 if err != nil { 21 t.Fatal(err) 22 } 23 if n != 4 { 24 t.Fatalf("Wrong number of bytes read: %d, should be %d", n, 4) 25 } 26 if string(rd) != "1234" { 27 t.Fatalf("Read %s, but must be %s", rd, "1234") 28 } 29 n, err = buf.Read(rd) 30 if err != nil { 31 t.Fatal(err) 32 } 33 if n != 4 { 34 t.Fatalf("Wrong number of bytes read: %d, should be %d", n, 4) 35 } 36 if string(rd) != "5678" { 37 t.Fatalf("Read %s, but must be %s", rd, "5679") 38 } 39 n, err = buf.Read(rd) 40 if err != nil { 41 t.Fatal(err) 42 } 43 if n != 2 { 44 t.Fatalf("Wrong number of bytes read: %d, should be %d", n, 2) 45 } 46 if string(rd[:n]) != "90" { 47 t.Fatalf("Read %s, but must be %s", rd, "90") 48 } 49 } 50 51 func TestBytesPipeWrite(t *testing.T) { 52 buf := NewBytesPipe() 53 buf.Write([]byte("12")) 54 buf.Write([]byte("34")) 55 buf.Write([]byte("56")) 56 buf.Write([]byte("78")) 57 buf.Write([]byte("90")) 58 if buf.buf[0].String() != "1234567890" { 59 t.Fatalf("Buffer %q, must be %q", buf.buf[0].String(), "1234567890") 60 } 61 } 62 63 // Write and read in different speeds/chunk sizes and check valid data is read. 64 func TestBytesPipeWriteRandomChunks(t *testing.T) { 65 cases := []struct{ iterations, writesPerLoop, readsPerLoop int }{ 66 {100, 10, 1}, 67 {1000, 10, 5}, 68 {1000, 100, 0}, 69 {1000, 5, 6}, 70 {10000, 50, 25}, 71 } 72 73 testMessage := []byte("this is a random string for testing") 74 // random slice sizes to read and write 75 writeChunks := []int{25, 35, 15, 20} 76 readChunks := []int{5, 45, 20, 25} 77 78 for _, c := range cases { 79 // first pass: write directly to hash 80 hash := sha1.New() 81 for i := 0; i < c.iterations*c.writesPerLoop; i++ { 82 if _, err := hash.Write(testMessage[:writeChunks[i%len(writeChunks)]]); err != nil { 83 t.Fatal(err) 84 } 85 } 86 expected := hex.EncodeToString(hash.Sum(nil)) 87 88 // write/read through buffer 89 buf := NewBytesPipe() 90 hash.Reset() 91 92 done := make(chan struct{}) 93 94 go func() { 95 // random delay before read starts 96 <-time.After(time.Duration(rand.Intn(10)) * time.Millisecond) 97 for i := 0; ; i++ { 98 p := make([]byte, readChunks[(c.iterations*c.readsPerLoop+i)%len(readChunks)]) 99 n, _ := buf.Read(p) 100 if n == 0 { 101 break 102 } 103 hash.Write(p[:n]) 104 } 105 106 close(done) 107 }() 108 109 for i := 0; i < c.iterations; i++ { 110 for w := 0; w < c.writesPerLoop; w++ { 111 buf.Write(testMessage[:writeChunks[(i*c.writesPerLoop+w)%len(writeChunks)]]) 112 } 113 } 114 buf.Close() 115 <-done 116 117 actual := hex.EncodeToString(hash.Sum(nil)) 118 119 if expected != actual { 120 t.Fatalf("BytesPipe returned invalid data. Expected checksum %v, got %v", expected, actual) 121 } 122 123 } 124 } 125 126 func BenchmarkBytesPipeWrite(b *testing.B) { 127 testData := []byte("pretty short line, because why not?") 128 for i := 0; i < b.N; i++ { 129 readBuf := make([]byte, 1024) 130 buf := NewBytesPipe() 131 go func() { 132 var err error 133 for err == nil { 134 _, err = buf.Read(readBuf) 135 } 136 }() 137 for j := 0; j < 1000; j++ { 138 buf.Write(testData) 139 } 140 buf.Close() 141 } 142 } 143 144 func BenchmarkBytesPipeRead(b *testing.B) { 145 rd := make([]byte, 512) 146 for i := 0; i < b.N; i++ { 147 b.StopTimer() 148 buf := NewBytesPipe() 149 for j := 0; j < 500; j++ { 150 buf.Write(make([]byte, 1024)) 151 } 152 b.StartTimer() 153 for j := 0; j < 1000; j++ { 154 if n, _ := buf.Read(rd); n != 512 { 155 b.Fatalf("Wrong number of bytes: %d", n) 156 } 157 } 158 } 159 }