github.com/status-im/status-go@v1.1.0/protocol/messenger_storenode_comunity_test.go (about) 1 package protocol 2 3 import ( 4 "context" 5 "fmt" 6 "testing" 7 "time" 8 9 "github.com/libp2p/go-libp2p/core/peer" 10 "github.com/multiformats/go-multiaddr" 11 12 "github.com/status-im/status-go/protocol/storenodes" 13 14 gethbridge "github.com/status-im/status-go/eth-node/bridge/geth" 15 "github.com/status-im/status-go/protocol/common/shard" 16 "github.com/status-im/status-go/protocol/communities" 17 "github.com/status-im/status-go/protocol/tt" 18 19 "github.com/stretchr/testify/suite" 20 "go.uber.org/zap" 21 22 "github.com/ethereum/go-ethereum/crypto" 23 "github.com/status-im/status-go/appdatabase" 24 "github.com/status-im/status-go/eth-node/types" 25 "github.com/status-im/status-go/protocol/protobuf" 26 "github.com/status-im/status-go/protocol/requests" 27 "github.com/status-im/status-go/protocol/sqlite" 28 "github.com/status-im/status-go/t/helpers" 29 30 mailserversDB "github.com/status-im/status-go/services/mailservers" 31 waku2 "github.com/status-im/status-go/wakuv2" 32 wakuV2common "github.com/status-im/status-go/wakuv2/common" 33 ) 34 35 func TestMessengerStoreNodeCommunitySuite(t *testing.T) { 36 t.Skip("requires storev3 node") 37 suite.Run(t, new(MessengerStoreNodeCommunitySuite)) 38 } 39 40 type MessengerStoreNodeCommunitySuite struct { 41 suite.Suite 42 43 cancel chan struct{} 44 45 owner *Messenger 46 ownerWaku types.Waku 47 48 bob *Messenger 49 bobWaku types.Waku 50 51 storeNode *waku2.Waku 52 storeNodeAddress multiaddr.Multiaddr 53 communityStoreNode *waku2.Waku 54 communityStoreNodeAddress multiaddr.Multiaddr 55 56 collectiblesServiceMock *CollectiblesServiceMock 57 58 logger *zap.Logger 59 } 60 61 func (s *MessengerStoreNodeCommunitySuite) SetupTest() { 62 s.logger = tt.MustCreateTestLogger() 63 64 s.cancel = make(chan struct{}, 10) 65 66 s.collectiblesServiceMock = &CollectiblesServiceMock{} 67 68 s.storeNode, s.storeNodeAddress = s.createStore("store-1") 69 s.communityStoreNode, s.communityStoreNodeAddress = s.createStore("store-community") 70 71 s.owner, s.ownerWaku = s.newMessenger("owner", &s.storeNodeAddress) 72 s.bob, s.bobWaku = s.newMessenger("bob", &s.storeNodeAddress) 73 } 74 75 func (s *MessengerStoreNodeCommunitySuite) TearDown() { 76 close(s.cancel) 77 if s.storeNode != nil { 78 s.Require().NoError(s.storeNode.Stop()) 79 } 80 if s.communityStoreNode != nil { 81 s.Require().NoError(s.communityStoreNode.Stop()) 82 } 83 if s.owner != nil { 84 TearDownMessenger(&s.Suite, s.owner) 85 } 86 if s.bob != nil { 87 TearDownMessenger(&s.Suite, s.bob) 88 } 89 } 90 91 func (s *MessengerStoreNodeCommunitySuite) createStore(name string) (*waku2.Waku, multiaddr.Multiaddr) { 92 cfg := testWakuV2Config{ 93 logger: s.logger.Named(name), 94 enableStore: true, 95 clusterID: shard.MainStatusShardCluster, 96 } 97 98 storeNode := NewTestWakuV2(&s.Suite, cfg) 99 addresses := storeNode.ListenAddresses() 100 s.Require().GreaterOrEqual(len(addresses), 1, "no storenode listen address") 101 return storeNode, addresses[0] 102 } 103 104 func (s *MessengerStoreNodeCommunitySuite) newMessenger(name string, storenodeAddress *multiaddr.Multiaddr) (*Messenger, types.Waku) { 105 localMailserverID := "local-mailserver-007" 106 localFleet := "local-fleet-007" 107 108 logger := s.logger.Named(name) 109 cfg := testWakuV2Config{ 110 logger: logger, 111 enableStore: false, 112 clusterID: shard.MainStatusShardCluster, 113 } 114 wakuV2 := NewTestWakuV2(&s.Suite, cfg) 115 wakuV2Wrapper := gethbridge.NewGethWakuV2Wrapper(wakuV2) 116 117 privateKey, err := crypto.GenerateKey() 118 s.Require().NoError(err) 119 120 mailserversSQLDb, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{}) 121 s.Require().NoError(err) 122 err = sqlite.Migrate(mailserversSQLDb) // migrate default 123 s.Require().NoError(err) 124 125 mailserversDatabase := mailserversDB.NewDB(mailserversSQLDb) 126 err = mailserversDatabase.Add(mailserversDB.Mailserver{ 127 ID: localMailserverID, 128 Name: localMailserverID, 129 Addr: storenodeAddress, 130 Fleet: localFleet, 131 }) 132 s.Require().NoError(err) 133 134 options := []Option{ 135 WithAutoRequestHistoricMessages(false), 136 WithCuratedCommunitiesUpdateLoop(false), 137 } 138 139 if storenodeAddress != nil { 140 options = append(options, 141 WithTestStoreNode(&s.Suite, localMailserverID, *storenodeAddress, localFleet, s.collectiblesServiceMock), 142 ) 143 } 144 145 messenger, err := newMessengerWithKey(wakuV2Wrapper, privateKey, logger, options) 146 147 s.Require().NoError(err) 148 return messenger, wakuV2Wrapper 149 } 150 151 func (s *MessengerStoreNodeCommunitySuite) createCommunityWithChat(m *Messenger) (*communities.Community, *Chat) { 152 WaitForAvailableStoreNode(&s.Suite, m, 500*time.Millisecond) 153 154 storeNodeSubscription := s.setupStoreNodeEnvelopesWatcher(nil) 155 156 createCommunityRequest := &requests.CreateCommunity{ 157 Name: RandomLettersString(10), 158 Description: RandomLettersString(20), 159 Color: RandomColor(), 160 Tags: RandomCommunityTags(3), 161 Membership: protobuf.CommunityPermissions_AUTO_ACCEPT, 162 } 163 164 response, err := m.CreateCommunity(createCommunityRequest, true) 165 s.Require().NoError(err) 166 s.Require().NotNil(response) 167 s.Require().Len(response.Communities(), 1) 168 s.Require().Len(response.Chats(), 1) 169 s.Require().True(response.Communities()[0].Joined()) 170 s.Require().True(response.Communities()[0].IsControlNode()) 171 s.Require().True(response.Communities()[0].IsMemberOwner(&m.identity.PublicKey)) 172 173 s.waitForEnvelopes(storeNodeSubscription, 1) 174 175 return response.Communities()[0], response.Chats()[0] 176 } 177 178 func (s *MessengerStoreNodeCommunitySuite) requireCommunitiesEqual(c *communities.Community, expected *communities.Community) { 179 if expected == nil { 180 s.Require().Nil(c) 181 return 182 } 183 s.Require().NotNil(c) 184 s.Require().Equal(expected.IDString(), c.IDString()) 185 s.Require().Equal(expected.Clock(), c.Clock()) 186 s.Require().Equal(expected.Name(), c.Name()) 187 s.Require().Equal(expected.Identity().Description, c.Identity().Description) 188 s.Require().Equal(expected.Color(), c.Color()) 189 s.Require().Equal(expected.Tags(), c.Tags()) 190 s.Require().Equal(expected.Shard(), c.Shard()) 191 s.Require().Equal(expected.TokenPermissions(), c.TokenPermissions()) 192 s.Require().Equal(expected.CommunityTokensMetadata(), c.CommunityTokensMetadata()) 193 } 194 195 func (s *MessengerStoreNodeCommunitySuite) fetchCommunity(m *Messenger, communityShard communities.CommunityShard, expectedCommunity *communities.Community) StoreNodeRequestStats { 196 options := []StoreNodeRequestOption{ 197 WithWaitForResponseOption(true), 198 } 199 200 fetchedCommunity, stats, err := m.storeNodeRequestsManager.FetchCommunity(communityShard, options) 201 202 s.Require().NoError(err) 203 s.requireCommunitiesEqual(fetchedCommunity, expectedCommunity) 204 205 return stats 206 } 207 208 func (s *MessengerStoreNodeCommunitySuite) setupEnvelopesWatcher(wakuNode *waku2.Waku, topic *wakuV2common.TopicType, cb func(envelope *wakuV2common.ReceivedMessage)) { 209 envelopesWatcher := make(chan wakuV2common.EnvelopeEvent, 100) 210 envelopesSub := wakuNode.SubscribeEnvelopeEvents(envelopesWatcher) 211 212 go func() { 213 defer envelopesSub.Unsubscribe() 214 for { 215 select { 216 case <-s.cancel: 217 return 218 219 case envelopeEvent := <-envelopesWatcher: 220 if envelopeEvent.Event != wakuV2common.EventEnvelopeAvailable { 221 continue 222 } 223 if topic != nil && *topic != envelopeEvent.Topic { 224 continue 225 } 226 envelope := wakuNode.GetEnvelope(envelopeEvent.Hash) 227 cb(envelope) 228 s.logger.Debug("envelope available event for fetched content topic", 229 zap.Any("envelopeEvent", envelopeEvent), 230 zap.Any("envelope", envelope), 231 ) 232 } 233 234 } 235 }() 236 } 237 238 func (s *MessengerStoreNodeCommunitySuite) setupStoreNodeEnvelopesWatcher(topic *wakuV2common.TopicType) <-chan string { 239 storeNodeSubscription := make(chan string, 100) 240 s.setupEnvelopesWatcher(s.storeNode, topic, func(envelope *wakuV2common.ReceivedMessage) { 241 storeNodeSubscription <- envelope.Hash().String() 242 }) 243 return storeNodeSubscription 244 } 245 246 func (s *MessengerStoreNodeCommunitySuite) waitForEnvelopes(subscription <-chan string, expectedEnvelopesCount int) { 247 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 248 defer cancel() 249 250 for i := 0; i < expectedEnvelopesCount; i++ { 251 select { 252 case <-subscription: 253 case <-ctx.Done(): 254 err := fmt.Sprintf("timeout waiting for store node to receive envelopes, received: %d, expected: %d", i, expectedEnvelopesCount) 255 s.Require().Fail(err) 256 } 257 } 258 } 259 260 func (s *MessengerStoreNodeCommunitySuite) TestSetCommunityStorenodesAndFetch() { 261 err := s.owner.DialPeer(s.storeNodeAddress) 262 s.Require().NoError(err) 263 err = s.bob.DialPeer(s.storeNodeAddress) 264 s.Require().NoError(err) 265 266 // Create a community 267 community, _ := s.createCommunityWithChat(s.owner) 268 269 // Set the storenode for the community 270 _, err = s.owner.SetCommunityStorenodes(&requests.SetCommunityStorenodes{ 271 CommunityID: community.ID(), 272 Storenodes: []storenodes.Storenode{ 273 { 274 StorenodeID: "community-store-node", 275 Name: "community-store-node", 276 CommunityID: community.ID(), 277 Version: 2, 278 Address: s.communityStoreNodeAddress, 279 Fleet: "aaa", 280 }, 281 }, 282 }) 283 s.Require().NoError(err) 284 285 // Bob tetches the community 286 s.fetchCommunity(s.bob, community.CommunityShard(), community) 287 } 288 289 func (s *MessengerStoreNodeCommunitySuite) TestSetStorenodeForCommunity_fetchMessagesFromNewStorenode() { 290 s.T().Skip("flaky") 291 292 err := s.owner.DialPeer(s.storeNodeAddress) 293 s.Require().NoError(err) 294 err = s.bob.DialPeer(s.storeNodeAddress) 295 s.Require().NoError(err) 296 297 ownerPeerID := gethbridge.GetGethWakuV2From(s.ownerWaku).PeerID() 298 bobPeerID := gethbridge.GetGethWakuV2From(s.bobWaku).PeerID() 299 300 // 1. Owner creates a community 301 community, chat := s.createCommunityWithChat(s.owner) 302 303 // waits for onwer and bob to connect to the store node 304 WaitForPeersConnected(&s.Suite, s.storeNode, func() peer.IDSlice { 305 return peer.IDSlice{ownerPeerID, bobPeerID} 306 }) 307 308 // 2. Bob joins the community 309 advertiseCommunityTo(&s.Suite, community, s.owner, s.bob) 310 joinCommunity(&s.Suite, community.ID(), s.owner, s.bob, bobPassword, []string{bobAccountAddress}) 311 312 // waits for onwer and bob to connect to the community store node 313 WaitForPeersConnected(&s.Suite, s.communityStoreNode, func() peer.IDSlice { 314 err := s.bob.DialPeer(s.communityStoreNodeAddress) 315 s.Require().NoError(err) 316 err = s.owner.DialPeer(s.communityStoreNodeAddress) 317 s.Require().NoError(err) 318 319 return peer.IDSlice{ownerPeerID, bobPeerID} 320 }) 321 322 // 3. Owner sets the storenode for the community 323 _, err = s.owner.SetCommunityStorenodes(&requests.SetCommunityStorenodes{ 324 CommunityID: community.ID(), 325 Storenodes: []storenodes.Storenode{ 326 { 327 StorenodeID: "community-store-node", 328 Name: "community-store-node", 329 CommunityID: community.ID(), 330 Version: 2, 331 Address: s.communityStoreNodeAddress, 332 Fleet: "aaa", 333 }, 334 }, 335 }) 336 s.Require().NoError(err) 337 338 // 5. Bob sends a message to the community chat 339 inputMessage := buildTestMessage(*chat) 340 _, err = s.bob.SendChatMessage(context.Background(), inputMessage) 341 s.Require().NoError(err) 342 343 // 6. Owner fetches the message from the new storenode 344 err = s.owner.FetchMessages(&requests.FetchMessages{ 345 ID: chat.ID, 346 }) 347 s.Require().NoError(err) 348 } 349 350 func (s *MessengerStoreNodeCommunitySuite) TestToggleUseMailservers() { 351 // Enable use of mailservers 352 err := s.owner.ToggleUseMailservers(true) 353 s.Require().NoError(err) 354 s.Require().NotNil(s.owner.mailserverCycle.activeMailserver) 355 356 // Disable use of mailservers 357 err = s.owner.ToggleUseMailservers(false) 358 s.Require().NoError(err) 359 s.Require().Nil(s.owner.mailserverCycle.activeMailserver) 360 }