gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/buffer/view_test.go (about)

     1  // Copyright 2022 The gVisor 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 buffer
    16  
    17  import (
    18  	"bytes"
    19  	"math/rand"
    20  	"testing"
    21  
    22  	"github.com/google/go-cmp/cmp"
    23  )
    24  
    25  func TestNewView(t *testing.T) {
    26  	for sz := baseChunkSize; sz < MaxChunkSize; sz <<= 1 {
    27  		v := NewView(sz - 1)
    28  		defer v.Release()
    29  
    30  		if v.Capacity() != sz {
    31  			t.Errorf("v.Capacity() = %d, want %d", v.Capacity(), sz)
    32  		}
    33  		if v.AvailableSize() != sz {
    34  			t.Errorf("v.WriteSize() = %d, want %d", v.AvailableSize(), sz)
    35  		}
    36  		if v.Size() != 0 {
    37  			t.Errorf("v.ReadSize() = %d, want %d", v.Size(), 0)
    38  		}
    39  
    40  		v1 := NewView(sz)
    41  		defer v1.Release()
    42  
    43  		if v1.Capacity() != sz {
    44  			t.Errorf("v.Capacity() = %d, want %d", v.Capacity(), sz)
    45  		}
    46  		if v1.AvailableSize() != sz {
    47  			t.Errorf("v.WriteSize() = %d, want %d", v.AvailableSize(), sz)
    48  		}
    49  		if v1.Size() != 0 {
    50  			t.Errorf("v.ReadSize() = %d, want %d", v.Size(), 0)
    51  		}
    52  	}
    53  
    54  	// Allocating from heap should produce a chunk with the exact size requested
    55  	// instead of a chunk where the size is contingent on the pool it came from.
    56  	viewSize := MaxChunkSize + 1
    57  	v := NewView(viewSize)
    58  	defer v.Release()
    59  	if v.Capacity() != viewSize {
    60  		t.Errorf("v.Capacity() = %d, want %d", v.Capacity(), viewSize)
    61  	}
    62  }
    63  
    64  func TestClone(t *testing.T) {
    65  	orig := NewView(100)
    66  	clone := orig.Clone()
    67  	if orig.chunk != clone.chunk {
    68  		t.Errorf("orig.Clone().chunk = %p, want %p", clone.chunk, orig.chunk)
    69  	}
    70  	if orig.chunk.refCount.Load() != 2 {
    71  		t.Errorf("got orig.chunk.chunkRefs.Load() = %d, want 2", orig.chunk.refCount.Load())
    72  	}
    73  	orig.Release()
    74  	if clone.chunk.refCount.Load() != 1 {
    75  		t.Errorf("got clone.chunk.chunkRefs.Load() = %d, want 1", clone.chunk.refCount.Load())
    76  	}
    77  	clone.Release()
    78  }
    79  
    80  func TestWrite(t *testing.T) {
    81  	for _, tc := range []struct {
    82  		name      string
    83  		view      *View
    84  		initSize  int
    85  		writeSize int
    86  	}{
    87  		{
    88  			name:      "empty view",
    89  			view:      NewView(100),
    90  			writeSize: 50,
    91  		},
    92  		{
    93  			name:      "full view",
    94  			view:      NewView(100),
    95  			initSize:  100,
    96  			writeSize: 50,
    97  		},
    98  		{
    99  			name:      "full write to partially full view",
   100  			view:      NewView(100),
   101  			initSize:  20,
   102  			writeSize: 50,
   103  		},
   104  		{
   105  			name:      "partial write to partially full view",
   106  			view:      NewView(100),
   107  			initSize:  80,
   108  			writeSize: 50,
   109  		},
   110  	} {
   111  		t.Run(tc.name, func(t *testing.T) {
   112  			tc.view.Grow(tc.initSize)
   113  			defer tc.view.Release()
   114  			orig := append([]byte(nil), tc.view.AsSlice()...)
   115  			toWrite := make([]byte, tc.writeSize)
   116  			rand.Read(toWrite)
   117  
   118  			n, err := tc.view.Write(toWrite)
   119  			if err != nil {
   120  				t.Errorf("Write failed: %s", err)
   121  			}
   122  			if n != tc.writeSize {
   123  				t.Errorf("got n=%d, want %d", n, tc.writeSize)
   124  			}
   125  			if tc.view.Size() != len(orig)+tc.writeSize {
   126  				t.Errorf("got Size()=%d, want %d", tc.view.Size(), len(orig)+tc.writeSize)
   127  			}
   128  			if !cmp.Equal(tc.view.AsSlice(), append(orig, toWrite...)) {
   129  				t.Errorf("got tc.view.AsSlice() = %d, want %d", tc.view.AsSlice(), toWrite)
   130  			}
   131  		})
   132  	}
   133  }
   134  
   135  func TestWriteToCloned(t *testing.T) {
   136  	orig := NewView(100)
   137  	toWrite := make([]byte, 20)
   138  	rand.Read(toWrite)
   139  	orig.Write(toWrite)
   140  
   141  	clone := orig.Clone()
   142  	clone.Write(toWrite)
   143  
   144  	if !cmp.Equal(orig.AsSlice(), toWrite) {
   145  		t.Errorf("got orig.ReadSlice() = %v, want %v", orig.AsSlice(), toWrite)
   146  	}
   147  
   148  	toWrite = append(toWrite, toWrite...)
   149  	if !cmp.Equal(clone.AsSlice(), toWrite) {
   150  		t.Errorf("got clone.ReadSlice() = %v, want %v", clone.AsSlice(), toWrite)
   151  	}
   152  }
   153  
   154  func TestWriteAt(t *testing.T) {
   155  	size := 10
   156  	off := 5
   157  	v := NewViewSize(size)
   158  	p := make([]byte, 20)
   159  	rand.Read(p)
   160  	orig := v.Clone()
   161  
   162  	if n, _ := v.WriteAt(p, off); n != size-off {
   163  		t.Errorf("got v.CopyIn()= %v, want %v", n, size-off)
   164  	}
   165  	if !cmp.Equal(v.AsSlice()[off:], p[:size-off]) {
   166  		t.Errorf("got v.AsSlice()[off:] = %v, want %v", v.AsSlice()[off:], p[off:size])
   167  	}
   168  	if !cmp.Equal(v.AsSlice()[:off], orig.AsSlice()[:off]) {
   169  		t.Errorf("got v.AsSlice()[:off] = %v, want %v", v.AsSlice()[:off], orig.AsSlice()[:off])
   170  	}
   171  }
   172  
   173  func TestWriteTo(t *testing.T) {
   174  	writeToSize := 100
   175  	v := NewViewSize(writeToSize)
   176  	defer v.Release()
   177  
   178  	w := bytes.NewBuffer(make([]byte, 100))
   179  
   180  	n, err := v.WriteTo(w)
   181  	if err != nil {
   182  		t.Errorf("WriteTo failed: %s", err)
   183  	}
   184  	if n != int64(writeToSize) {
   185  		t.Errorf("got n=%d, want 100", n)
   186  	}
   187  	if v.Size() != 0 {
   188  		t.Errorf("got v.Size()=%d, want 0", v.Size())
   189  	}
   190  }
   191  
   192  func TestReadFrom(t *testing.T) {
   193  	for _, tc := range []struct {
   194  		name string
   195  		data []byte
   196  		view *View
   197  	}{
   198  		{
   199  			name: "basic",
   200  			data: []byte{1, 2, 3},
   201  			view: NewView(10),
   202  		},
   203  		{
   204  			name: "requires grow",
   205  			data: []byte{4, 5, 6},
   206  			view: NewViewSize(63),
   207  		},
   208  	} {
   209  		defer tc.view.Release()
   210  		clone := tc.view.Clone()
   211  		defer clone.Release()
   212  		r := bytes.NewReader(tc.data)
   213  
   214  		n, err := tc.view.ReadFrom(r)
   215  
   216  		if err != nil {
   217  			t.Errorf("v.ReadFrom failed: %s", err)
   218  		}
   219  		if int(n) != len(tc.data) {
   220  			t.Errorf("v.ReadFrom failed: want n=%d, got %d", len(tc.data), n)
   221  		}
   222  		if tc.view.Size() == clone.Size() {
   223  			t.Errorf("expected clone.Size() != v.Size(), got match")
   224  		}
   225  		if !bytes.Equal(tc.view.AsSlice(), append(clone.AsSlice(), tc.data...)) {
   226  			t.Errorf("v.ReadFrom failed: want %v, got %v", tc.data, tc.view.AsSlice())
   227  		}
   228  	}
   229  }