159 lines
4.6 KiB
Go
159 lines
4.6 KiB
Go
|
|
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()
|
||
|
|
}
|
||
|
|
}
|