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