status-go/services/wallet/saved_addresses_test.go

415 lines
11 KiB
Go
Raw Normal View History

2021-09-10 18:08:22 +00:00
package wallet
import (
"strconv"
2021-09-10 18:08:22 +00:00
"testing"
"time"
2021-09-10 18:08:22 +00:00
"github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/common"
"github.com/status-im/status-go/appdatabase"
"github.com/status-im/status-go/sqlite"
2021-09-10 18:08:22 +00:00
)
const (
ensMember int = iota
isTestMember
addressMember
)
2021-09-10 18:08:22 +00:00
func setupTestSavedAddressesDB(t *testing.T) (*SavedAddressesManager, func()) {
db, err := appdatabase.InitializeDB(sqlite.InMemoryPath, "wallet-saved_addresses-tests", sqlite.ReducedKDFIterationsNumber)
2021-09-10 18:08:22 +00:00
require.NoError(t, err)
2021-09-10 18:08:22 +00:00
return &SavedAddressesManager{db}, func() {
require.NoError(t, db.Close())
}
}
func TestSavedAddressesAdd(t *testing.T) {
2021-09-10 18:08:22 +00:00
manager, stop := setupTestSavedAddressesDB(t)
defer stop()
rst, err := manager.GetRawSavedAddresses()
2021-09-10 18:08:22 +00:00
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,
2021-09-10 18:08:22 +00:00
}
_, err = manager.UpdateMetadataAndUpsertSavedAddress(sa)
2021-09-10 18:08:22 +00:00
require.NoError(t, err)
rst, err = manager.GetRawSavedAddresses()
2021-09-10 18:08:22 +00:00
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)
2021-09-10 18:08:22 +00:00
}
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, dbSavedAddresses[0])
// 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, dbSavedAddresses[rawIndex])
require.Equal(t, sa2.Address, dbSavedAddresses[simpleIndex].Address)
require.Equal(t, sa2.Name, dbSavedAddresses[simpleIndex].Name)
require.Equal(t, sa2.Favourite, dbSavedAddresses[simpleIndex].Favourite)
require.Equal(t, sa2.IsTest, dbSavedAddresses[simpleIndex].IsTest)
// Check the default values
require.False(t, dbSavedAddresses[simpleIndex].Removed)
require.Equal(t, dbSavedAddresses[simpleIndex].UpdateClock, sa2UpdatedClock)
require.Greater(t, dbSavedAddresses[simpleIndex].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[simpleIndex].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[rawIndex].savedAddressMeta)
// Try to update sa2 with a newer entry
updatedClock := dbSavedAddresses[simpleIndex].UpdateClock + 1
updated, err = manager.AddSavedAddressIfNewerUpdate(sa2Newer, updatedClock)
require.NoError(t, err)
require.True(t, updated)
dbSavedAddresses, err = manager.GetRawSavedAddresses()
require.NoError(t, err)
simpleIndex = 1
if dbSavedAddresses[0] != sa1 {
simpleIndex = 0
}
require.Equal(t, 2, len(dbSavedAddresses))
require.True(t, haveSameElements([]SavedAddress{sa1, sa2Newer}, dbSavedAddresses, savedAddressDataIsEqual))
require.Equal(t, updatedClock, dbSavedAddresses[simpleIndex].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)
simpleIndex = 1
if dbSavedAddresses[0] != sa1 {
simpleIndex = 0
}
require.Equal(t, 2, len(dbSavedAddresses))
require.True(t, dbSavedAddresses[simpleIndex].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 TestSavedAddressesAddDifferentAddress(t *testing.T) {
testInsertSameAddressWithOneChange(t, addressMember)
}
func TestSavedAddressesAddDifferentIsTest(t *testing.T) {
testInsertSameAddressWithOneChange(t, isTestMember)
}
func TestSavedAddressesAddDifferentEns(t *testing.T) {
testInsertSameAddressWithOneChange(t, ensMember)
}
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))
}