mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-01-19 05:45:21 +01:00
7924542500
In this commit, a new AddressIterator type is added. It is a type that can be used to iterate over a list of addresses. It strictly disallows the list of addresses it holds to be empty. It also allows callers to place locks on certain addresses in order to prevent other callers from removing the addresses in question from the iterator.
189 lines
5.0 KiB
Go
189 lines
5.0 KiB
Go
package wtclient
|
|
|
|
import (
|
|
"net"
|
|
"testing"
|
|
|
|
"github.com/lightningnetwork/lnd/watchtower/wtdb"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// TestAddrIterator tests the behaviour of the addressIterator.
|
|
func TestAddrIterator(t *testing.T) {
|
|
// Assert that an iterator can't be initialised with an empty address
|
|
// list.
|
|
_, err := newAddressIterator()
|
|
require.ErrorContains(t, err, "must have at least one address")
|
|
|
|
addr1, err := net.ResolveTCPAddr("tcp", "1.2.3.4:8000")
|
|
require.NoError(t, err)
|
|
|
|
// Initialise the iterator with addr1.
|
|
iter, err := newAddressIterator(addr1)
|
|
require.NoError(t, err)
|
|
|
|
// Attempting to remove addr1 should fail now since it is the only
|
|
// address in the iterator.
|
|
iter.Add(addr1)
|
|
err = iter.Remove(addr1)
|
|
require.ErrorIs(t, err, wtdb.ErrLastTowerAddr)
|
|
|
|
// Adding a duplicate of addr1 and then calling Remove should still
|
|
// return an error.
|
|
err = iter.Remove(addr1)
|
|
require.ErrorIs(t, err, wtdb.ErrLastTowerAddr)
|
|
|
|
addr2, err := net.ResolveTCPAddr("tcp", "1.2.3.4:8001")
|
|
require.NoError(t, err)
|
|
|
|
// Add addr2 to the iterator.
|
|
iter.Add(addr2)
|
|
|
|
// Check that peek returns addr1.
|
|
a1 := iter.Peek()
|
|
require.NoError(t, err)
|
|
require.Equal(t, addr1, a1)
|
|
|
|
// Calling peek multiple times should return the same result.
|
|
a1 = iter.Peek()
|
|
require.Equal(t, addr1, a1)
|
|
|
|
// Calling Next should now return addr2.
|
|
a2, err := iter.Next()
|
|
require.NoError(t, err)
|
|
require.Equal(t, addr2, a2)
|
|
|
|
// Assert that Peek now returns addr2.
|
|
a2 = iter.Peek()
|
|
require.NoError(t, err)
|
|
require.Equal(t, addr2, a2)
|
|
|
|
// Calling Next should result in reaching the end of th list.
|
|
_, err = iter.Next()
|
|
require.ErrorIs(t, err, ErrAddressesExhausted)
|
|
|
|
// Calling Peek now should reset the queue and return addr1.
|
|
a1 = iter.Peek()
|
|
require.Equal(t, addr1, a1)
|
|
|
|
// Wind the list to the end again so that we can test the Reset func.
|
|
_, err = iter.Next()
|
|
require.NoError(t, err)
|
|
|
|
_, err = iter.Next()
|
|
require.ErrorIs(t, err, ErrAddressesExhausted)
|
|
|
|
iter.Reset()
|
|
|
|
// Now Next should return addr 2.
|
|
a2, err = iter.Next()
|
|
require.NoError(t, err)
|
|
require.Equal(t, addr2, a2)
|
|
|
|
addr3, err := net.ResolveTCPAddr("tcp", "1.2.3.4:8002")
|
|
require.NoError(t, err)
|
|
|
|
// Add addr3 now to ensure that the iteration works even if we are
|
|
// midway through the queue.
|
|
iter.Add(addr3)
|
|
|
|
// Now Next should return addr 3.
|
|
a3, err := iter.Next()
|
|
require.NoError(t, err)
|
|
require.Equal(t, addr3, a3)
|
|
|
|
// Quickly test that GetAll correctly returns a copy of all the
|
|
// addresses in the iterator.
|
|
addrList := iter.GetAll()
|
|
require.ElementsMatch(t, addrList, []net.Addr{addr1, addr2, addr3})
|
|
|
|
// Let's now remove addr3.
|
|
err = iter.Remove(addr3)
|
|
require.NoError(t, err)
|
|
|
|
// Since addr3 is gone, Peek should return addr1.
|
|
a1 = iter.Peek()
|
|
require.Equal(t, addr1, a1)
|
|
|
|
// Lastly, we will test the "locking" of addresses.
|
|
|
|
// First we test the locking of an address via the PeekAndLock function.
|
|
a1 = iter.PeekAndLock()
|
|
require.Equal(t, addr1, a1)
|
|
require.True(t, iter.HasLocked())
|
|
|
|
// Assert that we can't remove addr1 if there is a lock on it.
|
|
err = iter.Remove(addr1)
|
|
require.ErrorIs(t, err, ErrAddrInUse)
|
|
|
|
// Now release the lock on addr1.
|
|
iter.ReleaseLock(addr1)
|
|
require.False(t, iter.HasLocked())
|
|
|
|
// Since the lock has been released, we should now be able to remove
|
|
// addr1.
|
|
err = iter.Remove(addr1)
|
|
require.NoError(t, err)
|
|
|
|
// Now we test the locking of an address via the NextAndLock function.
|
|
// To do this, we first re-add addr3.
|
|
iter.Add(addr3)
|
|
|
|
a2, err = iter.NextAndLock()
|
|
require.NoError(t, err)
|
|
require.Equal(t, addr2, a2)
|
|
require.True(t, iter.HasLocked())
|
|
|
|
// Assert that we can't remove addr2 if there is a lock on it.
|
|
err = iter.Remove(addr2)
|
|
require.ErrorIs(t, err, ErrAddrInUse)
|
|
|
|
// Now release the lock on addr2.
|
|
iter.ReleaseLock(addr2)
|
|
require.False(t, iter.HasLocked())
|
|
|
|
// Since the lock has been released, we should now be able to remove
|
|
// addr1.
|
|
err = iter.Remove(addr2)
|
|
require.NoError(t, err)
|
|
|
|
// Only addr3 should still be left in the iterator.
|
|
addrList = iter.GetAll()
|
|
require.Len(t, addrList, 1)
|
|
require.Contains(t, addrList, addr3)
|
|
|
|
// Ensure that HasLocked acts correctly in the case where more than one
|
|
// address is being locked and unlock as well as the case where the same
|
|
// address is locked more than once.
|
|
|
|
require.False(t, iter.HasLocked())
|
|
|
|
a3 = iter.PeekAndLock()
|
|
require.Equal(t, addr3, a3)
|
|
require.True(t, iter.HasLocked())
|
|
|
|
a3 = iter.PeekAndLock()
|
|
require.Equal(t, addr3, a3)
|
|
require.True(t, iter.HasLocked())
|
|
|
|
iter.Add(addr2)
|
|
a2, err = iter.NextAndLock()
|
|
require.NoError(t, err)
|
|
require.Equal(t, addr2, a2)
|
|
require.True(t, iter.HasLocked())
|
|
|
|
// Now release addr2 and asset that HasLock is still true.
|
|
iter.ReleaseLock(addr2)
|
|
require.True(t, iter.HasLocked())
|
|
|
|
// Releasing one of the locks on addr3 now should still result in
|
|
// HasLocked returning true.
|
|
iter.ReleaseLock(addr3)
|
|
require.True(t, iter.HasLocked())
|
|
|
|
// Releasing it again should now result in should still result in
|
|
// HasLocked returning false.
|
|
iter.ReleaseLock(addr3)
|
|
require.False(t, iter.HasLocked())
|
|
}
|