2
0
mirror of https://github.com/lightninglabs/loop synced 2024-11-13 13:10:30 +00:00
loop/client/testcontext_test.go
2019-03-06 15:29:49 -08:00

235 lines
4.6 KiB
Go

package client
import (
"context"
"testing"
"time"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lightninglabs/loop/sweep"
"github.com/lightninglabs/loop/test"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/lntypes"
)
var (
testPreimage = lntypes.Preimage([32]byte{
1, 1, 1, 1, 2, 2, 2, 2,
3, 3, 3, 3, 4, 4, 4, 4,
1, 1, 1, 1, 2, 2, 2, 2,
3, 3, 3, 3, 4, 4, 4, 4,
})
testPrepayPreimage = lntypes.Preimage([32]byte{
1, 1, 1, 1, 2, 2, 2, 2,
3, 3, 3, 3, 4, 4, 4, 4,
1, 1, 1, 1, 2, 2, 2, 2,
3, 3, 3, 3, 4, 4, 4, 5,
})
testStartingHeight = uint32(600)
)
// testContext contains functionality to support client unit tests.
type testContext struct {
test.Context
serverMock *serverMock
swapClient *Client
statusChan chan SwapInfo
store *storeMock
expiryChan chan time.Time
runErr chan error
stop func()
}
func newSwapClient(config *clientConfig) *Client {
sweeper := &sweep.Sweeper{
Lnd: config.LndServices,
}
lndServices := config.LndServices
executor := newExecutor(&executorConfig{
lnd: lndServices,
store: config.Store,
sweeper: sweeper,
createExpiryTimer: config.CreateExpiryTimer,
})
return &Client{
errChan: make(chan error),
clientConfig: *config,
lndServices: lndServices,
sweeper: sweeper,
executor: executor,
resumeReady: make(chan struct{}),
}
}
func createClientTestContext(t *testing.T,
pendingSwaps []*PersistentUncharge) *testContext {
serverMock := newServerMock()
clientLnd := test.NewMockLnd()
store := newStoreMock(t)
for _, s := range pendingSwaps {
store.unchargeSwaps[s.Hash] = s.Contract
updates := []SwapState{}
for _, e := range s.Events {
updates = append(updates, e.State)
}
store.unchargeUpdates[s.Hash] = updates
}
expiryChan := make(chan time.Time)
timerFactory := func(expiry time.Duration) <-chan time.Time {
return expiryChan
}
swapClient := newSwapClient(&clientConfig{
LndServices: &clientLnd.LndServices,
Server: serverMock,
Store: store,
CreateExpiryTimer: timerFactory,
})
statusChan := make(chan SwapInfo)
ctx := &testContext{
Context: test.NewContext(
t,
clientLnd,
),
swapClient: swapClient,
statusChan: statusChan,
expiryChan: expiryChan,
store: store,
serverMock: serverMock,
}
ctx.runErr = make(chan error)
runCtx, stop := context.WithCancel(context.Background())
ctx.stop = stop
go func() {
ctx.runErr <- swapClient.Run(
runCtx,
statusChan,
)
}()
return ctx
}
func (ctx *testContext) finish() {
ctx.stop()
select {
case err := <-ctx.runErr:
if err != nil {
ctx.T.Fatal(err)
}
case <-time.After(test.Timeout):
ctx.T.Fatal("client not stopping")
}
ctx.assertIsDone()
}
// notifyHeight notifies swap client of the arrival of a new block and waits for
// the notification to be processed by selecting on a dedicated test channel.
func (ctx *testContext) notifyHeight(height int32) {
ctx.T.Helper()
if err := ctx.Lnd.NotifyHeight(height); err != nil {
ctx.T.Fatal(err)
}
}
func (ctx *testContext) assertIsDone() {
if err := ctx.Lnd.IsDone(); err != nil {
ctx.T.Fatal(err)
}
if err := ctx.store.isDone(); err != nil {
ctx.T.Fatal(err)
}
select {
case <-ctx.statusChan:
ctx.T.Fatalf("not all status updates read")
default:
}
}
func (ctx *testContext) assertStored() {
ctx.T.Helper()
ctx.store.assertUnchargeStored()
}
func (ctx *testContext) assertStorePreimageReveal() {
ctx.T.Helper()
ctx.store.assertStorePreimageReveal()
}
func (ctx *testContext) assertStoreFinished(expectedResult SwapState) {
ctx.T.Helper()
ctx.store.assertStoreFinished(expectedResult)
}
func (ctx *testContext) assertStatus(expectedState SwapState) {
ctx.T.Helper()
for {
select {
case update := <-ctx.statusChan:
if update.SwapType != SwapTypeUncharge {
continue
}
if update.State == expectedState {
return
}
case <-time.After(test.Timeout):
ctx.T.Fatalf("expected status %v not "+
"received in time", expectedState)
}
}
}
func (ctx *testContext) publishHtlc(script []byte, amt btcutil.Amount) wire.OutPoint {
// Create the htlc tx.
htlcTx := wire.MsgTx{}
htlcTx.AddTxIn(&wire.TxIn{
PreviousOutPoint: wire.OutPoint{},
})
htlcTx.AddTxOut(&wire.TxOut{
PkScript: script,
Value: int64(amt),
})
htlcTxHash := htlcTx.TxHash()
// Signal client that script has been published.
select {
case ctx.Lnd.ConfChannel <- &chainntnfs.TxConfirmation{
Tx: &htlcTx,
}:
case <-time.After(test.Timeout):
ctx.T.Fatalf("htlc confirmed not consumed")
}
return wire.OutPoint{
Hash: htlcTxHash,
Index: 0,
}
}