github.com/status-im/status-go@v1.1.0/protocol/messenger_messages_tracking_test.go (about)

     1  package protocol
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"sync"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/cenkalti/backoff/v3"
    11  	"github.com/stretchr/testify/suite"
    12  	"go.uber.org/zap"
    13  
    14  	gethbridge "github.com/status-im/status-go/eth-node/bridge/geth"
    15  	"github.com/status-im/status-go/eth-node/crypto"
    16  	"github.com/status-im/status-go/eth-node/types"
    17  	"github.com/status-im/status-go/protocol/transport"
    18  	"github.com/status-im/status-go/protocol/tt"
    19  	"github.com/status-im/status-go/signal"
    20  )
    21  
    22  func TestMessengerMessagesTrackingSuite(t *testing.T) {
    23  	suite.Run(t, new(MessengerMessagesTrackingSuite))
    24  }
    25  
    26  type EnvelopeSignalHandlerMock struct{}
    27  
    28  // EnvelopeSent triggered when envelope delivered atleast to 1 peer.
    29  func (h EnvelopeSignalHandlerMock) EnvelopeSent(identifiers [][]byte) {
    30  	signal.SendEnvelopeSent(identifiers)
    31  }
    32  
    33  // EnvelopeExpired triggered when envelope is expired but wasn't delivered to any peer.
    34  func (h EnvelopeSignalHandlerMock) EnvelopeExpired(identifiers [][]byte, err error) {
    35  	signal.SendEnvelopeExpired(identifiers, err)
    36  }
    37  
    38  // MailServerRequestCompleted triggered when the mailserver sends a message to notify that the request has been completed
    39  func (h EnvelopeSignalHandlerMock) MailServerRequestCompleted(requestID types.Hash, lastEnvelopeHash types.Hash, cursor []byte, err error) {
    40  	signal.SendMailServerRequestCompleted(requestID, lastEnvelopeHash, cursor, err)
    41  }
    42  
    43  // MailServerRequestExpired triggered when the mailserver request expires
    44  func (h EnvelopeSignalHandlerMock) MailServerRequestExpired(hash types.Hash) {
    45  	signal.SendMailServerRequestExpired(hash)
    46  }
    47  
    48  type EnvelopeEventsInterceptorMock struct {
    49  	EnvelopeEventsInterceptor
    50  
    51  	enabled          bool
    52  	lock             sync.Mutex
    53  	identifiersQueue [][][]byte
    54  }
    55  
    56  func (i *EnvelopeEventsInterceptorMock) EnvelopeSent(identifiers [][]byte) {
    57  	i.lock.Lock()
    58  	defer i.lock.Unlock()
    59  
    60  	if i.enabled {
    61  		i.EnvelopeEventsInterceptor.EnvelopeSent(identifiers)
    62  	} else {
    63  		i.identifiersQueue = append(i.identifiersQueue, identifiers)
    64  	}
    65  }
    66  
    67  func (i *EnvelopeEventsInterceptorMock) Enable() {
    68  	i.lock.Lock()
    69  	defer i.lock.Unlock()
    70  
    71  	for _, identifiers := range i.identifiersQueue {
    72  		i.EnvelopeEventsInterceptor.EnvelopeSent(identifiers)
    73  	}
    74  	i.enabled = true
    75  }
    76  
    77  type MessengerMessagesTrackingSuite struct {
    78  	suite.Suite
    79  
    80  	bobWaku        types.Waku
    81  	bobInterceptor *EnvelopeEventsInterceptorMock
    82  	bob            *Messenger
    83  
    84  	aliceWaku        types.Waku
    85  	aliceInterceptor *EnvelopeEventsInterceptorMock
    86  	alice            *Messenger
    87  
    88  	logger *zap.Logger
    89  }
    90  
    91  func (s *MessengerMessagesTrackingSuite) SetupTest() {
    92  	s.logger = tt.MustCreateTestLogger()
    93  
    94  	wakuNodes := CreateWakuV2Network(&s.Suite, s.logger, []string{"bob", "alice"})
    95  
    96  	s.bobWaku = wakuNodes[0]
    97  	s.bob, s.bobInterceptor = s.newMessenger(s.bobWaku, s.logger.With(zap.String("name", "bob")))
    98  
    99  	s.aliceWaku = wakuNodes[1]
   100  	s.alice, s.aliceInterceptor = s.newMessenger(s.aliceWaku, s.logger.With(zap.String("name", "alice")))
   101  }
   102  
   103  func (s *MessengerMessagesTrackingSuite) TearDownTest() {
   104  	if s.bob != nil {
   105  		TearDownMessenger(&s.Suite, s.bob)
   106  
   107  	}
   108  	if s.bobWaku != nil {
   109  		s.Require().NoError(gethbridge.GetGethWakuV2From(s.bobWaku).Stop())
   110  	}
   111  
   112  	if s.alice != nil {
   113  		TearDownMessenger(&s.Suite, s.alice)
   114  	}
   115  	if s.aliceWaku != nil {
   116  		s.Require().NoError(gethbridge.GetGethWakuV2From(s.aliceWaku).Stop())
   117  	}
   118  
   119  	_ = s.logger.Sync()
   120  }
   121  
   122  func (s *MessengerMessagesTrackingSuite) newMessenger(waku types.Waku, logger *zap.Logger) (*Messenger, *EnvelopeEventsInterceptorMock) {
   123  	privateKey, err := crypto.GenerateKey()
   124  	s.Require().NoError(err)
   125  
   126  	envelopesMonitorConfig := &transport.EnvelopesMonitorConfig{
   127  		EnvelopeEventsHandler:            EnvelopeSignalHandlerMock{},
   128  		MaxAttempts:                      1,
   129  		AwaitOnlyMailServerConfirmations: false,
   130  		IsMailserver:                     func(peer types.EnodeID) bool { return false },
   131  		Logger:                           s.logger,
   132  	}
   133  
   134  	messenger, err := newMessengerWithKey(waku, privateKey, s.logger, []Option{WithEnvelopesMonitorConfig(envelopesMonitorConfig)})
   135  	s.Require().NoError(err)
   136  
   137  	interceptor := &EnvelopeEventsInterceptorMock{
   138  		EnvelopeEventsInterceptor: EnvelopeEventsInterceptor{
   139  			EnvelopeEventsHandler: envelopesMonitorConfig.EnvelopeEventsHandler,
   140  			Messenger:             messenger,
   141  		},
   142  	}
   143  
   144  	err = messenger.transport.SetEnvelopeEventsHandler(interceptor)
   145  	s.Require().NoError(err)
   146  
   147  	return messenger, interceptor
   148  }
   149  
   150  func (s *MessengerMessagesTrackingSuite) testMessageMarkedAsSent(textSize int) {
   151  	//when message sent, its sent field should be "false" until we got confirmation
   152  	chat := CreatePublicChat("test-chat", s.bob.getTimesource())
   153  	err := s.bob.SaveChat(chat)
   154  	s.Require().NoError(err)
   155  	inputMessage := buildTestMessage(*chat)
   156  	inputMessage.Text = string(make([]byte, textSize))
   157  
   158  	_, err = s.bob.SendChatMessage(context.Background(), inputMessage)
   159  	s.Require().NoError(err)
   160  
   161  	rawMessage, err := s.bob.persistence.RawMessageByID(inputMessage.ID)
   162  	s.Require().NoError(err)
   163  	s.Require().False(rawMessage.Sent)
   164  
   165  	// enables "EnvelopeSent" callback processing
   166  	s.bobInterceptor.Enable()
   167  
   168  	options := func(b *backoff.ExponentialBackOff) {
   169  		b.MaxElapsedTime = 1 * time.Second
   170  	}
   171  
   172  	// Message should be marked as sent eventually
   173  	err = tt.RetryWithBackOff(func() error {
   174  		rawMessage, err = s.bob.persistence.RawMessageByID(inputMessage.ID)
   175  		if err != nil || rawMessage.SendCount < 1 {
   176  			return errors.New("message not marked as sent")
   177  		}
   178  		return nil
   179  	}, options)
   180  	s.Require().NoError(err)
   181  }
   182  
   183  func (s *MessengerMessagesTrackingSuite) TestMessageMarkedAsSent() {
   184  	s.testMessageMarkedAsSent(1)
   185  }
   186  func (s *MessengerMessagesTrackingSuite) TestSegmentedMessageMarkedAsSent() {
   187  	s.testMessageMarkedAsSent(4 * 1024 * 1024) // 4MB - ensure message is segmented
   188  }