Skip to content

Commit 82556f5

Browse files
committed
itest+make: add remote mode integration test
1 parent defe05b commit 82556f5

File tree

8 files changed

+188
-15
lines changed

8 files changed

+188
-15
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ litcli-debug
1010

1111
itest/btcd-itest
1212
itest/litd-itest
13+
itest/lnd-itest
1314
itest/itest.test
1415
itest/.logs
1516
itest/*.log

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ travis-itest: lint
167167
build-itest: app-build
168168
@$(call print, "Building itest btcd and litd.")
169169
CGO_ENABLED=0 $(GOBUILD) -tags="$(ITEST_TAGS)" -o itest/btcd-itest -ldflags "$(ITEST_LDFLAGS)" $(BTCD_PKG)
170+
CGO_ENABLED=0 $(GOBUILD) -tags="$(ITEST_TAGS)" -o itest/lnd-itest -ldflags "$(ITEST_LDFLAGS)" $(LND_PKG)/cmd/lnd
170171

171172
itest-only:
172173
@$(call print, "Building itest binary.")

itest/litd_mode_remote_test.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package itest
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/btcsuite/btcutil"
8+
"github.com/lightningnetwork/lnd/lnrpc"
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
// testModeRemote makes sure that in remote mode all daemons work correctly.
13+
func testModeRemote(net *NetworkHarness, t *harnessTest) {
14+
ctx := context.Background()
15+
16+
// Some very basic functionality tests to make sure lnd is working fine
17+
// in remote mode.
18+
net.SendCoins(t.t, btcutil.SatoshiPerBitcoin, net.Bob)
19+
20+
// We expect a non-empty alias (truncated node ID) to be returned.
21+
resp, err := net.Bob.GetInfo(ctx, &lnrpc.GetInfoRequest{})
22+
require.NoError(t.t, err)
23+
require.NotEmpty(t.t, resp.Alias)
24+
require.Contains(t.t, resp.Alias, "0")
25+
26+
t.t.Run("certificate check", func(tt *testing.T) {
27+
cfg := net.Bob.Cfg
28+
29+
// In remote mode we expect the LiT HTTPS port (8443 by default)
30+
// and to have its own certificate
31+
litCerts, err := getServerCertificates(cfg.LitAddr())
32+
require.NoError(tt, err)
33+
require.Len(tt, litCerts, 1)
34+
require.Equal(
35+
tt, "litd autogenerated cert",
36+
litCerts[0].Issuer.Organization[0],
37+
)
38+
})
39+
t.t.Run("gRPC macaroon auth check", func(tt *testing.T) {
40+
cfg := net.Bob.Cfg
41+
42+
for _, endpoint := range endpoints {
43+
endpoint := endpoint
44+
tt.Run(endpoint.name+" lit port", func(ttt *testing.T) {
45+
if !endpoint.supportsMacAuthOnLitPort {
46+
return
47+
}
48+
49+
runGRPCAuthTest(
50+
ttt, cfg.LitAddr(), cfg.LitTLSCertPath,
51+
endpoint.macaroonFn(cfg),
52+
endpoint.requestFn,
53+
endpoint.successPattern,
54+
)
55+
})
56+
}
57+
})
58+
59+
t.t.Run("UI password auth check", func(tt *testing.T) {
60+
cfg := net.Bob.Cfg
61+
62+
for _, endpoint := range endpoints {
63+
endpoint := endpoint
64+
tt.Run(endpoint.name+" lit port", func(ttt *testing.T) {
65+
runUIPasswordCheck(
66+
ttt, cfg.LitAddr(), cfg.LitTLSCertPath,
67+
cfg.UIPassword,
68+
endpoint.requestFn, false,
69+
!endpoint.supportsUIPasswordOnLitPort,
70+
endpoint.successPattern,
71+
)
72+
})
73+
}
74+
})
75+
76+
t.t.Run("UI index page fallback", func(tt *testing.T) {
77+
runIndexPageCheck(tt, net.Bob.Cfg.LitAddr())
78+
})
79+
80+
t.t.Run("grpc-web auth", func(tt *testing.T) {
81+
cfg := net.Bob.Cfg
82+
83+
for _, endpoint := range endpoints {
84+
endpoint := endpoint
85+
tt.Run(endpoint.name+" lit port", func(ttt *testing.T) {
86+
runGRPCWebAuthTest(
87+
ttt, cfg.LitAddr(), cfg.UIPassword,
88+
endpoint.grpcWebURI,
89+
)
90+
})
91+
}
92+
})
93+
}

itest/litd_node.go

Lines changed: 80 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,21 @@ var (
5252
// numActiveNodes is the number of active nodes within the test network.
5353
numActiveNodes = 0
5454
numActiveNodesMtx sync.Mutex
55+
56+
defaultLndPassphrase = []byte("default-wallet-password")
5557
)
5658

5759
type LitNodeConfig struct {
5860
*lntest.BaseNodeConfig
5961

6062
LitArgs []string
6163

64+
RemoteMode bool
65+
6266
FaradayMacPath string
6367
LoopMacPath string
6468
PoolMacPath string
69+
LitTLSCertPath string
6570

6671
UIPassword string
6772
LitDir string
@@ -105,9 +110,9 @@ func (cfg *LitNodeConfig) GenArgs() []string {
105110
fmt.Sprintf("--pool.basedir=%s", cfg.PoolDir),
106111
fmt.Sprintf("--uipassword=%s", cfg.UIPassword),
107112
"--restcors=*",
108-
"--lnd-mode=integrated",
109113
}
110114
)
115+
litArgs = append(litArgs, cfg.LitArgs...)
111116

112117
switch cfg.NetParams {
113118
case &chaincfg.TestNet3Params:
@@ -118,9 +123,27 @@ func (cfg *LitNodeConfig) GenArgs() []string {
118123
litArgs = append(litArgs, "--network=regtest")
119124
}
120125

126+
// In remote mode, we don't need any lnd specific arguments other than
127+
// those we need to connect.
128+
if cfg.RemoteMode {
129+
litArgs = append(litArgs, "--lnd-mode=remote")
130+
litArgs = append(litArgs, fmt.Sprintf(
131+
"--remote.lnd.rpcserver=%s", cfg.RPCAddr()),
132+
)
133+
litArgs = append(litArgs, fmt.Sprintf(
134+
"--remote.lnd.tlscertpath=%s", cfg.TLSCertPath),
135+
)
136+
litArgs = append(litArgs, fmt.Sprintf(
137+
"--remote.lnd.macaroonpath=%s", cfg.AdminMacPath),
138+
)
139+
140+
return litArgs
141+
}
142+
121143
// All arguments so far were for lnd. Let's namespace them now so we can
122144
// add args for the other daemons and LiT itself afterwards.
123145
litArgs = append(litArgs, cfg.LitArgs...)
146+
litArgs = append(litArgs, "--lnd-mode=integrated")
124147
lndArgs := cfg.BaseNodeConfig.GenArgs()
125148
for idx := range lndArgs {
126149
litArgs = append(
@@ -156,6 +179,9 @@ type HarnessNode struct {
156179
// NodeID is a unique identifier for the node within a NetworkHarness.
157180
NodeID int
158181

182+
RemoteLnd *lntest.HarnessNode
183+
RemoteLndHarness *lntest.NetworkHarness
184+
159185
// PubKey is the serialized compressed identity public key of the node.
160186
// This field will only be populated once the node itself has been
161187
// started via the start() method.
@@ -220,7 +246,7 @@ var _ lnrpc.WalletUnlockerClient = (*HarnessNode)(nil)
220246
var _ invoicesrpc.InvoicesClient = (*HarnessNode)(nil)
221247

222248
// newNode creates a new test lightning node instance from the passed config.
223-
func newNode(cfg *LitNodeConfig) (*HarnessNode, error) {
249+
func newNode(cfg *LitNodeConfig, harness *NetworkHarness) (*HarnessNode, error) {
224250
if cfg.BaseDir == "" {
225251
var err error
226252
cfg.BaseDir, err = ioutil.TempDir("", "litdtest-node")
@@ -252,6 +278,7 @@ func newNode(cfg *LitNodeConfig) (*HarnessNode, error) {
252278
cfg.PoolMacPath = filepath.Join(
253279
cfg.PoolDir, cfg.NetParams.Name, "pool.macaroon",
254280
)
281+
cfg.LitTLSCertPath = filepath.Join(cfg.LitDir, "tls.cert")
255282
cfg.GenerateListeningPorts()
256283

257284
// Generate a random UI password by reading 16 random bytes and base64
@@ -270,9 +297,41 @@ func newNode(cfg *LitNodeConfig) (*HarnessNode, error) {
270297
numActiveNodes++
271298
numActiveNodesMtx.Unlock()
272299

300+
var (
301+
remoteNode *lntest.HarnessNode
302+
remoteNodeHarness *lntest.NetworkHarness
303+
err error
304+
)
305+
if cfg.RemoteMode {
306+
lndBinary := strings.ReplaceAll(
307+
getLitdBinary(), itestLitdBinary, itestLndBinary,
308+
)
309+
remoteNodeHarness, err = lntest.NewNetworkHarness(
310+
harness.Miner, harness.BackendCfg, lndBinary,
311+
lntest.BackendBbolt,
312+
)
313+
if err != nil {
314+
return nil, err
315+
}
316+
317+
remoteNode, _, _, err = remoteNodeHarness.NewNodeWithSeed(
318+
cfg.Name, cfg.ExtraArgs, defaultLndPassphrase, false,
319+
)
320+
if err != nil {
321+
return nil, err
322+
}
323+
324+
cfg.RPCPort = remoteNode.Cfg.RPCPort
325+
cfg.P2PPort = remoteNode.Cfg.P2PPort
326+
cfg.TLSCertPath = remoteNode.Cfg.TLSCertPath
327+
cfg.AdminMacPath = remoteNode.Cfg.AdminMacPath
328+
}
329+
273330
return &HarnessNode{
274331
Cfg: cfg,
275332
NodeID: nodeNum,
333+
RemoteLnd: remoteNode,
334+
RemoteLndHarness: remoteNodeHarness,
276335
chanWatchRequests: make(chan *chanWatchRequest),
277336
openChans: make(map[wire.OutPoint]int),
278337
openChanWatchers: make(map[wire.OutPoint][]chan struct{}),
@@ -929,14 +988,21 @@ func (hn *HarnessNode) ReadMacaroon(macPath string, timeout time.Duration) (
929988
func (hn *HarnessNode) ConnectRPCWithMacaroon(mac *macaroon.Macaroon) (
930989
*grpc.ClientConn, error) {
931990

991+
var (
992+
certPath = hn.Cfg.TLSCertPath
993+
connectAddr = hn.Cfg.RPCAddr()
994+
)
995+
if hn.Cfg.RemoteMode {
996+
certPath = hn.Cfg.LitTLSCertPath
997+
connectAddr = hn.Cfg.LitAddr()
998+
}
999+
9321000
// Wait until TLS certificate is created and has valid content before
9331001
// using it, up to 30 sec.
9341002
var tlsCreds credentials.TransportCredentials
9351003
err := wait.NoError(func() error {
9361004
var err error
937-
tlsCreds, err = credentials.NewClientTLSFromFile(
938-
hn.Cfg.TLSCertPath, "",
939-
)
1005+
tlsCreds, err = credentials.NewClientTLSFromFile(certPath, "")
9401006
return err
9411007
}, lntest.DefaultTimeout)
9421008
if err != nil {
@@ -948,19 +1014,21 @@ func (hn *HarnessNode) ConnectRPCWithMacaroon(mac *macaroon.Macaroon) (
9481014
grpc.WithTransportCredentials(tlsCreds),
9491015
}
9501016

951-
ctx, cancel := context.WithTimeout(context.Background(), lntest.DefaultTimeout)
1017+
ctx, cancel := context.WithTimeout(
1018+
context.Background(), lntest.DefaultTimeout,
1019+
)
9521020
defer cancel()
9531021

9541022
if mac == nil {
955-
return grpc.DialContext(ctx, hn.Cfg.RPCAddr(), opts...)
1023+
return grpc.DialContext(ctx, connectAddr, opts...)
9561024
}
9571025
macCred, err := macaroons.NewMacaroonCredential(mac)
9581026
if err != nil {
9591027
return nil, fmt.Errorf("error cloning mac: %v", err)
9601028
}
9611029
opts = append(opts, grpc.WithPerRPCCredentials(macCred))
9621030

963-
return grpc.DialContext(ctx, hn.Cfg.RPCAddr(), opts...)
1031+
return grpc.DialContext(ctx, connectAddr, opts...)
9641032
}
9651033

9661034
// ConnectRPC uses the TLS certificate and admin macaroon files written by the
@@ -1061,6 +1129,10 @@ func (hn *HarnessNode) stop() error {
10611129
}
10621130
}
10631131

1132+
if hn.Cfg.RemoteMode {
1133+
return hn.RemoteLndHarness.ShutdownNode(hn.RemoteLnd)
1134+
}
1135+
10641136
return nil
10651137
}
10661138

itest/litd_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func TestLightningTerminal(t *testing.T) {
7373
// Now we can set up our test harness (LND instance), with the chain
7474
// backend we just created.
7575
ht := newHarnessTest(t, nil)
76-
binary := ht.getLitdBinary()
76+
binary := getLitdBinary()
7777
litdHarness, err = NewNetworkHarness(miner, chainBackend, binary)
7878
if err != nil {
7979
ht.Fatalf("unable to create lightning network harness: %v", err)

itest/litd_test_list_on_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,8 @@ var allTestCases = []*testCase{
88
name: "test mode integrated",
99
test: testModeIntegrated,
1010
},
11+
{
12+
name: "test mode remote",
13+
test: testModeRemote,
14+
},
1115
}

itest/network_harness.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -144,14 +144,14 @@ func (n *NetworkHarness) SetUp(t *testing.T,
144144
eg.Go(func() error {
145145
var err error
146146
n.Alice, err = n.newNode(
147-
"Alice", lndArgs, litArgs, false, nil, true,
147+
"Alice", lndArgs, litArgs, false, false, nil, true,
148148
)
149149
return err
150150
})
151151
eg.Go(func() error {
152152
var err error
153153
n.Bob, err = n.newNode(
154-
"Bob", lndArgs, litArgs, false, nil, true,
154+
"Bob", lndArgs, litArgs, false, true, nil, true,
155155
)
156156
return err
157157
})
@@ -265,8 +265,8 @@ func (n *NetworkHarness) Stop() {
265265
// can be used immediately. Otherwise, the node will require an additional
266266
// initialization phase where the wallet is either created or restored.
267267
func (n *NetworkHarness) newNode(name string, extraArgs, litArgs []string,
268-
hasSeed bool, password []byte, wait bool, opts ...lntest.NodeOption) (
269-
*HarnessNode, error) {
268+
hasSeed, remoteMode bool, password []byte, wait bool,
269+
opts ...lntest.NodeOption) (*HarnessNode, error) {
270270

271271
baseCfg := &lntest.BaseNodeConfig{
272272
Name: name,
@@ -283,9 +283,10 @@ func (n *NetworkHarness) newNode(name string, extraArgs, litArgs []string,
283283
cfg := &LitNodeConfig{
284284
BaseNodeConfig: baseCfg,
285285
LitArgs: litArgs,
286+
RemoteMode: remoteMode,
286287
}
287288

288-
node, err := newNode(cfg)
289+
node, err := newNode(cfg, n)
289290
if err != nil {
290291
return nil, err
291292
}

itest/test_harness.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const (
3131
defaultTimeout = lntest.DefaultTimeout
3232
minerMempoolTimeout = lntest.MinerMempoolTimeout
3333
itestLitdBinary = "litd-itest"
34+
itestLndBinary = "lnd-itest"
3435
)
3536

3637
// harnessTest wraps a regular testing.T providing enhanced error detection
@@ -103,7 +104,7 @@ func (h *harnessTest) Log(args ...interface{}) {
103104
h.t.Log(args...)
104105
}
105106

106-
func (h *harnessTest) getLitdBinary() string {
107+
func getLitdBinary() string {
107108
binary := itestLitdBinary
108109
litdExec := ""
109110
if litdExecutable != nil && *litdExecutable != "" {

0 commit comments

Comments
 (0)