go.etcd.io/etcd@v3.3.27+incompatible/pkg/ioutil/pagewriter_test.go (about)

     1  // Copyright 2016 The etcd Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package ioutil
    16  
    17  import (
    18  	"math/rand"
    19  	"testing"
    20  )
    21  
    22  func TestPageWriterRandom(t *testing.T) {
    23  	// smaller buffer for stress testing
    24  	defaultBufferBytes = 8 * 1024
    25  	pageBytes := 128
    26  	buf := make([]byte, 4*defaultBufferBytes)
    27  	cw := &checkPageWriter{pageBytes: pageBytes, t: t}
    28  	w := NewPageWriter(cw, pageBytes, 0)
    29  	n := 0
    30  	for i := 0; i < 4096; i++ {
    31  		c, err := w.Write(buf[:rand.Intn(len(buf))])
    32  		if err != nil {
    33  			t.Fatal(err)
    34  		}
    35  		n += c
    36  	}
    37  	if cw.writeBytes > n {
    38  		t.Fatalf("wrote %d bytes to io.Writer, but only wrote %d bytes", cw.writeBytes, n)
    39  	}
    40  	if cw.writeBytes-n > pageBytes {
    41  		t.Fatalf("got %d bytes pending, expected less than %d bytes", cw.writeBytes-n, pageBytes)
    42  	}
    43  	t.Logf("total writes: %d", cw.writes)
    44  	t.Logf("total write bytes: %d (of %d)", cw.writeBytes, n)
    45  }
    46  
    47  // TestPageWriterPariallack tests the case where a write overflows the buffer
    48  // but there is not enough data to complete the slack write.
    49  func TestPageWriterPartialSlack(t *testing.T) {
    50  	defaultBufferBytes = 1024
    51  	pageBytes := 128
    52  	buf := make([]byte, defaultBufferBytes)
    53  	cw := &checkPageWriter{pageBytes: 64, t: t}
    54  	w := NewPageWriter(cw, pageBytes, 0)
    55  	// put writer in non-zero page offset
    56  	if _, err := w.Write(buf[:64]); err != nil {
    57  		t.Fatal(err)
    58  	}
    59  	if err := w.Flush(); err != nil {
    60  		t.Fatal(err)
    61  	}
    62  	if cw.writes != 1 {
    63  		t.Fatalf("got %d writes, expected 1", cw.writes)
    64  	}
    65  	// nearly fill buffer
    66  	if _, err := w.Write(buf[:1022]); err != nil {
    67  		t.Fatal(err)
    68  	}
    69  	// overflow buffer, but without enough to write as aligned
    70  	if _, err := w.Write(buf[:8]); err != nil {
    71  		t.Fatal(err)
    72  	}
    73  	if cw.writes != 1 {
    74  		t.Fatalf("got %d writes, expected 1", cw.writes)
    75  	}
    76  	// finish writing slack space
    77  	if _, err := w.Write(buf[:128]); err != nil {
    78  		t.Fatal(err)
    79  	}
    80  	if cw.writes != 2 {
    81  		t.Fatalf("got %d writes, expected 2", cw.writes)
    82  	}
    83  }
    84  
    85  // TestPageWriterOffset tests if page writer correctly repositions when offset is given.
    86  func TestPageWriterOffset(t *testing.T) {
    87  	defaultBufferBytes = 1024
    88  	pageBytes := 128
    89  	buf := make([]byte, defaultBufferBytes)
    90  	cw := &checkPageWriter{pageBytes: 64, t: t}
    91  	w := NewPageWriter(cw, pageBytes, 0)
    92  	if _, err := w.Write(buf[:64]); err != nil {
    93  		t.Fatal(err)
    94  	}
    95  	if err := w.Flush(); err != nil {
    96  		t.Fatal(err)
    97  	}
    98  	if w.pageOffset != 64 {
    99  		t.Fatalf("w.pageOffset expected 64, got %d", w.pageOffset)
   100  	}
   101  
   102  	w = NewPageWriter(cw, w.pageOffset, pageBytes)
   103  	if _, err := w.Write(buf[:64]); err != nil {
   104  		t.Fatal(err)
   105  	}
   106  	if err := w.Flush(); err != nil {
   107  		t.Fatal(err)
   108  	}
   109  	if w.pageOffset != 0 {
   110  		t.Fatalf("w.pageOffset expected 0, got %d", w.pageOffset)
   111  	}
   112  }
   113  
   114  // checkPageWriter implements an io.Writer that fails a test on unaligned writes.
   115  type checkPageWriter struct {
   116  	pageBytes  int
   117  	writes     int
   118  	writeBytes int
   119  	t          *testing.T
   120  }
   121  
   122  func (cw *checkPageWriter) Write(p []byte) (int, error) {
   123  	if len(p)%cw.pageBytes != 0 {
   124  		cw.t.Fatalf("got write len(p) = %d, expected len(p) == k*cw.pageBytes", len(p))
   125  	}
   126  	cw.writes++
   127  	cw.writeBytes += len(p)
   128  	return len(p), nil
   129  }