refactor-for-testability #3

Merged
johnnylee merged 26 commits from refactor-for-testability into main 2025-03-01 20:02:27 +00:00
6 changed files with 124 additions and 19 deletions
Showing only changes of commit ea3e997df8 - Show all commits

View File

@ -1,6 +1,9 @@
package peer package peer
import "testing" import (
"testing"
"time"
)
func TestStateClient_peerUpdate(t *testing.T) { func TestStateClient_peerUpdate(t *testing.T) {
h := NewPeerStateTestHarness() h := NewPeerStateTestHarness()
@ -32,3 +35,78 @@ func TestStateClient_onAck_incorrectTraceID(t *testing.T) {
assertType[*stateClient](t, h.State) assertType[*stateClient](t, h.State)
assertEqual(t, len(h.Sent), 0) assertEqual(t, len(h.Sent), 0)
} }
func TestStateClient_onAck_direct_downToUp(t *testing.T) {
h := NewPeerStateTestHarness()
h.ConfigClientDirect(t)
assertEqual(t, len(h.Sent), 2)
syn := assertType[packetSyn](t, h.Sent[1].Packet)
h.Sent = h.Sent[:0]
assertEqual(t, h.Published.Up, false)
ack := controlMsg[packetAck]{
Packet: packetAck{TraceID: syn.TraceID},
}
h.OnAck(ack)
assertEqual(t, len(h.Sent), 0)
}
func TestStateClient_onAck_relayed_sendsProbes(t *testing.T) {
h := NewPeerStateTestHarness()
h.ConfigClientRelayed(t)
assertEqual(t, len(h.Sent), 2)
syn := assertType[packetSyn](t, h.Sent[1].Packet)
h.Sent = h.Sent[:0]
assertEqual(t, h.Published.Up, false)
ack := controlMsg[packetAck]{
Packet: packetAck{TraceID: syn.TraceID},
}
ack.Packet.PossibleAddrs[0] = addrPort4(1, 2, 3, 4, 100)
ack.Packet.PossibleAddrs[1] = addrPort4(2, 3, 4, 5, 200)
h.OnAck(ack)
assertEqual(t, len(h.Sent), 2)
assertType[packetProbe](t, h.Sent[0].Packet)
assertEqual(t, h.Sent[0].Peer.DirectAddr, ack.Packet.PossibleAddrs[0])
assertType[packetProbe](t, h.Sent[1].Packet)
assertEqual(t, h.Sent[1].Peer.DirectAddr, ack.Packet.PossibleAddrs[1])
}
func TestStateClient_onPing(t *testing.T) {
h := NewPeerStateTestHarness()
h.ConfigClientRelayed(t)
h.Sent = h.Sent[:0]
h.OnPingTimer()
assertEqual(t, len(h.Sent), 1)
assertType[*stateClient](t, h.State)
assertType[packetSyn](t, h.Sent[0].Packet)
}
func TestStateClient_onPing_timeout(t *testing.T) {
h := NewPeerStateTestHarness()
h.ConfigClientRelayed(t)
h.Sent = h.Sent[:0]
state := assertType[*stateClient](t, h.State)
state.lastSeen = time.Now().Add(-2 * timeoutInterval)
state.staged.Up = true
h.OnPingTimer()
newState := assertType[*stateClientInit](t, h.State)
assertEqual(t, newState.staged.Up, false)
assertEqual(t, len(h.Sent), 1)
assertType[packetInit](t, h.Sent[0].Packet)
}
// probe direct
// probe relayed - no match
// probe relayed - match

View File

@ -47,10 +47,20 @@ func (s *stateClientInit) OnMsg(raw any) peerState {
return initPeerState(s.peerData, msg.Peer) return initPeerState(s.peerData, msg.Peer)
case controlMsg[packetInit]: case controlMsg[packetInit]:
return s.onInit(msg) return s.onInit(msg)
case controlMsg[packetSyn]:
s.logf("Unexpected SYN")
return s
case controlMsg[packetAck]:
s.logf("Unexpected ACK")
return s
case controlMsg[packetProbe]:
return s
case controlMsg[packetLocalDiscovery]:
return s
case pingTimerMsg: case pingTimerMsg:
return s.onPing() return s.onPing()
default: default:
s.logf("Ignoring message: %v", raw) s.logf("Ignoring message: %#v", raw)
return s return s
} }
} }

View File

@ -26,8 +26,25 @@ func (s *stateDisconnected) OnMsg(raw any) peerState {
switch msg := raw.(type) { switch msg := raw.(type) {
case peerUpdateMsg: case peerUpdateMsg:
return initPeerState(s.peerData, msg.Peer) return initPeerState(s.peerData, msg.Peer)
case controlMsg[packetInit]:
s.logf("Unexpected INIT")
return s
case controlMsg[packetSyn]:
s.logf("Unexpected SYN")
return s
case controlMsg[packetAck]:
s.logf("Unexpected ACK")
return s
case controlMsg[packetProbe]:
s.logf("Unexpected probe")
return s
case controlMsg[packetLocalDiscovery]:
return s
case pingTimerMsg:
s.logf("Unexpected ping")
return s
default: default:
s.logf("Ignoring message: %v", raw) s.logf("Ignoring message: %#v", raw)
return s return s
} }
} }

View File

@ -44,6 +44,9 @@ func (s *stateServer) OnMsg(raw any) peerState {
return s.onInit(msg) return s.onInit(msg)
case controlMsg[packetSyn]: case controlMsg[packetSyn]:
return s.onSyn(msg) return s.onSyn(msg)
case controlMsg[packetAck]:
s.logf("Unexpected ACK")
return s
case controlMsg[packetProbe]: case controlMsg[packetProbe]:
return s.onProbe(msg) return s.onProbe(msg)
case controlMsg[packetLocalDiscovery]: case controlMsg[packetLocalDiscovery]:
@ -51,7 +54,7 @@ func (s *stateServer) OnMsg(raw any) peerState {
case pingTimerMsg: case pingTimerMsg:
return s.onPingTimer() return s.onPingTimer()
default: default:
s.logf("Ignoring message: %v", raw) s.logf("Unexpected message: %#v", raw)
return s return s
} }
} }

View File

@ -15,6 +15,7 @@ type PeerStateControlMsg struct {
} }
type PeerStateTestHarness struct { type PeerStateTestHarness struct {
data *peerData
State peerState State peerState
Published remotePeer Published remotePeer
Sent []PeerStateControlMsg Sent []PeerStateControlMsg
@ -42,6 +43,7 @@ func NewPeerStateTestHarness() *PeerStateTestHarness {
MaxWaitCount: 1, MaxWaitCount: 1,
}), }),
} }
h.data = state
h.State = enterStateDisconnected(state) h.State = enterStateDisconnected(state)
return h return h
@ -109,6 +111,8 @@ func (h *PeerStateTestHarness) ConfigServer_Relayed(t *testing.T) *stateServer {
} }
func (h *PeerStateTestHarness) ConfigClientInit(t *testing.T) *stateClientInit { func (h *PeerStateTestHarness) ConfigClientInit(t *testing.T) *stateClientInit {
// Remote IP should be less than local IP.
h.data.localIP = 4
keys := generateKeys() keys := generateKeys()
peer := &m.Peer{ peer := &m.Peer{
PeerIP: 3, PeerIP: 3,
@ -134,21 +138,14 @@ func (h *PeerStateTestHarness) ConfigClientDirect(t *testing.T) *stateClient {
} }
func (h *PeerStateTestHarness) ConfigClientRelayed(t *testing.T) *stateClient { func (h *PeerStateTestHarness) ConfigClientRelayed(t *testing.T) *stateClient {
keys := generateKeys() h.ConfigClientInit(t)
state := assertType[*stateClientInit](t, h.State)
state.peer.PublicIP = nil // Force relay.
state := h.State.(*stateDisconnected) init := assertType[packetInit](t, h.Sent[0].Packet)
state.remoteIP = 1 h.OnInit(controlMsg[packetInit]{
Packet: init,
})
peer := &m.Peer{
PeerIP: 3,
Port: 456,
PubKey: keys.PubKey,
PubSignKey: keys.PubSignKey,
}
// TODO: Fix me.
h.PeerUpdate(peer)
assertEqual(t, h.Published.Up, false)
return assertType[*stateClient](t, h.State) return assertType[*stateClient](t, h.State)
} }

View File

@ -20,7 +20,7 @@ func assertType[T any](t *testing.T, obj any) T {
t.Helper() t.Helper()
x, ok := obj.(T) x, ok := obj.(T)
if !ok { if !ok {
t.Fatal("invalid type", obj) t.Fatalf("invalid type: %#v", obj)
} }
return x return x
} }