status-go/services/wallet/saved_addresses_test.go
Ivan Belyakov 2df9df10ab fix(tests): moved test db setup to a common place 't/helpers', created
interface for initializing db, which is implemented for appdatabase and
walletdatabase. TBD for multiaccounts DB.
Unified DB initializion for all tests using helpers and new interface.
Reduced sqlcipher kdf iterations for all tests to 1.
2023-08-18 09:00:56 +02:00

396 lines
11 KiB
Go

package wallet
import (
"strconv"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/common"
"github.com/status-im/status-go/t/helpers"
"github.com/status-im/status-go/walletdatabase"
)
const (
ensMember int = iota
isTestMember
addressMember
)
func setupTestSavedAddressesDB(t *testing.T) (*SavedAddressesManager, func()) {
db, err := helpers.SetupTestMemorySQLDB(walletdatabase.DbInitializer{})
require.NoError(t, err)
return &SavedAddressesManager{db}, func() {
require.NoError(t, db.Close())
}
}
func TestSavedAddressesAdd(t *testing.T) {
manager, stop := setupTestSavedAddressesDB(t)
defer stop()
rst, err := manager.GetRawSavedAddresses()
require.NoError(t, err)
require.Nil(t, rst)
sa := SavedAddress{
Address: common.Address{1},
Name: "Zilliqa",
Favourite: true,
ChainShortNames: "eth:arb:",
ENSName: "test.stateofus.eth",
IsTest: false,
}
_, err = manager.UpdateMetadataAndUpsertSavedAddress(sa)
require.NoError(t, err)
rst, err = manager.GetRawSavedAddresses()
require.NoError(t, err)
require.Equal(t, 1, len(rst))
require.Equal(t, sa.Address, rst[0].Address)
require.Equal(t, sa.Name, rst[0].Name)
require.Equal(t, sa.Favourite, rst[0].Favourite)
require.Equal(t, sa.ChainShortNames, rst[0].ChainShortNames)
require.Equal(t, sa.ENSName, rst[0].ENSName)
require.Equal(t, sa.IsTest, rst[0].IsTest)
}
func contains[T comparable](container []T, element T, isEqual func(T, T) bool) bool {
for _, e := range container {
if isEqual(e, element) {
return true
}
}
return false
}
func haveSameElements[T comparable](a []T, b []T, isEqual func(T, T) bool) bool {
for _, v := range a {
if !contains(b, v, isEqual) {
return false
}
}
return true
}
func savedAddressDataIsEqual(a, b SavedAddress) bool {
return a.Address == b.Address && a.Name == b.Name && a.Favourite == b.Favourite &&
a.ChainShortNames == b.ChainShortNames && a.ENSName == b.ENSName && a.IsTest == b.IsTest
}
func TestSavedAddressesMetadata(t *testing.T) {
manager, stop := setupTestSavedAddressesDB(t)
defer stop()
savedAddresses, err := manager.GetRawSavedAddresses()
require.NoError(t, err)
require.Nil(t, savedAddresses)
// Add raw saved addresses
sa1 := SavedAddress{
Address: common.Address{1},
Name: "Raw",
Favourite: true,
savedAddressMeta: savedAddressMeta{
Removed: false,
UpdateClock: 234,
},
ChainShortNames: "eth:arb:",
ENSName: "test.stateofus.eth",
IsTest: false,
}
err = manager.upsertSavedAddress(sa1, nil)
require.NoError(t, err)
dbSavedAddresses, err := manager.GetRawSavedAddresses()
require.NoError(t, err)
require.Equal(t, 1, len(dbSavedAddresses))
require.Equal(t, sa1.Address, dbSavedAddresses[0].Address)
// Add simple saved address without sync metadata
sa2 := SavedAddress{
Address: common.Address{2},
Name: "Simple",
Favourite: false,
IsTest: false,
}
var sa2UpdatedClock uint64
sa2UpdatedClock, err = manager.UpdateMetadataAndUpsertSavedAddress(sa2)
require.NoError(t, err)
dbSavedAddresses, err = manager.GetRawSavedAddresses()
require.NoError(t, err)
require.Equal(t, 2, len(dbSavedAddresses))
// The order is not guaranteed check raw entry to decide
rawIndex := 0
simpleIndex := 1
if dbSavedAddresses[0] != sa1 {
rawIndex = 1
simpleIndex = 0
}
require.Equal(t, sa1.Address, dbSavedAddresses[simpleIndex].Address)
require.Equal(t, sa2.Address, dbSavedAddresses[rawIndex].Address)
require.Equal(t, sa2.Name, dbSavedAddresses[rawIndex].Name)
require.Equal(t, sa2.Favourite, dbSavedAddresses[rawIndex].Favourite)
require.Equal(t, sa2.IsTest, dbSavedAddresses[rawIndex].IsTest)
// Check the default values
require.False(t, dbSavedAddresses[rawIndex].Removed)
require.Equal(t, dbSavedAddresses[rawIndex].UpdateClock, sa2UpdatedClock)
require.Greater(t, dbSavedAddresses[rawIndex].UpdateClock, uint64(0))
sa2Older := sa2
sa2Older.Favourite = true
sa2Older.IsTest = false
sa2Newer := sa2
sa2Newer.Favourite = false
sa2Newer.IsTest = false
// Try to add an older entry
updated := false
updated, err = manager.AddSavedAddressIfNewerUpdate(sa2Older, dbSavedAddresses[rawIndex].UpdateClock-1)
require.NoError(t, err)
require.False(t, updated)
dbSavedAddresses, err = manager.GetRawSavedAddresses()
require.NoError(t, err)
rawIndex = 0
simpleIndex = 1
if dbSavedAddresses[0] != sa1 {
rawIndex = 1
simpleIndex = 0
}
require.Equal(t, 2, len(dbSavedAddresses))
require.True(t, haveSameElements([]SavedAddress{sa1, sa2}, dbSavedAddresses, savedAddressDataIsEqual))
require.Equal(t, sa1.savedAddressMeta, dbSavedAddresses[simpleIndex].savedAddressMeta)
// Try to update sa2 with a newer entry
updatedClock := dbSavedAddresses[rawIndex].UpdateClock + 1
updated, err = manager.AddSavedAddressIfNewerUpdate(sa2Newer, updatedClock)
require.NoError(t, err)
require.True(t, updated)
dbSavedAddresses, err = manager.GetRawSavedAddresses()
require.NoError(t, err)
require.Equal(t, 2, len(dbSavedAddresses))
require.True(t, haveSameElements([]SavedAddress{sa1, sa2Newer}, dbSavedAddresses, savedAddressDataIsEqual))
require.Equal(t, updatedClock, dbSavedAddresses[rawIndex].UpdateClock)
// Try to delete the sa2 newer entry
updatedDeleteClock := updatedClock + 1
updated, err = manager.DeleteSavedAddress(sa2Newer.Address, sa2Newer.ENSName, sa2Newer.IsTest, updatedDeleteClock)
require.NoError(t, err)
require.True(t, updated)
dbSavedAddresses, err = manager.GetRawSavedAddresses()
require.NoError(t, err)
require.Equal(t, 2, len(dbSavedAddresses))
require.True(t, dbSavedAddresses[rawIndex].Removed)
// Check that deleted entry is not returned with the regular API (non-raw)
dbSavedAddresses, err = manager.GetSavedAddresses()
require.NoError(t, err)
require.Equal(t, 1, len(dbSavedAddresses))
}
func TestSavedAddressesCleanSoftDeletes(t *testing.T) {
manager, stop := setupTestSavedAddressesDB(t)
defer stop()
firstTimestamp := 10
for i := 0; i < 5; i++ {
sa := SavedAddress{
Address: common.Address{byte(i)},
Name: "Test" + strconv.Itoa(i),
Favourite: false,
savedAddressMeta: savedAddressMeta{
Removed: true,
UpdateClock: uint64(firstTimestamp + i),
},
}
err := manager.upsertSavedAddress(sa, nil)
require.NoError(t, err)
}
err := manager.DeleteSoftRemovedSavedAddresses(uint64(firstTimestamp + 3))
require.NoError(t, err)
dbSavedAddresses, err := manager.GetRawSavedAddresses()
require.NoError(t, err)
require.Equal(t, 2, len(dbSavedAddresses))
require.True(t, haveSameElements([]uint64{dbSavedAddresses[0].UpdateClock,
dbSavedAddresses[1].UpdateClock}, []uint64{uint64(firstTimestamp + 3), uint64(firstTimestamp + 4)},
func(a, b uint64) bool {
return a == b
},
))
}
func TestSavedAddressesGet(t *testing.T) {
manager, stop := setupTestSavedAddressesDB(t)
defer stop()
sa := SavedAddress{
Address: common.Address{1},
ENSName: "test.ens.eth",
IsTest: false,
savedAddressMeta: savedAddressMeta{
Removed: true,
},
}
err := manager.upsertSavedAddress(sa, nil)
require.NoError(t, err)
dbSavedAddresses, err := manager.GetRawSavedAddresses()
require.NoError(t, err)
require.Equal(t, 1, len(dbSavedAddresses))
require.True(t, savedAddressDataIsEqual(sa, dbSavedAddresses[0]))
dbSavedAddresses, err = manager.GetSavedAddresses()
require.NoError(t, err)
require.Equal(t, 0, len(dbSavedAddresses))
}
func TestSavedAddressesDelete(t *testing.T) {
manager, stop := setupTestSavedAddressesDB(t)
defer stop()
sa0 := SavedAddress{
Address: common.Address{1},
IsTest: false,
}
err := manager.upsertSavedAddress(sa0, nil)
require.NoError(t, err)
rst, err := manager.GetRawSavedAddresses()
require.NoError(t, err)
require.Equal(t, 1, len(rst))
require.True(t, savedAddressDataIsEqual(sa0, rst[0]))
// Modify IsTest flag, insert
sa1 := sa0
sa1.IsTest = !sa1.IsTest
err = manager.upsertSavedAddress(sa1, nil)
require.NoError(t, err)
// Delete s0, test that only s1 is left
updateClock := uint64(time.Now().Unix())
_, err = manager.DeleteSavedAddress(sa0.Address, sa0.ENSName, sa0.IsTest, updateClock)
require.NoError(t, err)
rst, err = manager.GetSavedAddresses()
require.NoError(t, err)
require.Equal(t, 1, len(rst))
require.True(t, savedAddressDataIsEqual(sa1, rst[0]))
// Test that we still have both addresses
rst, err = manager.GetRawSavedAddresses()
require.NoError(t, err)
require.Equal(t, 2, len(rst))
// Delete s0 one more time with the same timestamp
deleted, err := manager.DeleteSavedAddress(sa0.Address, sa0.ENSName, sa0.IsTest, updateClock)
require.NoError(t, err)
require.False(t, deleted)
}
func testInsertSameAddressWithOneChange(t *testing.T, member int) {
manager, stop := setupTestSavedAddressesDB(t)
defer stop()
// Insert one address
sa := SavedAddress{
Address: common.Address{1},
ENSName: "test.ens.eth",
IsTest: true,
}
err := manager.upsertSavedAddress(sa, nil)
require.NoError(t, err)
rst, err := manager.GetRawSavedAddresses()
require.NoError(t, err)
require.Equal(t, 1, len(rst))
require.True(t, savedAddressDataIsEqual(sa, rst[0]))
sa2 := sa
if member == isTestMember {
sa2.IsTest = !sa2.IsTest
} else if member == addressMember {
sa2.Address = common.Address{7}
} else if member == ensMember {
sa2.ENSName += "_"
} else {
t.Error("Unsupported member change. Please add it to the list")
}
err = manager.upsertSavedAddress(sa2, nil)
require.NoError(t, err)
rst, err = manager.GetRawSavedAddresses()
require.NoError(t, err)
require.Equal(t, 2, len(rst))
// The order of records returned by GetRawSavedAddresses is not
// guaranteed to be the same as insertions, so swap indices if first record does not match
firstIndex := 0
secondIndex := 1
if rst[firstIndex] != sa {
firstIndex = 1
secondIndex = 0
}
require.True(t, savedAddressDataIsEqual(sa, rst[firstIndex]))
require.True(t, savedAddressDataIsEqual(sa2, rst[secondIndex]))
}
func TestSavedAddressesAddDifferentIsTest(t *testing.T) {
testInsertSameAddressWithOneChange(t, isTestMember)
}
func TestSavedAddressesAddSame(t *testing.T) {
manager, stop := setupTestSavedAddressesDB(t)
defer stop()
// Insert one address
sa := SavedAddress{
Address: common.Address{1},
ENSName: "test.ens.eth",
IsTest: true,
}
err := manager.upsertSavedAddress(sa, nil)
require.NoError(t, err)
rst, err := manager.GetRawSavedAddresses()
require.NoError(t, err)
require.Equal(t, 1, len(rst))
require.True(t, savedAddressDataIsEqual(sa, rst[0]))
sa2 := sa
err = manager.upsertSavedAddress(sa2, nil)
require.NoError(t, err)
rst, err = manager.GetRawSavedAddresses()
require.NoError(t, err)
require.Equal(t, 1, len(rst))
}