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  }