mirror of
https://github.com/lightninglabs/lightning-terminal.git
synced 2026-08-13 12:33:36 +02:00
itest+make: add remote mode integration test
This commit is contained in:
parent
defe05bac3
commit
82556f5775
8 changed files with 188 additions and 15 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -10,6 +10,7 @@ litcli-debug
|
|||
|
||||
itest/btcd-itest
|
||||
itest/litd-itest
|
||||
itest/lnd-itest
|
||||
itest/itest.test
|
||||
itest/.logs
|
||||
itest/*.log
|
||||
1
Makefile
1
Makefile
|
|
@ -167,6 +167,7 @@ travis-itest: lint
|
|||
build-itest: app-build
|
||||
@$(call print, "Building itest btcd and litd.")
|
||||
CGO_ENABLED=0 $(GOBUILD) -tags="$(ITEST_TAGS)" -o itest/btcd-itest -ldflags "$(ITEST_LDFLAGS)" $(BTCD_PKG)
|
||||
CGO_ENABLED=0 $(GOBUILD) -tags="$(ITEST_TAGS)" -o itest/lnd-itest -ldflags "$(ITEST_LDFLAGS)" $(LND_PKG)/cmd/lnd
|
||||
|
||||
itest-only:
|
||||
@$(call print, "Building itest binary.")
|
||||
|
|
|
|||
93
itest/litd_mode_remote_test.go
Normal file
93
itest/litd_mode_remote_test.go
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
package itest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// testModeRemote makes sure that in remote mode all daemons work correctly.
|
||||
func testModeRemote(net *NetworkHarness, t *harnessTest) {
|
||||
ctx := context.Background()
|
||||
|
||||
// Some very basic functionality tests to make sure lnd is working fine
|
||||
// in remote mode.
|
||||
net.SendCoins(t.t, btcutil.SatoshiPerBitcoin, net.Bob)
|
||||
|
||||
// We expect a non-empty alias (truncated node ID) to be returned.
|
||||
resp, err := net.Bob.GetInfo(ctx, &lnrpc.GetInfoRequest{})
|
||||
require.NoError(t.t, err)
|
||||
require.NotEmpty(t.t, resp.Alias)
|
||||
require.Contains(t.t, resp.Alias, "0")
|
||||
|
||||
t.t.Run("certificate check", func(tt *testing.T) {
|
||||
cfg := net.Bob.Cfg
|
||||
|
||||
// In remote mode we expect the LiT HTTPS port (8443 by default)
|
||||
// and to have its own certificate
|
||||
litCerts, err := getServerCertificates(cfg.LitAddr())
|
||||
require.NoError(tt, err)
|
||||
require.Len(tt, litCerts, 1)
|
||||
require.Equal(
|
||||
tt, "litd autogenerated cert",
|
||||
litCerts[0].Issuer.Organization[0],
|
||||
)
|
||||
})
|
||||
t.t.Run("gRPC macaroon auth check", func(tt *testing.T) {
|
||||
cfg := net.Bob.Cfg
|
||||
|
||||
for _, endpoint := range endpoints {
|
||||
endpoint := endpoint
|
||||
tt.Run(endpoint.name+" lit port", func(ttt *testing.T) {
|
||||
if !endpoint.supportsMacAuthOnLitPort {
|
||||
return
|
||||
}
|
||||
|
||||
runGRPCAuthTest(
|
||||
ttt, cfg.LitAddr(), cfg.LitTLSCertPath,
|
||||
endpoint.macaroonFn(cfg),
|
||||
endpoint.requestFn,
|
||||
endpoint.successPattern,
|
||||
)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.t.Run("UI password auth check", func(tt *testing.T) {
|
||||
cfg := net.Bob.Cfg
|
||||
|
||||
for _, endpoint := range endpoints {
|
||||
endpoint := endpoint
|
||||
tt.Run(endpoint.name+" lit port", func(ttt *testing.T) {
|
||||
runUIPasswordCheck(
|
||||
ttt, cfg.LitAddr(), cfg.LitTLSCertPath,
|
||||
cfg.UIPassword,
|
||||
endpoint.requestFn, false,
|
||||
!endpoint.supportsUIPasswordOnLitPort,
|
||||
endpoint.successPattern,
|
||||
)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.t.Run("UI index page fallback", func(tt *testing.T) {
|
||||
runIndexPageCheck(tt, net.Bob.Cfg.LitAddr())
|
||||
})
|
||||
|
||||
t.t.Run("grpc-web auth", func(tt *testing.T) {
|
||||
cfg := net.Bob.Cfg
|
||||
|
||||
for _, endpoint := range endpoints {
|
||||
endpoint := endpoint
|
||||
tt.Run(endpoint.name+" lit port", func(ttt *testing.T) {
|
||||
runGRPCWebAuthTest(
|
||||
ttt, cfg.LitAddr(), cfg.UIPassword,
|
||||
endpoint.grpcWebURI,
|
||||
)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -52,6 +52,8 @@ var (
|
|||
// numActiveNodes is the number of active nodes within the test network.
|
||||
numActiveNodes = 0
|
||||
numActiveNodesMtx sync.Mutex
|
||||
|
||||
defaultLndPassphrase = []byte("default-wallet-password")
|
||||
)
|
||||
|
||||
type LitNodeConfig struct {
|
||||
|
|
@ -59,9 +61,12 @@ type LitNodeConfig struct {
|
|||
|
||||
LitArgs []string
|
||||
|
||||
RemoteMode bool
|
||||
|
||||
FaradayMacPath string
|
||||
LoopMacPath string
|
||||
PoolMacPath string
|
||||
LitTLSCertPath string
|
||||
|
||||
UIPassword string
|
||||
LitDir string
|
||||
|
|
@ -105,9 +110,9 @@ func (cfg *LitNodeConfig) GenArgs() []string {
|
|||
fmt.Sprintf("--pool.basedir=%s", cfg.PoolDir),
|
||||
fmt.Sprintf("--uipassword=%s", cfg.UIPassword),
|
||||
"--restcors=*",
|
||||
"--lnd-mode=integrated",
|
||||
}
|
||||
)
|
||||
litArgs = append(litArgs, cfg.LitArgs...)
|
||||
|
||||
switch cfg.NetParams {
|
||||
case &chaincfg.TestNet3Params:
|
||||
|
|
@ -118,9 +123,27 @@ func (cfg *LitNodeConfig) GenArgs() []string {
|
|||
litArgs = append(litArgs, "--network=regtest")
|
||||
}
|
||||
|
||||
// In remote mode, we don't need any lnd specific arguments other than
|
||||
// those we need to connect.
|
||||
if cfg.RemoteMode {
|
||||
litArgs = append(litArgs, "--lnd-mode=remote")
|
||||
litArgs = append(litArgs, fmt.Sprintf(
|
||||
"--remote.lnd.rpcserver=%s", cfg.RPCAddr()),
|
||||
)
|
||||
litArgs = append(litArgs, fmt.Sprintf(
|
||||
"--remote.lnd.tlscertpath=%s", cfg.TLSCertPath),
|
||||
)
|
||||
litArgs = append(litArgs, fmt.Sprintf(
|
||||
"--remote.lnd.macaroonpath=%s", cfg.AdminMacPath),
|
||||
)
|
||||
|
||||
return litArgs
|
||||
}
|
||||
|
||||
// All arguments so far were for lnd. Let's namespace them now so we can
|
||||
// add args for the other daemons and LiT itself afterwards.
|
||||
litArgs = append(litArgs, cfg.LitArgs...)
|
||||
litArgs = append(litArgs, "--lnd-mode=integrated")
|
||||
lndArgs := cfg.BaseNodeConfig.GenArgs()
|
||||
for idx := range lndArgs {
|
||||
litArgs = append(
|
||||
|
|
@ -156,6 +179,9 @@ type HarnessNode struct {
|
|||
// NodeID is a unique identifier for the node within a NetworkHarness.
|
||||
NodeID int
|
||||
|
||||
RemoteLnd *lntest.HarnessNode
|
||||
RemoteLndHarness *lntest.NetworkHarness
|
||||
|
||||
// PubKey is the serialized compressed identity public key of the node.
|
||||
// This field will only be populated once the node itself has been
|
||||
// started via the start() method.
|
||||
|
|
@ -220,7 +246,7 @@ var _ lnrpc.WalletUnlockerClient = (*HarnessNode)(nil)
|
|||
var _ invoicesrpc.InvoicesClient = (*HarnessNode)(nil)
|
||||
|
||||
// newNode creates a new test lightning node instance from the passed config.
|
||||
func newNode(cfg *LitNodeConfig) (*HarnessNode, error) {
|
||||
func newNode(cfg *LitNodeConfig, harness *NetworkHarness) (*HarnessNode, error) {
|
||||
if cfg.BaseDir == "" {
|
||||
var err error
|
||||
cfg.BaseDir, err = ioutil.TempDir("", "litdtest-node")
|
||||
|
|
@ -252,6 +278,7 @@ func newNode(cfg *LitNodeConfig) (*HarnessNode, error) {
|
|||
cfg.PoolMacPath = filepath.Join(
|
||||
cfg.PoolDir, cfg.NetParams.Name, "pool.macaroon",
|
||||
)
|
||||
cfg.LitTLSCertPath = filepath.Join(cfg.LitDir, "tls.cert")
|
||||
cfg.GenerateListeningPorts()
|
||||
|
||||
// Generate a random UI password by reading 16 random bytes and base64
|
||||
|
|
@ -270,9 +297,41 @@ func newNode(cfg *LitNodeConfig) (*HarnessNode, error) {
|
|||
numActiveNodes++
|
||||
numActiveNodesMtx.Unlock()
|
||||
|
||||
var (
|
||||
remoteNode *lntest.HarnessNode
|
||||
remoteNodeHarness *lntest.NetworkHarness
|
||||
err error
|
||||
)
|
||||
if cfg.RemoteMode {
|
||||
lndBinary := strings.ReplaceAll(
|
||||
getLitdBinary(), itestLitdBinary, itestLndBinary,
|
||||
)
|
||||
remoteNodeHarness, err = lntest.NewNetworkHarness(
|
||||
harness.Miner, harness.BackendCfg, lndBinary,
|
||||
lntest.BackendBbolt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
remoteNode, _, _, err = remoteNodeHarness.NewNodeWithSeed(
|
||||
cfg.Name, cfg.ExtraArgs, defaultLndPassphrase, false,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cfg.RPCPort = remoteNode.Cfg.RPCPort
|
||||
cfg.P2PPort = remoteNode.Cfg.P2PPort
|
||||
cfg.TLSCertPath = remoteNode.Cfg.TLSCertPath
|
||||
cfg.AdminMacPath = remoteNode.Cfg.AdminMacPath
|
||||
}
|
||||
|
||||
return &HarnessNode{
|
||||
Cfg: cfg,
|
||||
NodeID: nodeNum,
|
||||
RemoteLnd: remoteNode,
|
||||
RemoteLndHarness: remoteNodeHarness,
|
||||
chanWatchRequests: make(chan *chanWatchRequest),
|
||||
openChans: make(map[wire.OutPoint]int),
|
||||
openChanWatchers: make(map[wire.OutPoint][]chan struct{}),
|
||||
|
|
@ -929,14 +988,21 @@ func (hn *HarnessNode) ReadMacaroon(macPath string, timeout time.Duration) (
|
|||
func (hn *HarnessNode) ConnectRPCWithMacaroon(mac *macaroon.Macaroon) (
|
||||
*grpc.ClientConn, error) {
|
||||
|
||||
var (
|
||||
certPath = hn.Cfg.TLSCertPath
|
||||
connectAddr = hn.Cfg.RPCAddr()
|
||||
)
|
||||
if hn.Cfg.RemoteMode {
|
||||
certPath = hn.Cfg.LitTLSCertPath
|
||||
connectAddr = hn.Cfg.LitAddr()
|
||||
}
|
||||
|
||||
// Wait until TLS certificate is created and has valid content before
|
||||
// using it, up to 30 sec.
|
||||
var tlsCreds credentials.TransportCredentials
|
||||
err := wait.NoError(func() error {
|
||||
var err error
|
||||
tlsCreds, err = credentials.NewClientTLSFromFile(
|
||||
hn.Cfg.TLSCertPath, "",
|
||||
)
|
||||
tlsCreds, err = credentials.NewClientTLSFromFile(certPath, "")
|
||||
return err
|
||||
}, lntest.DefaultTimeout)
|
||||
if err != nil {
|
||||
|
|
@ -948,11 +1014,13 @@ func (hn *HarnessNode) ConnectRPCWithMacaroon(mac *macaroon.Macaroon) (
|
|||
grpc.WithTransportCredentials(tlsCreds),
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), lntest.DefaultTimeout)
|
||||
ctx, cancel := context.WithTimeout(
|
||||
context.Background(), lntest.DefaultTimeout,
|
||||
)
|
||||
defer cancel()
|
||||
|
||||
if mac == nil {
|
||||
return grpc.DialContext(ctx, hn.Cfg.RPCAddr(), opts...)
|
||||
return grpc.DialContext(ctx, connectAddr, opts...)
|
||||
}
|
||||
macCred, err := macaroons.NewMacaroonCredential(mac)
|
||||
if err != nil {
|
||||
|
|
@ -960,7 +1028,7 @@ func (hn *HarnessNode) ConnectRPCWithMacaroon(mac *macaroon.Macaroon) (
|
|||
}
|
||||
opts = append(opts, grpc.WithPerRPCCredentials(macCred))
|
||||
|
||||
return grpc.DialContext(ctx, hn.Cfg.RPCAddr(), opts...)
|
||||
return grpc.DialContext(ctx, connectAddr, opts...)
|
||||
}
|
||||
|
||||
// ConnectRPC uses the TLS certificate and admin macaroon files written by the
|
||||
|
|
@ -1061,6 +1129,10 @@ func (hn *HarnessNode) stop() error {
|
|||
}
|
||||
}
|
||||
|
||||
if hn.Cfg.RemoteMode {
|
||||
return hn.RemoteLndHarness.ShutdownNode(hn.RemoteLnd)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ func TestLightningTerminal(t *testing.T) {
|
|||
// Now we can set up our test harness (LND instance), with the chain
|
||||
// backend we just created.
|
||||
ht := newHarnessTest(t, nil)
|
||||
binary := ht.getLitdBinary()
|
||||
binary := getLitdBinary()
|
||||
litdHarness, err = NewNetworkHarness(miner, chainBackend, binary)
|
||||
if err != nil {
|
||||
ht.Fatalf("unable to create lightning network harness: %v", err)
|
||||
|
|
|
|||
|
|
@ -8,4 +8,8 @@ var allTestCases = []*testCase{
|
|||
name: "test mode integrated",
|
||||
test: testModeIntegrated,
|
||||
},
|
||||
{
|
||||
name: "test mode remote",
|
||||
test: testModeRemote,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,14 +144,14 @@ func (n *NetworkHarness) SetUp(t *testing.T,
|
|||
eg.Go(func() error {
|
||||
var err error
|
||||
n.Alice, err = n.newNode(
|
||||
"Alice", lndArgs, litArgs, false, nil, true,
|
||||
"Alice", lndArgs, litArgs, false, false, nil, true,
|
||||
)
|
||||
return err
|
||||
})
|
||||
eg.Go(func() error {
|
||||
var err error
|
||||
n.Bob, err = n.newNode(
|
||||
"Bob", lndArgs, litArgs, false, nil, true,
|
||||
"Bob", lndArgs, litArgs, false, true, nil, true,
|
||||
)
|
||||
return err
|
||||
})
|
||||
|
|
@ -265,8 +265,8 @@ func (n *NetworkHarness) Stop() {
|
|||
// can be used immediately. Otherwise, the node will require an additional
|
||||
// initialization phase where the wallet is either created or restored.
|
||||
func (n *NetworkHarness) newNode(name string, extraArgs, litArgs []string,
|
||||
hasSeed bool, password []byte, wait bool, opts ...lntest.NodeOption) (
|
||||
*HarnessNode, error) {
|
||||
hasSeed, remoteMode bool, password []byte, wait bool,
|
||||
opts ...lntest.NodeOption) (*HarnessNode, error) {
|
||||
|
||||
baseCfg := &lntest.BaseNodeConfig{
|
||||
Name: name,
|
||||
|
|
@ -283,9 +283,10 @@ func (n *NetworkHarness) newNode(name string, extraArgs, litArgs []string,
|
|||
cfg := &LitNodeConfig{
|
||||
BaseNodeConfig: baseCfg,
|
||||
LitArgs: litArgs,
|
||||
RemoteMode: remoteMode,
|
||||
}
|
||||
|
||||
node, err := newNode(cfg)
|
||||
node, err := newNode(cfg, n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ const (
|
|||
defaultTimeout = lntest.DefaultTimeout
|
||||
minerMempoolTimeout = lntest.MinerMempoolTimeout
|
||||
itestLitdBinary = "litd-itest"
|
||||
itestLndBinary = "lnd-itest"
|
||||
)
|
||||
|
||||
// harnessTest wraps a regular testing.T providing enhanced error detection
|
||||
|
|
@ -103,7 +104,7 @@ func (h *harnessTest) Log(args ...interface{}) {
|
|||
h.t.Log(args...)
|
||||
}
|
||||
|
||||
func (h *harnessTest) getLitdBinary() string {
|
||||
func getLitdBinary() string {
|
||||
binary := itestLitdBinary
|
||||
litdExec := ""
|
||||
if litdExecutable != nil && *litdExecutable != "" {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue