1ace7ede01
This commit fixes the build for version 1.6.3 of golang. In go 1.7, the “context” package was moved into the standard library, however go 1.6.3 doesn’t have that change, so we must refer to the prior WIP package until a new version of Go is released.
189 lines
5.8 KiB
Go
189 lines
5.8 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"runtime/debug"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"golang.org/x/net/context"
|
|
|
|
"github.com/lightningnetwork/lnd/lnrpc"
|
|
"github.com/roasbeef/btcd/rpctest"
|
|
"github.com/roasbeef/btcd/wire"
|
|
"github.com/roasbeef/btcutil"
|
|
)
|
|
|
|
type lndTestCase func(net *networkHarness, t *testing.T)
|
|
|
|
func assertTxInBlock(block *btcutil.Block, txid *wire.ShaHash, t *testing.T) {
|
|
for _, tx := range block.Transactions() {
|
|
if bytes.Equal(txid[:], tx.Sha()[:]) {
|
|
return
|
|
}
|
|
}
|
|
|
|
t.Fatalf("funding tx was not included in block")
|
|
}
|
|
|
|
// testBasicChannelFunding performs a test excercising expected behavior from a
|
|
// basic funding workflow. The test creates a new channel between Alice and
|
|
// Bob, then immediately closes the channel after asserting some expected post
|
|
// conditions. Finally, the chain itelf is checked to ensure the closing
|
|
// transaction was mined.
|
|
func testBasicChannelFunding(net *networkHarness, t *testing.T) {
|
|
ctxb := context.Background()
|
|
|
|
// First establish a channel between Alice and Bob.
|
|
openReq := &lnrpc.OpenChannelRequest{
|
|
// TODO(roasbeef): should pass actual id instead, will fail if
|
|
// more connections added for Alice.
|
|
TargetPeerId: 1,
|
|
LocalFundingAmount: btcutil.SatoshiPerBitcoin / 2,
|
|
RemoteFundingAmount: 0,
|
|
NumConfs: 1,
|
|
}
|
|
time.Sleep(time.Millisecond * 500)
|
|
respStream, err := net.AliceClient.OpenChannel(ctxb, openReq)
|
|
if err != nil {
|
|
t.Fatalf("unable to open channel between alice and bob: %v", err)
|
|
}
|
|
|
|
// Mine a block, the funding txid should be included, and both nodes should
|
|
// be aware of the channel.
|
|
// TODO(roasbeef): replace sleep with something more robust
|
|
time.Sleep(time.Second * 1)
|
|
blockHash, err := net.Miner.Node.Generate(1)
|
|
if err != nil {
|
|
t.Fatalf("unable to generate block: %v", err)
|
|
}
|
|
resp, err := respStream.Recv()
|
|
if err != nil {
|
|
t.Fatalf("unable to read rpc resp: %v", err)
|
|
}
|
|
block, err := net.Miner.Node.GetBlock(blockHash[0])
|
|
if err != nil {
|
|
t.Fatalf("unable to get block: %v", err)
|
|
}
|
|
if len(block.Transactions()) < 2 {
|
|
t.Fatalf("funding transaction not included")
|
|
}
|
|
|
|
fundingTxID, _ := wire.NewShaHash(resp.ChannelPoint.FundingTxid)
|
|
fundingTxIDStr := fundingTxID.String()
|
|
assertTxInBlock(block, fundingTxID, t)
|
|
|
|
// TODO(roasbeef): remove and use "listchannels" command after
|
|
// implemented.
|
|
req := &lnrpc.ListPeersRequest{}
|
|
alicePeerInfo, err := net.AliceClient.ListPeers(ctxb, req)
|
|
if err != nil {
|
|
t.Fatalf("unable to list alice peers: %v", err)
|
|
}
|
|
bobPeerInfo, err := net.BobClient.ListPeers(ctxb, req)
|
|
if err != nil {
|
|
t.Fatalf("unable to list bob peers: %v", err)
|
|
}
|
|
|
|
// The channel should be listed in the peer information returned by
|
|
// both peers.
|
|
aliceTxID := alicePeerInfo.Peers[0].Channels[0].ChannelPoint
|
|
bobTxID := bobPeerInfo.Peers[0].Channels[0].ChannelPoint
|
|
if !strings.Contains(bobTxID, fundingTxIDStr) {
|
|
t.Fatalf("alice's channel not found")
|
|
}
|
|
if !strings.Contains(aliceTxID, fundingTxIDStr) {
|
|
t.Fatalf("bob's channel not found")
|
|
}
|
|
|
|
// Initiate a close from Alice's side. After mining a block, the closing
|
|
// transaction should be included, and both nodes should have forgotten
|
|
// about the channel.
|
|
closeReq := &lnrpc.CloseChannelRequest{
|
|
ChannelPoint: resp.ChannelPoint,
|
|
}
|
|
closeRespStream, err := net.AliceClient.CloseChannel(ctxb, closeReq)
|
|
if err != nil {
|
|
t.Fatalf("unable to close channel: %v", err)
|
|
}
|
|
time.Sleep(time.Second * 1)
|
|
blockHash, err = net.Miner.Node.Generate(1)
|
|
if err != nil {
|
|
t.Fatalf("unable to generate block: %v", err)
|
|
}
|
|
block, err = net.Miner.Node.GetBlock(blockHash[0])
|
|
if err != nil {
|
|
t.Fatalf("unable to get block: %v", err)
|
|
}
|
|
closeResp, err := closeRespStream.Recv()
|
|
if err != nil {
|
|
t.Fatalf("unable to read rpc resp: %v", err)
|
|
}
|
|
|
|
closingTxID, _ := wire.NewShaHash(closeResp.ClosingTxid)
|
|
assertTxInBlock(block, closingTxID, t)
|
|
}
|
|
|
|
var lndTestCases = map[string]lndTestCase{
|
|
"basic funding flow": testBasicChannelFunding,
|
|
}
|
|
|
|
// TestLightningNetworkDaemon performs a series of integration tests amongst a
|
|
// programatically driven network of lnd nodes.
|
|
func TestLightningNetworkDaemon(t *testing.T) {
|
|
var btcdHarness *rpctest.Harness
|
|
var lightningNetwork *networkHarness
|
|
var currentTest string
|
|
var err error
|
|
|
|
defer func() {
|
|
// If one of the integration tests caused a panic within the main
|
|
// goroutine, then tear down all the harnesses in order to avoid
|
|
// any leaked processes.
|
|
if r := recover(); r != nil {
|
|
fmt.Println("recovering from test panic: ", r)
|
|
if err := btcdHarness.TearDown(); err != nil {
|
|
fmt.Println("unable to tear btcd harnesses: ", err)
|
|
}
|
|
if err := lightningNetwork.TearDownAll(); err != nil {
|
|
fmt.Println("unable to tear lnd harnesses: ", err)
|
|
}
|
|
t.Fatalf("test %v panicked: %s", currentTest, debug.Stack())
|
|
}
|
|
}()
|
|
|
|
// First create an intance of the btcd's rpctest.Harness. This will be
|
|
// used to fund the wallets of the nodes within the test network and to
|
|
// drive blockchain related events within the network.
|
|
btcdHarness, err = rpctest.New(harnessNetParams, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("unable to create mining node: %v", err)
|
|
}
|
|
defer btcdHarness.TearDown()
|
|
if err = btcdHarness.SetUp(true, 50); err != nil {
|
|
t.Fatalf("unable to set up mining node: %v", err)
|
|
}
|
|
|
|
// With the btcd harness created, create an instance of the lightning
|
|
// network harness as it depends on the btcd harness to script network
|
|
// activity.
|
|
lightningNetwork, err = newNetworkHarness(btcdHarness, nil)
|
|
if err != nil {
|
|
t.Fatalf("unable to create lightning network harness: %v", err)
|
|
}
|
|
defer lightningNetwork.TearDownAll()
|
|
if err = lightningNetwork.SetUp(); err != nil {
|
|
t.Fatalf("unable to set up test lightning network: %v", err)
|
|
}
|
|
|
|
t.Logf("Running %v integration tests", len(lndTestCases))
|
|
for testName, lnTest := range lndTestCases {
|
|
t.Logf("Executing test %v", testName)
|
|
|
|
currentTest = testName
|
|
lnTest(lightningNetwork, t)
|
|
}
|
|
}
|