package notify import ( "context" "errors" "net" "testing" ) func TestReconnectClientRejectsDirectConnSource(t *testing.T) { client := NewClient().(*ClientCommon) secret := []byte("0123456789abcdef0123456789abcdef") left, right := net.Pipe() defer left.Close() defer right.Close() server := newRunningPeerAttachServerForTest(t, func(server *ServerCommon) { server.SetSecretKey(secret) }) bootstrapPeerAttachConnForTest(t, server, right) client.SetSecretKey(secret) if err := client.ConnectByConn(left); err != nil { t.Fatalf("ConnectByConn failed: %v", err) } client.setByeFromServer(true) if err := client.Stop(); err != nil { t.Fatalf("Stop failed: %v", err) } err := ReconnectClient(context.Background(), client) if !errors.Is(err, errClientReconnectSourceUnavailable) { t.Fatalf("ReconnectClient error = %v, want %v", err, errClientReconnectSourceUnavailable) } } func TestReconnectClientWithFactorySource(t *testing.T) { client := NewClient().(*ClientCommon) secret := []byte("0123456789abcdef0123456789abcdef") client.SetSecretKey(secret) server := newRunningPeerAttachServerForTest(t, func(server *ServerCommon) { server.SetSecretKey(secret) }) dialCount := 0 var peers []net.Conn dialFn := func(context.Context) (net.Conn, error) { dialCount++ left, right := net.Pipe() peers = append(peers, right) bootstrapPeerAttachConnForTest(t, server, right) return left, nil } if err := client.ConnectByFactory(context.Background(), dialFn); err != nil { t.Fatalf("ConnectByFactory failed: %v", err) } client.setByeFromServer(true) if err := client.Stop(); err != nil { t.Fatalf("Stop failed: %v", err) } before, err := GetClientRuntimeSnapshot(client) if err != nil { t.Fatalf("GetClientRuntimeSnapshot before reconnect failed: %v", err) } if !before.CanReconnect || before.ConnectSource != clientConnectSourceFactory { t.Fatalf("unexpected reconnect snapshot before reconnect: %+v", before) } if err := ReconnectClient(context.Background(), client); err != nil { t.Fatalf("ReconnectClient failed: %v", err) } after, err := GetClientRuntimeSnapshot(client) if err != nil { t.Fatalf("GetClientRuntimeSnapshot after reconnect failed: %v", err) } if !after.Alive || !after.HasRuntimeConn || !after.CanReconnect { t.Fatalf("unexpected reconnect snapshot after reconnect: %+v", after) } if got, want := dialCount, 2; got != want { t.Fatalf("dial count mismatch: got %d want %d", got, want) } client.setByeFromServer(true) if err := client.Stop(); err != nil { t.Fatalf("final Stop failed: %v", err) } for _, peer := range peers { _ = peer.Close() } } func TestReconnectClientWithRetryRecordsRetryState(t *testing.T) { client := NewClient().(*ClientCommon) secret := []byte("0123456789abcdef0123456789abcdef") client.SetSecretKey(secret) server := newRunningPeerAttachServerForTest(t, func(server *ServerCommon) { server.SetSecretKey(secret) }) dialCount := 0 wantErr := errors.New("dial failed once") var peers []net.Conn dialFn := func(context.Context) (net.Conn, error) { dialCount++ if dialCount == 2 { return nil, wantErr } left, right := net.Pipe() peers = append(peers, right) bootstrapPeerAttachConnForTest(t, server, right) return left, nil } if err := client.ConnectByFactory(context.Background(), dialFn); err != nil { t.Fatalf("ConnectByFactory failed: %v", err) } client.setByeFromServer(true) if err := client.Stop(); err != nil { t.Fatalf("Stop failed: %v", err) } if err := ReconnectClientWithRetry(context.Background(), client, &ConnectRetryOptions{ MaxAttempts: 3, BaseDelay: 0, MaxDelay: 0, }); err != nil { t.Fatalf("ReconnectClientWithRetry failed: %v", err) } snapshot, err := GetClientRuntimeSnapshot(client) if err != nil { t.Fatalf("GetClientRuntimeSnapshot failed: %v", err) } if got, want := snapshot.Retry.RetryEventTotal, uint64(1); got != want { t.Fatalf("retry events mismatch: got %d want %d", got, want) } if got, want := snapshot.Retry.LastRetryAttempt, 1; got != want { t.Fatalf("last retry attempt mismatch: got %d want %d", got, want) } if got, want := snapshot.Retry.LastRetryError, wantErr.Error(); got != want { t.Fatalf("last retry error mismatch: got %q want %q", got, want) } if snapshot.Retry.LastResultError != "" { t.Fatalf("last result error should be empty, got %q", snapshot.Retry.LastResultError) } if got, want := dialCount, 3; got != want { t.Fatalf("dial count mismatch: got %d want %d", got, want) } client.setByeFromServer(true) if err := client.Stop(); err != nil { t.Fatalf("final Stop failed: %v", err) } for _, peer := range peers { _ = peer.Close() } }