Skip to content

Commit

Permalink
test: additional handshake client tests (#560)
Browse files Browse the repository at this point in the history
Fixes #316
  • Loading branch information
agaffney authored Mar 23, 2024
1 parent 4e908ae commit e438f45
Showing 1 changed file with 238 additions and 6 deletions.
244 changes: 238 additions & 6 deletions protocol/handshake/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,85 @@ package handshake_test

import (
"fmt"
"reflect"
"testing"
"time"

ouroboros "github.com/blinklabs-io/gouroboros"
"github.com/blinklabs-io/gouroboros/internal/test/ouroboros_mock"
"github.com/blinklabs-io/gouroboros/protocol"
"github.com/blinklabs-io/gouroboros/protocol/handshake"
"go.uber.org/goleak"
)

func TestClientBasicHandshake(t *testing.T) {
const (
mockProtocolVersionNtC uint16 = (14 + protocol.ProtocolVersionNtCOffset)
mockProtocolVersionNtN uint16 = 13
mockProtocolVersionNtNV11 uint16 = 11
)

var conversationEntryNtCResponse = ouroboros_mock.ConversationEntry{
Type: ouroboros_mock.EntryTypeOutput,
ProtocolId: handshake.ProtocolId,
IsResponse: true,
OutputMessages: []protocol.Message{
handshake.NewMsgAcceptVersion(
mockProtocolVersionNtC,
mockNtCVersionData(),
),
},
}

var conversationEntryNtNResponse = ouroboros_mock.ConversationEntry{
Type: ouroboros_mock.EntryTypeOutput,
ProtocolId: handshake.ProtocolId,
IsResponse: true,
OutputMessages: []protocol.Message{
handshake.NewMsgAcceptVersion(
mockProtocolVersionNtN,
mockNtNVersionData(),
),
},
}

var conversationEntryNtNResponseV11 = ouroboros_mock.ConversationEntry{
Type: ouroboros_mock.EntryTypeOutput,
ProtocolId: handshake.ProtocolId,
IsResponse: true,
OutputMessages: []protocol.Message{
handshake.NewMsgAcceptVersion(
mockProtocolVersionNtNV11,
mockNtNVersionDataV11(),
),
},
}

func mockNtCVersionData() protocol.VersionData {
return protocol.VersionDataNtC9to14(ouroboros_mock.MockNetworkMagic)
}

func mockNtNVersionDataV11() protocol.VersionData {
return protocol.VersionDataNtN11to12{
CborNetworkMagic: ouroboros_mock.MockNetworkMagic,
CborInitiatorAndResponderDiffusionMode: protocol.DiffusionModeInitiatorOnly,
CborPeerSharing: protocol.PeerSharingModeNoPeerSharing,
CborQuery: protocol.QueryModeDisabled,
}
}

func mockNtNVersionData() protocol.VersionData {
return protocol.VersionDataNtN13andUp{
VersionDataNtN11to12: mockNtNVersionDataV11().(protocol.VersionDataNtN11to12),
}
}

func TestClientNtCAccept(t *testing.T) {
defer goleak.VerifyNone(t)
mockConn := ouroboros_mock.NewConnection(
ouroboros_mock.ProtocolRoleClient,
[]ouroboros_mock.ConversationEntry{
ouroboros_mock.ConversationEntryHandshakeRequestGeneric,
ouroboros_mock.ConversationEntryHandshakeNtCResponse,
conversationEntryNtCResponse,
},
)
oConn, err := ouroboros.New(
Expand All @@ -49,6 +113,14 @@ func TestClientBasicHandshake(t *testing.T) {
// We can't call t.Fatalf() from a different Goroutine, so we panic instead
panic(fmt.Sprintf("unexpected Ouroboros connection error: %s", err))
}()
// Check negotiated version and version data
protoVersion, protoVersionData := oConn.ProtocolVersion()
if protoVersion != mockProtocolVersionNtC {
t.Fatalf("did not get expected protocol version: got %d, wanted %d", protoVersion, mockProtocolVersionNtC)
}
if !reflect.DeepEqual(protoVersionData, mockNtCVersionData()) {
t.Fatalf("did not get expected protocol version data:\n got: %#v\n wanted: %#v", protoVersionData, mockNtCVersionData())
}
// Close Ouroboros connection
if err := oConn.Close(); err != nil {
t.Fatalf("unexpected error when closing Ouroboros object: %s", err)
Expand All @@ -61,18 +133,19 @@ func TestClientBasicHandshake(t *testing.T) {
}
}

func TestClientDoubleStart(t *testing.T) {
func TestClientNtNAccept(t *testing.T) {
defer goleak.VerifyNone(t)
mockConn := ouroboros_mock.NewConnection(
ouroboros_mock.ProtocolRoleClient,
[]ouroboros_mock.ConversationEntry{
ouroboros_mock.ConversationEntryHandshakeRequestGeneric,
ouroboros_mock.ConversationEntryHandshakeNtCResponse,
conversationEntryNtNResponse,
},
)
oConn, err := ouroboros.New(
ouroboros.WithConnection(mockConn),
ouroboros.WithNetworkMagic(ouroboros_mock.MockNetworkMagic),
ouroboros.WithNodeToNode(true),
)
if err != nil {
t.Fatalf("unexpected error when creating Ouroboros object: %s", err)
Expand All @@ -86,8 +159,14 @@ func TestClientDoubleStart(t *testing.T) {
// We can't call t.Fatalf() from a different Goroutine, so we panic instead
panic(fmt.Sprintf("unexpected Ouroboros connection error: %s", err))
}()
// Try to start the Handshake client again
oConn.Handshake().Client.Start()
// Check negotiated version and version data
protoVersion, protoVersionData := oConn.ProtocolVersion()
if protoVersion != mockProtocolVersionNtN {
t.Fatalf("did not get expected protocol version: got %d, wanted %d", protoVersion, mockProtocolVersionNtN)
}
if !reflect.DeepEqual(protoVersionData, mockNtNVersionData()) {
t.Fatalf("did not get expected protocol version data:\n got: %#v\n wanted: %#v", protoVersionData, mockNtNVersionData())
}
// Close Ouroboros connection
if err := oConn.Close(); err != nil {
t.Fatalf("unexpected error when closing Ouroboros object: %s", err)
Expand All @@ -99,3 +178,156 @@ func TestClientDoubleStart(t *testing.T) {
t.Errorf("did not shutdown within timeout")
}
}

func TestClientNtNAcceptV11(t *testing.T) {
defer goleak.VerifyNone(t)
mockConn := ouroboros_mock.NewConnection(
ouroboros_mock.ProtocolRoleClient,
[]ouroboros_mock.ConversationEntry{
ouroboros_mock.ConversationEntryHandshakeRequestGeneric,
conversationEntryNtNResponseV11,
},
)
oConn, err := ouroboros.New(
ouroboros.WithConnection(mockConn),
ouroboros.WithNetworkMagic(ouroboros_mock.MockNetworkMagic),
ouroboros.WithNodeToNode(true),
)
if err != nil {
t.Fatalf("unexpected error when creating Ouroboros object: %s", err)
}
// Async error handler
go func() {
err, ok := <-oConn.ErrorChan()
if !ok {
return
}
// We can't call t.Fatalf() from a different Goroutine, so we panic instead
panic(fmt.Sprintf("unexpected Ouroboros connection error: %s", err))
}()
// Check negotiated version and version data
protoVersion, protoVersionData := oConn.ProtocolVersion()
if protoVersion != mockProtocolVersionNtNV11 {
t.Fatalf("did not get expected protocol version: got %d, wanted %d", protoVersion, mockProtocolVersionNtNV11)
}
if !reflect.DeepEqual(protoVersionData, mockNtNVersionDataV11()) {
t.Fatalf("did not get expected protocol version data:\n got: %#v\n wanted: %#v", protoVersionData, mockNtNVersionDataV11())
}
// Close Ouroboros connection
if err := oConn.Close(); err != nil {
t.Fatalf("unexpected error when closing Ouroboros object: %s", err)
}
// Wait for connection shutdown
select {
case <-oConn.ErrorChan():
case <-time.After(10 * time.Second):
t.Errorf("did not shutdown within timeout")
}
}

func TestClientNtCRefuseVersionMismatch(t *testing.T) {
defer goleak.VerifyNone(t)
expectedErr := fmt.Sprintf("%s: version mismatch", handshake.ProtocolName)
mockConn := ouroboros_mock.NewConnection(
ouroboros_mock.ProtocolRoleClient,
[]ouroboros_mock.ConversationEntry{
ouroboros_mock.ConversationEntryHandshakeRequestGeneric,
ouroboros_mock.ConversationEntry{
Type: ouroboros_mock.EntryTypeOutput,
ProtocolId: handshake.ProtocolId,
IsResponse: true,
OutputMessages: []protocol.Message{
handshake.NewMsgRefuse(
[]any{
handshake.RefuseReasonVersionMismatch,
[]uint16{1, 2, 3},
},
),
},
},
},
)
_, err := ouroboros.New(
ouroboros.WithConnection(mockConn),
ouroboros.WithNetworkMagic(ouroboros_mock.MockNetworkMagic),
)
if err == nil {
t.Fatalf("did not receive expected error")
} else {
if err.Error() != expectedErr {
t.Fatalf("received unexpected error\n got: %v\n wanted: %v", err, expectedErr)
}
}
}

func TestClientNtCRefuseDecodeError(t *testing.T) {
defer goleak.VerifyNone(t)
expectedErr := fmt.Sprintf("%s: decode error: foo", handshake.ProtocolName)
mockConn := ouroboros_mock.NewConnection(
ouroboros_mock.ProtocolRoleClient,
[]ouroboros_mock.ConversationEntry{
ouroboros_mock.ConversationEntryHandshakeRequestGeneric,
ouroboros_mock.ConversationEntry{
Type: ouroboros_mock.EntryTypeOutput,
ProtocolId: handshake.ProtocolId,
IsResponse: true,
OutputMessages: []protocol.Message{
handshake.NewMsgRefuse(
[]any{
handshake.RefuseReasonDecodeError,
mockProtocolVersionNtC,
"foo",
},
),
},
},
},
)
_, err := ouroboros.New(
ouroboros.WithConnection(mockConn),
ouroboros.WithNetworkMagic(ouroboros_mock.MockNetworkMagic),
)
if err == nil {
t.Fatalf("did not receive expected error")
} else {
if err.Error() != expectedErr {
t.Fatalf("received unexpected error\n got: %v\n wanted: %v", err, expectedErr)
}
}
}

func TestClientNtCRefuseRefused(t *testing.T) {
defer goleak.VerifyNone(t)
expectedErr := fmt.Sprintf("%s: refused: foo", handshake.ProtocolName)
mockConn := ouroboros_mock.NewConnection(
ouroboros_mock.ProtocolRoleClient,
[]ouroboros_mock.ConversationEntry{
ouroboros_mock.ConversationEntryHandshakeRequestGeneric,
ouroboros_mock.ConversationEntry{
Type: ouroboros_mock.EntryTypeOutput,
ProtocolId: handshake.ProtocolId,
IsResponse: true,
OutputMessages: []protocol.Message{
handshake.NewMsgRefuse(
[]any{
handshake.RefuseReasonRefused,
mockProtocolVersionNtC,
"foo",
},
),
},
},
},
)
_, err := ouroboros.New(
ouroboros.WithConnection(mockConn),
ouroboros.WithNetworkMagic(ouroboros_mock.MockNetworkMagic),
)
if err == nil {
t.Fatalf("did not receive expected error")
} else {
if err.Error() != expectedErr {
t.Fatalf("received unexpected error\n got: %v\n wanted: %v", err, expectedErr)
}
}
}

0 comments on commit e438f45

Please sign in to comment.