github.com/status-im/status-go@v1.1.0/services/wallet/walletconnect/database_test.go (about) 1 package walletconnect 2 3 import ( 4 "strconv" 5 "testing" 6 7 "database/sql" 8 9 "github.com/status-im/status-go/services/wallet/common" 10 11 "github.com/stretchr/testify/require" 12 ) 13 14 type urlOverride *string 15 type timestampOverride *int64 16 17 // testSession will override defaults for the fields that are not null 18 type testSession struct { 19 url urlOverride 20 created timestampOverride 21 expiry timestampOverride 22 disconnected *bool 23 testChains *bool 24 } 25 26 const testDappUrl = "https://test.url/" 27 28 // generateTestData generates alternative disconnected and active sessions starting with the active one 29 // timestamps start with 1234567890 and increase by 1 for each session 30 // all sessions will share the same two pairing sessions (roll over after index 1) 31 // testChains is false if not overridden 32 func generateTestData(sessions []testSession) []DBSession { 33 res := make([]DBSession, len(sessions)) 34 pairingIdx := 0 35 for i := 0; i < len(res); i++ { 36 strI := strconv.Itoa(i) 37 if i%2 == 0 { 38 pairingIdx++ 39 } 40 pairingIdxStr := strconv.Itoa(pairingIdx) 41 42 s := sessions[i] 43 44 url := testDappUrl + strI 45 if s.url != nil { 46 url = *s.url 47 } 48 49 createdTimestamp := 1234567890 + int64(i) 50 if s.created != nil { 51 createdTimestamp = *s.created 52 } 53 54 expiryTimestamp := createdTimestamp + 1000 + int64(i) 55 if s.expiry != nil { 56 expiryTimestamp = *s.expiry 57 } 58 59 disconnected := (i % 2) != 0 60 if s.disconnected != nil { 61 disconnected = *s.disconnected 62 } 63 64 testChains := false 65 if s.testChains != nil { 66 testChains = *s.testChains 67 } 68 69 res[i] = DBSession{ 70 Topic: Topic(strI + "aaaaaa1234567890"), 71 Disconnected: disconnected, 72 SessionJSON: "{}", 73 Expiry: expiryTimestamp, 74 CreatedTimestamp: createdTimestamp, 75 PairingTopic: Topic(pairingIdxStr + "bbbbbb1234567890"), 76 TestChains: testChains, 77 DBDApp: DBDApp{ 78 URL: url, 79 Name: "TestApp" + strI, 80 IconURL: "https://test.icon" + strI, 81 }, 82 } 83 } 84 return res 85 } 86 87 func insertTestData(t *testing.T, db *sql.DB, entries []DBSession) { 88 for _, entry := range entries { 89 err := UpsertSession(db, entry) 90 require.NoError(t, err) 91 } 92 } 93 94 func TestInsertUpdateAndGetSession(t *testing.T) { 95 db, close := SetupTestDB(t) 96 defer close() 97 98 entry := generateTestData(make([]testSession, 1))[0] 99 err := UpsertSession(db, entry) 100 require.NoError(t, err) 101 102 retrievedSession, err := GetSessionByTopic(db, entry.Topic) 103 require.NoError(t, err) 104 105 require.Equal(t, entry, *retrievedSession) 106 107 updatedEntry := entry 108 updatedEntry.Disconnected = true 109 updatedEntry.Expiry = 1111111111 110 err = UpsertSession(db, updatedEntry) 111 112 require.NoError(t, err) 113 114 retrievedSession, err = GetSessionByTopic(db, updatedEntry.Topic) 115 require.NoError(t, err) 116 117 require.Equal(t, updatedEntry, *retrievedSession) 118 } 119 120 func TestInsertAndGetSessionsByPairingTopic(t *testing.T) { 121 db, close := SetupTestDB(t) 122 defer close() 123 124 generatedSessions := generateTestData(make([]testSession, 4)) 125 for _, session := range generatedSessions { 126 err := UpsertSession(db, session) 127 require.NoError(t, err) 128 } 129 130 retrievedSessions, err := GetSessionsByPairingTopic(db, generatedSessions[2].Topic) 131 require.NoError(t, err) 132 require.Equal(t, 0, len(retrievedSessions)) 133 134 retrievedSessions, err = GetSessionsByPairingTopic(db, generatedSessions[2].PairingTopic) 135 require.NoError(t, err) 136 require.Equal(t, 2, len(retrievedSessions)) 137 138 for i := 2; i < 4; i++ { 139 found := false 140 for _, session := range retrievedSessions { 141 if session.Topic == generatedSessions[i].Topic { 142 found = true 143 require.Equal(t, generatedSessions[i], session) 144 } 145 } 146 require.True(t, found) 147 } 148 } 149 150 func TestGet(t *testing.T) { 151 db, close := SetupTestDB(t) 152 defer close() 153 154 entries := generateTestData(make([]testSession, 3)) 155 insertTestData(t, db, entries) 156 157 retrievedSession, err := GetSessionByTopic(db, entries[1].Topic) 158 require.NoError(t, err) 159 160 require.Equal(t, entries[1], *retrievedSession) 161 162 err = DeleteSession(db, entries[1].Topic) 163 require.NoError(t, err) 164 165 deletedSession, err := GetSessionByTopic(db, entries[1].Topic) 166 require.ErrorIs(t, err, sql.ErrNoRows) 167 require.Nil(t, deletedSession) 168 } 169 170 func TestGetActiveSessions(t *testing.T) { 171 db, close := SetupTestDB(t) 172 defer close() 173 174 // insert two disconnected and three active sessions 175 entries := generateTestData(make([]testSession, 5)) 176 insertTestData(t, db, entries) 177 178 activeSessions, err := GetActiveSessions(db, entries[2].Expiry) 179 require.NoError(t, err) 180 181 require.Equal(t, 2, len(activeSessions)) 182 // Expect newest on top 183 require.Equal(t, entries[4], activeSessions[0]) 184 require.Equal(t, entries[2], activeSessions[1]) 185 } 186 187 func TestDeleteSession(t *testing.T) { 188 db, close := SetupTestDB(t) 189 defer close() 190 191 entries := generateTestData(make([]testSession, 3)) 192 insertTestData(t, db, entries) 193 194 err := DeleteSession(db, entries[1].Topic) 195 require.NoError(t, err) 196 197 sessions, err := GetSessions(db) 198 require.NoError(t, err) 199 require.Equal(t, 2, len(sessions)) 200 201 require.Equal(t, entries[0], sessions[1]) 202 require.Equal(t, entries[2], sessions[0]) 203 204 err = DeleteSession(db, entries[0].Topic) 205 require.NoError(t, err) 206 err = DeleteSession(db, entries[2].Topic) 207 require.NoError(t, err) 208 209 sessions, err = GetSessions(db) 210 require.NoError(t, err) 211 require.Equal(t, 0, len(sessions)) 212 } 213 214 // urlFor prepares a value to be used in testSession 215 func urlFor(i int) urlOverride { 216 return common.NewAndSet(testDappUrl + strconv.Itoa(i)) 217 } 218 219 // at prepares a value to be used in testSession 220 func at(i int) timestampOverride { 221 return common.NewAndSet(int64(i)) 222 } 223 224 // TestGetActiveDapps_JoinWorksAsExpected also validates that GetActiveDapps returns the dapps in the order of the last first time added 225 func TestGetActiveDapps_JoinWorksAsExpected(t *testing.T) { 226 db, close := SetupTestDB(t) 227 defer close() 228 229 not := common.NewAndSet(false) 230 // The first creation date is 1, 2, 3 but the last name update is, respectively, 1, 4, 5 231 entries := generateTestData([]testSession{ 232 {url: urlFor(1), created: at(1), disconnected: not}, 233 {url: urlFor(1), created: at(2), disconnected: not}, 234 {url: urlFor(2), created: at(3), disconnected: not}, 235 {url: urlFor(3), created: at(4), disconnected: not}, 236 {url: urlFor(2), created: at(5), disconnected: not}, 237 {url: urlFor(3), created: at(6), disconnected: not}, 238 }) 239 insertTestData(t, db, entries) 240 241 getTestnet := false 242 validAtTimestamp := entries[0].Expiry 243 dapps, err := GetActiveDapps(db, validAtTimestamp, getTestnet) 244 require.NoError(t, err) 245 require.Equal(t, 3, len(dapps)) 246 247 require.Equal(t, 3, len(dapps)) 248 require.Equal(t, entries[5].Name, dapps[0].Name) 249 require.Equal(t, entries[4].Name, dapps[1].Name) 250 require.Equal(t, entries[1].Name, dapps[2].Name) 251 } 252 253 // TestGetActiveDapps_ActiveWorksAsExpected tests the combination of disconnected and expired sessions 254 func TestGetActiveDapps_ActiveWorksAsExpected(t *testing.T) { 255 db, close := SetupTestDB(t) 256 defer close() 257 258 not := common.NewAndSet(false) 259 yes := common.NewAndSet(true) 260 timeNow := 4 261 entries := generateTestData([]testSession{ 262 {url: urlFor(1), expiry: at(timeNow - 3), disconnected: not}, 263 {url: urlFor(1), expiry: at(timeNow - 2), disconnected: yes}, 264 {url: urlFor(2), expiry: at(timeNow - 2), disconnected: not}, 265 {url: urlFor(3), expiry: at(timeNow - 1), disconnected: yes}, 266 // ----- timeNow 267 {url: urlFor(3), expiry: at(timeNow + 1), disconnected: not}, 268 {url: urlFor(4), expiry: at(timeNow + 1), disconnected: yes}, 269 {url: urlFor(4), expiry: at(timeNow + 2), disconnected: not}, 270 {url: urlFor(5), expiry: at(timeNow + 2), disconnected: yes}, 271 {url: urlFor(6), expiry: at(timeNow + 3), disconnected: not}, 272 }) 273 insertTestData(t, db, entries) 274 275 getTestnet := false 276 dapps, err := GetActiveDapps(db, int64(timeNow), getTestnet) 277 require.NoError(t, err) 278 require.Equal(t, 3, len(dapps)) 279 } 280 281 // TestGetActiveDapps_TestChainsWorksAsExpected tests the combination of disconnected and expired sessions 282 func TestGetActiveDapps_TestChainsWorksAsExpected(t *testing.T) { 283 db, close := SetupTestDB(t) 284 defer close() 285 286 not := common.NewAndSet(false) 287 yes := common.NewAndSet(true) 288 timeNow := 4 289 entries := generateTestData([]testSession{ 290 {url: urlFor(1), testChains: not, expiry: at(timeNow - 3), disconnected: not}, 291 {url: urlFor(2), testChains: yes, expiry: at(timeNow - 2), disconnected: not}, 292 {url: urlFor(2), testChains: not, expiry: at(timeNow - 1), disconnected: not}, 293 // ----- timeNow 294 {url: urlFor(3), testChains: not, expiry: at(timeNow + 1), disconnected: not}, 295 {url: urlFor(4), testChains: not, expiry: at(timeNow + 2), disconnected: not}, 296 {url: urlFor(4), testChains: yes, expiry: at(timeNow + 3), disconnected: not}, 297 {url: urlFor(5), testChains: yes, expiry: at(timeNow + 4), disconnected: not}, 298 }) 299 insertTestData(t, db, entries) 300 301 getTestnet := true 302 dapps, err := GetActiveDapps(db, int64(timeNow), getTestnet) 303 require.NoError(t, err) 304 require.Equal(t, 2, len(dapps)) 305 } 306 307 // TestGetDapps_EmptyDB tests that an empty database will return an empty list 308 func TestGetDapps_EmptyDB(t *testing.T) { 309 db, close := SetupTestDB(t) 310 defer close() 311 312 entries := generateTestData([]testSession{}) 313 insertTestData(t, db, entries) 314 315 getTestnet := false 316 validAtTimestamp := int64(0) 317 dapps, err := GetActiveDapps(db, validAtTimestamp, getTestnet) 318 require.NoError(t, err) 319 require.Equal(t, 0, len(dapps)) 320 } 321 322 // TestGetDapps_OrphanDapps tests that missing session will place the dapp at the end 323 func TestGetDapps_OrphanDapps(t *testing.T) { 324 db, close := SetupTestDB(t) 325 defer close() 326 327 not := common.NewAndSet(false) 328 entries := generateTestData([]testSession{ 329 {url: urlFor(1), disconnected: not}, 330 {url: urlFor(2), disconnected: not}, 331 {url: urlFor(2), disconnected: not}, 332 }) 333 insertTestData(t, db, entries) 334 335 err := DeleteSession(db, entries[1].Topic) 336 require.NoError(t, err) 337 err = DeleteSession(db, entries[2].Topic) 338 require.NoError(t, err) 339 340 getTestnet := false 341 validAtTimestamp := entries[0].Expiry 342 dapps, err := GetActiveDapps(db, validAtTimestamp, getTestnet) 343 require.NoError(t, err) 344 // The orphan dapp is not considered active 345 require.Equal(t, 1, len(dapps)) 346 require.Equal(t, entries[0].Name, dapps[0].Name) 347 } 348 349 func TestDisconnectSession(t *testing.T) { 350 db, close := SetupTestDB(t) 351 defer close() 352 353 not := common.NewAndSet(false) 354 entries := generateTestData([]testSession{ 355 {url: urlFor(1), disconnected: not}, 356 {url: urlFor(2), disconnected: not}, 357 {url: urlFor(2), disconnected: not}, 358 }) 359 insertTestData(t, db, entries) 360 361 activeSessions, err := GetActiveSessions(db, 0) 362 require.NoError(t, err) 363 require.Equal(t, 3, len(activeSessions)) 364 365 getTestnet := false 366 validAtTimestamp := entries[0].Expiry 367 dapps, err := GetActiveDapps(db, validAtTimestamp, getTestnet) 368 require.NoError(t, err) 369 require.Equal(t, 2, len(dapps)) 370 371 err = DisconnectSession(db, entries[1].Topic) 372 require.NoError(t, err) 373 374 activeSessions, err = GetActiveSessions(db, 0) 375 require.NoError(t, err) 376 require.Equal(t, 2, len(activeSessions)) 377 378 err = DisconnectSession(db, entries[2].Topic) 379 require.NoError(t, err) 380 381 activeSessions, err = GetActiveSessions(db, 0) 382 require.NoError(t, err) 383 require.Equal(t, 1, len(activeSessions)) 384 385 dapps, err = GetActiveDapps(db, validAtTimestamp, getTestnet) 386 require.NoError(t, err) 387 require.Equal(t, 1, len(dapps)) 388 require.Equal(t, entries[0].Name, dapps[0].Name) 389 }