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 }