github.com/status-im/status-go@v1.1.0/protocol/pushnotificationclient/persistence_test.go (about) 1 package pushnotificationclient 2 3 import ( 4 "crypto/ecdsa" 5 "testing" 6 "time" 7 8 "github.com/golang/protobuf/proto" 9 "github.com/stretchr/testify/suite" 10 11 "github.com/status-im/status-go/appdatabase" 12 "github.com/status-im/status-go/eth-node/crypto" 13 "github.com/status-im/status-go/protocol/common" 14 "github.com/status-im/status-go/protocol/protobuf" 15 "github.com/status-im/status-go/protocol/sqlite" 16 "github.com/status-im/status-go/t/helpers" 17 ) 18 19 const ( 20 testAccessToken = "token" 21 installationID1 = "installation-id-1" 22 installationID2 = "installation-id-2" 23 installationID3 = "installation-id-3" 24 ) 25 26 func TestSQLitePersistenceSuite(t *testing.T) { 27 suite.Run(t, new(SQLitePersistenceSuite)) 28 } 29 30 type SQLitePersistenceSuite struct { 31 suite.Suite 32 persistence *Persistence 33 } 34 35 func (s *SQLitePersistenceSuite) SetupTest() { 36 db, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{}) 37 s.Require().NoError(err) 38 err = sqlite.Migrate(db) 39 s.Require().NoError(err) 40 41 s.persistence = NewPersistence(db) 42 } 43 44 func (s *SQLitePersistenceSuite) TestSaveAndRetrieveServer() { 45 key, err := crypto.GenerateKey() 46 s.Require().NoError(err) 47 48 server := &PushNotificationServer{ 49 PublicKey: &key.PublicKey, 50 Registered: true, 51 RegisteredAt: 1, 52 AccessToken: testAccessToken, 53 } 54 55 s.Require().NoError(s.persistence.UpsertServer(server)) 56 57 retrievedServers, err := s.persistence.GetServers() 58 s.Require().NoError(err) 59 60 s.Require().Len(retrievedServers, 1) 61 s.Require().True(retrievedServers[0].Registered) 62 s.Require().Equal(int64(1), retrievedServers[0].RegisteredAt) 63 s.Require().True(common.IsPubKeyEqual(retrievedServers[0].PublicKey, &key.PublicKey)) 64 s.Require().Equal(testAccessToken, retrievedServers[0].AccessToken) 65 66 server.Registered = false 67 server.RegisteredAt = 2 68 69 s.Require().NoError(s.persistence.UpsertServer(server)) 70 71 retrievedServers, err = s.persistence.GetServers() 72 s.Require().NoError(err) 73 74 s.Require().Len(retrievedServers, 1) 75 s.Require().False(retrievedServers[0].Registered) 76 s.Require().Equal(int64(2), retrievedServers[0].RegisteredAt) 77 s.Require().True(common.IsPubKeyEqual(retrievedServers[0].PublicKey, &key.PublicKey)) 78 } 79 80 func (s *SQLitePersistenceSuite) TestSaveAndRetrieveInfo() { 81 key1, err := crypto.GenerateKey() 82 s.Require().NoError(err) 83 key2, err := crypto.GenerateKey() 84 s.Require().NoError(err) 85 serverKey, err := crypto.GenerateKey() 86 s.Require().NoError(err) 87 88 infos := []*PushNotificationInfo{ 89 { 90 PublicKey: &key1.PublicKey, 91 ServerPublicKey: &serverKey.PublicKey, 92 RetrievedAt: 1, 93 Version: 1, 94 AccessToken: testAccessToken, 95 InstallationID: installationID1, 96 }, 97 { 98 PublicKey: &key1.PublicKey, 99 ServerPublicKey: &serverKey.PublicKey, 100 RetrievedAt: 1, 101 Version: 1, 102 AccessToken: testAccessToken, 103 InstallationID: installationID2, 104 }, 105 { 106 PublicKey: &key1.PublicKey, 107 ServerPublicKey: &serverKey.PublicKey, 108 RetrievedAt: 1, 109 Version: 1, 110 AccessToken: testAccessToken, 111 InstallationID: installationID3, 112 }, 113 { 114 PublicKey: &key2.PublicKey, 115 ServerPublicKey: &serverKey.PublicKey, 116 RetrievedAt: 1, 117 Version: 1, 118 AccessToken: testAccessToken, 119 InstallationID: installationID1, 120 }, 121 { 122 PublicKey: &key2.PublicKey, 123 ServerPublicKey: &serverKey.PublicKey, 124 RetrievedAt: 1, 125 Version: 1, 126 AccessToken: testAccessToken, 127 InstallationID: installationID2, 128 }, 129 { 130 PublicKey: &key2.PublicKey, 131 ServerPublicKey: &serverKey.PublicKey, 132 RetrievedAt: 1, 133 Version: 1, 134 AccessToken: testAccessToken, 135 InstallationID: installationID3, 136 }, 137 } 138 139 s.Require().NoError(s.persistence.SavePushNotificationInfo(infos)) 140 141 retrievedInfos, err := s.persistence.GetPushNotificationInfo(&key1.PublicKey, []string{installationID1, installationID2}) 142 s.Require().NoError(err) 143 144 s.Require().Len(retrievedInfos, 2) 145 } 146 147 func (s *SQLitePersistenceSuite) TestSaveAndRetrieveInfoWithVersion() { 148 installationID := "installation-id-1" 149 key, err := crypto.GenerateKey() 150 s.Require().NoError(err) 151 serverKey1, err := crypto.GenerateKey() 152 s.Require().NoError(err) 153 serverKey2, err := crypto.GenerateKey() 154 s.Require().NoError(err) 155 156 infos := []*PushNotificationInfo{ 157 { 158 PublicKey: &key.PublicKey, 159 ServerPublicKey: &serverKey1.PublicKey, 160 RetrievedAt: 1, 161 Version: 1, 162 AccessToken: testAccessToken, 163 InstallationID: installationID, 164 }, 165 { 166 PublicKey: &key.PublicKey, 167 ServerPublicKey: &serverKey2.PublicKey, 168 RetrievedAt: 1, 169 Version: 1, 170 AccessToken: testAccessToken, 171 InstallationID: installationID, 172 }, 173 } 174 175 s.Require().NoError(s.persistence.SavePushNotificationInfo(infos)) 176 177 retrievedInfos, err := s.persistence.GetPushNotificationInfo(&key.PublicKey, []string{installationID}) 178 s.Require().NoError(err) 179 180 // We should retrieve both 181 s.Require().Len(retrievedInfos, 2) 182 s.Require().Equal(uint64(1), retrievedInfos[0].Version) 183 184 // Bump version 185 infos[0].Version = 2 186 187 s.Require().NoError(s.persistence.SavePushNotificationInfo(infos)) 188 189 retrievedInfos, err = s.persistence.GetPushNotificationInfo(&key.PublicKey, []string{installationID}) 190 s.Require().NoError(err) 191 192 // Only one should be retrieved now 193 s.Require().Len(retrievedInfos, 1) 194 s.Require().Equal(uint64(2), retrievedInfos[0].Version) 195 196 // Lower version 197 infos[0].Version = 1 198 199 s.Require().NoError(s.persistence.SavePushNotificationInfo(infos)) 200 201 retrievedInfos, err = s.persistence.GetPushNotificationInfo(&key.PublicKey, []string{installationID}) 202 s.Require().NoError(err) 203 204 s.Require().Len(retrievedInfos, 1) 205 s.Require().Equal(uint64(2), retrievedInfos[0].Version) 206 } 207 208 func (s *SQLitePersistenceSuite) TestNotifiedOnAndUpdateNotificationResponse() { 209 key, err := crypto.GenerateKey() 210 s.Require().NoError(err) 211 installationID := "installation-id" 212 messageID := []byte("message-id") 213 214 sentNotification := &SentNotification{ 215 PublicKey: &key.PublicKey, 216 InstallationID: installationID, 217 MessageID: messageID, 218 LastTriedAt: time.Now().Unix(), 219 } 220 221 s.Require().NoError(s.persistence.UpsertSentNotification(sentNotification)) 222 223 retrievedNotification, err := s.persistence.GetSentNotification(sentNotification.HashedPublicKey(), installationID, messageID) 224 s.Require().NoError(err) 225 s.Require().Equal(sentNotification, retrievedNotification) 226 227 retriableNotifications, err := s.persistence.GetRetriablePushNotifications() 228 s.Require().NoError(err) 229 s.Require().Len(retriableNotifications, 0) 230 231 response := &protobuf.PushNotificationReport{ 232 Success: false, 233 Error: protobuf.PushNotificationReport_WRONG_TOKEN, 234 PublicKey: sentNotification.HashedPublicKey(), 235 InstallationId: installationID, 236 } 237 238 s.Require().NoError(s.persistence.UpdateNotificationResponse(messageID, response)) 239 // This notification should be retriable 240 retriableNotifications, err = s.persistence.GetRetriablePushNotifications() 241 s.Require().NoError(err) 242 s.Require().Len(retriableNotifications, 1) 243 244 sentNotification.Error = protobuf.PushNotificationReport_WRONG_TOKEN 245 246 retrievedNotification, err = s.persistence.GetSentNotification(sentNotification.HashedPublicKey(), installationID, messageID) 247 s.Require().NoError(err) 248 s.Require().Equal(sentNotification, retrievedNotification) 249 250 // Update with a successful notification 251 response = &protobuf.PushNotificationReport{ 252 Success: true, 253 PublicKey: sentNotification.HashedPublicKey(), 254 InstallationId: installationID, 255 } 256 257 s.Require().NoError(s.persistence.UpdateNotificationResponse(messageID, response)) 258 259 sentNotification.Success = true 260 sentNotification.Error = protobuf.PushNotificationReport_UNKNOWN_ERROR_TYPE 261 262 retrievedNotification, err = s.persistence.GetSentNotification(sentNotification.HashedPublicKey(), installationID, messageID) 263 s.Require().NoError(err) 264 s.Require().Equal(sentNotification, retrievedNotification) 265 266 // This notification should not be retriable 267 retriableNotifications, err = s.persistence.GetRetriablePushNotifications() 268 s.Require().NoError(err) 269 s.Require().Len(retriableNotifications, 0) 270 271 // Update with a unsuccessful notification, it should be ignored 272 response = &protobuf.PushNotificationReport{ 273 Success: false, 274 Error: protobuf.PushNotificationReport_WRONG_TOKEN, 275 PublicKey: sentNotification.HashedPublicKey(), 276 InstallationId: installationID, 277 } 278 279 s.Require().NoError(s.persistence.UpdateNotificationResponse(messageID, response)) 280 281 sentNotification.Success = true 282 sentNotification.Error = protobuf.PushNotificationReport_UNKNOWN_ERROR_TYPE 283 284 retrievedNotification, err = s.persistence.GetSentNotification(sentNotification.HashedPublicKey(), installationID, messageID) 285 s.Require().NoError(err) 286 s.Require().Equal(sentNotification, retrievedNotification) 287 } 288 289 func (s *SQLitePersistenceSuite) TestSaveAndRetrieveRegistration() { 290 // Try with nil first 291 retrievedRegistration, retrievedContactIDs, err := s.persistence.GetLastPushNotificationRegistration() 292 s.Require().NoError(err) 293 s.Require().Nil(retrievedRegistration) 294 s.Require().Nil(retrievedContactIDs) 295 296 // Save & retrieve registration 297 registration := &protobuf.PushNotificationRegistration{ 298 AccessToken: "test", 299 Version: 3, 300 } 301 302 key1, err := crypto.GenerateKey() 303 s.Require().NoError(err) 304 305 key2, err := crypto.GenerateKey() 306 s.Require().NoError(err) 307 308 key3, err := crypto.GenerateKey() 309 s.Require().NoError(err) 310 311 publicKeys := []*ecdsa.PublicKey{&key1.PublicKey, &key2.PublicKey} 312 313 s.Require().NoError(s.persistence.SaveLastPushNotificationRegistration(registration, publicKeys)) 314 retrievedRegistration, retrievedContactIDs, err = s.persistence.GetLastPushNotificationRegistration() 315 s.Require().NoError(err) 316 s.Require().True(proto.Equal(registration, retrievedRegistration)) 317 s.Require().Equal(publicKeys, retrievedContactIDs) 318 319 // Override and retrieve 320 321 registration.Version = 5 322 publicKeys = append(publicKeys, &key3.PublicKey) 323 s.Require().NoError(s.persistence.SaveLastPushNotificationRegistration(registration, publicKeys)) 324 retrievedRegistration, retrievedContactIDs, err = s.persistence.GetLastPushNotificationRegistration() 325 s.Require().NoError(err) 326 s.Require().True(proto.Equal(registration, retrievedRegistration)) 327 s.Require().Equal(publicKeys, retrievedContactIDs) 328 }