status-im/status-go

View on GitHub
protocol/messenger_sync_activity_center_test.go

Summary

Maintainability
A
0 mins
Test Coverage
package protocol

import (
    "context"
    "encoding/hex"
    "testing"
    "time"

    "github.com/status-im/status-go/eth-node/types"
    "github.com/status-im/status-go/protocol/common"
    "github.com/status-im/status-go/protocol/protobuf"
    "github.com/status-im/status-go/protocol/requests"

    "github.com/stretchr/testify/suite"
)

const (
    actionAccept  = "Accept"
    actionDecline = "Decline"
)

func TestMessengerSyncActivityCenter(t *testing.T) {
    suite.Run(t, new(MessengerSyncActivityCenterSuite))
}

type MessengerSyncActivityCenterSuite struct {
    CommunitiesMessengerTestSuiteBase
    m  *Messenger
    m2 *Messenger
}

func (s *MessengerSyncActivityCenterSuite) SetupTest() {
    s.CommunitiesMessengerTestSuiteBase.SetupTest()

    s.m = s.newMessenger(alicePassword, []string{aliceAccountAddress})

    _, err := s.m.Start()
    s.Require().NoError(err)

    s.m2 = s.newMessengerWithKey(s.m.identity, alicePassword, []string{aliceAccountAddress})
    s.Require().NoError(err)

    _, err = s.m2.Start()
    s.Require().NoError(err)

    PairDevices(&s.Suite, s.m2, s.m)
    PairDevices(&s.Suite, s.m, s.m2)
}

func (s *MessengerSyncActivityCenterSuite) TearDownTest() {
    TearDownMessenger(&s.Suite, s.m2)
    TearDownMessenger(&s.Suite, s.m)
    s.CommunitiesMessengerTestSuiteBase.TearDownTest()
}

func (s *MessengerSyncActivityCenterSuite) createAndSaveNotification(m *Messenger, t ActivityCenterType, read bool) types.HexBytes {
    now := uint64(time.Now().Unix())
    id := types.HexBytes{0x01}
    notification := &ActivityCenterNotification{
        ID:               id,
        Timestamp:        now,
        Type:             t,
        Read:             read,
        Dismissed:        false,
        Accepted:         false,
        MembershipStatus: ActivityCenterMembershipStatusIdle,
        Deleted:          false,
        UpdatedAt:        now,
    }

    num, err := m.persistence.SaveActivityCenterNotification(notification, true)
    s.Require().NoError(err)
    s.Require().Equal(1, int(num))
    return id
}

func (s *MessengerSyncActivityCenterSuite) TestSyncUnread() {
    s.syncTest(ActivityCenterNotificationTypeMention, true, (*Messenger).MarkActivityCenterNotificationsUnread, func(n *ActivityCenterNotification) bool { return !n.Read })
}

func (s *MessengerSyncActivityCenterSuite) TestSyncDeleted() {
    s.syncTest(ActivityCenterNotificationTypeMention, true, (*Messenger).MarkActivityCenterNotificationsDeleted, func(n *ActivityCenterNotification) bool { return n.Deleted })
}

func (s *MessengerSyncActivityCenterSuite) TestSyncRead() {
    s.syncTest(ActivityCenterNotificationTypeMention, false, (*Messenger).MarkActivityCenterNotificationsRead, func(n *ActivityCenterNotification) bool { return n.Read })
}

func (s *MessengerSyncActivityCenterSuite) TestSyncAccepted() {
    s.syncTest(ActivityCenterNotificationTypeContactRequest, false, (*Messenger).AcceptActivityCenterNotifications, func(n *ActivityCenterNotification) bool { return n.Accepted })
}

func (s *MessengerSyncActivityCenterSuite) TestSyncDismissed() {
    s.syncTest(ActivityCenterNotificationTypeContactRequest, false, (*Messenger).DismissActivityCenterNotifications, func(n *ActivityCenterNotification) bool { return n.Dismissed })
}

func (s *MessengerSyncActivityCenterSuite) syncTest(notiType ActivityCenterType, initial bool, action func(*Messenger, context.Context, []types.HexBytes, uint64, bool) (*MessengerResponse, error), validator func(*ActivityCenterNotification) bool) {

    id := s.createAndSaveNotification(s.m, notiType, initial)
    s.createAndSaveNotification(s.m2, notiType, initial)

    now := uint64(time.Now().Unix())
    _, err := action(s.m, context.Background(), []types.HexBytes{id}, now+1, true)
    s.Require().NoError(err)

    _, err = WaitOnMessengerResponse(s.m2, func(r *MessengerResponse) bool {
        return r.ActivityCenterState() != nil
    }, "activity center notification state not received")
    s.Require().NoError(err)

    notificationByID, err := s.m2.persistence.GetActivityCenterNotificationByID(id)
    s.Require().NoError(err)
    s.Require().True(validator(notificationByID))
}

func (s *MessengerSyncActivityCenterSuite) TestSyncCommunityRequestDecisionAccept() {
    s.testSyncCommunityRequestDecision(actionAccept)
}

func (s *MessengerSyncActivityCenterSuite) TestSyncCommunityRequestDecisionDecline() {
    s.testSyncCommunityRequestDecision(actionDecline)
}

func (s *MessengerSyncActivityCenterSuite) testSyncCommunityRequestDecision(action string) {

    userB := s.newMessenger(accountPassword, []string{commonAccountAddress})
    defer func() {
        s.Require().NoError(userB.Shutdown())
    }()

    _, err := userB.Start()
    s.Require().NoError(err)

    communityID := s.createClosedCommunity()

    s.addContactAndShareCommunity(userB, communityID)

    request := createRequestToJoinCommunity(&s.Suite, communityID, userB, accountPassword, []string{commonAccountAddress})
    _, err = userB.RequestToJoinCommunity(request)
    s.Require().NoError(err)

    requestToJoinID := s.waitForRequestToJoin(s.m)

    s.waitForRequestToJoinOnDevice2()

    switch action {
    case actionAccept:
        _, err := s.m.AcceptRequestToJoinCommunity(&requests.AcceptRequestToJoinCommunity{ID: requestToJoinID})
        s.Require().NoError(err)
    case actionDecline:
        _, err := s.m.DeclineRequestToJoinCommunity(&requests.DeclineRequestToJoinCommunity{ID: requestToJoinID})
        s.Require().NoError(err)
    default:
        s.T().Fatal("Unknown action")
    }

    s.waitForDecisionOnDevice2(requestToJoinID, action)
}

func (s *MessengerSyncActivityCenterSuite) createClosedCommunity() types.HexBytes {
    response, err := s.m.CreateClosedCommunity()
    s.Require().NoError(err)
    s.Require().Len(response.Communities(), 1)

    response, err = WaitOnMessengerResponse(s.m2, func(r *MessengerResponse) bool {
        return len(r.Communities()) > 0
    }, "community not received on device 2")
    s.Require().NoError(err)
    return response.Communities()[0].ID()
}

func (s *MessengerSyncActivityCenterSuite) addContactAndShareCommunity(userB *Messenger, communityID types.HexBytes) {
    request := &requests.AddContact{ID: common.PubkeyToHex(&s.m2.identity.PublicKey)}
    response, err := userB.AddContact(context.Background(), request)
    s.Require().NoError(err)
    s.Require().Len(response.Messages(), 2)
    existContactRequestMessage := false
    for _, m := range response.Messages() {
        if m.ContentType == protobuf.ChatMessage_CONTACT_REQUEST {
            existContactRequestMessage = true
        }
    }
    s.Require().True(existContactRequestMessage)
    var contactRequestMessageID types.HexBytes
    _, err = WaitOnMessengerResponse(s.m, func(r *MessengerResponse) bool {
        if len(r.ActivityCenterNotifications()) > 0 {
            for _, n := range r.ActivityCenterNotifications() {
                if n.Type == ActivityCenterNotificationTypeContactRequest {
                    contactRequestMessageID = n.ID
                    return true
                }
            }
        }
        return false
    }, "contact request not received on device 1")
    s.Require().NoError(err)

    _, err = WaitOnMessengerResponse(s.m2, func(r *MessengerResponse) bool {
        if len(r.ActivityCenterNotifications()) > 0 {
            for _, n := range r.ActivityCenterNotifications() {
                if n.Type == ActivityCenterNotificationTypeContactRequest {
                    return true
                }
            }
        }
        return false
    }, "contact request not received on device 2")
    s.Require().NoError(err)
    _, err = s.m.AcceptContactRequest(context.Background(), &requests.AcceptContactRequest{ID: contactRequestMessageID})
    s.Require().NoError(err)
    _, err = WaitOnMessengerResponse(s.m2, func(r *MessengerResponse) bool {
        if len(r.ActivityCenterNotifications()) > 0 {
            for _, n := range r.ActivityCenterNotifications() {
                if n.Type == ActivityCenterNotificationTypeContactRequest && n.Accepted {
                    return true
                }
            }
        }
        return false
    }, "contact request not accepted on device 2")
    s.Require().NoError(err)
    community, err := s.m.GetCommunityByID(communityID)
    s.Require().NoError(err)
    advertiseCommunityToUserOldWay(&s.Suite, community, s.m, userB)
}

func (s *MessengerSyncActivityCenterSuite) waitForRequestToJoin(messenger *Messenger) types.HexBytes {
    var requestToJoinID types.HexBytes
    _, err := WaitOnMessengerResponse(messenger, func(r *MessengerResponse) bool {
        for _, n := range r.ActivityCenterNotifications() {
            if n.Type == ActivityCenterNotificationTypeCommunityMembershipRequest {
                requestToJoinID = n.ID
                return true
            }
        }
        return false
    }, "community request to join not received")
    s.Require().NoError(err)
    return requestToJoinID
}

func (s *MessengerSyncActivityCenterSuite) waitForRequestToJoinOnDevice2() {
    _, err := WaitOnMessengerResponse(s.m2, func(r *MessengerResponse) bool {
        for _, n := range r.ActivityCenterNotifications() {
            if n.Type == ActivityCenterNotificationTypeCommunityMembershipRequest {
                return true
            }
        }
        return false
    }, "community request to join not received on device 2")
    s.Require().NoError(err)
}

func (s *MessengerSyncActivityCenterSuite) waitForDecisionOnDevice2(requestToJoinID types.HexBytes, action string) {
    requestToJoinIDString := hex.Dump(requestToJoinID)
    conditionFunc := func(r *MessengerResponse) bool {
        for _, n := range r.ActivityCenterNotifications() {
            if n.Type == ActivityCenterNotificationTypeCommunityMembershipRequest && hex.Dump(n.ID) == requestToJoinIDString {
                if action == actionAccept && n.Accepted {
                    return true
                } else if action == actionDecline && n.Dismissed {
                    return true
                }
            }
        }
        return false
    }
    _, err := WaitOnMessengerResponse(s.m2, conditionFunc, "community request decision not received on device 2")
    s.Require().NoError(err)
}