status-go/services/wallet/saved_addresses_test.go
Sale Djenic 280f48877d chore(savedaddresses)!: favourite property removed and primary key updated
- favourite column removed from the saved_addresses table
- favourite property removed from the SavedAddress struct
- ens name removed from the primary key, the primary key now is composed of address and is_test columns
- ens parameter removed from wakuext_deleteSavedAddress
- wallet_getSavedAddresses moved to wakuext_getSavedAddresses (to keep them all in a single place)
- saved addresses related endpoints removed from the wallet service, even they logically belong there, a reason for that
is avoiding emitting sync message if one uses calls from the wallet service, while that's not the case in ext service. Once
we refactor this and introduce devices syncing mechanism in the wallet service, we should not only these but other wallet
related endpoints move there (removed: wallet_getSavedAddresses, wallet_addSavedAddress and wallet_deleteSavedAddress).

Affected area:
Saved addresses
2024-01-10 19:30:56 +01:00

396 lines
11 KiB
Go

package wallet
import (
"strconv"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/common"
multiAccCommon "github.com/status-im/status-go/multiaccounts/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",
ChainShortNames: "eth:arb:",
ENSName: "test.stateofus.eth",
ColorID: multiAccCommon.CustomizationColorGreen,
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.ChainShortNames, rst[0].ChainShortNames)
require.Equal(t, sa.ENSName, rst[0].ENSName)
require.Equal(t, sa.ColorID, rst[0].ColorID)
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.ChainShortNames == b.ChainShortNames &&
a.ENSName == b.ENSName && a.IsTest == b.IsTest && a.ColorID == b.ColorID
}
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",
savedAddressMeta: savedAddressMeta{
Removed: false,
UpdateClock: 234,
},
ChainShortNames: "eth:arb:",
ENSName: "test.stateofus.eth",
ColorID: multiAccCommon.CustomizationColorGreen,
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",
ColorID: multiAccCommon.CustomizationColorBlue,
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.ColorID, dbSavedAddresses[rawIndex].ColorID)
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.IsTest = false
sa2Newer := sa2
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.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),
ColorID: multiAccCommon.CustomizationColorGreen,
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",
ColorID: multiAccCommon.CustomizationColorGreen,
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.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.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))
}