github.com/bhojpur/cache@v0.0.4/pkg/ioutils/bytespipe_test.go (about) 1 package ioutils 2 3 // Copyright (c) 2018 Bhojpur Consulting Private Limited, India. All rights reserved. 4 5 // Permission is hereby granted, free of charge, to any person obtaining a copy 6 // of this software and associated documentation files (the "Software"), to deal 7 // in the Software without restriction, including without limitation the rights 8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 // copies of the Software, and to permit persons to whom the Software is 10 // furnished to do so, subject to the following conditions: 11 12 // The above copyright notice and this permission notice shall be included in 13 // all copies or substantial portions of the Software. 14 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 // THE SOFTWARE. 22 23 import ( 24 "crypto/sha256" 25 "encoding/hex" 26 "math/rand" 27 "testing" 28 "time" 29 ) 30 31 func TestBytesPipeRead(t *testing.T) { 32 buf := NewBytesPipe() 33 buf.Write([]byte("12")) 34 buf.Write([]byte("34")) 35 buf.Write([]byte("56")) 36 buf.Write([]byte("78")) 37 buf.Write([]byte("90")) 38 rd := make([]byte, 4) 39 n, err := buf.Read(rd) 40 if err != nil { 41 t.Fatal(err) 42 } 43 if n != 4 { 44 t.Fatalf("Wrong number of bytes read: %d, should be %d", n, 4) 45 } 46 if string(rd) != "1234" { 47 t.Fatalf("Read %s, but must be %s", rd, "1234") 48 } 49 n, err = buf.Read(rd) 50 if err != nil { 51 t.Fatal(err) 52 } 53 if n != 4 { 54 t.Fatalf("Wrong number of bytes read: %d, should be %d", n, 4) 55 } 56 if string(rd) != "5678" { 57 t.Fatalf("Read %s, but must be %s", rd, "5679") 58 } 59 n, err = buf.Read(rd) 60 if err != nil { 61 t.Fatal(err) 62 } 63 if n != 2 { 64 t.Fatalf("Wrong number of bytes read: %d, should be %d", n, 2) 65 } 66 if string(rd[:n]) != "90" { 67 t.Fatalf("Read %s, but must be %s", rd, "90") 68 } 69 } 70 71 func TestBytesPipeWrite(t *testing.T) { 72 buf := NewBytesPipe() 73 buf.Write([]byte("12")) 74 buf.Write([]byte("34")) 75 buf.Write([]byte("56")) 76 buf.Write([]byte("78")) 77 buf.Write([]byte("90")) 78 if buf.buf[0].String() != "1234567890" { 79 t.Fatalf("Buffer %q, must be %q", buf.buf[0].String(), "1234567890") 80 } 81 } 82 83 // Write and read in different speeds/chunk sizes and check valid data is read. 84 func TestBytesPipeWriteRandomChunks(t *testing.T) { 85 cases := []struct{ iterations, writesPerLoop, readsPerLoop int }{ 86 {100, 10, 1}, 87 {1000, 10, 5}, 88 {1000, 100, 0}, 89 {1000, 5, 6}, 90 {10000, 50, 25}, 91 } 92 93 testMessage := []byte("this is a random string for testing") 94 // random slice sizes to read and write 95 writeChunks := []int{25, 35, 15, 20} 96 readChunks := []int{5, 45, 20, 25} 97 98 for _, c := range cases { 99 // first pass: write directly to hash 100 hash := sha256.New() 101 for i := 0; i < c.iterations*c.writesPerLoop; i++ { 102 if _, err := hash.Write(testMessage[:writeChunks[i%len(writeChunks)]]); err != nil { 103 t.Fatal(err) 104 } 105 } 106 expected := hex.EncodeToString(hash.Sum(nil)) 107 108 // write/read through buffer 109 buf := NewBytesPipe() 110 hash.Reset() 111 112 done := make(chan struct{}) 113 114 go func() { 115 // random delay before read starts 116 <-time.After(time.Duration(rand.Intn(10)) * time.Millisecond) 117 for i := 0; ; i++ { 118 p := make([]byte, readChunks[(c.iterations*c.readsPerLoop+i)%len(readChunks)]) 119 n, _ := buf.Read(p) 120 if n == 0 { 121 break 122 } 123 hash.Write(p[:n]) 124 } 125 126 close(done) 127 }() 128 129 for i := 0; i < c.iterations; i++ { 130 for w := 0; w < c.writesPerLoop; w++ { 131 buf.Write(testMessage[:writeChunks[(i*c.writesPerLoop+w)%len(writeChunks)]]) 132 } 133 } 134 buf.Close() 135 <-done 136 137 actual := hex.EncodeToString(hash.Sum(nil)) 138 139 if expected != actual { 140 t.Fatalf("BytesPipe returned invalid data. Expected checksum %v, got %v", expected, actual) 141 } 142 143 } 144 } 145 146 func BenchmarkBytesPipeWrite(b *testing.B) { 147 testData := []byte("pretty short line, because why not?") 148 for i := 0; i < b.N; i++ { 149 readBuf := make([]byte, 1024) 150 buf := NewBytesPipe() 151 go func() { 152 var err error 153 for err == nil { 154 _, err = buf.Read(readBuf) 155 } 156 }() 157 for j := 0; j < 1000; j++ { 158 buf.Write(testData) 159 } 160 buf.Close() 161 } 162 } 163 164 func BenchmarkBytesPipeRead(b *testing.B) { 165 rd := make([]byte, 512) 166 for i := 0; i < b.N; i++ { 167 b.StopTimer() 168 buf := NewBytesPipe() 169 for j := 0; j < 500; j++ { 170 buf.Write(make([]byte, 1024)) 171 } 172 b.StartTimer() 173 for j := 0; j < 1000; j++ { 174 if n, _ := buf.Read(rd); n != 512 { 175 b.Fatalf("Wrong number of bytes: %d", n) 176 } 177 } 178 } 179 }