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  }