github.com/cmd-stream/base-go@v0.0.0-20230813145615-dd6ac24c16f5/client/client_test.go (about)

     1  package client
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net"
     7  	"sync"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/cmd-stream/base-go"
    12  	"github.com/cmd-stream/base-go/testdata/mock"
    13  	"github.com/ymz-ncnk/mok"
    14  )
    15  
    16  const Delta = 100 * time.Millisecond
    17  
    18  func TestClient(t *testing.T) {
    19  
    20  	t.Run("We should be able to send cmd and receive several results",
    21  		func(t *testing.T) {
    22  			var (
    23  				wantSeq     base.Seq = 1
    24  				wantCmd              = mock.NewCmd()
    25  				wantResult1          = mock.NewResult().RegisterLastOne(
    26  					func() (lastOne bool) { return false },
    27  				)
    28  				wantResult2 = mock.NewResult().RegisterLastOne(
    29  					func() (lastOne bool) { return true },
    30  				)
    31  				delegate = func() (delegate mock.ClientDelegate) {
    32  					receive := make(chan struct{})
    33  					delegate = mock.NewClientDelegate().RegisterSend(
    34  						func(seq base.Seq, cmd base.Cmd[any]) (err error) {
    35  							defer close(receive)
    36  							if seq != wantSeq {
    37  								return fmt.Errorf("unexpected seq, want '%v' actual '%v'",
    38  									wantSeq,
    39  									seq)
    40  							}
    41  							if cmd != wantCmd {
    42  								return fmt.Errorf("unexpected cmd, want '%v' actual '%v'",
    43  									wantCmd,
    44  									cmd)
    45  							}
    46  							return
    47  						},
    48  					).RegisterFlush(func() (err error) {
    49  						return nil
    50  					}).RegisterReceive(
    51  						func() (seq base.Seq, result base.Result, err error) {
    52  							<-receive
    53  							return wantSeq, wantResult1, nil
    54  						},
    55  					).RegisterReceive(
    56  						func() (seq base.Seq, result base.Result, err error) {
    57  							return wantSeq, wantResult2, nil
    58  						},
    59  					).RegisterReceive(
    60  						func() (seq base.Seq, result base.Result, err error) {
    61  							err = errors.New("done error")
    62  							return
    63  						},
    64  					).RegisterClose(
    65  						func() (err error) { return nil },
    66  					)
    67  					return
    68  				}()
    69  				mocks = []*mok.Mock{wantCmd.Mock, wantResult1.Mock, wantResult2.Mock,
    70  					delegate.Mock}
    71  				client  = New[any](delegate, nil)
    72  				results = make(chan base.AsyncResult, 2)
    73  			)
    74  			seq, err := client.Send(wantCmd, results)
    75  			if err != nil {
    76  				t.Errorf("unexpected error, watn '%v' actual %v", nil, err)
    77  			}
    78  			if seq != wantSeq {
    79  				t.Errorf("unexpected seq, want '%v' actual '%v'", wantSeq, seq)
    80  			}
    81  			if !client.Has(seq) {
    82  				t.Error("cmd was not memorized")
    83  			}
    84  			result1 := <-results
    85  			if result1.Result != wantResult1 {
    86  				t.Errorf("unexpected result, want '%v' actual '%v'", wantResult1,
    87  					result1)
    88  			}
    89  			result2 := <-results
    90  			if result2.Result != wantResult2 {
    91  				t.Errorf("unexpected result, want '%v' actual '%v'", wantResult2,
    92  					result2.Result)
    93  			}
    94  			if infomap := mok.CheckCalls(mocks); len(infomap) > 0 {
    95  				t.Error(infomap)
    96  			}
    97  		})
    98  
    99  	t.Run("When the client receives the last one result it should forget cmd",
   100  		func(t *testing.T) {
   101  			var (
   102  				done        = make(chan struct{})
   103  				wantCmd     = mock.NewCmd()
   104  				wantResult1 = mock.NewResult().RegisterLastOne(
   105  					func() (lastOne bool) { return true },
   106  				)
   107  				wantResult2 = mock.NewResult().RegisterLastOne(
   108  					func() (lastOne bool) { return true },
   109  				)
   110  				delegate = func() (delegate mock.ClientDelegate) {
   111  					receive := make(chan struct{})
   112  					delegate = mock.NewClientDelegate().RegisterSend(
   113  						func(seq base.Seq, cmd base.Cmd[any]) (err error) {
   114  							defer close(receive)
   115  							return
   116  						},
   117  					).RegisterFlush(
   118  						func() (err error) { return nil },
   119  					).RegisterReceive(
   120  						func() (seq base.Seq, result base.Result, err error) {
   121  							<-receive
   122  							return 1, wantResult1, nil
   123  						},
   124  					).RegisterReceive(
   125  						func() (seq base.Seq, result base.Result, err error) {
   126  							return 1, wantResult2, nil
   127  						},
   128  					).RegisterReceive(
   129  						func() (seq base.Seq, result base.Result, err error) {
   130  							err = errors.New("done error")
   131  							return
   132  						},
   133  					).RegisterClose(
   134  						func() (err error) { return nil },
   135  					)
   136  					return
   137  				}()
   138  				mocks = []*mok.Mock{wantCmd.Mock, wantResult1.Mock, wantResult2.Mock,
   139  					delegate.Mock}
   140  				callback = func(seq base.Seq, result base.Result) {
   141  					if result != wantResult2 {
   142  						t.Errorf("unexpected result, want '%v' actual '%v'", wantResult2,
   143  							result)
   144  					}
   145  					close(done)
   146  				}
   147  				client  = New[any](delegate, callback)
   148  				results = make(chan base.AsyncResult, 1)
   149  			)
   150  			client.Send(wantCmd, results)
   151  			waitDone(done, t)
   152  			if infomap := mok.CheckCalls(mocks); len(infomap) > 0 {
   153  				t.Error(infomap)
   154  			}
   155  		})
   156  
   157  	t.Run("Send should increment seq", func(t *testing.T) {
   158  		var (
   159  			done              = make(chan struct{})
   160  			wantSeq1 base.Seq = 1
   161  			wantSeq2 base.Seq = 2
   162  			wantCmd1          = mock.NewCmd()
   163  			wantCmd2          = mock.NewCmd()
   164  			delegate          = func() (delegate mock.ClientDelegate) {
   165  				receive := make(chan struct{})
   166  				delegate = mock.NewClientDelegate().RegisterSend(
   167  					func(seq base.Seq, cmd base.Cmd[any]) (err error) {
   168  						if seq != wantSeq1 {
   169  							t.Errorf("unexpected seq, want '%v' actual '%v'", wantSeq1, seq)
   170  						}
   171  						if cmd != wantCmd1 {
   172  							t.Errorf("unexpected cmd, want '%v' actual '%v'", wantCmd1, cmd)
   173  						}
   174  						return
   175  					},
   176  				).RegisterFlush(
   177  					func() (err error) { return nil },
   178  				).RegisterSend(
   179  					func(seq base.Seq, cmd base.Cmd[any]) (err error) {
   180  						defer close(receive)
   181  						if seq != wantSeq2 {
   182  							t.Errorf("unexpected seq, want '%v' actual '%v'", wantSeq1, seq)
   183  						}
   184  						if cmd != wantCmd2 {
   185  							t.Errorf("unexpected cmd, want '%v' actual '%v'", wantCmd2, cmd)
   186  						}
   187  						return
   188  					},
   189  				).RegisterReceive(
   190  					func() (seq base.Seq, result base.Result, err error) {
   191  						defer close(done)
   192  						<-receive
   193  						err = errors.New("done error")
   194  						return
   195  					},
   196  				).RegisterFlush(
   197  					func() (err error) { return nil },
   198  				).RegisterClose(
   199  					func() (err error) { return nil },
   200  				)
   201  				return
   202  			}()
   203  			mocks  = []*mok.Mock{wantCmd1.Mock, wantCmd2.Mock, delegate.Mock}
   204  			client = New[any](delegate, nil)
   205  		)
   206  		seq, _ := client.Send(wantCmd1, nil)
   207  		if seq != wantSeq1 {
   208  			t.Errorf("unexpected seq, want '%v' actual '%v'", wantSeq1, seq)
   209  		}
   210  		seq, _ = client.Send(wantCmd2, nil)
   211  		if seq != wantSeq2 {
   212  			t.Errorf("unexpected seq, want '%v' actual '%v'", wantSeq2, seq)
   213  		}
   214  		waitDone(done, t)
   215  		if infomap := mok.CheckCalls(mocks); len(infomap) > 0 {
   216  			t.Error(infomap)
   217  		}
   218  	})
   219  
   220  	t.Run("Send should memorize cmd", func(t *testing.T) {
   221  		var (
   222  			done     = make(chan struct{})
   223  			delegate = mock.NewClientDelegate().RegisterSend(
   224  				func(seq base.Seq, cmd base.Cmd[any]) (err error) {
   225  					return nil
   226  				},
   227  			).RegisterFlush(
   228  				func() (err error) { return nil },
   229  			).RegisterReceive(
   230  				func() (seq base.Seq, result base.Result, err error) {
   231  					defer close(done)
   232  					err = errors.New("Delegate.Receive error")
   233  					return
   234  				},
   235  			).RegisterClose(
   236  				func() (err error) { return nil },
   237  			)
   238  			mocks  = []*mok.Mock{delegate.Mock}
   239  			client = New[any](delegate, nil)
   240  		)
   241  		seq, _ := client.Send(nil, nil)
   242  		if !client.Has(seq) {
   243  			t.Error("cmd was not memorized")
   244  		}
   245  		waitDone(done, t)
   246  		if infomap := mok.CheckCalls(mocks); len(infomap) > 0 {
   247  			t.Error(infomap)
   248  		}
   249  	})
   250  
   251  	t.Run("Seq should be incremented even if Send fails", func(t *testing.T) {
   252  		var (
   253  			done              = make(chan struct{})
   254  			wantSeq  base.Seq = 1
   255  			wantErr           = errors.New("Delegate.Send error")
   256  			delegate          = mock.NewClientDelegate().RegisterSend(
   257  				func(seq base.Seq, cmd base.Cmd[any]) (err error) {
   258  					return wantErr
   259  				},
   260  			).RegisterReceive(
   261  				func() (seq base.Seq, result base.Result, err error) {
   262  					defer close(done)
   263  					err = errors.New("Delegate.Receive error")
   264  					return
   265  				},
   266  			).RegisterClose(
   267  				func() (err error) { return nil },
   268  			)
   269  			mocks  = []*mok.Mock{delegate.Mock}
   270  			client = New[any](delegate, nil)
   271  		)
   272  		seq, err := client.Send(nil, nil)
   273  		if err != wantErr {
   274  			t.Errorf("unexpected err, want '%v' actual '%v'", wantErr, err)
   275  		}
   276  		if seq != wantSeq {
   277  			t.Errorf("unexpected seq, want '%v' actual '%v'", wantSeq, seq)
   278  		}
   279  		waitDone(done, t)
   280  		if infomap := mok.CheckCalls(mocks); len(infomap) > 0 {
   281  			t.Error(infomap)
   282  		}
   283  	})
   284  
   285  	t.Run("If Send fails cmd should be forgotten", func(t *testing.T) {
   286  		var (
   287  			done     = make(chan struct{})
   288  			delegate = mock.NewClientDelegate().RegisterSend(
   289  				func(seq base.Seq, cmd base.Cmd[any]) (err error) {
   290  					return errors.New("Delegate.Send error")
   291  				},
   292  			).RegisterReceive(
   293  				func() (seq base.Seq, result base.Result, err error) {
   294  					defer close(done)
   295  					err = errors.New("Delegate.Receive error")
   296  					return
   297  				},
   298  			).RegisterClose(
   299  				func() (err error) { return nil },
   300  			)
   301  			mocks  = []*mok.Mock{delegate.Mock}
   302  			client = New[any](delegate, nil)
   303  		)
   304  		seq, _ := client.Send(nil, nil)
   305  		if client.Has(seq) {
   306  			t.Error("cmd was not forgotten")
   307  		}
   308  		waitDone(done, t)
   309  		if infomap := mok.CheckCalls(mocks); len(infomap) > 0 {
   310  			t.Error(infomap)
   311  		}
   312  	})
   313  
   314  	t.Run("We should be able to send cmd by SendWithDeadline", func(t *testing.T) {
   315  		var (
   316  			done                  = make(chan struct{})
   317  			wantSeq      base.Seq = 1
   318  			wantDeadline          = time.Now()
   319  			wantCmd               = mock.NewCmd()
   320  			delegate              = func() (delegate mock.ClientDelegate) {
   321  				receive := make(chan struct{})
   322  				delegate = mock.NewClientDelegate().RegisterSetSendDeadline(
   323  					func(deadline time.Time) (err error) {
   324  						if !SameTime(deadline, wantDeadline) {
   325  							return fmt.Errorf("unexpected deadline, want '%v' actual '%v'",
   326  								wantDeadline,
   327  								deadline)
   328  						}
   329  						return nil
   330  					},
   331  				).RegisterSend(
   332  					func(seq base.Seq, cmd base.Cmd[any]) (err error) {
   333  						defer close(receive)
   334  						if seq != wantSeq {
   335  							t.Errorf("unexpected seq, want '%v' actual '%v'", wantSeq, seq)
   336  						}
   337  						if cmd != wantCmd {
   338  							t.Errorf("unexpected cmd, want '%v' actual '%v'", wantCmd, cmd)
   339  						}
   340  						return
   341  					},
   342  				).RegisterFlush(
   343  					func() (err error) { return nil },
   344  				).RegisterReceive(
   345  					func() (seq base.Seq, result base.Result, err error) {
   346  						defer close(done)
   347  						<-receive
   348  						err = errors.New("done error")
   349  						return
   350  					},
   351  				).RegisterClose(
   352  					func() (err error) { return nil },
   353  				)
   354  				return
   355  			}()
   356  			mocks  = []*mok.Mock{wantCmd.Mock, delegate.Mock}
   357  			client = New[any](delegate, nil)
   358  		)
   359  		seq, err := client.SendWithDeadline(wantDeadline, wantCmd, nil)
   360  		if err != nil {
   361  			t.Errorf("unexpected error, want '%v' actual '%v'", nil, err)
   362  		}
   363  		if seq != wantSeq {
   364  			t.Errorf("unexpected seq, want '%v' actual '%v'", wantSeq, seq)
   365  		}
   366  		if !client.Has(seq) {
   367  			t.Error("cmd was not memorized")
   368  		}
   369  		waitDone(done, t)
   370  		if infomap := mok.CheckCalls(mocks); len(infomap) > 0 {
   371  			t.Error(infomap)
   372  		}
   373  	})
   374  
   375  	t.Run("Seq should be incremented even if SendWithDeadline fails",
   376  		func(t *testing.T) {
   377  			var (
   378  				done              = make(chan struct{})
   379  				wantSeq  base.Seq = 1
   380  				wantErr           = errors.New("Delegate.Send error")
   381  				delegate          = mock.NewClientDelegate().RegisterSetSendDeadline(
   382  					func(deadline time.Time) (err error) {
   383  						return wantErr
   384  					},
   385  				).RegisterReceive(
   386  					func() (seq base.Seq, result base.Result, err error) {
   387  						defer close(done)
   388  						err = errors.New("Delegate.Receive error")
   389  						return
   390  					},
   391  				).RegisterClose(
   392  					func() (err error) { return nil },
   393  				)
   394  				mocks  = []*mok.Mock{delegate.Mock}
   395  				client = New[any](delegate, nil)
   396  			)
   397  			seq, err := client.SendWithDeadline(time.Time{}, nil, nil)
   398  			if err != wantErr {
   399  				t.Errorf("unexpected err, want '%v' actual '%v'", wantErr, err)
   400  			}
   401  			if seq != wantSeq {
   402  				t.Errorf("unexpected seq, want '%v' actual '%v'", wantSeq, seq)
   403  			}
   404  			waitDone(done, t)
   405  			if infomap := mok.CheckCalls(mocks); len(infomap) > 0 {
   406  				t.Error(infomap)
   407  			}
   408  		})
   409  
   410  	t.Run("If Delegate.SetSendDeadline fails with an error, SendWithDeadline should return it",
   411  		func(t *testing.T) {
   412  			var (
   413  				done     = make(chan struct{})
   414  				wantErr  = errors.New("Delegate.SetSendDeadline error")
   415  				delegate = mock.NewClientDelegate().RegisterSetSendDeadline(
   416  					func(deadline time.Time) (err error) {
   417  						return wantErr
   418  					},
   419  				).RegisterReceive(
   420  					func() (seq base.Seq, result base.Result, err error) {
   421  						defer close(done)
   422  						err = errors.New("Delegate.Receive error")
   423  						return
   424  					},
   425  				).RegisterClose(
   426  					func() (err error) { return nil },
   427  				)
   428  				mocks  = []*mok.Mock{delegate.Mock}
   429  				client = New[any](delegate, nil)
   430  			)
   431  			_, err := client.SendWithDeadline(time.Time{}, nil, nil)
   432  			if err != wantErr {
   433  				t.Errorf("unexpected error, want '%v' actual '%v'", nil, err)
   434  			}
   435  			waitDone(done, t)
   436  			if infomap := mok.CheckCalls(mocks); len(infomap) > 0 {
   437  				t.Error(infomap)
   438  			}
   439  		})
   440  
   441  	t.Run("If Delegate.Send fails with an error, SendWithDeadline should return it",
   442  		func(t *testing.T) {
   443  			var (
   444  				done     = make(chan struct{})
   445  				wantErr  = errors.New("Delegate.Send error")
   446  				delegate = mock.NewClientDelegate().RegisterSetSendDeadline(
   447  					func(deadline time.Time) (err error) {
   448  						return nil
   449  					},
   450  				).RegisterSend(
   451  					func(seq base.Seq, cmd base.Cmd[any]) (err error) {
   452  						return wantErr
   453  					},
   454  				).RegisterReceive(
   455  					func() (seq base.Seq, result base.Result, err error) {
   456  						defer close(done)
   457  						err = errors.New("Delegate.Receive error")
   458  						return
   459  					},
   460  				).RegisterClose(
   461  					func() (err error) { return nil },
   462  				)
   463  				mocks  = []*mok.Mock{delegate.Mock}
   464  				client = New[any](delegate, nil)
   465  			)
   466  			_, err := client.SendWithDeadline(time.Time{}, nil, nil)
   467  			if err != wantErr {
   468  				t.Errorf("unexpected error, want '%v' actual '%v'", nil, err)
   469  			}
   470  			waitDone(done, t)
   471  			if infomap := mok.CheckCalls(mocks); len(infomap) > 0 {
   472  				t.Error(infomap)
   473  			}
   474  		})
   475  
   476  	t.Run("Client should forget cmd, if SendWithDeadline failed, because of Delegate.SetSendDeadline",
   477  		func(t *testing.T) {
   478  			var (
   479  				done     = make(chan struct{})
   480  				delegate = mock.NewClientDelegate().RegisterSetSendDeadline(
   481  					func(deadline time.Time) (err error) {
   482  						return errors.New("Delegate.SetSendDeadline error")
   483  					},
   484  				).RegisterReceive(
   485  					func() (seq base.Seq, result base.Result, err error) {
   486  						defer close(done)
   487  						err = errors.New("Delegate.Receive error")
   488  						return
   489  					},
   490  				).RegisterClose(
   491  					func() (err error) { return nil },
   492  				)
   493  				mocks  = []*mok.Mock{delegate.Mock}
   494  				client = New[any](delegate, nil)
   495  			)
   496  			seq, _ := client.SendWithDeadline(time.Time{}, nil, nil)
   497  			if client.Has(seq) {
   498  				t.Error("cmd was not forgotten")
   499  			}
   500  			waitDone(done, t)
   501  			if infomap := mok.CheckCalls(mocks); len(infomap) > 0 {
   502  				t.Error(infomap)
   503  			}
   504  		})
   505  
   506  	t.Run("Client should forget cmd, if SendWithDeadline failed, because of Delegate.Send",
   507  		func(t *testing.T) {
   508  			var (
   509  				done     = make(chan struct{})
   510  				delegate = mock.NewClientDelegate().RegisterSetSendDeadline(
   511  					func(deadline time.Time) (err error) {
   512  						return nil
   513  					},
   514  				).RegisterSend(
   515  					func(seq base.Seq, cmd base.Cmd[any]) (err error) {
   516  						return errors.New("Delegate.Send error")
   517  					},
   518  				).RegisterReceive(
   519  					func() (seq base.Seq, result base.Result, err error) {
   520  						defer close(done)
   521  						err = errors.New("Delegate.Receive error")
   522  						return
   523  					},
   524  				).RegisterClose(
   525  					func() (err error) { return nil },
   526  				)
   527  				mocks  = []*mok.Mock{delegate.Mock}
   528  				client = New[any](delegate, nil)
   529  			)
   530  			seq, _ := client.SendWithDeadline(time.Time{}, nil, nil)
   531  			if client.Has(seq) {
   532  				t.Error("cmd was not forgotten")
   533  			}
   534  			waitDone(done, t)
   535  			if infomap := mok.CheckCalls(mocks); len(infomap) > 0 {
   536  				t.Error(infomap)
   537  			}
   538  		})
   539  
   540  	t.Run("We should be able to forget cmd", func(t *testing.T) {
   541  		var (
   542  			done     = make(chan struct{})
   543  			cmd      = mock.NewCmd()
   544  			delegate = mock.NewClientDelegate().RegisterSend(
   545  				func(seq base.Seq, cmd base.Cmd[any]) (err error) {
   546  					return nil
   547  				},
   548  			).RegisterFlush(
   549  				func() (err error) { return nil },
   550  			).RegisterReceive(
   551  				func() (seq base.Seq, result base.Result, err error) {
   552  					defer close(done)
   553  					err = errors.New("Delegate.Receive error")
   554  					return
   555  				},
   556  			).RegisterClose(
   557  				func() (err error) { return nil },
   558  			)
   559  			mocks  = []*mok.Mock{cmd.Mock, delegate.Mock}
   560  			client = New[any](delegate, nil)
   561  		)
   562  		seq, _ := client.Send(cmd, nil)
   563  		client.Forget(seq)
   564  		if client.Has(seq) {
   565  			t.Error("cmd was not forgotten")
   566  		}
   567  		waitDone(done, t)
   568  		if infomap := mok.CheckCalls(mocks); len(infomap) > 0 {
   569  			t.Error(infomap)
   570  		}
   571  	})
   572  
   573  	t.Run("If the client was closed or failed to receive a next result, Done channel should be closed and Err method should return the cause",
   574  		func(t *testing.T) {
   575  			var (
   576  				done     = make(chan struct{})
   577  				wantErr  = errors.New("Delegate.Receive error")
   578  				delegate = mock.NewClientDelegate().RegisterReceive(
   579  					func() (seq base.Seq, result base.Result, err error) {
   580  						err = wantErr
   581  						return
   582  					},
   583  				).RegisterClose(
   584  					func() (err error) { return nil },
   585  				)
   586  				mocks  = []*mok.Mock{delegate.Mock}
   587  				client = New[any](delegate, nil)
   588  			)
   589  			<-client.Done()
   590  			go func() {
   591  				defer close(done)
   592  				err := client.Err()
   593  				if err != wantErr {
   594  					t.Errorf("unexpected error, want '%v' actual '%v'", nil, err)
   595  				}
   596  			}()
   597  			waitDone(done, t)
   598  			if infomap := mok.CheckCalls(mocks); len(infomap) > 0 {
   599  				t.Error(infomap)
   600  			}
   601  		})
   602  
   603  	t.Run("We should be able to close the client while it queues a result",
   604  		func(t *testing.T) {
   605  			var (
   606  				done       = make(chan struct{})
   607  				wantCmd    = mock.NewCmd()
   608  				wantResult = mock.NewResult().RegisterLastOne(
   609  					func() (lastOne bool) { return true },
   610  				)
   611  				results  = make(chan base.AsyncResult)
   612  				delegate = mock.NewClientDelegate().RegisterSend(
   613  					func(seq base.Seq, cmd base.Cmd[any]) (err error) {
   614  						return errors.New("Delegate.Send error")
   615  					},
   616  				).RegisterReceive(
   617  					func() (seq base.Seq, result base.Result, err error) {
   618  						return 1, wantResult, nil
   619  					},
   620  				).RegisterClose(
   621  					func() (err error) {
   622  						defer close(done)
   623  						return nil
   624  					},
   625  				)
   626  				mocks  = []*mok.Mock{wantCmd.Mock, wantResult.Mock, delegate.Mock}
   627  				client = New[any](delegate, nil)
   628  			)
   629  			client.Send(wantCmd, results)
   630  			time.Sleep(100 * time.Millisecond)
   631  			client.Close()
   632  			<-client.Done()
   633  			err := client.Err()
   634  			if err != ErrClosed {
   635  				t.Errorf("unexpected error, want '%v' actual '%v'", ErrClosed, err)
   636  			}
   637  			waitDone(done, t)
   638  			if infomap := mok.CheckCalls(mocks); len(infomap) > 0 {
   639  				t.Error(infomap)
   640  			}
   641  		})
   642  
   643  	t.Run("If Delegate.Close fails with an error, Close should return it",
   644  		func(t *testing.T) {
   645  			var (
   646  				done        = make(chan struct{})
   647  				receiveDone = make(chan struct{})
   648  				wantErr     = errors.New("Delegate.Close error")
   649  				delegate    = mock.NewClientDelegate().RegisterReceive(
   650  					func() (seq base.Seq, result base.Result, err error) {
   651  						<-receiveDone
   652  						err = errors.New("Delegate.Receive error")
   653  						return
   654  					},
   655  				).RegisterClose(
   656  					func() (err error) {
   657  						defer close(receiveDone)
   658  						return wantErr
   659  					},
   660  				).RegisterClose(
   661  					func() (err error) { defer close(done); return nil },
   662  				)
   663  				mocks  = []*mok.Mock{delegate.Mock}
   664  				client = New[any](delegate, nil)
   665  			)
   666  			time.Sleep(100 * time.Millisecond)
   667  			err := client.Close()
   668  			if err != wantErr {
   669  				t.Errorf("unexpected error, want '%v' actual '%v'", nil, err)
   670  			}
   671  			waitDone(done, t)
   672  			if infomap := mok.CheckCalls(mocks); len(infomap) > 0 {
   673  				t.Error(infomap)
   674  			}
   675  		})
   676  
   677  	t.Run("If Delegate.Flush fails with an error, Send of all involved commands should return error",
   678  		func(t *testing.T) {
   679  			var (
   680  				wantErr  = errors.New("flush error")
   681  				done     = make(chan struct{})
   682  				cmd1     = mock.NewCmd()
   683  				cmd2     = mock.NewCmd()
   684  				cmd3     = mock.NewCmd()
   685  				delegate = mock.NewClientDelegate().RegisterNSend(3,
   686  					func(seq base.Seq, cmd base.Cmd[any]) (err error) {
   687  						return nil
   688  					},
   689  				).RegisterNFlush(3,
   690  					func() (err error) { return wantErr },
   691  				).RegisterReceive(
   692  					func() (seq base.Seq, result base.Result, err error) {
   693  						<-done
   694  						err = errors.New("receive error")
   695  						return
   696  					},
   697  				).RegisterClose(
   698  					func() (err error) { return nil },
   699  				)
   700  				wg = &sync.WaitGroup{}
   701  				// mocks  = []*mok.Mock{delegate.Mock}
   702  				client = New[any](delegate, nil)
   703  			)
   704  			wg.Add(1)
   705  			go func() {
   706  				defer wg.Done()
   707  				_, err := client.Send(cmd1, nil)
   708  				if err != wantErr {
   709  					t.Errorf("unexpected error, want '%v' actual '%v'", wantErr, err)
   710  				}
   711  			}()
   712  			wg.Add(1)
   713  			go func() {
   714  				defer wg.Done()
   715  				_, err := client.Send(cmd2, nil)
   716  				if err != wantErr {
   717  					t.Errorf("unexpected error, want '%v' actual '%v'", wantErr, err)
   718  				}
   719  			}()
   720  			wg.Add(1)
   721  			go func() {
   722  				defer wg.Done()
   723  				_, err := client.Send(cmd3, nil)
   724  				if err != wantErr {
   725  					t.Errorf("unexpected error, want '%v' actual '%v'", wantErr, err)
   726  				}
   727  			}()
   728  			wg.Wait()
   729  			close(done)
   730  			// Commented out, because we do not know the actual count of the
   731  			// Delegate.Flush() method calls.
   732  			//
   733  			// If we want the flush method to be called only once, we should put
   734  			// time.Sleep(200*time.Milisecond) before the flush method acquires a
   735  			// lock.
   736  			//
   737  			// if infomap := mok.CheckCalls(mocks); len(infomap) > 0 {
   738  			// 	t.Error(infomap)
   739  			// }
   740  		})
   741  
   742  	t.Run("If the client has lost a connection it should try to reconnect",
   743  		func(t *testing.T) {
   744  			var (
   745  				reconected = make(chan struct{})
   746  				delegate   = func() (delegate mock.ReconnectClientDelegate) {
   747  					done := make(chan struct{})
   748  					delegate = mock.NewReconnectClientDelegate().RegisterReceive(
   749  						func() (seq base.Seq, result base.Result, err error) {
   750  							err = net.ErrClosed
   751  							return
   752  						},
   753  					).RegisterReconnect(
   754  						func() error { close(reconected); return nil },
   755  					).RegisterReceive(
   756  						func() (seq base.Seq, result base.Result, err error) {
   757  							<-done
   758  							err = errors.New("closed")
   759  							return
   760  						},
   761  					).RegisterClose(
   762  						func() (err error) { close(done); return nil },
   763  					)
   764  					return
   765  				}()
   766  				mocks  = []*mok.Mock{delegate.Mock}
   767  				client = New[any](delegate, nil)
   768  			)
   769  			<-reconected
   770  			if err := client.Close(); err != nil {
   771  				t.Errorf("unexpected error, want '%v' actual '%v'", nil, err)
   772  			}
   773  			<-client.Done()
   774  			if infomap := mok.CheckCalls(mocks); len(infomap) > 0 {
   775  				t.Error(infomap)
   776  			}
   777  		})
   778  
   779  	t.Run("If the client is closed it should not reconnect", func(t *testing.T) {
   780  		var (
   781  			delegate = func() (delegate mock.ReconnectClientDelegate) {
   782  				done := make(chan struct{})
   783  				delegate = mock.NewReconnectClientDelegate().RegisterReceive(
   784  					func() (seq base.Seq, result base.Result, err error) {
   785  						<-done
   786  						err = errors.New("receive error")
   787  						return
   788  					},
   789  				).RegisterClose(
   790  					func() (err error) { close(done); return nil },
   791  				)
   792  				return
   793  			}()
   794  			mocks  = []*mok.Mock{delegate.Mock}
   795  			client = New[any](delegate, nil)
   796  		)
   797  		if err := client.Close(); err != nil {
   798  			t.Errorf("unexpected error, want '%v' actual '%v'", nil, err)
   799  		}
   800  		<-client.Done()
   801  		if infomap := mok.CheckCalls(mocks); len(infomap) > 0 {
   802  			t.Error(infomap)
   803  		}
   804  	})
   805  
   806  	t.Run("If reconnection fails with an error, it should became the client error",
   807  		func(t *testing.T) {
   808  			var (
   809  				wantErr  = errors.New("reconnection error")
   810  				delegate = func() (delegate mock.ReconnectClientDelegate) {
   811  					delegate = mock.NewReconnectClientDelegate().RegisterReceive(
   812  						func() (seq base.Seq, result base.Result, err error) {
   813  							err = net.ErrClosed
   814  							return
   815  						},
   816  					).RegisterReconnect(
   817  						func() error { return wantErr },
   818  					).RegisterClose(
   819  						func() (err error) { return nil },
   820  					)
   821  					return
   822  				}()
   823  				mocks  = []*mok.Mock{delegate.Mock}
   824  				client = New[any](delegate, nil)
   825  			)
   826  			<-client.Done()
   827  			err := client.Err()
   828  			if err != wantErr {
   829  				t.Errorf("unexpected error, want '%v' actual '%v'", wantErr, err)
   830  			}
   831  			if infomap := mok.CheckCalls(mocks); len(infomap) > 0 {
   832  				t.Error(infomap)
   833  			}
   834  		})
   835  
   836  }
   837  
   838  func SameTime(t1, t2 time.Time) bool {
   839  	return !(t1.Before(t2.Truncate(Delta)) || t1.After(t2.Add(Delta)))
   840  }
   841  
   842  func waitDone(done chan struct{}, t *testing.T) {
   843  	select {
   844  	case <-done:
   845  	case <-time.NewTimer(time.Second).C:
   846  		t.Fatal("test lasts too long")
   847  	}
   848  }