Skip to content

Commit e438f45

Browse files
authored
test: additional handshake client tests (#560)
Fixes #316
1 parent 4e908ae commit e438f45

File tree

1 file changed

+238
-6
lines changed

1 file changed

+238
-6
lines changed

protocol/handshake/client_test.go

Lines changed: 238 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,85 @@ package handshake_test
1616

1717
import (
1818
"fmt"
19+
"reflect"
1920
"testing"
2021
"time"
2122

2223
ouroboros "github.com/blinklabs-io/gouroboros"
2324
"github.com/blinklabs-io/gouroboros/internal/test/ouroboros_mock"
25+
"github.com/blinklabs-io/gouroboros/protocol"
26+
"github.com/blinklabs-io/gouroboros/protocol/handshake"
2427
"go.uber.org/goleak"
2528
)
2629

27-
func TestClientBasicHandshake(t *testing.T) {
30+
const (
31+
mockProtocolVersionNtC uint16 = (14 + protocol.ProtocolVersionNtCOffset)
32+
mockProtocolVersionNtN uint16 = 13
33+
mockProtocolVersionNtNV11 uint16 = 11
34+
)
35+
36+
var conversationEntryNtCResponse = ouroboros_mock.ConversationEntry{
37+
Type: ouroboros_mock.EntryTypeOutput,
38+
ProtocolId: handshake.ProtocolId,
39+
IsResponse: true,
40+
OutputMessages: []protocol.Message{
41+
handshake.NewMsgAcceptVersion(
42+
mockProtocolVersionNtC,
43+
mockNtCVersionData(),
44+
),
45+
},
46+
}
47+
48+
var conversationEntryNtNResponse = ouroboros_mock.ConversationEntry{
49+
Type: ouroboros_mock.EntryTypeOutput,
50+
ProtocolId: handshake.ProtocolId,
51+
IsResponse: true,
52+
OutputMessages: []protocol.Message{
53+
handshake.NewMsgAcceptVersion(
54+
mockProtocolVersionNtN,
55+
mockNtNVersionData(),
56+
),
57+
},
58+
}
59+
60+
var conversationEntryNtNResponseV11 = ouroboros_mock.ConversationEntry{
61+
Type: ouroboros_mock.EntryTypeOutput,
62+
ProtocolId: handshake.ProtocolId,
63+
IsResponse: true,
64+
OutputMessages: []protocol.Message{
65+
handshake.NewMsgAcceptVersion(
66+
mockProtocolVersionNtNV11,
67+
mockNtNVersionDataV11(),
68+
),
69+
},
70+
}
71+
72+
func mockNtCVersionData() protocol.VersionData {
73+
return protocol.VersionDataNtC9to14(ouroboros_mock.MockNetworkMagic)
74+
}
75+
76+
func mockNtNVersionDataV11() protocol.VersionData {
77+
return protocol.VersionDataNtN11to12{
78+
CborNetworkMagic: ouroboros_mock.MockNetworkMagic,
79+
CborInitiatorAndResponderDiffusionMode: protocol.DiffusionModeInitiatorOnly,
80+
CborPeerSharing: protocol.PeerSharingModeNoPeerSharing,
81+
CborQuery: protocol.QueryModeDisabled,
82+
}
83+
}
84+
85+
func mockNtNVersionData() protocol.VersionData {
86+
return protocol.VersionDataNtN13andUp{
87+
VersionDataNtN11to12: mockNtNVersionDataV11().(protocol.VersionDataNtN11to12),
88+
}
89+
}
90+
91+
func TestClientNtCAccept(t *testing.T) {
2892
defer goleak.VerifyNone(t)
2993
mockConn := ouroboros_mock.NewConnection(
3094
ouroboros_mock.ProtocolRoleClient,
3195
[]ouroboros_mock.ConversationEntry{
3296
ouroboros_mock.ConversationEntryHandshakeRequestGeneric,
33-
ouroboros_mock.ConversationEntryHandshakeNtCResponse,
97+
conversationEntryNtCResponse,
3498
},
3599
)
36100
oConn, err := ouroboros.New(
@@ -49,6 +113,14 @@ func TestClientBasicHandshake(t *testing.T) {
49113
// We can't call t.Fatalf() from a different Goroutine, so we panic instead
50114
panic(fmt.Sprintf("unexpected Ouroboros connection error: %s", err))
51115
}()
116+
// Check negotiated version and version data
117+
protoVersion, protoVersionData := oConn.ProtocolVersion()
118+
if protoVersion != mockProtocolVersionNtC {
119+
t.Fatalf("did not get expected protocol version: got %d, wanted %d", protoVersion, mockProtocolVersionNtC)
120+
}
121+
if !reflect.DeepEqual(protoVersionData, mockNtCVersionData()) {
122+
t.Fatalf("did not get expected protocol version data:\n got: %#v\n wanted: %#v", protoVersionData, mockNtCVersionData())
123+
}
52124
// Close Ouroboros connection
53125
if err := oConn.Close(); err != nil {
54126
t.Fatalf("unexpected error when closing Ouroboros object: %s", err)
@@ -61,18 +133,19 @@ func TestClientBasicHandshake(t *testing.T) {
61133
}
62134
}
63135

64-
func TestClientDoubleStart(t *testing.T) {
136+
func TestClientNtNAccept(t *testing.T) {
65137
defer goleak.VerifyNone(t)
66138
mockConn := ouroboros_mock.NewConnection(
67139
ouroboros_mock.ProtocolRoleClient,
68140
[]ouroboros_mock.ConversationEntry{
69141
ouroboros_mock.ConversationEntryHandshakeRequestGeneric,
70-
ouroboros_mock.ConversationEntryHandshakeNtCResponse,
142+
conversationEntryNtNResponse,
71143
},
72144
)
73145
oConn, err := ouroboros.New(
74146
ouroboros.WithConnection(mockConn),
75147
ouroboros.WithNetworkMagic(ouroboros_mock.MockNetworkMagic),
148+
ouroboros.WithNodeToNode(true),
76149
)
77150
if err != nil {
78151
t.Fatalf("unexpected error when creating Ouroboros object: %s", err)
@@ -86,8 +159,14 @@ func TestClientDoubleStart(t *testing.T) {
86159
// We can't call t.Fatalf() from a different Goroutine, so we panic instead
87160
panic(fmt.Sprintf("unexpected Ouroboros connection error: %s", err))
88161
}()
89-
// Try to start the Handshake client again
90-
oConn.Handshake().Client.Start()
162+
// Check negotiated version and version data
163+
protoVersion, protoVersionData := oConn.ProtocolVersion()
164+
if protoVersion != mockProtocolVersionNtN {
165+
t.Fatalf("did not get expected protocol version: got %d, wanted %d", protoVersion, mockProtocolVersionNtN)
166+
}
167+
if !reflect.DeepEqual(protoVersionData, mockNtNVersionData()) {
168+
t.Fatalf("did not get expected protocol version data:\n got: %#v\n wanted: %#v", protoVersionData, mockNtNVersionData())
169+
}
91170
// Close Ouroboros connection
92171
if err := oConn.Close(); err != nil {
93172
t.Fatalf("unexpected error when closing Ouroboros object: %s", err)
@@ -99,3 +178,156 @@ func TestClientDoubleStart(t *testing.T) {
99178
t.Errorf("did not shutdown within timeout")
100179
}
101180
}
181+
182+
func TestClientNtNAcceptV11(t *testing.T) {
183+
defer goleak.VerifyNone(t)
184+
mockConn := ouroboros_mock.NewConnection(
185+
ouroboros_mock.ProtocolRoleClient,
186+
[]ouroboros_mock.ConversationEntry{
187+
ouroboros_mock.ConversationEntryHandshakeRequestGeneric,
188+
conversationEntryNtNResponseV11,
189+
},
190+
)
191+
oConn, err := ouroboros.New(
192+
ouroboros.WithConnection(mockConn),
193+
ouroboros.WithNetworkMagic(ouroboros_mock.MockNetworkMagic),
194+
ouroboros.WithNodeToNode(true),
195+
)
196+
if err != nil {
197+
t.Fatalf("unexpected error when creating Ouroboros object: %s", err)
198+
}
199+
// Async error handler
200+
go func() {
201+
err, ok := <-oConn.ErrorChan()
202+
if !ok {
203+
return
204+
}
205+
// We can't call t.Fatalf() from a different Goroutine, so we panic instead
206+
panic(fmt.Sprintf("unexpected Ouroboros connection error: %s", err))
207+
}()
208+
// Check negotiated version and version data
209+
protoVersion, protoVersionData := oConn.ProtocolVersion()
210+
if protoVersion != mockProtocolVersionNtNV11 {
211+
t.Fatalf("did not get expected protocol version: got %d, wanted %d", protoVersion, mockProtocolVersionNtNV11)
212+
}
213+
if !reflect.DeepEqual(protoVersionData, mockNtNVersionDataV11()) {
214+
t.Fatalf("did not get expected protocol version data:\n got: %#v\n wanted: %#v", protoVersionData, mockNtNVersionDataV11())
215+
}
216+
// Close Ouroboros connection
217+
if err := oConn.Close(); err != nil {
218+
t.Fatalf("unexpected error when closing Ouroboros object: %s", err)
219+
}
220+
// Wait for connection shutdown
221+
select {
222+
case <-oConn.ErrorChan():
223+
case <-time.After(10 * time.Second):
224+
t.Errorf("did not shutdown within timeout")
225+
}
226+
}
227+
228+
func TestClientNtCRefuseVersionMismatch(t *testing.T) {
229+
defer goleak.VerifyNone(t)
230+
expectedErr := fmt.Sprintf("%s: version mismatch", handshake.ProtocolName)
231+
mockConn := ouroboros_mock.NewConnection(
232+
ouroboros_mock.ProtocolRoleClient,
233+
[]ouroboros_mock.ConversationEntry{
234+
ouroboros_mock.ConversationEntryHandshakeRequestGeneric,
235+
ouroboros_mock.ConversationEntry{
236+
Type: ouroboros_mock.EntryTypeOutput,
237+
ProtocolId: handshake.ProtocolId,
238+
IsResponse: true,
239+
OutputMessages: []protocol.Message{
240+
handshake.NewMsgRefuse(
241+
[]any{
242+
handshake.RefuseReasonVersionMismatch,
243+
[]uint16{1, 2, 3},
244+
},
245+
),
246+
},
247+
},
248+
},
249+
)
250+
_, err := ouroboros.New(
251+
ouroboros.WithConnection(mockConn),
252+
ouroboros.WithNetworkMagic(ouroboros_mock.MockNetworkMagic),
253+
)
254+
if err == nil {
255+
t.Fatalf("did not receive expected error")
256+
} else {
257+
if err.Error() != expectedErr {
258+
t.Fatalf("received unexpected error\n got: %v\n wanted: %v", err, expectedErr)
259+
}
260+
}
261+
}
262+
263+
func TestClientNtCRefuseDecodeError(t *testing.T) {
264+
defer goleak.VerifyNone(t)
265+
expectedErr := fmt.Sprintf("%s: decode error: foo", handshake.ProtocolName)
266+
mockConn := ouroboros_mock.NewConnection(
267+
ouroboros_mock.ProtocolRoleClient,
268+
[]ouroboros_mock.ConversationEntry{
269+
ouroboros_mock.ConversationEntryHandshakeRequestGeneric,
270+
ouroboros_mock.ConversationEntry{
271+
Type: ouroboros_mock.EntryTypeOutput,
272+
ProtocolId: handshake.ProtocolId,
273+
IsResponse: true,
274+
OutputMessages: []protocol.Message{
275+
handshake.NewMsgRefuse(
276+
[]any{
277+
handshake.RefuseReasonDecodeError,
278+
mockProtocolVersionNtC,
279+
"foo",
280+
},
281+
),
282+
},
283+
},
284+
},
285+
)
286+
_, err := ouroboros.New(
287+
ouroboros.WithConnection(mockConn),
288+
ouroboros.WithNetworkMagic(ouroboros_mock.MockNetworkMagic),
289+
)
290+
if err == nil {
291+
t.Fatalf("did not receive expected error")
292+
} else {
293+
if err.Error() != expectedErr {
294+
t.Fatalf("received unexpected error\n got: %v\n wanted: %v", err, expectedErr)
295+
}
296+
}
297+
}
298+
299+
func TestClientNtCRefuseRefused(t *testing.T) {
300+
defer goleak.VerifyNone(t)
301+
expectedErr := fmt.Sprintf("%s: refused: foo", handshake.ProtocolName)
302+
mockConn := ouroboros_mock.NewConnection(
303+
ouroboros_mock.ProtocolRoleClient,
304+
[]ouroboros_mock.ConversationEntry{
305+
ouroboros_mock.ConversationEntryHandshakeRequestGeneric,
306+
ouroboros_mock.ConversationEntry{
307+
Type: ouroboros_mock.EntryTypeOutput,
308+
ProtocolId: handshake.ProtocolId,
309+
IsResponse: true,
310+
OutputMessages: []protocol.Message{
311+
handshake.NewMsgRefuse(
312+
[]any{
313+
handshake.RefuseReasonRefused,
314+
mockProtocolVersionNtC,
315+
"foo",
316+
},
317+
),
318+
},
319+
},
320+
},
321+
)
322+
_, err := ouroboros.New(
323+
ouroboros.WithConnection(mockConn),
324+
ouroboros.WithNetworkMagic(ouroboros_mock.MockNetworkMagic),
325+
)
326+
if err == nil {
327+
t.Fatalf("did not receive expected error")
328+
} else {
329+
if err.Error() != expectedErr {
330+
t.Fatalf("received unexpected error\n got: %v\n wanted: %v", err, expectedErr)
331+
}
332+
}
333+
}

0 commit comments

Comments
 (0)