github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/internal/grid/grid_test.go (about)

     1  // Copyright (c) 2015-2023 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package grid
    19  
    20  import (
    21  	"bytes"
    22  	"context"
    23  	"errors"
    24  	"fmt"
    25  	"os"
    26  	"runtime"
    27  	"strconv"
    28  	"strings"
    29  	"testing"
    30  	"time"
    31  
    32  	"github.com/minio/minio/internal/logger/target/testlogger"
    33  )
    34  
    35  func TestSingleRoundtrip(t *testing.T) {
    36  	defer testlogger.T.SetLogTB(t)()
    37  	errFatal := func(err error) {
    38  		t.Helper()
    39  		if err != nil {
    40  			t.Fatal(err)
    41  		}
    42  	}
    43  	grid, err := SetupTestGrid(2)
    44  	errFatal(err)
    45  	remoteHost := grid.Hosts[1]
    46  	local := grid.Managers[0]
    47  
    48  	// 1: Echo
    49  	errFatal(local.RegisterSingleHandler(handlerTest, func(payload []byte) ([]byte, *RemoteErr) {
    50  		t.Log("1: server payload: ", len(payload), "bytes.")
    51  		return append([]byte{}, payload...), nil
    52  	}))
    53  	// 2: Return as error
    54  	errFatal(local.RegisterSingleHandler(handlerTest2, func(payload []byte) ([]byte, *RemoteErr) {
    55  		t.Log("2: server payload: ", len(payload), "bytes.")
    56  		err := RemoteErr(payload)
    57  		return nil, &err
    58  	}))
    59  
    60  	remote := grid.Managers[1]
    61  
    62  	// 1: Echo
    63  	errFatal(remote.RegisterSingleHandler(handlerTest, func(payload []byte) ([]byte, *RemoteErr) {
    64  		t.Log("1: server payload: ", len(payload), "bytes.")
    65  		return append([]byte{}, payload...), nil
    66  	}))
    67  	// 2: Return as error
    68  	errFatal(remote.RegisterSingleHandler(handlerTest2, func(payload []byte) ([]byte, *RemoteErr) {
    69  		t.Log("2: server payload: ", len(payload), "bytes.")
    70  		err := RemoteErr(payload)
    71  		return nil, &err
    72  	}))
    73  
    74  	// local to remote
    75  	remoteConn := local.Connection(remoteHost)
    76  	remoteConn.WaitForConnect(context.Background())
    77  	defer testlogger.T.SetErrorTB(t)()
    78  
    79  	t.Run("localToRemote", func(t *testing.T) {
    80  		const testPayload = "Hello Grid World!"
    81  
    82  		start := time.Now()
    83  		resp, err := remoteConn.Request(context.Background(), handlerTest, []byte(testPayload))
    84  		errFatal(err)
    85  		if string(resp) != testPayload {
    86  			t.Errorf("want %q, got %q", testPayload, string(resp))
    87  		}
    88  		t.Log("Roundtrip:", time.Since(start))
    89  	})
    90  
    91  	t.Run("localToRemoteErr", func(t *testing.T) {
    92  		const testPayload = "Hello Grid World!"
    93  		start := time.Now()
    94  		resp, err := remoteConn.Request(context.Background(), handlerTest2, []byte(testPayload))
    95  		t.Log("Roundtrip:", time.Since(start))
    96  		if len(resp) != 0 {
    97  			t.Errorf("want nil, got %q", string(resp))
    98  		}
    99  		if err != RemoteErr(testPayload) {
   100  			t.Errorf("want error %v(%T), got %v(%T)", RemoteErr(testPayload), RemoteErr(testPayload), err, err)
   101  		}
   102  		t.Log("Roundtrip:", time.Since(start))
   103  	})
   104  
   105  	t.Run("localToRemoteHuge", func(t *testing.T) {
   106  		testPayload := bytes.Repeat([]byte("?"), 1<<20)
   107  
   108  		start := time.Now()
   109  		resp, err := remoteConn.Request(context.Background(), handlerTest, testPayload)
   110  		errFatal(err)
   111  		if string(resp) != string(testPayload) {
   112  			t.Errorf("want %q, got %q", testPayload, string(resp))
   113  		}
   114  		t.Log("Roundtrip:", time.Since(start))
   115  	})
   116  
   117  	t.Run("localToRemoteErrHuge", func(t *testing.T) {
   118  		testPayload := bytes.Repeat([]byte("!"), 1<<10)
   119  
   120  		start := time.Now()
   121  		resp, err := remoteConn.Request(context.Background(), handlerTest2, testPayload)
   122  		if len(resp) != 0 {
   123  			t.Errorf("want nil, got %q", string(resp))
   124  		}
   125  		if err != RemoteErr(testPayload) {
   126  			t.Errorf("want error %v(%T), got %v(%T)", RemoteErr(testPayload), RemoteErr(testPayload), err, err)
   127  		}
   128  		t.Log("Roundtrip:", time.Since(start))
   129  	})
   130  }
   131  
   132  func TestSingleRoundtripNotReady(t *testing.T) {
   133  	defer testlogger.T.SetLogTB(t)()
   134  	errFatal := func(t testing.TB, err error) {
   135  		t.Helper()
   136  		if err != nil {
   137  			t.Fatal(err)
   138  		}
   139  	}
   140  	grid, err := SetupTestGrid(2)
   141  	errFatal(t, err)
   142  	remoteHost := grid.Hosts[1]
   143  	local := grid.Managers[0]
   144  
   145  	// 1: Echo
   146  	errFatal(t, local.RegisterSingleHandler(handlerTest, func(payload []byte) ([]byte, *RemoteErr) {
   147  		t.Log("1: server payload: ", len(payload), "bytes.")
   148  		return append([]byte{}, payload...), nil
   149  	}))
   150  	// 2: Return as error
   151  	errFatal(t, local.RegisterSingleHandler(handlerTest2, func(payload []byte) ([]byte, *RemoteErr) {
   152  		t.Log("2: server payload: ", len(payload), "bytes.")
   153  		err := RemoteErr(payload)
   154  		return nil, &err
   155  	}))
   156  
   157  	// Do not register remote handlers
   158  
   159  	// local to remote
   160  	remoteConn := local.Connection(remoteHost)
   161  	remoteConn.WaitForConnect(context.Background())
   162  	defer testlogger.T.SetErrorTB(t)()
   163  
   164  	t.Run("localToRemote", func(t *testing.T) {
   165  		const testPayload = "Hello Grid World!"
   166  		// Single requests should have remote errors.
   167  		_, err := remoteConn.Request(context.Background(), handlerTest, []byte(testPayload))
   168  		if v, ok := err.(*RemoteErr); !ok || v.Error() != "Invalid Handler for type" {
   169  			t.Fatalf("Unexpected error: %v, %T", err, err)
   170  		}
   171  		// Streams should not be able to set up until registered.
   172  		// Thus, the error is a local error.
   173  		_, err = remoteConn.NewStream(context.Background(), handlerTest, []byte(testPayload))
   174  		if !errors.Is(err, ErrUnknownHandler) {
   175  			t.Fatalf("Unexpected error: %v, %T", err, err)
   176  		}
   177  	})
   178  }
   179  
   180  func TestSingleRoundtripGenerics(t *testing.T) {
   181  	defer testlogger.T.SetLogTB(t)()
   182  	errFatal := func(err error) {
   183  		t.Helper()
   184  		if err != nil {
   185  			t.Fatal(err)
   186  		}
   187  	}
   188  	grid, err := SetupTestGrid(2)
   189  	errFatal(err)
   190  	remoteHost := grid.Hosts[1]
   191  	local := grid.Managers[0]
   192  	remote := grid.Managers[1]
   193  
   194  	// 1: Echo
   195  	h1 := NewSingleHandler[*testRequest, *testResponse](handlerTest, func() *testRequest {
   196  		return &testRequest{}
   197  	}, func() *testResponse {
   198  		return &testResponse{}
   199  	})
   200  	// Handles incoming requests, returns a response
   201  	handler1 := func(req *testRequest) (resp *testResponse, err *RemoteErr) {
   202  		resp = h1.NewResponse()
   203  		*resp = testResponse{
   204  			OrgNum:    req.Num,
   205  			OrgString: req.String,
   206  			Embedded:  *req,
   207  		}
   208  		return resp, nil
   209  	}
   210  	// Return error
   211  	h2 := NewSingleHandler[*testRequest, *testResponse](handlerTest2, newTestRequest, newTestResponse)
   212  	handler2 := func(req *testRequest) (resp *testResponse, err *RemoteErr) {
   213  		r := RemoteErr(req.String)
   214  		return nil, &r
   215  	}
   216  	errFatal(h1.Register(local, handler1))
   217  	errFatal(h2.Register(local, handler2))
   218  
   219  	errFatal(h1.Register(remote, handler1))
   220  	errFatal(h2.Register(remote, handler2))
   221  
   222  	// local to remote connection
   223  	remoteConn := local.Connection(remoteHost)
   224  	const testPayload = "Hello Grid World!"
   225  
   226  	start := time.Now()
   227  	req := testRequest{Num: 1, String: testPayload}
   228  	resp, err := h1.Call(context.Background(), remoteConn, &req)
   229  	errFatal(err)
   230  	if resp.OrgString != testPayload {
   231  		t.Errorf("want %q, got %q", testPayload, resp.OrgString)
   232  	}
   233  	t.Log("Roundtrip:", time.Since(start))
   234  	h1.PutResponse(resp)
   235  
   236  	start = time.Now()
   237  	resp, err = h2.Call(context.Background(), remoteConn, &testRequest{Num: 1, String: testPayload})
   238  	t.Log("Roundtrip:", time.Since(start))
   239  	if err != RemoteErr(testPayload) {
   240  		t.Errorf("want error %v(%T), got %v(%T)", RemoteErr(testPayload), RemoteErr(testPayload), err, err)
   241  	}
   242  	if resp != nil {
   243  		t.Errorf("want nil, got %q", resp)
   244  	}
   245  	h2.PutResponse(resp)
   246  	t.Log("Roundtrip:", time.Since(start))
   247  }
   248  
   249  func TestSingleRoundtripGenericsRecycle(t *testing.T) {
   250  	defer testlogger.T.SetLogTB(t)()
   251  	errFatal := func(err error) {
   252  		t.Helper()
   253  		if err != nil {
   254  			t.Fatal(err)
   255  		}
   256  	}
   257  	grid, err := SetupTestGrid(2)
   258  	errFatal(err)
   259  	remoteHost := grid.Hosts[1]
   260  	local := grid.Managers[0]
   261  	remote := grid.Managers[1]
   262  
   263  	// 1: Echo
   264  	h1 := NewSingleHandler[*MSS, *MSS](handlerTest, NewMSS, NewMSS)
   265  	// Handles incoming requests, returns a response
   266  	handler1 := func(req *MSS) (resp *MSS, err *RemoteErr) {
   267  		resp = h1.NewResponse()
   268  		for k, v := range *req {
   269  			(*resp)[k] = v
   270  		}
   271  		return resp, nil
   272  	}
   273  	// Return error
   274  	h2 := NewSingleHandler[*MSS, *MSS](handlerTest2, NewMSS, NewMSS)
   275  	handler2 := func(req *MSS) (resp *MSS, err *RemoteErr) {
   276  		defer req.Recycle()
   277  		r := RemoteErr(req.Get("err"))
   278  		return nil, &r
   279  	}
   280  	errFatal(h1.Register(local, handler1))
   281  	errFatal(h2.Register(local, handler2))
   282  
   283  	errFatal(h1.Register(remote, handler1))
   284  	errFatal(h2.Register(remote, handler2))
   285  
   286  	// local to remote connection
   287  	remoteConn := local.Connection(remoteHost)
   288  	const testPayload = "Hello Grid World!"
   289  
   290  	start := time.Now()
   291  	req := NewMSSWith(map[string]string{"test": testPayload})
   292  	resp, err := h1.Call(context.Background(), remoteConn, req)
   293  	errFatal(err)
   294  	if resp.Get("test") != testPayload {
   295  		t.Errorf("want %q, got %q", testPayload, resp.Get("test"))
   296  	}
   297  	t.Log("Roundtrip:", time.Since(start))
   298  	h1.PutResponse(resp)
   299  
   300  	start = time.Now()
   301  	resp, err = h2.Call(context.Background(), remoteConn, NewMSSWith(map[string]string{"err": testPayload}))
   302  	t.Log("Roundtrip:", time.Since(start))
   303  	if err != RemoteErr(testPayload) {
   304  		t.Errorf("want error %v(%T), got %v(%T)", RemoteErr(testPayload), RemoteErr(testPayload), err, err)
   305  	}
   306  	if resp != nil {
   307  		t.Errorf("want nil, got %q", resp)
   308  	}
   309  	t.Log("Roundtrip:", time.Since(start))
   310  	h2.PutResponse(resp)
   311  }
   312  
   313  func TestStreamSuite(t *testing.T) {
   314  	defer testlogger.T.SetErrorTB(t)()
   315  	errFatal := func(err error) {
   316  		t.Helper()
   317  		if err != nil {
   318  			t.Fatal(err)
   319  		}
   320  	}
   321  	grid, err := SetupTestGrid(2)
   322  	errFatal(err)
   323  	t.Cleanup(grid.Cleanup)
   324  
   325  	local := grid.Managers[0]
   326  	localHost := grid.Hosts[0]
   327  	remote := grid.Managers[1]
   328  	remoteHost := grid.Hosts[1]
   329  
   330  	connLocalToRemote := local.Connection(remoteHost)
   331  	connRemoteLocal := remote.Connection(localHost)
   332  
   333  	t.Run("testStreamRoundtrip", func(t *testing.T) {
   334  		defer timeout(5 * time.Second)()
   335  		testStreamRoundtrip(t, local, remote)
   336  		assertNoActive(t, connRemoteLocal)
   337  		assertNoActive(t, connLocalToRemote)
   338  	})
   339  	t.Run("testStreamCancel", func(t *testing.T) {
   340  		defer timeout(5 * time.Second)()
   341  		testStreamCancel(t, local, remote)
   342  		assertNoActive(t, connRemoteLocal)
   343  		assertNoActive(t, connLocalToRemote)
   344  	})
   345  	t.Run("testStreamDeadline", func(t *testing.T) {
   346  		defer timeout(5 * time.Second)()
   347  		testStreamDeadline(t, local, remote)
   348  		assertNoActive(t, connRemoteLocal)
   349  		assertNoActive(t, connLocalToRemote)
   350  	})
   351  	t.Run("testServerOutCongestion", func(t *testing.T) {
   352  		defer timeout(1 * time.Minute)()
   353  		testServerOutCongestion(t, local, remote)
   354  		assertNoActive(t, connRemoteLocal)
   355  		assertNoActive(t, connLocalToRemote)
   356  	})
   357  	t.Run("testServerInCongestion", func(t *testing.T) {
   358  		defer timeout(1 * time.Minute)()
   359  		testServerInCongestion(t, local, remote)
   360  		assertNoActive(t, connRemoteLocal)
   361  		assertNoActive(t, connLocalToRemote)
   362  	})
   363  	t.Run("testGenericsStreamRoundtrip", func(t *testing.T) {
   364  		defer timeout(1 * time.Minute)()
   365  		testGenericsStreamRoundtrip(t, local, remote)
   366  		assertNoActive(t, connRemoteLocal)
   367  		assertNoActive(t, connLocalToRemote)
   368  	})
   369  	t.Run("testGenericsStreamRoundtripSubroute", func(t *testing.T) {
   370  		defer timeout(1 * time.Minute)()
   371  		testGenericsStreamRoundtripSubroute(t, local, remote)
   372  		assertNoActive(t, connRemoteLocal)
   373  		assertNoActive(t, connLocalToRemote)
   374  	})
   375  	t.Run("testServerStreamResponseBlocked", func(t *testing.T) {
   376  		defer timeout(1 * time.Minute)()
   377  		testServerStreamResponseBlocked(t, local, remote)
   378  		assertNoActive(t, connRemoteLocal)
   379  		assertNoActive(t, connLocalToRemote)
   380  	})
   381  }
   382  
   383  func testStreamRoundtrip(t *testing.T, local, remote *Manager) {
   384  	defer testlogger.T.SetErrorTB(t)()
   385  	defer timeout(5 * time.Second)()
   386  	errFatal := func(err error) {
   387  		t.Helper()
   388  		if err != nil {
   389  			t.Fatal(err)
   390  		}
   391  	}
   392  
   393  	// We fake a local and remote server.
   394  	remoteHost := remote.HostName()
   395  
   396  	// 1: Echo
   397  	register := func(manager *Manager) {
   398  		errFatal(manager.RegisterStreamingHandler(handlerTest, StreamHandler{
   399  			Handle: func(ctx context.Context, payload []byte, request <-chan []byte, resp chan<- []byte) *RemoteErr {
   400  				for in := range request {
   401  					b := append([]byte{}, payload...)
   402  					b = append(b, in...)
   403  					resp <- b
   404  				}
   405  				t.Log(GetCaller(ctx).Name, "Handler done")
   406  				return nil
   407  			},
   408  			OutCapacity: 1,
   409  			InCapacity:  1,
   410  		}))
   411  		// 2: Return as error
   412  		errFatal(manager.RegisterStreamingHandler(handlerTest2, StreamHandler{
   413  			Handle: func(ctx context.Context, payload []byte, request <-chan []byte, resp chan<- []byte) *RemoteErr {
   414  				for in := range request {
   415  					t.Log("2: Got err request", string(in))
   416  					err := RemoteErr(append(payload, in...))
   417  					return &err
   418  				}
   419  				return nil
   420  			},
   421  			OutCapacity: 1,
   422  			InCapacity:  1,
   423  		}))
   424  	}
   425  	register(local)
   426  	register(remote)
   427  
   428  	// local to remote
   429  	remoteConn := local.Connection(remoteHost)
   430  	const testPayload = "Hello Grid World!"
   431  
   432  	start := time.Now()
   433  	stream, err := remoteConn.NewStream(context.Background(), handlerTest, []byte(testPayload))
   434  	errFatal(err)
   435  	var n int
   436  	stream.Requests <- []byte(strconv.Itoa(n))
   437  	for resp := range stream.responses {
   438  		errFatal(resp.Err)
   439  		t.Logf("got resp: %+v", string(resp.Msg))
   440  		if string(resp.Msg) != testPayload+strconv.Itoa(n) {
   441  			t.Errorf("want %q, got %q", testPayload+strconv.Itoa(n), string(resp.Msg))
   442  		}
   443  		if n == 10 {
   444  			close(stream.Requests)
   445  			continue
   446  		}
   447  		n++
   448  		t.Log("sending new client request")
   449  		stream.Requests <- []byte(strconv.Itoa(n))
   450  	}
   451  	t.Log("EOF. 10 Roundtrips:", time.Since(start))
   452  }
   453  
   454  func testStreamCancel(t *testing.T, local, remote *Manager) {
   455  	defer testlogger.T.SetErrorTB(t)()
   456  	errFatal := func(err error) {
   457  		t.Helper()
   458  		if err != nil {
   459  			t.Fatal(err)
   460  		}
   461  	}
   462  
   463  	// We fake a local and remote server.
   464  	remoteHost := remote.HostName()
   465  
   466  	// 1: Echo
   467  	serverCanceled := make(chan struct{})
   468  	register := func(manager *Manager) {
   469  		errFatal(manager.RegisterStreamingHandler(handlerTest, StreamHandler{
   470  			Handle: func(ctx context.Context, payload []byte, request <-chan []byte, resp chan<- []byte) *RemoteErr {
   471  				<-ctx.Done()
   472  				serverCanceled <- struct{}{}
   473  				t.Log(GetCaller(ctx).Name, "Server Context canceled")
   474  				return nil
   475  			},
   476  			OutCapacity: 1,
   477  			InCapacity:  0,
   478  		}))
   479  		errFatal(manager.RegisterStreamingHandler(handlerTest2, StreamHandler{
   480  			Handle: func(ctx context.Context, payload []byte, request <-chan []byte, resp chan<- []byte) *RemoteErr {
   481  				<-ctx.Done()
   482  				serverCanceled <- struct{}{}
   483  				t.Log(GetCaller(ctx).Name, "Server Context canceled")
   484  				return nil
   485  			},
   486  			OutCapacity: 1,
   487  			InCapacity:  1,
   488  		}))
   489  	}
   490  	register(local)
   491  	register(remote)
   492  
   493  	// local to remote
   494  	testHandler := func(t *testing.T, handler HandlerID) {
   495  		remoteConn := local.Connection(remoteHost)
   496  		const testPayload = "Hello Grid World!"
   497  
   498  		ctx, cancel := context.WithCancel(context.Background())
   499  		st, err := remoteConn.NewStream(ctx, handlerTest, []byte(testPayload))
   500  		errFatal(err)
   501  		clientCanceled := make(chan time.Time, 1)
   502  		err = nil
   503  		go func(t *testing.T) {
   504  			for resp := range st.responses {
   505  				t.Log("got resp:", string(resp.Msg), "err:", resp.Err)
   506  				if err != nil {
   507  					t.Log("ERROR: got second error:", resp.Err, "first:", err)
   508  					continue
   509  				}
   510  				err = resp.Err
   511  			}
   512  			t.Log("Client Context canceled. err state:", err)
   513  			clientCanceled <- time.Now()
   514  		}(t)
   515  		start := time.Now()
   516  		cancel()
   517  		<-serverCanceled
   518  		t.Log("server cancel time:", time.Since(start))
   519  		clientEnd := <-clientCanceled
   520  		if !errors.Is(err, context.Canceled) {
   521  			t.Error("expected context.Canceled, got", err)
   522  		}
   523  		t.Log("client after", time.Since(clientEnd))
   524  	}
   525  	// local to remote, unbuffered
   526  	t.Run("unbuffered", func(t *testing.T) {
   527  		testHandler(t, handlerTest)
   528  	})
   529  
   530  	t.Run("buffered", func(t *testing.T) {
   531  		testHandler(t, handlerTest2)
   532  	})
   533  }
   534  
   535  // testStreamDeadline will test if server
   536  func testStreamDeadline(t *testing.T, local, remote *Manager) {
   537  	defer testlogger.T.SetErrorTB(t)()
   538  	errFatal := func(err error) {
   539  		t.Helper()
   540  		if err != nil {
   541  			t.Fatal(err)
   542  		}
   543  	}
   544  
   545  	const wantDL = 50 * time.Millisecond
   546  	// We fake a local and remote server.
   547  	remoteHost := remote.HostName()
   548  
   549  	// 1: Echo
   550  	serverCanceled := make(chan time.Duration, 1)
   551  	register := func(manager *Manager) {
   552  		errFatal(manager.RegisterStreamingHandler(handlerTest, StreamHandler{
   553  			Handle: func(ctx context.Context, payload []byte, request <-chan []byte, resp chan<- []byte) *RemoteErr {
   554  				started := time.Now()
   555  				dl, _ := ctx.Deadline()
   556  				if testing.Verbose() {
   557  					fmt.Println(GetCaller(ctx).Name, "Server deadline:", time.Until(dl))
   558  				}
   559  				<-ctx.Done()
   560  				serverCanceled <- time.Since(started)
   561  				if testing.Verbose() {
   562  					fmt.Println(GetCaller(ctx).Name, "Server Context canceled with", ctx.Err(), "after", time.Since(started))
   563  				}
   564  				return nil
   565  			},
   566  			OutCapacity: 1,
   567  			InCapacity:  0,
   568  		}))
   569  		errFatal(manager.RegisterStreamingHandler(handlerTest2, StreamHandler{
   570  			Handle: func(ctx context.Context, payload []byte, request <-chan []byte, resp chan<- []byte) *RemoteErr {
   571  				started := time.Now()
   572  				dl, _ := ctx.Deadline()
   573  				if testing.Verbose() {
   574  					fmt.Println(GetCaller(ctx).Name, "Server deadline:", time.Until(dl))
   575  				}
   576  				<-ctx.Done()
   577  				serverCanceled <- time.Since(started)
   578  				if testing.Verbose() {
   579  					fmt.Println(GetCaller(ctx).Name, "Server Context canceled with", ctx.Err(), "after", time.Since(started))
   580  				}
   581  				return nil
   582  			},
   583  			OutCapacity: 1,
   584  			InCapacity:  1,
   585  		}))
   586  	}
   587  	register(local)
   588  	register(remote)
   589  	// Double remote DL
   590  	local.debugMsg(debugAddToDeadline, wantDL)
   591  	defer local.debugMsg(debugAddToDeadline, time.Duration(0))
   592  	remote.debugMsg(debugAddToDeadline, wantDL)
   593  	defer remote.debugMsg(debugAddToDeadline, time.Duration(0))
   594  
   595  	testHandler := func(t *testing.T, handler HandlerID) {
   596  		remoteConn := local.Connection(remoteHost)
   597  		const testPayload = "Hello Grid World!"
   598  
   599  		ctx, cancel := context.WithTimeout(context.Background(), wantDL)
   600  		defer cancel()
   601  		st, err := remoteConn.NewStream(ctx, handler, []byte(testPayload))
   602  		errFatal(err)
   603  		clientCanceled := make(chan time.Duration, 1)
   604  		go func() {
   605  			started := time.Now()
   606  			for resp := range st.responses {
   607  				err = resp.Err
   608  			}
   609  			clientCanceled <- time.Since(started)
   610  		}()
   611  		serverEnd := <-serverCanceled
   612  		clientEnd := <-clientCanceled
   613  		t.Log("server cancel time:", serverEnd)
   614  		t.Log("client cancel time:", clientEnd)
   615  		if !errors.Is(err, context.DeadlineExceeded) {
   616  			t.Error("expected context.DeadlineExceeded, got", err)
   617  		}
   618  	}
   619  	// local to remote, unbuffered
   620  	t.Run("unbuffered", func(t *testing.T) {
   621  		testHandler(t, handlerTest)
   622  	})
   623  
   624  	t.Run("buffered", func(t *testing.T) {
   625  		testHandler(t, handlerTest2)
   626  	})
   627  }
   628  
   629  func testServerOutCongestion(t *testing.T, local, remote *Manager) {
   630  	defer testlogger.T.SetErrorTB(t)()
   631  	errFatal := func(err error) {
   632  		t.Helper()
   633  		if err != nil {
   634  			t.Fatal(err)
   635  		}
   636  	}
   637  
   638  	// We fake a local and remote server.
   639  	remoteHost := remote.HostName()
   640  
   641  	// 1: Echo
   642  	serverSent := make(chan struct{})
   643  	register := func(manager *Manager) {
   644  		errFatal(manager.RegisterStreamingHandler(handlerTest, StreamHandler{
   645  			Handle: func(ctx context.Context, payload []byte, request <-chan []byte, resp chan<- []byte) *RemoteErr {
   646  				// Send many responses.
   647  				// Test that this doesn't block.
   648  				for i := byte(0); i < 100; i++ {
   649  					select {
   650  					case resp <- []byte{i}:
   651  					// ok
   652  					case <-ctx.Done():
   653  						return NewRemoteErr(ctx.Err())
   654  					}
   655  					if i == 0 {
   656  						close(serverSent)
   657  					}
   658  				}
   659  				return nil
   660  			},
   661  			OutCapacity: 1,
   662  			InCapacity:  0,
   663  		}))
   664  		errFatal(manager.RegisterSingleHandler(handlerTest2, func(payload []byte) ([]byte, *RemoteErr) {
   665  			// Simple roundtrip
   666  			return append([]byte{}, payload...), nil
   667  		}))
   668  	}
   669  	register(local)
   670  	register(remote)
   671  
   672  	remoteConn := local.Connection(remoteHost)
   673  	const testPayload = "Hello Grid World!"
   674  
   675  	ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
   676  	defer cancel()
   677  	st, err := remoteConn.NewStream(ctx, handlerTest, []byte(testPayload))
   678  	errFatal(err)
   679  
   680  	// Wait for the server to send the first response.
   681  	<-serverSent
   682  
   683  	// Now do 100 other requests to ensure that the server doesn't block.
   684  	for i := 0; i < 100; i++ {
   685  		_, err := remoteConn.Request(ctx, handlerTest2, []byte(testPayload))
   686  		errFatal(err)
   687  	}
   688  	// Drain responses
   689  	got := 0
   690  	for resp := range st.responses {
   691  		// t.Log("got response", resp)
   692  		errFatal(resp.Err)
   693  		if resp.Msg[0] != byte(got) {
   694  			t.Error("expected response", got, "got", resp.Msg[0])
   695  		}
   696  		got++
   697  	}
   698  	if got != 100 {
   699  		t.Error("expected 100 responses, got", got)
   700  	}
   701  }
   702  
   703  func testServerInCongestion(t *testing.T, local, remote *Manager) {
   704  	defer testlogger.T.SetErrorTB(t)()
   705  	errFatal := func(err error) {
   706  		t.Helper()
   707  		if err != nil {
   708  			t.Fatal(err)
   709  		}
   710  	}
   711  
   712  	// We fake a local and remote server.
   713  	remoteHost := remote.HostName()
   714  
   715  	// 1: Echo
   716  	processHandler := make(chan struct{})
   717  	register := func(manager *Manager) {
   718  		errFatal(manager.RegisterStreamingHandler(handlerTest, StreamHandler{
   719  			Handle: func(ctx context.Context, payload []byte, request <-chan []byte, resp chan<- []byte) *RemoteErr {
   720  				// Block incoming requests.
   721  				var n byte
   722  				<-processHandler
   723  				for {
   724  					select {
   725  					case in, ok := <-request:
   726  						if !ok {
   727  							return nil
   728  						}
   729  						if in[0] != n {
   730  							return NewRemoteErrString(fmt.Sprintf("expected incoming %d, got %d", n, in[0]))
   731  						}
   732  						n++
   733  						resp <- append([]byte{}, in...)
   734  					case <-ctx.Done():
   735  						return NewRemoteErr(ctx.Err())
   736  					}
   737  				}
   738  			},
   739  			OutCapacity: 5,
   740  			InCapacity:  5,
   741  		}))
   742  		errFatal(manager.RegisterSingleHandler(handlerTest2, func(payload []byte) ([]byte, *RemoteErr) {
   743  			// Simple roundtrip
   744  			return append([]byte{}, payload...), nil
   745  		}))
   746  	}
   747  	register(local)
   748  	register(remote)
   749  
   750  	remoteConn := local.Connection(remoteHost)
   751  	const testPayload = "Hello Grid World!"
   752  
   753  	ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
   754  	defer cancel()
   755  	st, err := remoteConn.NewStream(ctx, handlerTest, []byte(testPayload))
   756  	errFatal(err)
   757  
   758  	// Start sending requests.
   759  	go func() {
   760  		for i := byte(0); i < 100; i++ {
   761  			st.Requests <- []byte{i}
   762  		}
   763  		close(st.Requests)
   764  	}()
   765  	// Now do 100 other requests to ensure that the server doesn't block.
   766  	for i := 0; i < 100; i++ {
   767  		_, err := remoteConn.Request(ctx, handlerTest2, []byte(testPayload))
   768  		errFatal(err)
   769  	}
   770  	// Start processing requests.
   771  	close(processHandler)
   772  
   773  	// Drain responses
   774  	got := 0
   775  	for resp := range st.responses {
   776  		// t.Log("got response", resp)
   777  		errFatal(resp.Err)
   778  		if resp.Msg[0] != byte(got) {
   779  			t.Error("expected response", got, "got", resp.Msg[0])
   780  		}
   781  		got++
   782  	}
   783  	if got != 100 {
   784  		t.Error("expected 100 responses, got", got)
   785  	}
   786  }
   787  
   788  func testGenericsStreamRoundtrip(t *testing.T, local, remote *Manager) {
   789  	defer testlogger.T.SetErrorTB(t)()
   790  	defer timeout(5 * time.Second)()
   791  	errFatal := func(err error) {
   792  		t.Helper()
   793  		if err != nil {
   794  			t.Fatal(err)
   795  		}
   796  	}
   797  
   798  	// We fake a local and remote server.
   799  	remoteHost := remote.HostName()
   800  	handler := NewStream[*testRequest, *testRequest, *testResponse](handlerTest, newTestRequest, newTestRequest, newTestResponse)
   801  	handler.InCapacity = 1
   802  	handler.OutCapacity = 1
   803  	const payloads = 10
   804  
   805  	// 1: Echo
   806  	register := func(manager *Manager) {
   807  		errFatal(handler.Register(manager, func(ctx context.Context, pp *testRequest, in <-chan *testRequest, out chan<- *testResponse) *RemoteErr {
   808  			n := 0
   809  			for i := range in {
   810  				if n > payloads {
   811  					panic("too many requests")
   812  				}
   813  
   814  				// t.Log("Got request:", *i)
   815  				out <- &testResponse{
   816  					OrgNum:    i.Num + pp.Num,
   817  					OrgString: pp.String + i.String,
   818  					Embedded:  *i,
   819  				}
   820  				n++
   821  			}
   822  			return nil
   823  		}))
   824  	}
   825  	register(local)
   826  	register(remote)
   827  
   828  	// local to remote
   829  	remoteConn := local.Connection(remoteHost)
   830  	const testPayload = "Hello Grid World!"
   831  
   832  	start := time.Now()
   833  	stream, err := handler.Call(context.Background(), remoteConn, &testRequest{Num: 1, String: testPayload})
   834  	errFatal(err)
   835  	go func() {
   836  		defer close(stream.Requests)
   837  		for i := 0; i < payloads; i++ {
   838  			// t.Log("sending new client request")
   839  			stream.Requests <- &testRequest{Num: i, String: testPayload}
   840  		}
   841  	}()
   842  	var n int
   843  	err = stream.Results(func(resp *testResponse) error {
   844  		const wantString = testPayload + testPayload
   845  		if resp.OrgString != testPayload+testPayload {
   846  			t.Errorf("want %q, got %q", wantString, resp.OrgString)
   847  		}
   848  		if resp.OrgNum != n+1 {
   849  			t.Errorf("want %d, got %d", n+1, resp.OrgNum)
   850  		}
   851  		handler.PutResponse(resp)
   852  		n++
   853  		return nil
   854  	})
   855  	errFatal(err)
   856  	t.Log("EOF.", payloads, " Roundtrips:", time.Since(start))
   857  }
   858  
   859  func testGenericsStreamRoundtripSubroute(t *testing.T, local, remote *Manager) {
   860  	defer testlogger.T.SetErrorTB(t)()
   861  	defer timeout(5 * time.Second)()
   862  	errFatal := func(err error) {
   863  		t.Helper()
   864  		if err != nil {
   865  			t.Fatal(err)
   866  		}
   867  	}
   868  
   869  	// We fake a local and remote server.
   870  	remoteHost := remote.HostName()
   871  	handler := NewStream[*testRequest, *testRequest, *testResponse](handlerTest, newTestRequest, newTestRequest, newTestResponse)
   872  	handler.InCapacity = 1
   873  	handler.OutCapacity = 1
   874  	const payloads = 10
   875  
   876  	// 1: Echo
   877  	register := func(manager *Manager) {
   878  		errFatal(handler.Register(manager, func(ctx context.Context, pp *testRequest, in <-chan *testRequest, out chan<- *testResponse) *RemoteErr {
   879  			sub := GetSubroute(ctx)
   880  			if sub != "subroute/1" {
   881  				t.Fatal("expected subroute/1, got", sub)
   882  			}
   883  			n := 0
   884  			for i := range in {
   885  				if n > payloads {
   886  					panic("too many requests")
   887  				}
   888  
   889  				// t.Log("Got request:", *i)
   890  				out <- &testResponse{
   891  					OrgNum:    i.Num + pp.Num,
   892  					OrgString: pp.String + i.String,
   893  					Embedded:  *i,
   894  				}
   895  				n++
   896  			}
   897  			return nil
   898  		}, "subroute", "1"))
   899  	}
   900  	register(local)
   901  	register(remote)
   902  
   903  	// local to remote
   904  	remoteConn := local.Connection(remoteHost)
   905  	const testPayload = "Hello Grid World!"
   906  	// Add subroute
   907  	remoteSub := remoteConn.Subroute(strings.Join([]string{"subroute", "1"}, "/"))
   908  
   909  	start := time.Now()
   910  	stream, err := handler.Call(context.Background(), remoteSub, &testRequest{Num: 1, String: testPayload})
   911  	errFatal(err)
   912  	go func() {
   913  		defer close(stream.Requests)
   914  		for i := 0; i < payloads; i++ {
   915  			// t.Log("sending new client request")
   916  			stream.Requests <- &testRequest{Num: i, String: testPayload}
   917  		}
   918  	}()
   919  	var n int
   920  	err = stream.Results(func(resp *testResponse) error {
   921  		// t.Logf("got resp: %+v", *resp.Msg)
   922  		const wantString = testPayload + testPayload
   923  		if resp.OrgString != testPayload+testPayload {
   924  			t.Errorf("want %q, got %q", wantString, resp.OrgString)
   925  		}
   926  		if resp.OrgNum != n+1 {
   927  			t.Errorf("want %d, got %d", n+1, resp.OrgNum)
   928  		}
   929  		handler.PutResponse(resp)
   930  		n++
   931  		return nil
   932  	})
   933  
   934  	errFatal(err)
   935  	t.Log("EOF.", payloads, " Roundtrips:", time.Since(start))
   936  }
   937  
   938  // testServerStreamResponseBlocked will test if server can handle a blocked response stream
   939  func testServerStreamResponseBlocked(t *testing.T, local, remote *Manager) {
   940  	defer testlogger.T.SetErrorTB(t)()
   941  	errFatal := func(err error) {
   942  		t.Helper()
   943  		if err != nil {
   944  			t.Fatal(err)
   945  		}
   946  	}
   947  
   948  	// We fake a local and remote server.
   949  	remoteHost := remote.HostName()
   950  
   951  	// 1: Echo
   952  	serverSent := make(chan struct{})
   953  	serverCanceled := make(chan struct{})
   954  	register := func(manager *Manager) {
   955  		errFatal(manager.RegisterStreamingHandler(handlerTest, StreamHandler{
   956  			Handle: func(ctx context.Context, payload []byte, _ <-chan []byte, resp chan<- []byte) *RemoteErr {
   957  				// Send many responses.
   958  				// Test that this doesn't block.
   959  				for i := byte(0); i < 100; i++ {
   960  					select {
   961  					case resp <- []byte{i}:
   962  					// ok
   963  					case <-ctx.Done():
   964  						close(serverCanceled)
   965  						return NewRemoteErr(ctx.Err())
   966  					}
   967  					if i == 1 {
   968  						close(serverSent)
   969  					}
   970  				}
   971  				return nil
   972  			},
   973  			OutCapacity: 1,
   974  			InCapacity:  0,
   975  		}))
   976  	}
   977  	register(local)
   978  	register(remote)
   979  
   980  	remoteConn := local.Connection(remoteHost)
   981  	const testPayload = "Hello Grid World!"
   982  
   983  	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
   984  
   985  	st, err := remoteConn.NewStream(ctx, handlerTest, []byte(testPayload))
   986  	errFatal(err)
   987  
   988  	// Wait for the server to send the first response.
   989  	<-serverSent
   990  
   991  	// Read back from the stream and block.
   992  	nowBlocking := make(chan struct{})
   993  	stopBlocking := make(chan struct{})
   994  	defer close(stopBlocking)
   995  	go func() {
   996  		st.Results(func(b []byte) error {
   997  			close(nowBlocking)
   998  			// Block until test is done.
   999  			<-stopBlocking
  1000  			return nil
  1001  		})
  1002  	}()
  1003  
  1004  	<-nowBlocking
  1005  	// Wait for the receiver channel to fill.
  1006  	for len(st.responses) != cap(st.responses) {
  1007  		time.Sleep(time.Millisecond)
  1008  	}
  1009  	cancel()
  1010  	<-serverCanceled
  1011  	local.debugMsg(debugIsOutgoingClosed, st.muxID, func(closed bool) {
  1012  		if !closed {
  1013  			t.Error("expected outgoing closed")
  1014  		} else {
  1015  			t.Log("outgoing was closed")
  1016  		}
  1017  	})
  1018  
  1019  	// Drain responses and check if error propagated.
  1020  	err = st.Results(func(b []byte) error {
  1021  		return nil
  1022  	})
  1023  	if !errors.Is(err, context.Canceled) {
  1024  		t.Error("expected context.Canceled, got", err)
  1025  	}
  1026  }
  1027  
  1028  func timeout(after time.Duration) (cancel func()) {
  1029  	c := time.After(after)
  1030  	cc := make(chan struct{})
  1031  	go func() {
  1032  		select {
  1033  		case <-cc:
  1034  			return
  1035  		case <-c:
  1036  			buf := make([]byte, 1<<20)
  1037  			stacklen := runtime.Stack(buf, true)
  1038  			fmt.Printf("=== Timeout, assuming deadlock ===\n*** goroutine dump...\n%s\n*** end\n", string(buf[:stacklen]))
  1039  			os.Exit(2)
  1040  		}
  1041  	}()
  1042  	return func() {
  1043  		close(cc)
  1044  	}
  1045  }
  1046  
  1047  func assertNoActive(t *testing.T, c *Connection) {
  1048  	t.Helper()
  1049  	// Tiny bit racy for tests, but we try to play nice.
  1050  	for i := 10; i >= 0; i-- {
  1051  		runtime.Gosched()
  1052  		stats := c.Stats()
  1053  		if stats.IncomingStreams != 0 {
  1054  			if i > 0 {
  1055  				time.Sleep(100 * time.Millisecond)
  1056  				continue
  1057  			}
  1058  			var found []uint64
  1059  			c.inStream.Range(func(key uint64, value *muxServer) bool {
  1060  				found = append(found, key)
  1061  				return true
  1062  			})
  1063  			t.Errorf("expected no active streams, got %d incoming: %v", stats.IncomingStreams, found)
  1064  		}
  1065  		if stats.OutgoingStreams != 0 {
  1066  			if i > 0 {
  1067  				time.Sleep(100 * time.Millisecond)
  1068  				continue
  1069  			}
  1070  			var found []uint64
  1071  			c.outgoing.Range(func(key uint64, value *muxClient) bool {
  1072  				found = append(found, key)
  1073  				return true
  1074  			})
  1075  			t.Errorf("expected no active streams, got %d outgoing: %v", stats.OutgoingStreams, found)
  1076  		}
  1077  		return
  1078  	}
  1079  }
  1080  
  1081  // Inserted manually.
  1082  func _() {
  1083  	// An "invalid array index" compiler error signifies that the constant values have changed.
  1084  	// Re-run the stringer command to generate them again.
  1085  	var x [1]struct{}
  1086  	_ = x[StateUnconnected-0]
  1087  	_ = x[StateConnecting-1]
  1088  	_ = x[StateConnected-2]
  1089  	_ = x[StateConnectionError-3]
  1090  	_ = x[StateShutdown-4]
  1091  }
  1092  
  1093  const stateName = "UnconnectedConnectingConnectedConnectionErrorShutdown"
  1094  
  1095  var stateIndex = [...]uint8{0, 11, 21, 30, 45, 53}
  1096  
  1097  func (i State) String() string {
  1098  	if i >= State(len(stateIndex)-1) {
  1099  		return "State(" + strconv.FormatInt(int64(i), 10) + ")"
  1100  	}
  1101  	return stateName[stateIndex[i]:stateIndex[i+1]]
  1102  }