/ msgmux / msg_router_test.go
msg_router_test.go
  1  package msgmux
  2  
  3  import (
  4  	"context"
  5  	"testing"
  6  
  7  	"github.com/lightningnetwork/lnd/lnwire"
  8  	"github.com/stretchr/testify/mock"
  9  	"github.com/stretchr/testify/require"
 10  )
 11  
 12  type mockEndpoint struct {
 13  	mock.Mock
 14  }
 15  
 16  func (m *mockEndpoint) Name() string {
 17  	args := m.Called()
 18  
 19  	return args.String(0)
 20  }
 21  
 22  func (m *mockEndpoint) CanHandle(msg PeerMsg) bool {
 23  	args := m.Called(msg)
 24  
 25  	return args.Bool(0)
 26  }
 27  
 28  func (m *mockEndpoint) SendMessage(ctx context.Context, msg PeerMsg) bool {
 29  	args := m.Called(ctx, msg)
 30  
 31  	return args.Bool(0)
 32  }
 33  
 34  // TestMessageRouterOperation tests the basic operation of the message router:
 35  // add new endpoints, route to them, remove, them, etc.
 36  func TestMessageRouterOperation(t *testing.T) {
 37  	ctx := t.Context()
 38  	msgRouter := NewMultiMsgRouter()
 39  	msgRouter.Start(ctx)
 40  	defer msgRouter.Stop()
 41  
 42  	openChanMsg := PeerMsg{
 43  		Message: &lnwire.OpenChannel{},
 44  	}
 45  	commitSigMsg := PeerMsg{
 46  		Message: &lnwire.CommitSig{},
 47  	}
 48  
 49  	errorMsg := PeerMsg{
 50  		Message: &lnwire.Error{},
 51  	}
 52  
 53  	// For this test, we'll have two endpoints, each with distinct names.
 54  	// One endpoint will only handle OpenChannel, while the other will
 55  	// handle the CommitSig message.
 56  	fundingEndpoint := &mockEndpoint{}
 57  	fundingEndpointName := "funding"
 58  	fundingEndpoint.On("Name").Return(fundingEndpointName)
 59  	fundingEndpoint.On("CanHandle", openChanMsg).Return(true)
 60  	fundingEndpoint.On("CanHandle", errorMsg).Return(false)
 61  	fundingEndpoint.On("CanHandle", commitSigMsg).Return(false)
 62  	fundingEndpoint.On("SendMessage", ctx, openChanMsg).Return(true)
 63  
 64  	commitEndpoint := &mockEndpoint{}
 65  	commitEndpointName := "commit"
 66  	commitEndpoint.On("Name").Return(commitEndpointName)
 67  	commitEndpoint.On("CanHandle", commitSigMsg).Return(true)
 68  	commitEndpoint.On("CanHandle", openChanMsg).Return(false)
 69  	commitEndpoint.On("CanHandle", errorMsg).Return(false)
 70  	commitEndpoint.On("SendMessage", ctx, commitSigMsg).Return(true)
 71  
 72  	t.Run("add endpoints", func(t *testing.T) {
 73  		// First, we'll add the funding endpoint to the router.
 74  		require.NoError(t, msgRouter.RegisterEndpoint(fundingEndpoint))
 75  
 76  		endpoints, err := msgRouter.endpoints().Unpack()
 77  		require.NoError(t, err)
 78  
 79  		// There should be a single endpoint registered.
 80  		require.Len(t, endpoints, 1)
 81  
 82  		// The name of the registered endpoint should be "funding".
 83  		require.Equal(
 84  			t, "funding", endpoints[fundingEndpointName].Name(),
 85  		)
 86  	})
 87  
 88  	t.Run("duplicate endpoint reject", func(t *testing.T) {
 89  		// Next, we'll attempt to add the funding endpoint again. This
 90  		// should return an ErrDuplicateEndpoint error.
 91  		require.ErrorIs(
 92  			t, msgRouter.RegisterEndpoint(fundingEndpoint),
 93  			ErrDuplicateEndpoint,
 94  		)
 95  	})
 96  
 97  	t.Run("route to endpoint", func(t *testing.T) {
 98  		// Next, we'll add our other endpoint, then attempt to route a
 99  		// message.
100  		require.NoError(t, msgRouter.RegisterEndpoint(commitEndpoint))
101  
102  		// If we try to route a message none of the endpoints know of,
103  		// we should get an error.
104  		require.ErrorIs(
105  			t, msgRouter.RouteMsg(errorMsg), ErrUnableToRouteMsg,
106  		)
107  
108  		fundingEndpoint.AssertCalled(t, "CanHandle", errorMsg)
109  		commitEndpoint.AssertCalled(t, "CanHandle", errorMsg)
110  
111  		// Next, we'll route the open channel message. Only the
112  		// fundingEndpoint should be used.
113  		require.NoError(t, msgRouter.RouteMsg(openChanMsg))
114  
115  		fundingEndpoint.AssertCalled(t, "CanHandle", openChanMsg)
116  		commitEndpoint.AssertCalled(t, "CanHandle", openChanMsg)
117  
118  		fundingEndpoint.AssertCalled(t, "SendMessage", ctx, openChanMsg)
119  		commitEndpoint.AssertNotCalled(
120  			t, "SendMessage", ctx, openChanMsg,
121  		)
122  
123  		// We'll do the same for the commit sig message.
124  		require.NoError(t, msgRouter.RouteMsg(commitSigMsg))
125  
126  		fundingEndpoint.AssertCalled(t, "CanHandle", commitSigMsg)
127  		commitEndpoint.AssertCalled(t, "CanHandle", commitSigMsg)
128  
129  		commitEndpoint.AssertCalled(t, "SendMessage", ctx, commitSigMsg)
130  		fundingEndpoint.AssertNotCalled(
131  			t, "SendMessage", ctx, commitSigMsg,
132  		)
133  	})
134  
135  	t.Run("remove endpoints", func(t *testing.T) {
136  		// Finally, we'll remove both endpoints.
137  		require.NoError(
138  			t, msgRouter.UnregisterEndpoint(fundingEndpointName),
139  		)
140  		require.NoError(
141  			t, msgRouter.UnregisterEndpoint(commitEndpointName),
142  		)
143  
144  		endpoints, err := msgRouter.endpoints().Unpack()
145  		require.NoError(t, err)
146  
147  		// There should be no endpoints registered.
148  		require.Len(t, endpoints, 0)
149  
150  		// Trying to route a message should fail.
151  		require.ErrorIs(
152  			t, msgRouter.RouteMsg(openChanMsg),
153  			ErrUnableToRouteMsg,
154  		)
155  		require.ErrorIs(
156  			t, msgRouter.RouteMsg(commitSigMsg),
157  			ErrUnableToRouteMsg,
158  		)
159  	})
160  
161  	commitEndpoint.AssertExpectations(t)
162  	fundingEndpoint.AssertExpectations(t)
163  }