Skip to content

Commit d527b0b

Browse files
committed
reservation: add test for manager
1 parent 61a5f9d commit d527b0b

File tree

1 file changed

+160
-0
lines changed

1 file changed

+160
-0
lines changed
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
package reservation
2+
3+
import (
4+
"context"
5+
"encoding/hex"
6+
"testing"
7+
"time"
8+
9+
"github.com/btcsuite/btcd/wire"
10+
"github.com/lightninglabs/loop/loopdb"
11+
"github.com/lightninglabs/loop/swapserverrpc"
12+
"github.com/lightninglabs/loop/test"
13+
"github.com/lightningnetwork/lnd/chainntnfs"
14+
"github.com/stretchr/testify/mock"
15+
"github.com/stretchr/testify/require"
16+
"google.golang.org/grpc"
17+
)
18+
19+
var (
20+
defaultReservationId = mustDecodeID("17cecc61ab4aafebdc0542dabdae0d0cb8907ec1c9c8ae387bc5a3309ca8b600")
21+
)
22+
23+
func TestManager(t *testing.T) {
24+
ctxb, cancel := context.WithCancel(context.Background())
25+
defer cancel()
26+
27+
testContext := newManagerTestContext(t)
28+
29+
// Start the manager.
30+
go func() {
31+
err := testContext.manager.Run(ctxb, testContext.mockLnd.Height)
32+
require.NoError(t, err)
33+
}()
34+
35+
// Create a new reservation.
36+
fsm, err := testContext.manager.newReservation(
37+
ctxb, uint32(testContext.mockLnd.Height),
38+
&swapserverrpc.ServerReservationNotification{
39+
ReservationId: defaultReservationId[:],
40+
Value: uint64(defaultValue),
41+
ServerKey: defaultPubkeyBytes,
42+
Expiry: uint32(testContext.mockLnd.Height) + defaultExpiry,
43+
},
44+
)
45+
require.NoError(t, err)
46+
47+
// We'll expect the spendConfirmation to be sent to the server.
48+
pkScript, err := fsm.reservation.GetPkScript()
49+
require.NoError(t, err)
50+
51+
conf := <-testContext.mockLnd.RegisterConfChannel
52+
require.Equal(t, conf.PkScript, pkScript)
53+
54+
confTx := &wire.MsgTx{
55+
TxOut: []*wire.TxOut{
56+
{
57+
PkScript: pkScript,
58+
},
59+
},
60+
}
61+
// We'll now confirm the spend.
62+
conf.ConfChan <- &chainntnfs.TxConfirmation{
63+
BlockHeight: uint32(testContext.mockLnd.Height),
64+
Tx: confTx,
65+
}
66+
67+
// We'll now expect the reservation to be confirmed.
68+
err = fsm.DefaultObserver.WaitForState(ctxb, 5*time.Second, Confirmed)
69+
require.NoError(t, err)
70+
71+
// We'll now expire the reservation.
72+
err = testContext.mockLnd.NotifyHeight(
73+
testContext.mockLnd.Height + int32(defaultExpiry),
74+
)
75+
require.NoError(t, err)
76+
77+
// We'll now expect the reservation to be expired.
78+
err = fsm.DefaultObserver.WaitForState(ctxb, 5*time.Second, TimedOut)
79+
require.NoError(t, err)
80+
}
81+
82+
// ManagerTestContext is a helper struct that contains all the necessary
83+
// components to test the reservation manager.
84+
type ManagerTestContext struct {
85+
manager *Manager
86+
context test.Context
87+
mockLnd *test.LndMockServices
88+
reservationNotificationChan chan *swapserverrpc.ServerReservationNotification
89+
mockReservationClient *mockReservationClient
90+
}
91+
92+
// newManagerTestContext creates a new test context for the reservation manager.
93+
func newManagerTestContext(t *testing.T) *ManagerTestContext {
94+
mockLnd := test.NewMockLnd()
95+
lndContext := test.NewContext(t, mockLnd)
96+
97+
dbFixture := loopdb.NewTestDB(t)
98+
99+
store := NewSQLStore(dbFixture)
100+
101+
mockReservationClient := new(mockReservationClient)
102+
103+
sendChan := make(chan *swapserverrpc.ServerReservationNotification)
104+
105+
mockReservationClient.On(
106+
"ReservationNotificationStream", mock.Anything, mock.Anything,
107+
mock.Anything,
108+
).Return(
109+
&dummyReservationNotificationServer{
110+
SendChan: sendChan,
111+
}, nil,
112+
)
113+
114+
mockReservationClient.On(
115+
"OpenReservation", mock.Anything, mock.Anything, mock.Anything,
116+
).Return(
117+
&swapserverrpc.ServerOpenReservationResponse{}, nil,
118+
)
119+
120+
cfg := &Config{
121+
Store: store,
122+
Wallet: mockLnd.WalletKit,
123+
ChainNotifier: mockLnd.ChainNotifier,
124+
FetchL402: func(context.Context) error { return nil },
125+
ReservationClient: mockReservationClient,
126+
}
127+
128+
manager := NewManager(cfg)
129+
130+
return &ManagerTestContext{
131+
manager: manager,
132+
context: lndContext,
133+
mockLnd: mockLnd,
134+
mockReservationClient: mockReservationClient,
135+
reservationNotificationChan: sendChan,
136+
}
137+
}
138+
139+
type dummyReservationNotificationServer struct {
140+
grpc.ClientStream
141+
142+
// SendChan is the channel that is used to send notifications.
143+
SendChan chan *swapserverrpc.ServerReservationNotification
144+
}
145+
146+
func (d *dummyReservationNotificationServer) Recv() (
147+
*swapserverrpc.ServerReservationNotification, error) {
148+
149+
return <-d.SendChan, nil
150+
}
151+
152+
func mustDecodeID(id string) ID {
153+
bytes, err := hex.DecodeString(id)
154+
if err != nil {
155+
panic(err)
156+
}
157+
var decoded ID
158+
copy(decoded[:], bytes)
159+
return decoded
160+
}

0 commit comments

Comments
 (0)