148 lines
3.5 KiB
Go
148 lines
3.5 KiB
Go
package pool
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
|
|
"dappco.re/go/proxy"
|
|
)
|
|
|
|
type disconnectSpy struct {
|
|
disconnects atomic.Int64
|
|
}
|
|
|
|
func (s *disconnectSpy) OnJob(proxy.Job) {}
|
|
|
|
func (s *disconnectSpy) OnResultAccepted(int64, bool, string) {}
|
|
|
|
func (s *disconnectSpy) OnDisconnect() {
|
|
s.disconnects.Add(1)
|
|
}
|
|
|
|
func TestFailoverStrategy_Disconnect_Good(t *testing.T) {
|
|
spy := &disconnectSpy{}
|
|
strategy := &FailoverStrategy{
|
|
listener: spy,
|
|
client: &StratumClient{listener: nil},
|
|
}
|
|
strategy.client.listener = strategy
|
|
|
|
strategy.Disconnect()
|
|
time.Sleep(10 * time.Millisecond)
|
|
|
|
if got := spy.disconnects.Load(); got != 0 {
|
|
t.Fatalf("expected intentional disconnect to suppress reconnect, got %d listener calls", got)
|
|
}
|
|
}
|
|
|
|
func TestFailoverStrategy_Disconnect_Bad(t *testing.T) {
|
|
spy := &disconnectSpy{}
|
|
strategy := &FailoverStrategy{listener: spy}
|
|
|
|
strategy.OnDisconnect()
|
|
|
|
if got := spy.disconnects.Load(); got != 1 {
|
|
t.Fatalf("expected external disconnect to notify listener once, got %d", got)
|
|
}
|
|
}
|
|
|
|
func TestFailoverStrategy_Disconnect_Ugly(t *testing.T) {
|
|
spy := &disconnectSpy{}
|
|
strategy := &FailoverStrategy{
|
|
listener: spy,
|
|
client: &StratumClient{listener: nil},
|
|
}
|
|
strategy.client.listener = strategy
|
|
|
|
strategy.Disconnect()
|
|
strategy.Disconnect()
|
|
time.Sleep(10 * time.Millisecond)
|
|
|
|
if got := spy.disconnects.Load(); got != 0 {
|
|
t.Fatalf("expected repeated intentional disconnects to remain silent, got %d listener calls", got)
|
|
}
|
|
}
|
|
|
|
func TestStratumClient_NotifyDisconnect_ClearsState_Good(t *testing.T) {
|
|
serverConn, clientConn := net.Pipe()
|
|
defer serverConn.Close()
|
|
|
|
spy := &disconnectSpy{}
|
|
client := &StratumClient{
|
|
conn: clientConn,
|
|
listener: spy,
|
|
sessionID: "session-1",
|
|
active: true,
|
|
pending: map[int64]struct{}{
|
|
7: {},
|
|
},
|
|
}
|
|
|
|
client.notifyDisconnect()
|
|
|
|
if got := spy.disconnects.Load(); got != 1 {
|
|
t.Fatalf("expected one disconnect notification, got %d", got)
|
|
}
|
|
if client.conn != nil {
|
|
t.Fatalf("expected pooled connection to be cleared")
|
|
}
|
|
if client.sessionID != "" {
|
|
t.Fatalf("expected session id to be cleared, got %q", client.sessionID)
|
|
}
|
|
if client.IsActive() {
|
|
t.Fatalf("expected client to stop reporting active after disconnect")
|
|
}
|
|
if len(client.pending) != 0 {
|
|
t.Fatalf("expected pending submit state to be cleared, got %d entries", len(client.pending))
|
|
}
|
|
}
|
|
|
|
func TestFailoverStrategy_OnDisconnect_ClearsClient_Bad(t *testing.T) {
|
|
spy := &disconnectSpy{}
|
|
strategy := &FailoverStrategy{
|
|
listener: spy,
|
|
client: &StratumClient{active: true, pending: make(map[int64]struct{})},
|
|
}
|
|
|
|
strategy.OnDisconnect()
|
|
time.Sleep(10 * time.Millisecond)
|
|
|
|
if strategy.client != nil {
|
|
t.Fatalf("expected strategy to drop the stale client before reconnect")
|
|
}
|
|
if strategy.IsActive() {
|
|
t.Fatalf("expected strategy to report inactive while reconnect is pending")
|
|
}
|
|
if got := spy.disconnects.Load(); got != 1 {
|
|
t.Fatalf("expected one disconnect notification, got %d", got)
|
|
}
|
|
}
|
|
|
|
func TestStratumClient_HandleMessage_LoginErrorDisconnects_Ugly(t *testing.T) {
|
|
spy := &disconnectSpy{}
|
|
client := &StratumClient{
|
|
listener: spy,
|
|
pending: make(map[int64]struct{}),
|
|
}
|
|
|
|
payload, err := json.Marshal(map[string]any{
|
|
"id": 1,
|
|
"jsonrpc": "2.0",
|
|
"error": map[string]any{
|
|
"code": -1,
|
|
"message": "Invalid payment address provided",
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("marshal login error payload: %v", err)
|
|
}
|
|
|
|
client.handleMessage(payload)
|
|
|
|
if got := spy.disconnects.Load(); got != 1 {
|
|
t.Fatalf("expected login failure to disconnect upstream once, got %d", got)
|
|
}
|
|
}
|