github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/tcpip/link/sharedmem/pipe/pipe_test.go (about) 1 // Copyright 2018 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 pipe 16 17 import ( 18 "math/rand" 19 "reflect" 20 "runtime" 21 "testing" 22 23 "github.com/SagerNet/gvisor/pkg/sync" 24 ) 25 26 func TestSimpleReadWrite(t *testing.T) { 27 // Check that a simple write can be properly read from the rx side. 28 tr := rand.New(rand.NewSource(99)) 29 rr := rand.New(rand.NewSource(99)) 30 31 b := make([]byte, 100) 32 var tx Tx 33 tx.Init(b) 34 35 wb := tx.Push(10) 36 if wb == nil { 37 t.Fatalf("Push failed on empty pipe") 38 } 39 for i := range wb { 40 wb[i] = byte(tr.Intn(256)) 41 } 42 tx.Flush() 43 44 var rx Rx 45 rx.Init(b) 46 rb := rx.Pull() 47 if len(rb) != 10 { 48 t.Fatalf("Bad buffer size returned: got %v, want %v", len(rb), 10) 49 } 50 51 for i := range rb { 52 if v := byte(rr.Intn(256)); v != rb[i] { 53 t.Fatalf("Bad read buffer at index %v: got %v, want %v", i, rb[i], v) 54 } 55 } 56 rx.Flush() 57 } 58 59 func TestEmptyRead(t *testing.T) { 60 // Check that pulling from an empty pipe fails. 61 b := make([]byte, 100) 62 var tx Tx 63 tx.Init(b) 64 65 var rx Rx 66 rx.Init(b) 67 if rb := rx.Pull(); rb != nil { 68 t.Fatalf("Pull succeeded on empty pipe") 69 } 70 } 71 72 func TestTooLargeWrite(t *testing.T) { 73 // Check that writes that are too large are properly rejected. 74 b := make([]byte, 96) 75 var tx Tx 76 tx.Init(b) 77 78 if wb := tx.Push(96); wb != nil { 79 t.Fatalf("Write of 96 bytes succeeded on 96-byte pipe") 80 } 81 82 if wb := tx.Push(88); wb != nil { 83 t.Fatalf("Write of 88 bytes succeeded on 96-byte pipe") 84 } 85 86 if wb := tx.Push(80); wb == nil { 87 t.Fatalf("Write of 80 bytes failed on 96-byte pipe") 88 } 89 } 90 91 func TestFullWrite(t *testing.T) { 92 // Check that writes fail when the pipe is full. 93 b := make([]byte, 100) 94 var tx Tx 95 tx.Init(b) 96 97 if wb := tx.Push(80); wb == nil { 98 t.Fatalf("Write of 80 bytes failed on 96-byte pipe") 99 } 100 101 if wb := tx.Push(1); wb != nil { 102 t.Fatalf("Write succeeded on full pipe") 103 } 104 } 105 106 func TestFullAndFlushedWrite(t *testing.T) { 107 // Check that writes fail when the pipe is full and has already been 108 // flushed. 109 b := make([]byte, 100) 110 var tx Tx 111 tx.Init(b) 112 113 if wb := tx.Push(80); wb == nil { 114 t.Fatalf("Write of 80 bytes failed on 96-byte pipe") 115 } 116 117 tx.Flush() 118 119 if wb := tx.Push(1); wb != nil { 120 t.Fatalf("Write succeeded on full pipe") 121 } 122 } 123 124 func TestTxFlushTwice(t *testing.T) { 125 // Checks that a second consecutive tx flush is a no-op. 126 b := make([]byte, 100) 127 var tx Tx 128 tx.Init(b) 129 130 if wb := tx.Push(50); wb == nil { 131 t.Fatalf("Push failed on empty pipe") 132 } 133 tx.Flush() 134 135 // Make copy of original tx queue, flush it, then check that it didn't 136 // change. 137 orig := tx 138 tx.Flush() 139 140 if !reflect.DeepEqual(orig, tx) { 141 t.Fatalf("Flush mutated tx pipe: got %v, want %v", tx, orig) 142 } 143 } 144 145 func TestRxFlushTwice(t *testing.T) { 146 // Checks that a second consecutive rx flush is a no-op. 147 b := make([]byte, 100) 148 var tx Tx 149 tx.Init(b) 150 151 if wb := tx.Push(50); wb == nil { 152 t.Fatalf("Push failed on empty pipe") 153 } 154 tx.Flush() 155 156 var rx Rx 157 rx.Init(b) 158 if rb := rx.Pull(); rb == nil { 159 t.Fatalf("Pull failed on non-empty pipe") 160 } 161 rx.Flush() 162 163 // Make copy of original rx queue, flush it, then check that it didn't 164 // change. 165 orig := rx 166 rx.Flush() 167 168 if !reflect.DeepEqual(orig, rx) { 169 t.Fatalf("Flush mutated rx pipe: got %v, want %v", rx, orig) 170 } 171 } 172 173 func TestWrapInMiddleOfTransaction(t *testing.T) { 174 // Check that writes are not flushed when we need to wrap the buffer 175 // around. 176 b := make([]byte, 100) 177 var tx Tx 178 tx.Init(b) 179 180 if wb := tx.Push(50); wb == nil { 181 t.Fatalf("Push failed on empty pipe") 182 } 183 tx.Flush() 184 185 var rx Rx 186 rx.Init(b) 187 if rb := rx.Pull(); rb == nil { 188 t.Fatalf("Pull failed on non-empty pipe") 189 } 190 rx.Flush() 191 192 // At this point the ring buffer is empty, but the write is at offset 193 // 64 (50 + sizeOfSlotHeader + padding-for-8-byte-alignment). 194 if wb := tx.Push(10); wb == nil { 195 t.Fatalf("Push failed on empty pipe") 196 } 197 198 if wb := tx.Push(50); wb == nil { 199 t.Fatalf("Push failed on non-full pipe") 200 } 201 202 // We haven't flushed yet, so pull must return nil. 203 if rb := rx.Pull(); rb != nil { 204 t.Fatalf("Pull succeeded on non-flushed pipe") 205 } 206 207 tx.Flush() 208 209 // The two buffers must be available now. 210 if rb := rx.Pull(); rb == nil { 211 t.Fatalf("Pull failed on non-empty pipe") 212 } 213 214 if rb := rx.Pull(); rb == nil { 215 t.Fatalf("Pull failed on non-empty pipe") 216 } 217 } 218 219 func TestWriteAbort(t *testing.T) { 220 // Check that a read fails on a pipe that has had data pushed to it but 221 // has aborted the push. 222 b := make([]byte, 100) 223 var tx Tx 224 tx.Init(b) 225 226 if wb := tx.Push(10); wb == nil { 227 t.Fatalf("Write failed on empty pipe") 228 } 229 230 var rx Rx 231 rx.Init(b) 232 if rb := rx.Pull(); rb != nil { 233 t.Fatalf("Pull succeeded on empty pipe") 234 } 235 236 tx.Abort() 237 if rb := rx.Pull(); rb != nil { 238 t.Fatalf("Pull succeeded on empty pipe") 239 } 240 } 241 242 func TestWrappedWriteAbort(t *testing.T) { 243 // Check that writes are properly aborted even if the writes wrap 244 // around. 245 b := make([]byte, 100) 246 var tx Tx 247 tx.Init(b) 248 249 if wb := tx.Push(50); wb == nil { 250 t.Fatalf("Push failed on empty pipe") 251 } 252 tx.Flush() 253 254 var rx Rx 255 rx.Init(b) 256 if rb := rx.Pull(); rb == nil { 257 t.Fatalf("Pull failed on non-empty pipe") 258 } 259 rx.Flush() 260 261 // At this point the ring buffer is empty, but the write is at offset 262 // 64 (50 + sizeOfSlotHeader + padding-for-8-byte-alignment). 263 if wb := tx.Push(10); wb == nil { 264 t.Fatalf("Push failed on empty pipe") 265 } 266 267 if wb := tx.Push(50); wb == nil { 268 t.Fatalf("Push failed on non-full pipe") 269 } 270 271 // We haven't flushed yet, so pull must return nil. 272 if rb := rx.Pull(); rb != nil { 273 t.Fatalf("Pull succeeded on non-flushed pipe") 274 } 275 276 tx.Abort() 277 278 // The pushes were aborted, so no data should be readable. 279 if rb := rx.Pull(); rb != nil { 280 t.Fatalf("Pull succeeded on non-flushed pipe") 281 } 282 283 // Try the same transactions again, but flush this time. 284 if wb := tx.Push(10); wb == nil { 285 t.Fatalf("Push failed on empty pipe") 286 } 287 288 if wb := tx.Push(50); wb == nil { 289 t.Fatalf("Push failed on non-full pipe") 290 } 291 292 tx.Flush() 293 294 // The two buffers must be available now. 295 if rb := rx.Pull(); rb == nil { 296 t.Fatalf("Pull failed on non-empty pipe") 297 } 298 299 if rb := rx.Pull(); rb == nil { 300 t.Fatalf("Pull failed on non-empty pipe") 301 } 302 } 303 304 func TestEmptyReadOnNonFlushedWrite(t *testing.T) { 305 // Check that a read fails on a pipe that has had data pushed to it 306 // but not yet flushed. 307 b := make([]byte, 100) 308 var tx Tx 309 tx.Init(b) 310 311 if wb := tx.Push(10); wb == nil { 312 t.Fatalf("Write failed on empty pipe") 313 } 314 315 var rx Rx 316 rx.Init(b) 317 if rb := rx.Pull(); rb != nil { 318 t.Fatalf("Pull succeeded on empty pipe") 319 } 320 321 tx.Flush() 322 if rb := rx.Pull(); rb == nil { 323 t.Fatalf("Pull on failed on non-empty pipe") 324 } 325 } 326 327 func TestPullAfterPullingEntirePipe(t *testing.T) { 328 // Check that Pull fails when the pipe is full, but all of it has 329 // already been pulled but not yet flushed. 330 b := make([]byte, 100) 331 var tx Tx 332 tx.Init(b) 333 334 if wb := tx.Push(50); wb == nil { 335 t.Fatalf("Push failed on empty pipe") 336 } 337 tx.Flush() 338 339 var rx Rx 340 rx.Init(b) 341 if rb := rx.Pull(); rb == nil { 342 t.Fatalf("Pull failed on non-empty pipe") 343 } 344 rx.Flush() 345 346 // At this point the ring buffer is empty, but the write is at offset 347 // 64 (50 + sizeOfSlotHeader + padding-for-8-byte-alignment). Write 3 348 // buffers that will fill the pipe. 349 if wb := tx.Push(10); wb == nil { 350 t.Fatalf("Push failed on empty pipe") 351 } 352 353 if wb := tx.Push(20); wb == nil { 354 t.Fatalf("Push failed on non-full pipe") 355 } 356 357 if wb := tx.Push(24); wb == nil { 358 t.Fatalf("Push failed on non-full pipe") 359 } 360 361 tx.Flush() 362 363 // The three buffers must be available now. 364 if rb := rx.Pull(); rb == nil { 365 t.Fatalf("Pull failed on non-empty pipe") 366 } 367 368 if rb := rx.Pull(); rb == nil { 369 t.Fatalf("Pull failed on non-empty pipe") 370 } 371 372 if rb := rx.Pull(); rb == nil { 373 t.Fatalf("Pull failed on non-empty pipe") 374 } 375 376 // Fourth pull must fail. 377 if rb := rx.Pull(); rb != nil { 378 t.Fatalf("Pull succeeded on empty pipe") 379 } 380 } 381 382 func TestNoRoomToWrapOnPush(t *testing.T) { 383 // Check that Push fails when it tries to allocate room to add a wrap 384 // message. 385 b := make([]byte, 100) 386 var tx Tx 387 tx.Init(b) 388 389 if wb := tx.Push(50); wb == nil { 390 t.Fatalf("Push failed on empty pipe") 391 } 392 tx.Flush() 393 394 var rx Rx 395 rx.Init(b) 396 if rb := rx.Pull(); rb == nil { 397 t.Fatalf("Pull failed on non-empty pipe") 398 } 399 rx.Flush() 400 401 // At this point the ring buffer is empty, but the write is at offset 402 // 64 (50 + sizeOfSlotHeader + padding-for-8-byte-alignment). Write 20, 403 // which won't fit (64+20+8+padding = 96, which wouldn't leave room for 404 // the padding), so it wraps around. 405 if wb := tx.Push(20); wb == nil { 406 t.Fatalf("Push failed on empty pipe") 407 } 408 409 tx.Flush() 410 411 // Buffer offset is at 28. Try to write 70, which would require a wrap 412 // slot which cannot be created now. 413 if wb := tx.Push(70); wb != nil { 414 t.Fatalf("Push succeeded on pipe with no room for wrap message") 415 } 416 } 417 418 func TestRxImplicitFlushOfWrapMessage(t *testing.T) { 419 // Check if the first read is that of a wrapping message, that it gets 420 // immediately flushed. 421 b := make([]byte, 100) 422 var tx Tx 423 tx.Init(b) 424 425 if wb := tx.Push(50); wb == nil { 426 t.Fatalf("Push failed on empty pipe") 427 } 428 tx.Flush() 429 430 // This will cause a wrapping message to written. 431 if wb := tx.Push(60); wb != nil { 432 t.Fatalf("Push succeeded when there is no room in pipe") 433 } 434 435 var rx Rx 436 rx.Init(b) 437 438 // Read the first message. 439 if rb := rx.Pull(); rb == nil { 440 t.Fatalf("Pull failed on non-empty pipe") 441 } 442 rx.Flush() 443 444 // This should fail because of the wrapping message is taking up space. 445 if wb := tx.Push(60); wb != nil { 446 t.Fatalf("Push succeeded when there is no room in pipe") 447 } 448 449 // Try to read the next one. This should consume the wrapping message. 450 rx.Pull() 451 452 // This must now succeed. 453 if wb := tx.Push(60); wb == nil { 454 t.Fatalf("Push failed on empty pipe") 455 } 456 } 457 458 func TestConcurrentReaderWriter(t *testing.T) { 459 // Push a million buffers of random sizes and random contents. Check 460 // that buffers read match what was written. 461 tr := rand.New(rand.NewSource(99)) 462 rr := rand.New(rand.NewSource(99)) 463 464 b := make([]byte, 100) 465 var tx Tx 466 tx.Init(b) 467 468 var rx Rx 469 rx.Init(b) 470 471 const count = 1000000 472 var wg sync.WaitGroup 473 defer wg.Wait() 474 wg.Add(1) 475 go func() { 476 defer wg.Done() 477 runtime.Gosched() 478 for i := 0; i < count; i++ { 479 n := 1 + tr.Intn(80) 480 wb := tx.Push(uint64(n)) 481 for wb == nil { 482 wb = tx.Push(uint64(n)) 483 } 484 485 for j := range wb { 486 wb[j] = byte(tr.Intn(256)) 487 } 488 489 tx.Flush() 490 } 491 }() 492 493 for i := 0; i < count; i++ { 494 n := 1 + rr.Intn(80) 495 rb := rx.Pull() 496 for rb == nil { 497 rb = rx.Pull() 498 } 499 500 if n != len(rb) { 501 t.Fatalf("Bad %v-th buffer length: got %v, want %v", i, len(rb), n) 502 } 503 504 for j := range rb { 505 if v := byte(rr.Intn(256)); v != rb[j] { 506 t.Fatalf("Bad %v-th read buffer at index %v: got %v, want %v", i, j, rb[j], v) 507 } 508 } 509 510 rx.Flush() 511 } 512 }