lnd/watchtower/wtclient/candidate_iterator_test.go
Elle Mouton 8a7329b988
watchtower: make use of the new AddressIterator
This commit upgrades the wtclient package to make use of the new
`AddressIterator`. It does so by first creating new `Tower` and
`ClientSession` types. The new `Tower` type has an `AddressIterator`
instead of a list of addresses. The `ClientSession` type contains a
`Tower`.
2022-10-20 15:46:52 +02:00

159 lines
4.5 KiB
Go

package wtclient
import (
"encoding/binary"
"math/rand"
"net"
"testing"
"time"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/lightningnetwork/lnd/watchtower/wtdb"
"github.com/stretchr/testify/require"
)
func init() {
rand.Seed(time.Now().Unix())
}
func randAddr(t *testing.T) net.Addr {
t.Helper()
var ip [4]byte
_, err := rand.Read(ip[:])
require.NoError(t, err)
var port [2]byte
_, err = rand.Read(port[:])
require.NoError(t, err)
return &net.TCPAddr{
IP: net.IP(ip[:]),
Port: int(binary.BigEndian.Uint16(port[:])),
}
}
func randTower(t *testing.T) *Tower {
t.Helper()
priv, err := btcec.NewPrivateKey()
require.NoError(t, err, "unable to create private key")
pubKey := priv.PubKey()
addrs, err := newAddressIterator(randAddr(t))
require.NoError(t, err)
return &Tower{
ID: wtdb.TowerID(rand.Uint64()),
IdentityKey: pubKey,
Addresses: addrs,
}
}
func copyTower(t *testing.T, tower *Tower) *Tower {
t.Helper()
addrs := tower.Addresses.GetAll()
addrIterator, err := newAddressIterator(addrs...)
require.NoError(t, err)
return &Tower{
ID: tower.ID,
IdentityKey: tower.IdentityKey,
Addresses: addrIterator,
}
}
func assertActiveCandidate(t *testing.T, i TowerCandidateIterator, c *Tower,
active bool) {
t.Helper()
isCandidate := i.IsActive(c.ID)
if isCandidate {
require.Truef(t, active, "expected tower %v to no longer be "+
"an active candidate", c.ID)
return
}
require.Falsef(t, active, "expected tower %v to be an active candidate",
c.ID)
}
func assertNextCandidate(t *testing.T, i TowerCandidateIterator, c *Tower) {
t.Helper()
tower, err := i.Next()
require.NoError(t, err)
require.True(t, tower.IdentityKey.IsEqual(c.IdentityKey))
require.Equal(t, tower.ID, c.ID)
require.Equal(t, tower.Addresses.GetAll(), c.Addresses.GetAll())
}
// TestTowerCandidateIterator asserts the internal state of a
// TowerCandidateIterator after a series of updates to its candidates.
func TestTowerCandidateIterator(t *testing.T) {
t.Parallel()
// We'll start our test by creating an iterator of four candidate
// towers. We'll use copies of these towers within the iterator to
// ensure the iterator properly updates the state of its candidates.
const numTowers = 4
towers := make([]*Tower, 0, numTowers)
for i := 0; i < numTowers; i++ {
towers = append(towers, randTower(t))
}
towerCopies := make([]*Tower, 0, numTowers)
for _, tower := range towers {
towerCopies = append(towerCopies, copyTower(t, tower))
}
towerIterator := newTowerListIterator(towerCopies...)
// We should expect to see all of our candidates in the order that they
// were added.
for _, expTower := range towers {
tower, err := towerIterator.Next()
require.NoError(t, err)
require.Equal(t, expTower, tower)
}
_, err := towerIterator.Next()
require.ErrorIs(t, err, ErrTowerCandidatesExhausted)
towerIterator.Reset()
// We'll then attempt to test the RemoveCandidate behavior of the
// iterator. We'll attempt to remove the address of the first tower,
// which should result in an error due to it being the last address of
// the tower.
firstTower := towers[0]
firstTowerAddr := firstTower.Addresses.Peek()
err = towerIterator.RemoveCandidate(firstTower.ID, firstTowerAddr)
require.ErrorIs(t, err, wtdb.ErrLastTowerAddr)
assertActiveCandidate(t, towerIterator, firstTower, true)
assertNextCandidate(t, towerIterator, firstTower)
// We'll then remove the second tower completely from the iterator by
// not providing the optional address. Since it's been removed, we
// should expect to see the third tower next.
secondTower, thirdTower := towers[1], towers[2]
err = towerIterator.RemoveCandidate(secondTower.ID, nil)
require.NoError(t, err)
assertActiveCandidate(t, towerIterator, secondTower, false)
assertNextCandidate(t, towerIterator, thirdTower)
// We'll then update the fourth candidate with a new address. A
// duplicate shouldn't be added since it already exists within the
// iterator, but the new address should be.
fourthTower := towers[3]
assertActiveCandidate(t, towerIterator, fourthTower, true)
fourthTower.Addresses.Add(randAddr(t))
towerIterator.AddCandidate(fourthTower)
assertNextCandidate(t, towerIterator, fourthTower)
// Finally, we'll attempt to add a new candidate to the end of the
// iterator. Since it didn't already exist and we've reached the end, it
// should be available as the next candidate.
towerIterator.AddCandidate(secondTower)
assertActiveCandidate(t, towerIterator, secondTower, true)
assertNextCandidate(t, towerIterator, secondTower)
}