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  }