|
|
|
@ -2,7 +2,9 @@ package liquidity
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"reflect"
|
|
|
|
|
"testing"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"github.com/btcsuite/btcd/btcutil"
|
|
|
|
|
"github.com/lightninglabs/lndclient"
|
|
|
|
@ -11,8 +13,10 @@ import (
|
|
|
|
|
"github.com/lightninglabs/loop/swap"
|
|
|
|
|
"github.com/lightninglabs/loop/test"
|
|
|
|
|
"github.com/lightningnetwork/lnd/clock"
|
|
|
|
|
"github.com/lightningnetwork/lnd/lntypes"
|
|
|
|
|
"github.com/lightningnetwork/lnd/ticker"
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type autoloopTestCtx struct {
|
|
|
|
@ -45,9 +49,17 @@ type autoloopTestCtx struct {
|
|
|
|
|
// loopOuts is a channel that we get existing loop out swaps on.
|
|
|
|
|
loopOuts chan []*loopdb.LoopOut
|
|
|
|
|
|
|
|
|
|
// loopOutSingle is the single loop out returned from fetching a single
|
|
|
|
|
// swap from store.
|
|
|
|
|
loopOutSingle *loopdb.LoopOut
|
|
|
|
|
|
|
|
|
|
// loopIns is a channel that we get existing loop in swaps on.
|
|
|
|
|
loopIns chan []*loopdb.LoopIn
|
|
|
|
|
|
|
|
|
|
// loopInSingle is the single loop in returned from fetching a single
|
|
|
|
|
// swap from store.
|
|
|
|
|
loopInSingle *loopdb.LoopIn
|
|
|
|
|
|
|
|
|
|
// restrictions is a channel that we get swap restrictions on.
|
|
|
|
|
restrictions chan *Restrictions
|
|
|
|
|
|
|
|
|
@ -131,6 +143,9 @@ func newAutoloopTestCtx(t *testing.T, parameters Parameters,
|
|
|
|
|
ListLoopOut: func() ([]*loopdb.LoopOut, error) {
|
|
|
|
|
return <-testCtx.loopOuts, nil
|
|
|
|
|
},
|
|
|
|
|
GetLoopOut: func(hash lntypes.Hash) (*loopdb.LoopOut, error) {
|
|
|
|
|
return testCtx.loopOutSingle, nil
|
|
|
|
|
},
|
|
|
|
|
ListLoopIn: func() ([]*loopdb.LoopIn, error) {
|
|
|
|
|
return <-testCtx.loopIns, nil
|
|
|
|
|
},
|
|
|
|
@ -188,6 +203,10 @@ func newAutoloopTestCtx(t *testing.T, parameters Parameters,
|
|
|
|
|
testCtx.manager = NewManager(cfg)
|
|
|
|
|
err := testCtx.manager.setParameters(context.Background(), parameters)
|
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
// Override the payments check interval for the tests in order to not
|
|
|
|
|
// timeout.
|
|
|
|
|
testCtx.manager.params.CustomPaymentCheckInterval =
|
|
|
|
|
150 * time.Millisecond
|
|
|
|
|
<-done
|
|
|
|
|
return testCtx
|
|
|
|
|
}
|
|
|
|
@ -241,14 +260,17 @@ type loopInRequestResp struct {
|
|
|
|
|
// autoloopStep contains all of the information to required to step
|
|
|
|
|
// through an autoloop tick.
|
|
|
|
|
type autoloopStep struct {
|
|
|
|
|
minAmt btcutil.Amount
|
|
|
|
|
maxAmt btcutil.Amount
|
|
|
|
|
existingOut []*loopdb.LoopOut
|
|
|
|
|
existingIn []*loopdb.LoopIn
|
|
|
|
|
quotesOut []quoteRequestResp
|
|
|
|
|
quotesIn []quoteInRequestResp
|
|
|
|
|
expectedOut []loopOutRequestResp
|
|
|
|
|
expectedIn []loopInRequestResp
|
|
|
|
|
minAmt btcutil.Amount
|
|
|
|
|
maxAmt btcutil.Amount
|
|
|
|
|
existingOut []*loopdb.LoopOut
|
|
|
|
|
existingOutSingle *loopdb.LoopOut
|
|
|
|
|
existingIn []*loopdb.LoopIn
|
|
|
|
|
existingInSingle *loopdb.LoopIn
|
|
|
|
|
quotesOut []quoteRequestResp
|
|
|
|
|
quotesIn []quoteInRequestResp
|
|
|
|
|
expectedOut []loopOutRequestResp
|
|
|
|
|
expectedIn []loopInRequestResp
|
|
|
|
|
keepDestAddr bool
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// autoloop walks our test context through the process of triggering our
|
|
|
|
@ -269,6 +291,9 @@ func (c *autoloopTestCtx) autoloop(step *autoloopStep) {
|
|
|
|
|
c.loopOuts <- step.existingOut
|
|
|
|
|
c.loopIns <- step.existingIn
|
|
|
|
|
|
|
|
|
|
c.loopOutSingle = step.existingOutSingle
|
|
|
|
|
c.loopInSingle = step.existingInSingle
|
|
|
|
|
|
|
|
|
|
// Assert that we query the server for a quote for each of our
|
|
|
|
|
// recommended swaps. Note that this differs from our set of expected
|
|
|
|
|
// swaps because we may get quotes for suggested swaps but then just
|
|
|
|
@ -299,25 +324,77 @@ func (c *autoloopTestCtx) autoloop(step *autoloopStep) {
|
|
|
|
|
c.quotes <- expected.quote
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Assert that we dispatch the expected set of swaps.
|
|
|
|
|
for _, expected := range step.expectedOut {
|
|
|
|
|
require.True(c.t, c.matchLoopOuts(step.expectedOut, step.keepDestAddr))
|
|
|
|
|
require.True(c.t, c.matchLoopIns(step.expectedIn))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// matchLoopOuts checks that the actual loop out requests we got match the
|
|
|
|
|
// expected ones. The argument keepDestAddr is used to indicate whether we keep
|
|
|
|
|
// the actual loops destination address for the comparison. This is useful
|
|
|
|
|
// because we don't want to compare the destination address generated by the
|
|
|
|
|
// wallet mock. We want to compare the destination address when testing the
|
|
|
|
|
// autoloop DestAddr parameter for loop outs.
|
|
|
|
|
func (c *autoloopTestCtx) matchLoopOuts(swaps []loopOutRequestResp,
|
|
|
|
|
keepDestAddr bool) bool {
|
|
|
|
|
|
|
|
|
|
swapsCopy := make([]loopOutRequestResp, len(swaps))
|
|
|
|
|
copy(swapsCopy, swaps)
|
|
|
|
|
|
|
|
|
|
length := len(swapsCopy)
|
|
|
|
|
|
|
|
|
|
for i := 0; i < length; i++ {
|
|
|
|
|
actual := <-c.outRequest
|
|
|
|
|
|
|
|
|
|
// Set our destination address to nil so that we do not need to
|
|
|
|
|
// provide the address that is obtained by the mock wallet kit.
|
|
|
|
|
if expected.request.DestAddr == nil {
|
|
|
|
|
if !keepDestAddr {
|
|
|
|
|
actual.DestAddr = nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert.Equal(c.t, expected.request, actual)
|
|
|
|
|
c.loopOut <- expected.response
|
|
|
|
|
inner:
|
|
|
|
|
for index, swap := range swapsCopy {
|
|
|
|
|
equal := reflect.DeepEqual(swap.request, actual)
|
|
|
|
|
|
|
|
|
|
if equal {
|
|
|
|
|
c.loopOut <- swap.response
|
|
|
|
|
|
|
|
|
|
swapsCopy = append(
|
|
|
|
|
swapsCopy[:index],
|
|
|
|
|
swapsCopy[index+1:]...,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
break inner
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, expected := range step.expectedIn {
|
|
|
|
|
return len(swapsCopy) == 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// matchLoopIns checks that the actual loop in requests we got match the
|
|
|
|
|
// expected ones.
|
|
|
|
|
func (c *autoloopTestCtx) matchLoopIns(
|
|
|
|
|
swaps []loopInRequestResp) bool {
|
|
|
|
|
|
|
|
|
|
swapsCopy := make([]loopInRequestResp, len(swaps))
|
|
|
|
|
copy(swapsCopy, swaps)
|
|
|
|
|
|
|
|
|
|
for i := 0; i < len(swapsCopy); i++ {
|
|
|
|
|
actual := <-c.inRequest
|
|
|
|
|
|
|
|
|
|
assert.Equal(c.t, expected.request, actual)
|
|
|
|
|
inner:
|
|
|
|
|
for i, swap := range swapsCopy {
|
|
|
|
|
equal := reflect.DeepEqual(swap.request, actual)
|
|
|
|
|
|
|
|
|
|
c.loopIn <- expected.response
|
|
|
|
|
if equal {
|
|
|
|
|
c.loopIn <- swap.response
|
|
|
|
|
|
|
|
|
|
swapsCopy = append(
|
|
|
|
|
swapsCopy[:i], swapsCopy[i+1:]...,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
break inner
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return len(swapsCopy) == 0
|
|
|
|
|
}
|
|
|
|
|