status-go/protocol/push_notification_test.go

468 lines
13 KiB
Go

package protocol
import (
"context"
"crypto/ecdsa"
"errors"
"io/ioutil"
"os"
"testing"
"time"
"github.com/google/uuid"
"github.com/stretchr/testify/suite"
"go.uber.org/zap"
gethbridge "github.com/status-im/status-go/eth-node/bridge/geth"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/protocol/push_notification_client"
"github.com/status-im/status-go/protocol/push_notification_server"
"github.com/status-im/status-go/protocol/tt"
"github.com/status-im/status-go/whisper/v6"
)
func TestMessengerPushNotificationSuite(t *testing.T) {
suite.Run(t, new(MessengerPushNotificationSuite))
}
type MessengerPushNotificationSuite struct {
suite.Suite
m *Messenger // main instance of Messenger
privateKey *ecdsa.PrivateKey // private key for the main instance of Messenger
// If one wants to send messages between different instances of Messenger,
// a single Whisper service should be shared.
shh types.Whisper
tmpFiles []*os.File // files to clean up
logger *zap.Logger
}
func (s *MessengerPushNotificationSuite) SetupTest() {
s.logger = tt.MustCreateTestLogger()
config := whisper.DefaultConfig
config.MinimumAcceptedPOW = 0
shh := whisper.New(&config)
s.shh = gethbridge.NewGethWhisperWrapper(shh)
s.Require().NoError(shh.Start(nil))
s.m = s.newMessenger(s.shh)
s.privateKey = s.m.identity
}
func (s *MessengerPushNotificationSuite) newMessengerWithOptions(shh types.Whisper, privateKey *ecdsa.PrivateKey, options []Option) *Messenger {
tmpFile, err := ioutil.TempFile("", "")
s.Require().NoError(err)
m, err := NewMessenger(
privateKey,
&testNode{shh: shh},
uuid.New().String(),
options...,
)
s.Require().NoError(err)
err = m.Init()
s.Require().NoError(err)
s.tmpFiles = append(s.tmpFiles, tmpFile)
return m
}
func (s *MessengerPushNotificationSuite) newMessengerWithKey(shh types.Whisper, privateKey *ecdsa.PrivateKey) *Messenger {
tmpFile, err := ioutil.TempFile("", "")
s.Require().NoError(err)
options := []Option{
WithCustomLogger(s.logger),
WithMessagesPersistenceEnabled(),
WithDatabaseConfig(tmpFile.Name(), "some-key"),
WithDatasync(),
}
return s.newMessengerWithOptions(shh, privateKey, options)
}
func (s *MessengerPushNotificationSuite) newMessenger(shh types.Whisper) *Messenger {
privateKey, err := crypto.GenerateKey()
s.Require().NoError(err)
return s.newMessengerWithKey(s.shh, privateKey)
}
func (s *MessengerPushNotificationSuite) newPushNotificationServer(shh types.Whisper) *Messenger {
privateKey, err := crypto.GenerateKey()
s.Require().NoError(err)
tmpFile, err := ioutil.TempFile("", "")
s.Require().NoError(err)
serverConfig := &push_notification_server.Config{
Logger: s.logger,
Identity: privateKey,
}
options := []Option{
WithCustomLogger(s.logger),
WithMessagesPersistenceEnabled(),
WithDatabaseConfig(tmpFile.Name(), "some-key"),
WithPushNotificationServerConfig(serverConfig),
WithDatasync(),
}
return s.newMessengerWithOptions(shh, privateKey, options)
}
func (s *MessengerPushNotificationSuite) TestReceivePushNotification() {
bob1DeviceToken := "token-1"
bob2DeviceToken := "token-2"
bob1 := s.m
bob2 := s.newMessengerWithKey(s.shh, s.m.identity)
server := s.newPushNotificationServer(s.shh)
alice := s.newMessenger(s.shh)
bobInstallationIDs := []string{bob1.installationID, bob2.installationID}
// Register bob1
err := bob1.AddPushNotificationServer(context.Background(), &server.identity.PublicKey)
s.Require().NoError(err)
err = bob1.RegisterForPushNotifications(context.Background(), bob1DeviceToken)
// Receive message, reply
// TODO: find a better way to handle this waiting
time.Sleep(500 * time.Millisecond)
_, err = server.RetrieveAll()
s.Require().NoError(err)
time.Sleep(500 * time.Millisecond)
_, err = server.RetrieveAll()
s.Require().NoError(err)
time.Sleep(500 * time.Millisecond)
_, err = server.RetrieveAll()
s.Require().NoError(err)
// Check reply
// TODO: find a better way to handle this waiting
time.Sleep(500 * time.Millisecond)
_, err = bob1.RetrieveAll()
s.Require().NoError(err)
time.Sleep(500 * time.Millisecond)
_, err = bob1.RetrieveAll()
s.Require().NoError(err)
time.Sleep(500 * time.Millisecond)
_, err = bob1.RetrieveAll()
s.Require().NoError(err)
// Pull servers and check we registered
err = tt.RetryWithBackOff(func() error {
registered, err := bob1.RegisteredForPushNotifications()
if err != nil {
return err
}
if !registered {
return errors.New("not registered")
}
return nil
})
// Make sure we receive it
s.Require().NoError(err)
bob1Servers, err := bob1.GetPushNotificationServers()
s.Require().NoError(err)
// Register bob2
err = bob2.AddPushNotificationServer(context.Background(), &server.identity.PublicKey)
s.Require().NoError(err)
err = bob2.RegisterForPushNotifications(context.Background(), bob2DeviceToken)
s.Require().NoError(err)
// Receive message, reply
// TODO: find a better way to handle this waiting
time.Sleep(500 * time.Millisecond)
_, err = server.RetrieveAll()
s.Require().NoError(err)
time.Sleep(500 * time.Millisecond)
_, err = server.RetrieveAll()
s.Require().NoError(err)
time.Sleep(500 * time.Millisecond)
_, err = server.RetrieveAll()
s.Require().NoError(err)
// Check reply
// TODO: find a better way to handle this waiting
time.Sleep(500 * time.Millisecond)
_, err = bob2.RetrieveAll()
s.Require().NoError(err)
time.Sleep(500 * time.Millisecond)
_, err = bob2.RetrieveAll()
s.Require().NoError(err)
time.Sleep(500 * time.Millisecond)
_, err = bob2.RetrieveAll()
s.Require().NoError(err)
err = tt.RetryWithBackOff(func() error {
registered, err := bob2.RegisteredForPushNotifications()
if err != nil {
return err
}
if !registered {
return errors.New("not registered")
}
return nil
})
// Make sure we receive it
s.Require().NoError(err)
bob2Servers, err := bob2.GetPushNotificationServers()
s.Require().NoError(err)
err = alice.pushNotificationClient.QueryPushNotificationInfo(&bob2.identity.PublicKey)
s.Require().NoError(err)
// Receive push notification query
// TODO: find a better way to handle this waiting
time.Sleep(500 * time.Millisecond)
_, err = server.RetrieveAll()
s.Require().NoError(err)
time.Sleep(500 * time.Millisecond)
_, err = server.RetrieveAll()
s.Require().NoError(err)
time.Sleep(500 * time.Millisecond)
_, err = server.RetrieveAll()
s.Require().NoError(err)
// Receive push notification query response
// TODO: find a better way to handle this waiting
time.Sleep(500 * time.Millisecond)
_, err = alice.RetrieveAll()
s.Require().NoError(err)
time.Sleep(500 * time.Millisecond)
_, err = alice.RetrieveAll()
s.Require().NoError(err)
time.Sleep(500 * time.Millisecond)
_, err = alice.RetrieveAll()
s.Require().NoError(err)
// Here we should poll, as we don't know whether they are already there
info, err := alice.pushNotificationClient.GetPushNotificationInfo(&bob1.identity.PublicKey, bobInstallationIDs)
s.Require().NoError(err)
// Check we have replies for both bob1 and bob2
s.Require().NotNil(info)
s.Require().Len(info, 2)
var bob1Info, bob2Info *push_notification_client.PushNotificationInfo
if info[0].AccessToken == bob1Servers[0].AccessToken {
bob1Info = info[0]
bob2Info = info[1]
} else {
bob2Info = info[0]
bob1Info = info[1]
}
s.Require().NotNil(bob1Info)
s.Require().Equal(bob1.installationID, bob1Info.InstallationID)
s.Require().Equal(bob1Info.AccessToken, bob1Servers[0].AccessToken, bob1Info.AccessToken)
s.Require().Equal(&bob1.identity.PublicKey, bob1Info.PublicKey)
s.Require().NotNil(bob2Info)
s.Require().Equal(bob2.installationID, bob2Info.InstallationID)
s.Require().Equal(bob2Servers[0].AccessToken, bob2Info.AccessToken)
s.Require().Equal(&bob2.identity.PublicKey, bob2Info.PublicKey)
retrievedNotificationInfo, err := alice.pushNotificationClient.GetPushNotificationInfo(&bob1.identity.PublicKey, bobInstallationIDs)
alice.logger.Info("BOB KEY", zap.Any("key", bob1.identity.PublicKey))
s.Require().NoError(err)
s.Require().NotNil(retrievedNotificationInfo)
s.Require().Len(retrievedNotificationInfo, 2)
}
func (s *MessengerPushNotificationSuite) TestReceivePushNotificationFromContactOnly() {
bob1DeviceToken := "token-1"
bob2DeviceToken := "token-2"
bob1 := s.m
bob2 := s.newMessengerWithKey(s.shh, s.m.identity)
server := s.newPushNotificationServer(s.shh)
alice := s.newMessenger(s.shh)
bobInstallationIDs := []string{bob1.installationID, bob2.installationID}
// Register bob1
err := bob1.AddPushNotificationServer(context.Background(), &server.identity.PublicKey)
s.Require().NoError(err)
err = bob1.RegisterForPushNotifications(context.Background(), bob1DeviceToken)
// Receive message, reply
// TODO: find a better way to handle this waiting
time.Sleep(500 * time.Millisecond)
_, err = server.RetrieveAll()
s.Require().NoError(err)
time.Sleep(500 * time.Millisecond)
_, err = server.RetrieveAll()
s.Require().NoError(err)
time.Sleep(500 * time.Millisecond)
_, err = server.RetrieveAll()
s.Require().NoError(err)
// Check reply
// TODO: find a better way to handle this waiting
time.Sleep(500 * time.Millisecond)
_, err = bob1.RetrieveAll()
s.Require().NoError(err)
time.Sleep(500 * time.Millisecond)
_, err = bob1.RetrieveAll()
s.Require().NoError(err)
time.Sleep(500 * time.Millisecond)
_, err = bob1.RetrieveAll()
s.Require().NoError(err)
// Pull servers and check we registered
err = tt.RetryWithBackOff(func() error {
registered, err := bob1.RegisteredForPushNotifications()
if err != nil {
return err
}
if !registered {
return errors.New("not registered")
}
return nil
})
// Make sure we receive it
s.Require().NoError(err)
bob1Servers, err := bob1.GetPushNotificationServers()
s.Require().NoError(err)
// Register bob2
err = bob2.AddPushNotificationServer(context.Background(), &server.identity.PublicKey)
s.Require().NoError(err)
err = bob2.RegisterForPushNotifications(context.Background(), bob2DeviceToken)
s.Require().NoError(err)
// Receive message, reply
// TODO: find a better way to handle this waiting
time.Sleep(500 * time.Millisecond)
_, err = server.RetrieveAll()
s.Require().NoError(err)
time.Sleep(500 * time.Millisecond)
_, err = server.RetrieveAll()
s.Require().NoError(err)
time.Sleep(500 * time.Millisecond)
_, err = server.RetrieveAll()
s.Require().NoError(err)
// Check reply
// TODO: find a better way to handle this waiting
time.Sleep(500 * time.Millisecond)
_, err = bob2.RetrieveAll()
s.Require().NoError(err)
time.Sleep(500 * time.Millisecond)
_, err = bob2.RetrieveAll()
s.Require().NoError(err)
time.Sleep(500 * time.Millisecond)
_, err = bob2.RetrieveAll()
s.Require().NoError(err)
err = tt.RetryWithBackOff(func() error {
registered, err := bob2.RegisteredForPushNotifications()
if err != nil {
return err
}
if !registered {
return errors.New("not registered")
}
return nil
})
// Make sure we receive it
s.Require().NoError(err)
bob2Servers, err := bob2.GetPushNotificationServers()
s.Require().NoError(err)
err = alice.pushNotificationClient.QueryPushNotificationInfo(&bob2.identity.PublicKey)
s.Require().NoError(err)
// Receive push notification query
// TODO: find a better way to handle this waiting
time.Sleep(500 * time.Millisecond)
_, err = server.RetrieveAll()
s.Require().NoError(err)
time.Sleep(500 * time.Millisecond)
_, err = server.RetrieveAll()
s.Require().NoError(err)
time.Sleep(500 * time.Millisecond)
_, err = server.RetrieveAll()
s.Require().NoError(err)
// Receive push notification query response
// TODO: find a better way to handle this waiting
time.Sleep(500 * time.Millisecond)
_, err = alice.RetrieveAll()
s.Require().NoError(err)
time.Sleep(500 * time.Millisecond)
_, err = alice.RetrieveAll()
s.Require().NoError(err)
time.Sleep(500 * time.Millisecond)
_, err = alice.RetrieveAll()
s.Require().NoError(err)
// Here we should poll, as we don't know whether they are already there
info, err := alice.pushNotificationClient.GetPushNotificationInfo(&bob1.identity.PublicKey, bobInstallationIDs)
s.Require().NoError(err)
// Check we have replies for both bob1 and bob2
s.Require().NotNil(info)
s.Require().Len(info, 2)
var bob1Info, bob2Info *push_notification_client.PushNotificationInfo
if info[0].AccessToken == bob1Servers[0].AccessToken {
bob1Info = info[0]
bob2Info = info[1]
} else {
bob2Info = info[0]
bob1Info = info[1]
}
s.Require().NotNil(bob1Info)
s.Require().Equal(bob1.installationID, bob1Info.InstallationID)
s.Require().Equal(bob1Info.AccessToken, bob1Servers[0].AccessToken, bob1Info.AccessToken)
s.Require().Equal(&bob1.identity.PublicKey, bob1Info.PublicKey)
s.Require().NotNil(bob2Info)
s.Require().Equal(bob2.installationID, bob2Info.InstallationID)
s.Require().Equal(bob2Servers[0].AccessToken, bob2Info.AccessToken)
s.Require().Equal(&bob2.identity.PublicKey, bob2Info.PublicKey)
retrievedNotificationInfo, err := alice.pushNotificationClient.GetPushNotificationInfo(&bob1.identity.PublicKey, bobInstallationIDs)
alice.logger.Info("BOB KEY", zap.Any("key", bob1.identity.PublicKey))
s.Require().NoError(err)
s.Require().NotNil(retrievedNotificationInfo)
s.Require().Len(retrievedNotificationInfo, 2)
}