lnd/chanbackup/recover_test.go

217 lines
5.3 KiB
Go

package chanbackup
import (
"bytes"
"errors"
"net"
"testing"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/lightningnetwork/lnd/lnencrypt"
"github.com/stretchr/testify/require"
)
var (
errRestoreFail = errors.New("restore fail")
errConnectFail = errors.New("connect fail")
)
type mockChannelRestorer struct {
fail bool
callCount int
}
func (m *mockChannelRestorer) RestoreChansFromSingles(...Single) error {
if m.fail {
return errRestoreFail
}
m.callCount++
return nil
}
type mockPeerConnector struct {
fail bool
callCount int
}
func (m *mockPeerConnector) ConnectPeer(_ *btcec.PublicKey,
_ []net.Addr) error {
if m.fail {
return errConnectFail
}
m.callCount++
return nil
}
// TestUnpackAndRecoverSingles tests that we're able to properly unpack and
// recover a set of packed singles.
func TestUnpackAndRecoverSingles(t *testing.T) {
t.Parallel()
keyRing := &lnencrypt.MockKeyRing{}
// First, we'll create a number of single chan backups that we'll
// shortly back to so we can begin our recovery attempt.
numSingles := 10
backups := make([]Single, 0, numSingles)
var packedBackups PackedSingles
for i := 0; i < numSingles; i++ {
channel, err := genRandomOpenChannelShell()
require.NoError(t, err)
single := NewSingle(channel, nil)
var b bytes.Buffer
err = single.PackToWriter(&b, keyRing)
require.NoError(t, err)
backups = append(backups, single)
packedBackups = append(packedBackups, b.Bytes())
}
chanRestorer := mockChannelRestorer{}
peerConnector := mockPeerConnector{}
// Now that we have our backups (packed and unpacked), we'll attempt to
// restore them all in a single batch.
// If we make the channel restore fail, then the entire method should
// as well
chanRestorer.fail = true
_, err := UnpackAndRecoverSingles(
packedBackups, keyRing, &chanRestorer, &peerConnector,
)
require.ErrorIs(t, err, errRestoreFail)
chanRestorer.fail = false
// If we make the peer connector fail, then the entire method should as
// well
peerConnector.fail = true
_, err = UnpackAndRecoverSingles(
packedBackups, keyRing, &chanRestorer, &peerConnector,
)
require.ErrorIs(t, err, errConnectFail)
chanRestorer.callCount--
peerConnector.fail = false
// Next, we'll ensure that if all the interfaces function as expected,
// then the channels will properly be unpacked and restored.
numRestored, err := UnpackAndRecoverSingles(
packedBackups, keyRing, &chanRestorer, &peerConnector,
)
require.NoError(t, err)
require.EqualValues(t, numSingles, numRestored)
// Both the restorer, and connector should have been called 10 times,
// once for each backup.
require.EqualValues(
t, numSingles, chanRestorer.callCount, "restorer call count",
)
require.EqualValues(
t, numSingles, peerConnector.callCount, "peer call count",
)
// If we modify the keyRing, then unpacking should fail.
keyRing.Fail = true
_, err = UnpackAndRecoverSingles(
packedBackups, keyRing, &chanRestorer, &peerConnector,
)
require.ErrorContains(t, err, "fail")
// TODO(roasbeef): verify proper call args
}
// TestUnpackAndRecoverMulti tests that we're able to properly unpack and
// recover a packed multi.
func TestUnpackAndRecoverMulti(t *testing.T) {
t.Parallel()
keyRing := &lnencrypt.MockKeyRing{}
// First, we'll create a number of single chan backups that we'll
// shortly back to so we can begin our recovery attempt.
numSingles := 10
backups := make([]Single, 0, numSingles)
for i := 0; i < numSingles; i++ {
channel, err := genRandomOpenChannelShell()
require.NoError(t, err)
single := NewSingle(channel, nil)
backups = append(backups, single)
}
multi := Multi{
StaticBackups: backups,
}
var b bytes.Buffer
err := multi.PackToWriter(&b, keyRing)
require.NoError(t, err)
// Next, we'll pack the set of singles into a packed multi, and also
// create the set of interfaces we need to carry out the remainder of
// the test.
packedMulti := PackedMulti(b.Bytes())
chanRestorer := mockChannelRestorer{}
peerConnector := mockPeerConnector{}
// If we make the channel restore fail, then the entire method should
// as well
chanRestorer.fail = true
_, err = UnpackAndRecoverMulti(
packedMulti, keyRing, &chanRestorer, &peerConnector,
)
require.ErrorIs(t, err, errRestoreFail)
chanRestorer.fail = false
// If we make the peer connector fail, then the entire method should as
// well
peerConnector.fail = true
_, err = UnpackAndRecoverMulti(
packedMulti, keyRing, &chanRestorer, &peerConnector,
)
require.ErrorIs(t, err, errConnectFail)
chanRestorer.callCount--
peerConnector.fail = false
// Next, we'll ensure that if all the interfaces function as expected,
// then the channels will properly be unpacked and restored.
numRestored, err := UnpackAndRecoverMulti(
packedMulti, keyRing, &chanRestorer, &peerConnector,
)
require.NoError(t, err)
require.EqualValues(t, numSingles, numRestored)
// Both the restorer, and connector should have been called 10 times,
// once for each backup.
require.EqualValues(
t, numSingles, chanRestorer.callCount, "restorer call count",
)
require.EqualValues(
t, numSingles, peerConnector.callCount, "peer call count",
)
// If we modify the keyRing, then unpacking should fail.
keyRing.Fail = true
_, err = UnpackAndRecoverMulti(
packedMulti, keyRing, &chanRestorer, &peerConnector,
)
require.ErrorContains(t, err, "fail")
// TODO(roasbeef): verify proper call args
}