Skip to content

Commit 2ea4ebd

Browse files
committed
itest: add test for litd surviving lnd shutdown
1 parent ff7eeeb commit 2ea4ebd

2 files changed

Lines changed: 133 additions & 0 deletions

File tree

itest/litd_lnd_shutdown_test.go

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package itest
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/lightninglabs/lightning-terminal/litrpc"
8+
"github.com/lightninglabs/lightning-terminal/subservers"
9+
"github.com/lightningnetwork/lnd/lnrpc"
10+
"github.com/lightningnetwork/lnd/lntest/wait"
11+
"github.com/stretchr/testify/require"
12+
)
13+
14+
// testLitdSurvivesLndShutdown asserts that when lnd stops in integrated mode,
15+
// litd keeps running and its status endpoint stays reachable, reporting lnd as
16+
// stopped rather than cascading to a full litd shutdown.
17+
func testLitdSurvivesLndShutdown(ctx context.Context, net *NetworkHarness,
18+
t *harnessTest) {
19+
20+
// Use a dedicated, throwaway node so that stopping its lnd cannot
21+
// affect any other test.
22+
node, err := net.NewNode(
23+
t.t, "lnd-stop", nil, false, true, "--autopilot.disable",
24+
)
25+
require.NoError(t.t, err)
26+
27+
// The harness ShutdownNode stops litd (via its StopDaemon) and waits
28+
// for the process to exit, so no manual litd shutdown is needed here.
29+
defer func() {
30+
_ = net.ShutdownNode(node)
31+
}()
32+
33+
ctxt, cancel := context.WithTimeout(ctx, defaultTimeout)
34+
defer cancel()
35+
36+
rawConn, err := connectLitRPC(
37+
ctxt, node.Cfg.LitAddr(), node.Cfg.LitTLSCertPath,
38+
node.Cfg.LitMacPath,
39+
)
40+
require.NoError(t.t, err)
41+
defer func() { _ = rawConn.Close() }()
42+
43+
statusClient := litrpc.NewStatusClient(rawConn)
44+
45+
// lnd should be running before we stop it.
46+
resp, err := statusClient.SubServerStatus(
47+
ctxt, &litrpc.SubServerStatusReq{},
48+
)
49+
require.NoError(t.t, err)
50+
51+
lndStatus, ok := resp.SubServers[subservers.LND]
52+
require.True(t.t, ok, "expected lnd sub-server status")
53+
require.True(t.t, lndStatus.Running, "lnd should be running initially")
54+
55+
// Stop lnd (but not litd) via the lnrpc StopDaemon. The call may return
56+
// an error as the connection is torn down, which is expected.
57+
_, _ = node.LightningClient.StopDaemon(ctxt, &lnrpc.StopRequest{})
58+
59+
// litd's status endpoint must remain reachable and must report lnd as
60+
// no longer running, with an error explaining why. We poll because lnd
61+
// shutdown is asynchronous.
62+
err = wait.NoError(func() error {
63+
ctxs, cancels := context.WithTimeout(
64+
context.Background(), defaultTimeout,
65+
)
66+
defer cancels()
67+
68+
resp, err := statusClient.SubServerStatus(
69+
ctxs, &litrpc.SubServerStatusReq{},
70+
)
71+
if err != nil {
72+
return fmt.Errorf("litd status endpoint unreachable "+
73+
"after lnd stopped: %w", err)
74+
}
75+
76+
lndStatus, ok := resp.SubServers[subservers.LND]
77+
if !ok {
78+
return fmt.Errorf("no lnd sub-server status returned")
79+
}
80+
81+
if lndStatus.Running {
82+
return fmt.Errorf("lnd still reported as running")
83+
}
84+
85+
if lndStatus.Error == "" {
86+
return fmt.Errorf("lnd error message not yet set")
87+
}
88+
89+
return nil
90+
}, defaultTimeout)
91+
require.NoError(t.t, err)
92+
93+
// litd's process itself must keep running after lnd has stopped: its
94+
// status endpoint stays reachable. The LIT sub-server is reported as no
95+
// longer running, since litd cannot function without lnd, but the
96+
// endpoint continuing to answer at all is what proves litd did not
97+
// cascade down with lnd. Check this holds over time.
98+
err = wait.InvariantNoError(func() error {
99+
ctxs, cancels := context.WithTimeout(
100+
context.Background(), defaultTimeout,
101+
)
102+
defer cancels()
103+
104+
resp, err := statusClient.SubServerStatus(
105+
ctxs, &litrpc.SubServerStatusReq{},
106+
)
107+
if err != nil {
108+
return fmt.Errorf("litd status endpoint must stay "+
109+
"reachable after lnd stopped: %w", err)
110+
}
111+
112+
litStatus, ok := resp.SubServers[subservers.LIT]
113+
if !ok {
114+
return fmt.Errorf("no lit sub-server status returned")
115+
}
116+
117+
if litStatus.Running {
118+
return fmt.Errorf("lit sub-server should be reported " +
119+
"as stopped once lnd has stopped")
120+
}
121+
122+
if litStatus.Error == "" {
123+
return fmt.Errorf("lit sub-server error message not set")
124+
}
125+
126+
return nil
127+
}, defaultTimeout)
128+
require.NoError(t.t, err)
129+
}

itest/litd_test_list_on_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,8 @@ var allTestCases = []*testCase{
3131
name: "kvdb to sql migration",
3232
test: testKvdbSQLMigration,
3333
},
34+
{
35+
name: "litd survives lnd shutdown",
36+
test: testLitdSurvivesLndShutdown,
37+
},
3438
}

0 commit comments

Comments
 (0)