itest: add integration test for forceclose command

This commit is contained in:
Oli 2025-12-10 09:02:23 +01:00
parent 1a31b6c7f4
commit f22fb11ce2
No known key found for this signature in database
GPG key ID: 8E4256593F177720
5 changed files with 96 additions and 11 deletions

View file

@ -11,15 +11,17 @@ around the network).
The network is set up as follows:
```
Alice ◄──► Bob ◄──► Charlie ◄──► Dave
Alice ◄──► Bob ◄──► Charlie ◄──► Dave*
└───────►└──► Rusty ◄──┘
| Nifty ◄──┘ |
└► Snyke ◄────────────
|────► Nifty ◄──┘ |
└► Snyke* ◄────────────┘
```
- Channel **Alice** - **Bob**: Remains open, used by `runZombieRecoveryLndLnd`.
- Channel **Alice** - **Rusty**: Is force closed by Alice, used by
`runSweepRemoteClosedCln`.
- Channel **Alice** - **Nifty**: Is force closed by Alice, used by
`runForceClose`.
- Channel **Alice** - **Snyke**: Remains open, used by
`runTriggerForceCloseCln`.
- Channel **Bob** - **Charlie**: Is force closed by Bob, used by
@ -32,6 +34,7 @@ The network is set up as follows:
`runZombieRecoveryClnLnd`.
- Channel **Rusty** - **Nifty**: Remains open, used by
`runZombieRecoveryClnCln`.
- `*`: Node is kept running after initial test setup.
All nodes except for Dave and Snyke are stopped before the integration tests
are run.

View file

@ -0,0 +1,30 @@
package itest
import (
"fmt"
"testing"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/stretchr/testify/require"
)
func runForceClose(t *testing.T) {
aliceChannels := readChannelsJSON(t, "alice")
niftyIdentity := getNodeIdentityKeyCln(t, "nifty")
var aliceNiftyChannel *lnrpc.Channel
for _, c := range aliceChannels {
if c.RemotePubkey == niftyIdentity {
aliceNiftyChannel = c
}
}
require.NotNil(t, aliceNiftyChannel, "alice-nifty channel not found")
channelDB := fmt.Sprintf(channelDBFilePattern, "alice")
txHex, _ := getForceClose(
t, "alice", tempDir, channelDB, aliceNiftyChannel.ChannelPoint,
)
backend := connectBitcoind(t)
publishTx(t, txHex, backend)
}

View file

@ -34,7 +34,7 @@ wait_for_nodes alice bob charlie dave rusty nifty snyke
do_for fund_node alice bob charlie dave rusty nifty snyke
# Alice, Bob and Charlie will open more than one channel each.
do_for fund_node alice alice bob charlie charlie
do_for fund_node alice alice alice bob charlie charlie
mine 6
@ -54,6 +54,7 @@ connect_nodes rusty nifty
open_channel alice bob
open_channel alice rusty
open_channel alice nifty
open_channel bob charlie
open_channel charlie dave
open_channel bob rusty
@ -64,15 +65,15 @@ open_channel alice snyke
echo "🔗 Set up network:"
cat << EOF
Alice ◄──► Bob ◄──► Charlie ◄──► Dave
Alice ◄──► Bob ◄──► Charlie ◄──► Dave*
└───────►└──► Rusty ◄──┘
| Nifty ◄──┘ |
└► Snyke ◄────────────
|────► Nifty ◄──┘ |
└► Snyke* ◄────────────┘
EOF
mine 12
num_channels=9
num_channels=10
wait_graph_sync alice $num_channels
wait_graph_sync bob $num_channels
@ -84,15 +85,17 @@ send_payment bob dave
send_payment dave bob
send_payment alice dave
send_payment alice rusty
send_payment alice nifty
send_payment dave rusty
send_payment alice snyke
send_payment charlie snyke
# Repeat the basic tests.
# Repeat the basic sends.
send_payment bob dave
send_payment dave bob
send_payment alice dave
send_payment alice rusty
send_payment alice nifty
send_payment dave rusty
send_payment alice snyke
send_payment charlie snyke

View file

@ -30,8 +30,10 @@ const (
)
const (
channelsFilePattern = "docker/node-data/chantools/%s-channels.json"
walletFilePattern = "docker/node-data/%s/data/chain/bitcoin/" +
channelsFilePattern = "docker/node-data/chantools/%s-channels.json"
channelDBFilePattern = "docker/node-data/%s/data/graph/regtest/" +
"channel.db"
walletFilePattern = "docker/node-data/%s/data/chain/bitcoin/" +
"regtest/wallet.db"
scbFilePattern = "docker/node-data/%s/data/chain/bitcoin/" +
"regtest/channel.backup"
@ -354,6 +356,32 @@ func invokeCmdScbForceClose(t *testing.T, walletPassword *string,
return output
}
func invokeCmdForceClose(t *testing.T, walletPassword *string,
resultsDir string, args ...string) string {
t.Helper()
fullArgs := append([]string{
"--regtest", "--resultsdir", resultsDir, "forceclose",
}, args...)
proc := StartChantools(t, fullArgs...)
defer proc.Wait(t)
if walletPassword != nil {
pwPrompt := proc.ReadAvailableOutput(t, readTimeout)
require.Contains(t, pwPrompt, "Input wallet password:")
proc.WriteInput(t, *walletPassword+"\n")
proc.AssertNoStderr(t)
}
proc.AssertNoStderr(t)
output := proc.ReadAvailableOutput(t, longTimeout)
return output
}
func getNodeIdentityKey(t *testing.T, node string) string {
t.Helper()
@ -553,3 +581,20 @@ func getScbForceClose(t *testing.T, node, tempDir, multiBackup,
return txHex, cmdOutput
}
func getForceClose(t *testing.T, node, tempDir, channelDB,
channelPoint string) (string, string) {
t.Helper()
walletDbPath := fmt.Sprintf(walletFilePattern, node)
cmdOutput := invokeCmdForceClose(
t, &emptyPassword, tempDir,
"--channelpoint", channelPoint, "--walletdb", walletDbPath,
"--channeldb", channelDB,
)
txHex := extractRowContent(cmdOutput, rowRawTransaction)
require.Contains(t, txHex, transactionHexIdent)
return txHex, cmdOutput
}

View file

@ -46,6 +46,10 @@ var testCases = []testCase{
name: "scb force close",
fn: runScbForceClose,
},
{
name: "force close",
fn: runForceClose,
},
}
// TestIntegration runs all integration test cases.