github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/pkg/ioutils/bytespipe_test.go (about) 1 package ioutils // import "github.com/Prakhar-Agarwal-byte/moby/pkg/ioutils" 2 3 import ( 4 "crypto/sha256" 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 // Regression test for #41941. 64 func TestBytesPipeDeadlock(t *testing.T) { 65 bp := NewBytesPipe() 66 bp.buf = []*fixedBuffer{getBuffer(blockThreshold)} 67 68 rd := make(chan error) 69 go func() { 70 n, err := bp.Read(make([]byte, 1)) 71 t.Logf("Read n=%d, err=%v", n, err) 72 if n != 1 { 73 t.Errorf("short read: got %d, want 1", n) 74 } 75 rd <- err 76 }() 77 78 wr := make(chan error) 79 go func() { 80 const writeLen int = blockThreshold + 1 81 time.Sleep(time.Millisecond) 82 n, err := bp.Write(make([]byte, writeLen)) 83 t.Logf("Write n=%d, err=%v", n, err) 84 if n != writeLen { 85 t.Errorf("short write: got %d, want %d", n, writeLen) 86 } 87 wr <- err 88 }() 89 90 timer := time.NewTimer(time.Second) 91 defer timer.Stop() 92 select { 93 case <-timer.C: 94 t.Fatal("deadlock! Neither Read() nor Write() returned.") 95 case rerr := <-rd: 96 if rerr != nil { 97 t.Fatal(rerr) 98 } 99 select { 100 case <-timer.C: 101 t.Fatal("deadlock! Write() did not return.") 102 case werr := <-wr: 103 if werr != nil { 104 t.Fatal(werr) 105 } 106 } 107 case werr := <-wr: 108 if werr != nil { 109 t.Fatal(werr) 110 } 111 select { 112 case <-timer.C: 113 t.Fatal("deadlock! Read() did not return.") 114 case rerr := <-rd: 115 if rerr != nil { 116 t.Fatal(rerr) 117 } 118 } 119 } 120 } 121 122 // Write and read in different speeds/chunk sizes and check valid data is read. 123 func TestBytesPipeWriteRandomChunks(t *testing.T) { 124 tests := []struct{ iterations, writesPerLoop, readsPerLoop int }{ 125 {iterations: 100, writesPerLoop: 10, readsPerLoop: 1}, 126 {iterations: 1000, writesPerLoop: 10, readsPerLoop: 5}, 127 {iterations: 1000, writesPerLoop: 100}, 128 {iterations: 1000, writesPerLoop: 5, readsPerLoop: 6}, 129 {iterations: 10000, writesPerLoop: 50, readsPerLoop: 25}, 130 } 131 132 testMessage := []byte("this is a random string for testing") 133 // random slice sizes to read and write 134 writeChunks := []int{25, 35, 15, 20} 135 readChunks := []int{5, 45, 20, 25} 136 137 for _, tc := range tests { 138 // first pass: write directly to hash 139 hash := sha256.New() 140 for i := 0; i < tc.iterations*tc.writesPerLoop; i++ { 141 if _, err := hash.Write(testMessage[:writeChunks[i%len(writeChunks)]]); err != nil { 142 t.Fatal(err) 143 } 144 } 145 expected := hex.EncodeToString(hash.Sum(nil)) 146 147 // write/read through buffer 148 buf := NewBytesPipe() 149 hash.Reset() 150 151 done := make(chan struct{}) 152 153 go func() { 154 // random delay before read starts 155 <-time.After(time.Duration(rand.Intn(10)) * time.Millisecond) 156 for i := 0; ; i++ { 157 p := make([]byte, readChunks[(tc.iterations*tc.readsPerLoop+i)%len(readChunks)]) 158 n, _ := buf.Read(p) 159 if n == 0 { 160 break 161 } 162 hash.Write(p[:n]) 163 } 164 165 close(done) 166 }() 167 168 for i := 0; i < tc.iterations; i++ { 169 for w := 0; w < tc.writesPerLoop; w++ { 170 buf.Write(testMessage[:writeChunks[(i*tc.writesPerLoop+w)%len(writeChunks)]]) 171 } 172 } 173 _ = buf.Close() 174 <-done 175 176 actual := hex.EncodeToString(hash.Sum(nil)) 177 178 if expected != actual { 179 t.Fatalf("BytesPipe returned invalid data. Expected checksum %v, got %v", expected, actual) 180 } 181 } 182 } 183 184 func BenchmarkBytesPipeWrite(b *testing.B) { 185 b.ReportAllocs() 186 testData := []byte("pretty short line, because why not?") 187 for i := 0; i < b.N; i++ { 188 readBuf := make([]byte, 1024) 189 buf := NewBytesPipe() 190 go func() { 191 var err error 192 for err == nil { 193 _, err = buf.Read(readBuf) 194 } 195 }() 196 for j := 0; j < 1000; j++ { 197 _, _ = buf.Write(testData) 198 } 199 _ = buf.Close() 200 } 201 } 202 203 func BenchmarkBytesPipeRead(b *testing.B) { 204 b.ReportAllocs() 205 rd := make([]byte, 512) 206 for i := 0; i < b.N; i++ { 207 b.StopTimer() 208 buf := NewBytesPipe() 209 for j := 0; j < 500; j++ { 210 _, _ = buf.Write(make([]byte, 1024)) 211 } 212 b.StartTimer() 213 for j := 0; j < 1000; j++ { 214 if n, _ := buf.Read(rd); n != 512 { 215 b.Fatalf("Wrong number of bytes: %d", n) 216 } 217 } 218 } 219 }