mirror of
https://github.com/status-im/status-go.git
synced 2026-08-31 00:51:12 +00:00
Part of the Go project layout migration, item 27. Pure move plus import-path rewrite across 502 files. No API or behaviour change. `internal/` keeps the messaging application logic unimportable from outside the module, which is what the issue asks for -- status-go is consumed through the C-bindings in mobile/, not as a Go library. Things that had to follow the move, beyond the Go imports: - tools/generate-handlers/template.txt. messenger_handlers.go is generated, and the template hard-codes the imports it emits, so the generated file kept importing protocol/common and failed typecheck. - .gitignore. The ignore rule for that generated file was pinned to the old path; without moving it, a 1486-line generated file starts being tracked. - Makefile: the logosstorage and torrent test targets (both the archive packages and ./protocol itself), the archive README, migration-protocol. - scripts/run_unit_tests.sh, which names the protocol package explicitly to shard its tests. - scripts/cleanup_generated_files.sh and .golangci.yml. scripts/migration_check.sh also needed a fix that is not specific to this move: it validated every file the branch touched under a migration dir against the timestamp naming rule, and a directory rename makes every migration in it look newly added. It now excludes renames, so moving a migration is not mistaken for adding one. refs #7067
345 lines
9.8 KiB
Go
345 lines
9.8 KiB
Go
package protocol
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"errors"
|
|
"math/big"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/suite"
|
|
|
|
"github.com/status-im/status-go/internal/panics"
|
|
"github.com/status-im/status-go/internal/protocol/backupsync"
|
|
"github.com/status-im/status-go/internal/protocol/common"
|
|
"github.com/status-im/status-go/internal/protocol/communities"
|
|
"github.com/status-im/status-go/internal/protocol/identity"
|
|
"github.com/status-im/status-go/internal/protocol/protobuf"
|
|
"github.com/status-im/status-go/internal/testutils"
|
|
)
|
|
|
|
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
|
var hexRunes = []rune("0123456789abcdef")
|
|
|
|
// WaitOnMessengerResponse Wait until the condition is true or the timeout is reached.
|
|
func WaitOnMessengerResponse(m *Messenger, condition func(*MessengerResponse) bool, errorMessage string) (*MessengerResponse, error) {
|
|
response := &MessengerResponse{}
|
|
err := testutils.RetryWithBackOff(func() error {
|
|
var err error
|
|
r, err := m.RetrieveAll()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
if err := response.Merge(r); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
if err == nil && !condition(response) {
|
|
err = errors.New(errorMessage)
|
|
}
|
|
return err
|
|
})
|
|
return response, err
|
|
}
|
|
|
|
type MessengerSignalsHandlerMock struct {
|
|
MessengerSignalsHandler
|
|
|
|
responseChan chan *MessengerResponse
|
|
communityFoundChan chan *communities.Community
|
|
}
|
|
|
|
func (m *MessengerSignalsHandlerMock) SendBackedUpProfile(*backupsync.BackedUpDataResponse) {}
|
|
func (m *MessengerSignalsHandlerMock) SendBackedUpSettings(*backupsync.BackedUpDataResponse) {}
|
|
|
|
func (m *MessengerSignalsHandlerMock) HistoryArchivesProtocolEnabled() {}
|
|
func (m *MessengerSignalsHandlerMock) HistoryArchivesProtocolDisabled() {}
|
|
func (m *MessengerSignalsHandlerMock) CreatingHistoryArchives(string) {}
|
|
func (m *MessengerSignalsHandlerMock) NoHistoryArchivesCreated(string, int, int) {}
|
|
func (m *MessengerSignalsHandlerMock) HistoryArchivesCreated(string, int, int) {}
|
|
func (m *MessengerSignalsHandlerMock) HistoryArchivesSeeding(string) {}
|
|
func (m *MessengerSignalsHandlerMock) HistoryArchivesUnseeded(string) {}
|
|
func (m *MessengerSignalsHandlerMock) HistoryArchiveDownloaded(string, int, int) {}
|
|
func (m *MessengerSignalsHandlerMock) IndexDownloadCompleted(string, string) {}
|
|
func (m *MessengerSignalsHandlerMock) DownloadingHistoryArchivesStarted(string) {}
|
|
func (m *MessengerSignalsHandlerMock) DownloadingHistoryArchivesFinished(string) {}
|
|
func (m *MessengerSignalsHandlerMock) ImportingHistoryArchiveMessages(string) {}
|
|
|
|
func (m *MessengerSignalsHandlerMock) MessengerResponse(response *MessengerResponse) {
|
|
// Non-blocking send
|
|
select {
|
|
case m.responseChan <- response:
|
|
default:
|
|
}
|
|
}
|
|
|
|
func (m *MessengerSignalsHandlerMock) MessageDelivered(chatID string, messageID string) {}
|
|
|
|
func (m *MessengerSignalsHandlerMock) CommunityInfoFound(community *communities.Community) {
|
|
select {
|
|
case m.communityFoundChan <- community:
|
|
default:
|
|
}
|
|
}
|
|
|
|
func WaitOnSignaledMessengerResponse(m *Messenger, condition func(*MessengerResponse) bool, errorMessage string) (*MessengerResponse, error) {
|
|
interval := 500 * time.Millisecond
|
|
timeoutChan := time.After(10 * time.Second)
|
|
|
|
if m.config.messengerSignalsHandler != nil {
|
|
return nil, errors.New("messengerSignalsHandler already provided/mocked")
|
|
}
|
|
|
|
responseChan := make(chan *MessengerResponse, 64)
|
|
m.config.messengerSignalsHandler = &MessengerSignalsHandlerMock{
|
|
responseChan: responseChan,
|
|
}
|
|
|
|
defer func() {
|
|
m.config.messengerSignalsHandler = nil
|
|
}()
|
|
|
|
for {
|
|
_, err := m.RetrieveAll()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
select {
|
|
case r := <-responseChan:
|
|
if condition(r) {
|
|
return r, nil
|
|
}
|
|
|
|
case <-timeoutChan:
|
|
return nil, errors.New(errorMessage)
|
|
|
|
default: // No immediate response, rest & loop back to retrieve again
|
|
time.Sleep(interval)
|
|
}
|
|
}
|
|
}
|
|
|
|
func FindFirstByContentType(messages []*common.Message, contentType protobuf.ChatMessage_ContentType) *common.Message {
|
|
for _, message := range messages {
|
|
if message.ContentType == contentType {
|
|
return message
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func PairDevices(s *suite.Suite, device1, device2 *Messenger) {
|
|
// Send pairing data
|
|
response, err := device1.SendPairInstallation(context.Background(), "", nil)
|
|
s.Require().NoError(err)
|
|
s.Require().NotNil(response)
|
|
s.Len(response.Chats(), 1)
|
|
s.False(response.Chats()[0].Active)
|
|
|
|
i, ok := device1.allInstallations.Load(device1.installationID)
|
|
s.Require().True(ok)
|
|
|
|
// Wait for the message to reach its destination
|
|
response, err = WaitOnMessengerResponse(
|
|
device2,
|
|
func(r *MessengerResponse) bool {
|
|
for _, installation := range r.Installations() {
|
|
if installation.ID == device1.installationID {
|
|
return installation.InstallationMetadata != nil &&
|
|
i.InstallationMetadata.Name == installation.InstallationMetadata.Name &&
|
|
i.InstallationMetadata.DeviceType == installation.InstallationMetadata.DeviceType
|
|
}
|
|
}
|
|
return false
|
|
|
|
},
|
|
"installation not received",
|
|
)
|
|
s.Require().NoError(err)
|
|
s.Require().NotNil(response)
|
|
|
|
// Ensure installation is enabled
|
|
_, err = device2.EnableInstallation(device1.installationID)
|
|
s.Require().NoError(err)
|
|
}
|
|
|
|
func SetSettingsAndWaitForChange(s *suite.Suite, messenger *Messenger, timeout time.Duration,
|
|
actionCallback func(), eventCallback func(*SelfContactChangeEvent) bool) {
|
|
|
|
allEventsReceived := false
|
|
channel := messenger.SubscribeToSelfContactChanges()
|
|
wg := sync.WaitGroup{}
|
|
wg.Add(1)
|
|
|
|
go func() {
|
|
defer panics.LogOnPanic()
|
|
defer wg.Done()
|
|
for !allEventsReceived {
|
|
select {
|
|
case event := <-channel:
|
|
allEventsReceived = eventCallback(event)
|
|
case <-time.After(timeout):
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
actionCallback()
|
|
|
|
wg.Wait()
|
|
|
|
s.Require().True(allEventsReceived)
|
|
}
|
|
|
|
func SetIdentityImagesAndWaitForChange(s *suite.Suite, messenger *Messenger, timeout time.Duration, actionCallback func()) {
|
|
channel := messenger.SubscribeToSelfContactChanges()
|
|
ok := false
|
|
wg := sync.WaitGroup{}
|
|
wg.Add(1)
|
|
|
|
go func() {
|
|
defer panics.LogOnPanic()
|
|
defer wg.Done()
|
|
select {
|
|
case event := <-channel:
|
|
if event.ImagesChanged {
|
|
ok = true
|
|
}
|
|
case <-time.After(timeout):
|
|
return
|
|
}
|
|
}()
|
|
|
|
actionCallback()
|
|
|
|
wg.Wait()
|
|
|
|
s.Require().True(ok)
|
|
}
|
|
|
|
func randomInt(length int) int {
|
|
max := big.NewInt(int64(length))
|
|
value, err := rand.Int(rand.Reader, max)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return int(value.Int64())
|
|
}
|
|
|
|
func randomString(length int, runes []rune) string {
|
|
out := make([]rune, length)
|
|
for i := range out {
|
|
out[i] = runes[randomInt(len(runes))] // nolint: gosec
|
|
}
|
|
return string(out)
|
|
}
|
|
|
|
func RandomLettersString(length int) string {
|
|
return randomString(length, letterRunes)
|
|
}
|
|
|
|
func RandomBytes(length int) []byte {
|
|
out := make([]byte, length)
|
|
_, err := rand.Read(out)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func DummyProfileShowcasePreferences(withCollectibles bool) *identity.ProfileShowcasePreferences {
|
|
preferences := &identity.ProfileShowcasePreferences{
|
|
Communities: []*identity.ProfileShowcaseCommunityPreference{
|
|
{
|
|
CommunityID: "0x254254546768764565565",
|
|
ShowcaseVisibility: identity.ProfileShowcaseVisibilityEveryone,
|
|
},
|
|
{
|
|
CommunityID: "0x865241434343432412343",
|
|
ShowcaseVisibility: identity.ProfileShowcaseVisibilityContacts,
|
|
},
|
|
},
|
|
Accounts: []*identity.ProfileShowcaseAccountPreference{
|
|
{
|
|
Address: "0x0000000000000000000000000033433445133423",
|
|
ShowcaseVisibility: identity.ProfileShowcaseVisibilityEveryone,
|
|
Order: 0,
|
|
},
|
|
{
|
|
Address: "0x0000000000000000000000000032433445133424",
|
|
ShowcaseVisibility: identity.ProfileShowcaseVisibilityContacts,
|
|
Order: 1,
|
|
},
|
|
},
|
|
VerifiedTokens: []*identity.ProfileShowcaseVerifiedTokenPreference{
|
|
{
|
|
Symbol: "ETH",
|
|
ShowcaseVisibility: identity.ProfileShowcaseVisibilityEveryone,
|
|
Order: 1,
|
|
},
|
|
{
|
|
Symbol: "DAI",
|
|
ShowcaseVisibility: identity.ProfileShowcaseVisibilityIDVerifiedContacts,
|
|
Order: 2,
|
|
},
|
|
{
|
|
Symbol: "SNT",
|
|
ShowcaseVisibility: identity.ProfileShowcaseVisibilityNoOne,
|
|
Order: 3,
|
|
},
|
|
},
|
|
UnverifiedTokens: []*identity.ProfileShowcaseUnverifiedTokenPreference{
|
|
{
|
|
ContractAddress: "0x454525452023452",
|
|
ChainID: 11155111,
|
|
ShowcaseVisibility: identity.ProfileShowcaseVisibilityEveryone,
|
|
Order: 0,
|
|
},
|
|
{
|
|
ContractAddress: "0x12312323323233",
|
|
ChainID: 1,
|
|
ShowcaseVisibility: identity.ProfileShowcaseVisibilityContacts,
|
|
Order: 1,
|
|
},
|
|
},
|
|
SocialLinks: []*identity.ProfileShowcaseSocialLinkPreference{
|
|
&identity.ProfileShowcaseSocialLinkPreference{
|
|
Text: identity.TwitterID,
|
|
URL: "https://twitter.com/ethstatus",
|
|
ShowcaseVisibility: identity.ProfileShowcaseVisibilityEveryone,
|
|
Order: 1,
|
|
},
|
|
&identity.ProfileShowcaseSocialLinkPreference{
|
|
Text: identity.TwitterID,
|
|
URL: "https://twitter.com/StatusIMBlog",
|
|
ShowcaseVisibility: identity.ProfileShowcaseVisibilityIDVerifiedContacts,
|
|
Order: 2,
|
|
},
|
|
&identity.ProfileShowcaseSocialLinkPreference{
|
|
Text: identity.GithubID,
|
|
URL: "https://github.com/status-im",
|
|
ShowcaseVisibility: identity.ProfileShowcaseVisibilityContacts,
|
|
Order: 3,
|
|
},
|
|
},
|
|
}
|
|
|
|
if withCollectibles {
|
|
preferences.Collectibles = []*identity.ProfileShowcaseCollectiblePreference{
|
|
{
|
|
ContractAddress: "0x12378534257568678487683576",
|
|
ChainID: 1,
|
|
TokenID: "12321389592999903",
|
|
ShowcaseVisibility: identity.ProfileShowcaseVisibilityEveryone,
|
|
Order: 0,
|
|
},
|
|
}
|
|
} else {
|
|
preferences.Collectibles = []*identity.ProfileShowcaseCollectiblePreference{}
|
|
}
|
|
|
|
return preferences
|
|
}
|