github.com/status-im/status-go@v1.1.0/protocol/transport/envelopes_monitor_test.go (about) 1 package transport 2 3 import ( 4 "context" 5 "reflect" 6 "testing" 7 "time" 8 9 "go.uber.org/zap" 10 11 "github.com/stretchr/testify/suite" 12 13 "github.com/ethereum/go-ethereum/p2p/enode" 14 15 "github.com/status-im/status-go/eth-node/crypto" 16 "github.com/status-im/status-go/eth-node/types" 17 ) 18 19 var ( 20 testHash = types.Hash{0x01} 21 testHashes = []types.Hash{testHash} 22 testIDs = [][]byte{[]byte("id")} 23 ) 24 25 type envelopeEventsHandlerMock struct { 26 envelopeSentCalls [][][]byte // slice of EnvelopeSent arguments 27 } 28 29 func (h *envelopeEventsHandlerMock) EnvelopeSent(identifiers [][]byte) { 30 h.envelopeSentCalls = append(h.envelopeSentCalls, identifiers) 31 } 32 func (h *envelopeEventsHandlerMock) EnvelopeExpired([][]byte, error) { 33 } 34 func (h *envelopeEventsHandlerMock) MailServerRequestCompleted(types.Hash, types.Hash, []byte, error) { 35 } 36 func (h *envelopeEventsHandlerMock) MailServerRequestExpired(types.Hash) { 37 } 38 39 type EnvelopesMonitorSuite struct { 40 suite.Suite 41 42 monitor *EnvelopesMonitor 43 eventsHandlerMock *envelopeEventsHandlerMock 44 } 45 46 func TestEnvelopesMonitorSuite(t *testing.T) { 47 suite.Run(t, new(EnvelopesMonitorSuite)) 48 } 49 50 func (s *EnvelopesMonitorSuite) SetupTest() { 51 s.eventsHandlerMock = &envelopeEventsHandlerMock{} 52 s.monitor = NewEnvelopesMonitor( 53 nil, 54 EnvelopesMonitorConfig{ 55 EnvelopeEventsHandler: s.eventsHandlerMock, 56 MaxAttempts: 6, 57 AwaitOnlyMailServerConfirmations: false, 58 IsMailserver: func(types.EnodeID) bool { return false }, 59 Logger: zap.NewNop(), 60 }, 61 ) 62 } 63 64 func (s *EnvelopesMonitorSuite) TestEnvelopePosted() { 65 err := s.monitor.Add(testIDs, testHashes, []*types.NewMessage{{}}) 66 s.Require().NoError(err) 67 s.Contains(s.monitor.envelopes, testHash) 68 s.Equal(EnvelopePosted, s.monitor.envelopes[testHash].state) 69 s.monitor.handleEvent(types.EnvelopeEvent{ 70 Event: types.EventEnvelopeSent, 71 Hash: testHash, 72 }) 73 s.Contains(s.monitor.envelopes, testHash) 74 s.Equal(EnvelopeSent, s.monitor.envelopes[testHash].state) 75 } 76 77 func (s *EnvelopesMonitorSuite) TestEnvelopePostedOutOfOrder() { 78 s.monitor.handleEvent(types.EnvelopeEvent{ 79 Event: types.EventEnvelopeSent, 80 Hash: testHash, 81 }) 82 83 err := s.monitor.Add(testIDs, testHashes, []*types.NewMessage{{}}) 84 s.Require().NoError(err) 85 s.Require().Contains(s.monitor.envelopes, testHash) 86 s.Require().Equal(EnvelopeSent, s.monitor.envelopes[testHash].state) 87 } 88 89 func (s *EnvelopesMonitorSuite) TestConfirmedWithAcknowledge() { 90 testBatch := types.Hash{1} 91 pkey, err := crypto.GenerateKey() 92 s.Require().NoError(err) 93 node := enode.NewV4(&pkey.PublicKey, nil, 0, 0) 94 err = s.monitor.Add(testIDs, testHashes, []*types.NewMessage{{}}) 95 s.Require().NoError(err) 96 s.Contains(s.monitor.envelopes, testHash) 97 s.Equal(EnvelopePosted, s.monitor.envelopes[testHash].state) 98 s.monitor.handleEvent(types.EnvelopeEvent{ 99 Event: types.EventEnvelopeSent, 100 Hash: testHash, 101 Batch: testBatch, 102 }) 103 s.Equal(EnvelopePosted, s.monitor.envelopes[testHash].state) 104 s.monitor.handleEvent(types.EnvelopeEvent{ 105 Event: types.EventBatchAcknowledged, 106 Batch: testBatch, 107 Peer: types.EnodeID(node.ID()), 108 }) 109 s.Contains(s.monitor.envelopes, testHash) 110 s.Equal(EnvelopeSent, s.monitor.envelopes[testHash].state) 111 } 112 113 func (s *EnvelopesMonitorSuite) TestRemoved() { 114 err := s.monitor.Add(testIDs, testHashes, []*types.NewMessage{{}}) 115 s.Require().NoError(err) 116 s.Contains(s.monitor.envelopes, testHash) 117 s.monitor.handleEvent(types.EnvelopeEvent{ 118 Event: types.EventEnvelopeExpired, 119 Hash: testHash, 120 }) 121 s.NotContains(s.monitor.envelopes, testHash) 122 } 123 124 func (s *EnvelopesMonitorSuite) TestIgnoreNotFromMailserver() { 125 // enables filter in the tracker to drop confirmations from non-mailserver peers 126 s.monitor.awaitOnlyMailServerConfirmations = true 127 err := s.monitor.Add(testIDs, testHashes, []*types.NewMessage{{}}) 128 s.Require().NoError(err) 129 s.monitor.handleEvent(types.EnvelopeEvent{ 130 Event: types.EventEnvelopeSent, 131 Hash: testHash, 132 Peer: types.EnodeID{1}, // could be empty, doesn't impact test behaviour 133 }) 134 s.Require().Equal(EnvelopePosted, s.monitor.GetState(testHash)) 135 } 136 137 func (s *EnvelopesMonitorSuite) TestReceived() { 138 s.monitor.isMailserver = func(peer types.EnodeID) bool { 139 return true 140 } 141 err := s.monitor.Add(testIDs, testHashes, []*types.NewMessage{{}}) 142 s.Require().NoError(err) 143 s.Contains(s.monitor.envelopes, testHash) 144 s.monitor.handleEvent(types.EnvelopeEvent{ 145 Event: types.EventEnvelopeReceived, 146 Hash: testHash, 147 }) 148 s.Require().Equal(EnvelopeSent, s.monitor.GetState(testHash)) 149 } 150 151 func (s *EnvelopesMonitorSuite) TestMultipleHashes() { 152 messageIDs := [][]byte{[]byte("id1"), []byte("id2")} 153 hashes := []types.Hash{{0x01}, {0x02}, {0x03}} 154 messages := []*types.NewMessage{{}, {}, {}} 155 156 err := s.monitor.Add(messageIDs, hashes, messages) 157 s.Require().NoError(err) 158 for _, hash := range hashes { 159 s.Contains(s.monitor.envelopes, hash) 160 } 161 s.Require().Empty(s.eventsHandlerMock.envelopeSentCalls) 162 s.Require().Equal(EnvelopePosted, s.monitor.envelopes[hashes[0]].state) 163 s.Require().Equal(EnvelopePosted, s.monitor.envelopes[hashes[1]].state) 164 s.Require().Equal(EnvelopePosted, s.monitor.envelopes[hashes[2]].state) 165 166 s.monitor.handleEvent(types.EnvelopeEvent{ 167 Event: types.EventEnvelopeSent, 168 Hash: hashes[0], 169 }) 170 s.Require().Empty(s.eventsHandlerMock.envelopeSentCalls) 171 s.Require().Equal(EnvelopeSent, s.monitor.envelopes[hashes[0]].state) 172 s.Require().Equal(EnvelopePosted, s.monitor.envelopes[hashes[1]].state) 173 s.Require().Equal(EnvelopePosted, s.monitor.envelopes[hashes[2]].state) 174 175 s.monitor.handleEvent(types.EnvelopeEvent{ 176 Event: types.EventEnvelopeSent, 177 Hash: hashes[1], 178 }) 179 s.Require().Empty(s.eventsHandlerMock.envelopeSentCalls) 180 s.Require().Equal(EnvelopeSent, s.monitor.envelopes[hashes[0]].state) 181 s.Require().Equal(EnvelopeSent, s.monitor.envelopes[hashes[1]].state) 182 s.Require().Equal(EnvelopePosted, s.monitor.envelopes[hashes[2]].state) 183 184 s.monitor.handleEvent(types.EnvelopeEvent{ 185 Event: types.EventEnvelopeSent, 186 Hash: hashes[2], 187 }) 188 // Identifiers should be marked as sent only if all corresponding envelopes are sent 189 s.Require().Len(s.eventsHandlerMock.envelopeSentCalls, 1) 190 s.Require().True(reflect.DeepEqual(messageIDs, s.eventsHandlerMock.envelopeSentCalls[0])) 191 s.Require().Equal(EnvelopeSent, s.monitor.envelopes[hashes[0]].state) 192 s.Require().Equal(EnvelopeSent, s.monitor.envelopes[hashes[1]].state) 193 s.Require().Equal(EnvelopeSent, s.monitor.envelopes[hashes[2]].state) 194 } 195 196 func (s *EnvelopesMonitorSuite) TestMultipleHashes_EnvelopeExpired() { 197 messageIDs := [][]byte{[]byte("id1"), []byte("id2")} 198 hashes := []types.Hash{{0x01}, {0x02}, {0x03}} 199 messages := []*types.NewMessage{{}, {}, {}} 200 201 err := s.monitor.Add(messageIDs, hashes, messages) 202 s.Require().NoError(err) 203 204 // If any envelope fails, then messageIDs are considered as not sent 205 s.monitor.handleEvent(types.EnvelopeEvent{ 206 Event: types.EventEnvelopeExpired, 207 Hash: hashes[0], 208 }) 209 s.monitor.handleEvent(types.EnvelopeEvent{ 210 Event: types.EventEnvelopeSent, 211 Hash: hashes[1], 212 }) 213 s.monitor.handleEvent(types.EnvelopeEvent{ 214 Event: types.EventEnvelopeSent, 215 Hash: hashes[2], 216 }) 217 218 s.Require().Empty(s.eventsHandlerMock.envelopeSentCalls) 219 s.Require().Empty(s.monitor.messageEnvelopeHashes) 220 s.Require().Len(s.monitor.envelopes, 2) 221 } 222 223 func (s *EnvelopesMonitorSuite) TestMultipleHashes_Failure() { 224 err := s.monitor.Add(testIDs, []types.Hash{{0x01}, {0x02}}, []*types.NewMessage{{}}) 225 s.Require().Error(err) 226 } 227 228 func (s *EnvelopesMonitorSuite) TestRetryOnce() { 229 s.monitor.api = &mockWakuAPI{} 230 err := s.monitor.Add(testIDs, testHashes, []*types.NewMessage{{}}) 231 s.Require().NoError(err) 232 envelope := s.monitor.envelopes[testHash] 233 envelope.attempts = 2 234 envelope.lastAttemptTime = time.Now().Add(-20 * time.Second) 235 s.monitor.retryQueue = append(s.monitor.retryQueue, envelope) 236 237 s.monitor.retryOnce() 238 239 s.Require().Equal(3, envelope.attempts) 240 s.Require().Len(s.monitor.retryQueue, 0) 241 s.Require().Equal(envelope.envelopeHashID, s.monitor.envelopes[envelope.envelopeHashID].envelopeHashID) 242 } 243 244 type mockWakuAPI struct{} 245 246 func (m *mockWakuAPI) Post(ctx context.Context, msg types.NewMessage) ([]byte, error) { 247 return []byte{0x01}, nil 248 } 249 250 func (m *mockWakuAPI) AddPrivateKey(ctx context.Context, privateKey types.HexBytes) (string, error) { 251 return "", nil 252 } 253 func (m *mockWakuAPI) GenerateSymKeyFromPassword(ctx context.Context, passwd string) (string, error) { 254 return "", nil 255 } 256 func (m *mockWakuAPI) DeleteKeyPair(ctx context.Context, key string) (bool, error) { 257 return false, nil 258 } 259 func (m *mockWakuAPI) NewMessageFilter(req types.Criteria) (string, error) { 260 return "", nil 261 } 262 func (m *mockWakuAPI) GetFilterMessages(id string) ([]*types.Message, error) { 263 return nil, nil 264 } 265 func (m *mockWakuAPI) BloomFilter() []byte { 266 return nil 267 }