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  }