refactor-for-testability #3
| @@ -1,6 +1,9 @@ | ||||
| package peer | ||||
|  | ||||
| import "testing" | ||||
| import ( | ||||
| 	"testing" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| func TestStateClient_peerUpdate(t *testing.T) { | ||||
| 	h := NewPeerStateTestHarness() | ||||
| @@ -32,3 +35,78 @@ func TestStateClient_onAck_incorrectTraceID(t *testing.T) { | ||||
| 	assertType[*stateClient](t, h.State) | ||||
| 	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 | ||||
|   | ||||
| @@ -47,10 +47,20 @@ func (s *stateClientInit) OnMsg(raw any) peerState { | ||||
| 		return initPeerState(s.peerData, msg.Peer) | ||||
| 	case controlMsg[packetInit]: | ||||
| 		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: | ||||
| 		return s.onPing() | ||||
| 	default: | ||||
| 		s.logf("Ignoring message: %v", raw) | ||||
| 		s.logf("Ignoring message: %#v", raw) | ||||
| 		return s | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -26,8 +26,25 @@ func (s *stateDisconnected) OnMsg(raw any) peerState { | ||||
| 	switch msg := raw.(type) { | ||||
| 	case peerUpdateMsg: | ||||
| 		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: | ||||
| 		s.logf("Ignoring message: %v", raw) | ||||
| 		s.logf("Ignoring message: %#v", raw) | ||||
| 		return s | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -44,6 +44,9 @@ func (s *stateServer) OnMsg(raw any) peerState { | ||||
| 		return s.onInit(msg) | ||||
| 	case controlMsg[packetSyn]: | ||||
| 		return s.onSyn(msg) | ||||
| 	case controlMsg[packetAck]: | ||||
| 		s.logf("Unexpected ACK") | ||||
| 		return s | ||||
| 	case controlMsg[packetProbe]: | ||||
| 		return s.onProbe(msg) | ||||
| 	case controlMsg[packetLocalDiscovery]: | ||||
| @@ -51,7 +54,7 @@ func (s *stateServer) OnMsg(raw any) peerState { | ||||
| 	case pingTimerMsg: | ||||
| 		return s.onPingTimer() | ||||
| 	default: | ||||
| 		s.logf("Ignoring message: %v", raw) | ||||
| 		s.logf("Unexpected message: %#v", raw) | ||||
| 		return s | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -15,6 +15,7 @@ type PeerStateControlMsg struct { | ||||
| } | ||||
|  | ||||
| type PeerStateTestHarness struct { | ||||
| 	data      *peerData | ||||
| 	State     peerState | ||||
| 	Published remotePeer | ||||
| 	Sent      []PeerStateControlMsg | ||||
| @@ -42,6 +43,7 @@ func NewPeerStateTestHarness() *PeerStateTestHarness { | ||||
| 			MaxWaitCount: 1, | ||||
| 		}), | ||||
| 	} | ||||
| 	h.data = state | ||||
|  | ||||
| 	h.State = enterStateDisconnected(state) | ||||
| 	return h | ||||
| @@ -109,6 +111,8 @@ func (h *PeerStateTestHarness) ConfigServer_Relayed(t *testing.T) *stateServer { | ||||
| } | ||||
|  | ||||
| func (h *PeerStateTestHarness) ConfigClientInit(t *testing.T) *stateClientInit { | ||||
| 	// Remote IP should be less than local IP. | ||||
| 	h.data.localIP = 4 | ||||
| 	keys := generateKeys() | ||||
| 	peer := &m.Peer{ | ||||
| 		PeerIP:     3, | ||||
| @@ -134,21 +138,14 @@ func (h *PeerStateTestHarness) ConfigClientDirect(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) | ||||
| 	state.remoteIP = 1 | ||||
| 	init := assertType[packetInit](t, h.Sent[0].Packet) | ||||
| 	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) | ||||
| } | ||||
|   | ||||
| @@ -20,7 +20,7 @@ func assertType[T any](t *testing.T, obj any) T { | ||||
| 	t.Helper() | ||||
| 	x, ok := obj.(T) | ||||
| 	if !ok { | ||||
| 		t.Fatal("invalid type", obj) | ||||
| 		t.Fatalf("invalid type: %#v", obj) | ||||
| 	} | ||||
| 	return x | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user