gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/flipcall/flipcall_test.go (about)

     1  // Copyright 2019 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 flipcall
    16  
    17  import (
    18  	"runtime"
    19  	"testing"
    20  	"time"
    21  
    22  	"gvisor.dev/gvisor/pkg/sync"
    23  )
    24  
    25  var testPacketWindowSize = pageSize
    26  
    27  type testConnection struct {
    28  	pwa      PacketWindowAllocator
    29  	clientEP Endpoint
    30  	serverEP Endpoint
    31  }
    32  
    33  func newTestConnectionWithOptions(tb testing.TB, clientOpts, serverOpts []EndpointOption) *testConnection {
    34  	c := &testConnection{}
    35  	if err := c.pwa.Init(); err != nil {
    36  		tb.Fatalf("failed to create PacketWindowAllocator: %v", err)
    37  	}
    38  	pwd, err := c.pwa.Allocate(testPacketWindowSize)
    39  	if err != nil {
    40  		c.pwa.Destroy()
    41  		tb.Fatalf("PacketWindowAllocator.Allocate() failed: %v", err)
    42  	}
    43  	if err := c.clientEP.Init(ClientSide, pwd, clientOpts...); err != nil {
    44  		c.pwa.Destroy()
    45  		tb.Fatalf("failed to create client Endpoint: %v", err)
    46  	}
    47  	if err := c.serverEP.Init(ServerSide, pwd, serverOpts...); err != nil {
    48  		c.pwa.Destroy()
    49  		c.clientEP.Destroy()
    50  		tb.Fatalf("failed to create server Endpoint: %v", err)
    51  	}
    52  	return c
    53  }
    54  
    55  func newTestConnection(tb testing.TB) *testConnection {
    56  	return newTestConnectionWithOptions(tb, nil, nil)
    57  }
    58  
    59  func (c *testConnection) destroy() {
    60  	c.pwa.Destroy()
    61  	c.clientEP.Destroy()
    62  	c.serverEP.Destroy()
    63  }
    64  
    65  func testSendRecv(t *testing.T, c *testConnection) {
    66  	// This shared variable is used to confirm that synchronization between
    67  	// flipcall endpoints is visible to the Go race detector.
    68  	state := 0
    69  	var serverRun sync.WaitGroup
    70  	serverRun.Add(1)
    71  	go func() {
    72  		defer serverRun.Done()
    73  		t.Logf("server Endpoint waiting for packet 1")
    74  		if _, err := c.serverEP.RecvFirst(); err != nil {
    75  			t.Errorf("server Endpoint.RecvFirst() failed: %v", err)
    76  			return
    77  		}
    78  		state++
    79  		if state != 2 {
    80  			t.Errorf("shared state counter: got %d, wanted 2", state)
    81  		}
    82  		t.Logf("server Endpoint got packet 1, sending packet 2 and waiting for packet 3")
    83  		if _, err := c.serverEP.SendRecv(0); err != nil {
    84  			t.Errorf("server Endpoint.SendRecv() failed: %v", err)
    85  			return
    86  		}
    87  		state++
    88  		if state != 4 {
    89  			t.Errorf("shared state counter: got %d, wanted 4", state)
    90  		}
    91  		t.Logf("server Endpoint got packet 3")
    92  	}()
    93  	defer func() {
    94  		// Ensure that the server goroutine is cleaned up before
    95  		// c.serverEP.Destroy(), even if the test fails.
    96  		c.serverEP.Shutdown()
    97  		serverRun.Wait()
    98  	}()
    99  
   100  	t.Logf("client Endpoint establishing connection")
   101  	if err := c.clientEP.Connect(); err != nil {
   102  		t.Fatalf("client Endpoint.Connect() failed: %v", err)
   103  	}
   104  	state++
   105  	if state != 1 {
   106  		t.Errorf("shared state counter: got %d, wanted 1", state)
   107  	}
   108  	t.Logf("client Endpoint sending packet 1 and waiting for packet 2")
   109  	if _, err := c.clientEP.SendRecv(0); err != nil {
   110  		t.Fatalf("client Endpoint.SendRecv() failed: %v", err)
   111  	}
   112  	state++
   113  	if state != 3 {
   114  		t.Errorf("shared state counter: got %d, wanted 3", state)
   115  	}
   116  	t.Logf("client Endpoint got packet 2, sending packet 3")
   117  	if err := c.clientEP.SendLast(0); err != nil {
   118  		t.Fatalf("client Endpoint.SendLast() failed: %v", err)
   119  	}
   120  	t.Logf("waiting for server goroutine to complete")
   121  	serverRun.Wait()
   122  }
   123  
   124  func TestSendRecv(t *testing.T) {
   125  	c := newTestConnection(t)
   126  	defer c.destroy()
   127  	testSendRecv(t, c)
   128  }
   129  
   130  func testShutdownBeforeConnect(t *testing.T, c *testConnection, remoteShutdown bool) {
   131  	if remoteShutdown {
   132  		c.serverEP.Shutdown()
   133  	} else {
   134  		c.clientEP.Shutdown()
   135  	}
   136  	if err := c.clientEP.Connect(); err == nil {
   137  		t.Errorf("client Endpoint.Connect() succeeded unexpectedly")
   138  	}
   139  }
   140  
   141  func TestShutdownBeforeConnectLocal(t *testing.T) {
   142  	c := newTestConnection(t)
   143  	defer c.destroy()
   144  	testShutdownBeforeConnect(t, c, false)
   145  }
   146  
   147  func TestShutdownBeforeConnectRemote(t *testing.T) {
   148  	c := newTestConnection(t)
   149  	defer c.destroy()
   150  	testShutdownBeforeConnect(t, c, true)
   151  }
   152  
   153  func testShutdownDuringConnect(t *testing.T, c *testConnection, remoteShutdown bool) {
   154  	var clientRun sync.WaitGroup
   155  	clientRun.Add(1)
   156  	go func() {
   157  		defer clientRun.Done()
   158  		if err := c.clientEP.Connect(); err == nil {
   159  			t.Errorf("client Endpoint.Connect() succeeded unexpectedly")
   160  		}
   161  	}()
   162  	time.Sleep(time.Second) // to allow c.clientEP.Connect() to block
   163  	if remoteShutdown {
   164  		c.serverEP.Shutdown()
   165  	} else {
   166  		c.clientEP.Shutdown()
   167  	}
   168  	clientRun.Wait()
   169  }
   170  
   171  func TestShutdownDuringConnectLocal(t *testing.T) {
   172  	c := newTestConnection(t)
   173  	defer c.destroy()
   174  	testShutdownDuringConnect(t, c, false)
   175  }
   176  
   177  func TestShutdownDuringConnectRemote(t *testing.T) {
   178  	c := newTestConnection(t)
   179  	defer c.destroy()
   180  	testShutdownDuringConnect(t, c, true)
   181  }
   182  
   183  func testShutdownBeforeRecvFirst(t *testing.T, c *testConnection, remoteShutdown bool) {
   184  	if remoteShutdown {
   185  		c.clientEP.Shutdown()
   186  	} else {
   187  		c.serverEP.Shutdown()
   188  	}
   189  	if _, err := c.serverEP.RecvFirst(); err == nil {
   190  		t.Errorf("server Endpoint.RecvFirst() succeeded unexpectedly")
   191  	}
   192  }
   193  
   194  func TestShutdownBeforeRecvFirstLocal(t *testing.T) {
   195  	c := newTestConnection(t)
   196  	defer c.destroy()
   197  	testShutdownBeforeRecvFirst(t, c, false)
   198  }
   199  
   200  func TestShutdownBeforeRecvFirstRemote(t *testing.T) {
   201  	c := newTestConnection(t)
   202  	defer c.destroy()
   203  	testShutdownBeforeRecvFirst(t, c, true)
   204  }
   205  
   206  func testShutdownDuringRecvFirstBeforeConnect(t *testing.T, c *testConnection, remoteShutdown bool) {
   207  	var serverRun sync.WaitGroup
   208  	serverRun.Add(1)
   209  	go func() {
   210  		defer serverRun.Done()
   211  		if _, err := c.serverEP.RecvFirst(); err == nil {
   212  			t.Errorf("server Endpoint.RecvFirst() succeeded unexpectedly")
   213  		}
   214  	}()
   215  	time.Sleep(time.Second) // to allow c.serverEP.RecvFirst() to block
   216  	if remoteShutdown {
   217  		c.clientEP.Shutdown()
   218  	} else {
   219  		c.serverEP.Shutdown()
   220  	}
   221  	serverRun.Wait()
   222  }
   223  
   224  func TestShutdownDuringRecvFirstBeforeConnectLocal(t *testing.T) {
   225  	c := newTestConnection(t)
   226  	defer c.destroy()
   227  	testShutdownDuringRecvFirstBeforeConnect(t, c, false)
   228  }
   229  
   230  func TestShutdownDuringRecvFirstBeforeConnectRemote(t *testing.T) {
   231  	c := newTestConnection(t)
   232  	defer c.destroy()
   233  	testShutdownDuringRecvFirstBeforeConnect(t, c, true)
   234  }
   235  
   236  func testShutdownDuringRecvFirstAfterConnect(t *testing.T, c *testConnection, remoteShutdown bool) {
   237  	var serverRun sync.WaitGroup
   238  	serverRun.Add(1)
   239  	go func() {
   240  		defer serverRun.Done()
   241  		if _, err := c.serverEP.RecvFirst(); err == nil {
   242  			t.Errorf("server Endpoint.RecvFirst() succeeded unexpectedly")
   243  		}
   244  	}()
   245  	defer func() {
   246  		// Ensure that the server goroutine is cleaned up before
   247  		// c.serverEP.Destroy(), even if the test fails.
   248  		c.serverEP.Shutdown()
   249  		serverRun.Wait()
   250  	}()
   251  	if err := c.clientEP.Connect(); err != nil {
   252  		t.Fatalf("client Endpoint.Connect() failed: %v", err)
   253  	}
   254  	if remoteShutdown {
   255  		c.clientEP.Shutdown()
   256  	} else {
   257  		c.serverEP.Shutdown()
   258  	}
   259  	serverRun.Wait()
   260  }
   261  
   262  func TestShutdownDuringRecvFirstAfterConnectLocal(t *testing.T) {
   263  	c := newTestConnection(t)
   264  	defer c.destroy()
   265  	testShutdownDuringRecvFirstAfterConnect(t, c, false)
   266  }
   267  
   268  func TestShutdownDuringRecvFirstAfterConnectRemote(t *testing.T) {
   269  	c := newTestConnection(t)
   270  	defer c.destroy()
   271  	testShutdownDuringRecvFirstAfterConnect(t, c, true)
   272  }
   273  
   274  func testShutdownDuringClientSendRecv(t *testing.T, c *testConnection, remoteShutdown bool) {
   275  	var serverRun sync.WaitGroup
   276  	serverRun.Add(1)
   277  	go func() {
   278  		defer serverRun.Done()
   279  		if _, err := c.serverEP.RecvFirst(); err != nil {
   280  			t.Errorf("server Endpoint.RecvFirst() failed: %v", err)
   281  		}
   282  		// At this point, the client must be blocked in c.clientEP.SendRecv().
   283  		if remoteShutdown {
   284  			c.serverEP.Shutdown()
   285  		} else {
   286  			c.clientEP.Shutdown()
   287  		}
   288  	}()
   289  	defer func() {
   290  		// Ensure that the server goroutine is cleaned up before
   291  		// c.serverEP.Destroy(), even if the test fails.
   292  		c.serverEP.Shutdown()
   293  		serverRun.Wait()
   294  	}()
   295  	if err := c.clientEP.Connect(); err != nil {
   296  		t.Fatalf("client Endpoint.Connect() failed: %v", err)
   297  	}
   298  	if _, err := c.clientEP.SendRecv(0); err == nil {
   299  		t.Errorf("client Endpoint.SendRecv() succeeded unexpectedly")
   300  	}
   301  }
   302  
   303  func TestShutdownDuringClientSendRecvLocal(t *testing.T) {
   304  	c := newTestConnection(t)
   305  	defer c.destroy()
   306  	testShutdownDuringClientSendRecv(t, c, false)
   307  }
   308  
   309  func TestShutdownDuringClientSendRecvRemote(t *testing.T) {
   310  	c := newTestConnection(t)
   311  	defer c.destroy()
   312  	testShutdownDuringClientSendRecv(t, c, true)
   313  }
   314  
   315  func testShutdownDuringServerSendRecv(t *testing.T, c *testConnection, remoteShutdown bool) {
   316  	var serverRun sync.WaitGroup
   317  	serverRun.Add(1)
   318  	go func() {
   319  		defer serverRun.Done()
   320  		if _, err := c.serverEP.RecvFirst(); err != nil {
   321  			t.Errorf("server Endpoint.RecvFirst() failed: %v", err)
   322  			return
   323  		}
   324  		if _, err := c.serverEP.SendRecv(0); err == nil {
   325  			t.Errorf("server Endpoint.SendRecv() succeeded unexpectedly")
   326  		}
   327  	}()
   328  	defer func() {
   329  		// Ensure that the server goroutine is cleaned up before
   330  		// c.serverEP.Destroy(), even if the test fails.
   331  		c.serverEP.Shutdown()
   332  		serverRun.Wait()
   333  	}()
   334  	if err := c.clientEP.Connect(); err != nil {
   335  		t.Fatalf("client Endpoint.Connect() failed: %v", err)
   336  	}
   337  	if _, err := c.clientEP.SendRecv(0); err != nil {
   338  		t.Fatalf("client Endpoint.SendRecv() failed: %v", err)
   339  	}
   340  	time.Sleep(time.Second) // to allow serverEP.SendRecv() to block
   341  	if remoteShutdown {
   342  		c.clientEP.Shutdown()
   343  	} else {
   344  		c.serverEP.Shutdown()
   345  	}
   346  	serverRun.Wait()
   347  }
   348  
   349  func TestShutdownDuringServerSendRecvLocal(t *testing.T) {
   350  	c := newTestConnection(t)
   351  	defer c.destroy()
   352  	testShutdownDuringServerSendRecv(t, c, false)
   353  }
   354  
   355  func TestShutdownDuringServerSendRecvRemote(t *testing.T) {
   356  	c := newTestConnection(t)
   357  	defer c.destroy()
   358  	testShutdownDuringServerSendRecv(t, c, true)
   359  }
   360  
   361  func benchmarkSendRecv(b *testing.B, c *testConnection) {
   362  	var serverRun sync.WaitGroup
   363  	serverRun.Add(1)
   364  	go func() {
   365  		defer serverRun.Done()
   366  		if b.N == 0 {
   367  			return
   368  		}
   369  		if _, err := c.serverEP.RecvFirst(); err != nil {
   370  			b.Errorf("server Endpoint.RecvFirst() failed: %v", err)
   371  			return
   372  		}
   373  		for i := 1; i < b.N; i++ {
   374  			if _, err := c.serverEP.SendRecv(0); err != nil {
   375  				b.Errorf("server Endpoint.SendRecv() failed: %v", err)
   376  				return
   377  			}
   378  		}
   379  		if err := c.serverEP.SendLast(0); err != nil {
   380  			b.Errorf("server Endpoint.SendLast() failed: %v", err)
   381  		}
   382  	}()
   383  	defer func() {
   384  		c.serverEP.Shutdown()
   385  		serverRun.Wait()
   386  	}()
   387  
   388  	if err := c.clientEP.Connect(); err != nil {
   389  		b.Fatalf("client Endpoint.Connect() failed: %v", err)
   390  	}
   391  	runtime.GC()
   392  	b.ResetTimer()
   393  	for i := 0; i < b.N; i++ {
   394  		if _, err := c.clientEP.SendRecv(0); err != nil {
   395  			b.Fatalf("client Endpoint.SendRecv() failed: %v", err)
   396  		}
   397  	}
   398  	b.StopTimer()
   399  }
   400  
   401  func BenchmarkSendRecv(b *testing.B) {
   402  	c := newTestConnection(b)
   403  	defer c.destroy()
   404  	benchmarkSendRecv(b, c)
   405  }