From 996c6826b982ba7c6bd2b489b2fb5cfb0b340cdf Mon Sep 17 00:00:00 2001 From: Jakub Date: Tue, 24 Jan 2023 07:47:25 +0100 Subject: [PATCH] GODT-2223: Handle gracefully multiple create events with same id. --- go.mod | 2 +- go.sum | 2 + internal/bridge/user_event_test.go | 100 +++++++++++++++++++++-------- 3 files changed, 76 insertions(+), 28 deletions(-) diff --git a/go.mod b/go.mod index 089ccd44..d079dc45 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/Masterminds/semver/v3 v3.1.1 github.com/ProtonMail/gluon v0.14.2-0.20230123154940-b7793a0c0bd4 github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a - github.com/ProtonMail/go-proton-api v0.3.1-0.20230118091111-93ad9245e8ee + github.com/ProtonMail/go-proton-api v0.3.1-0.20230124064827-4a09eaa5d1bb github.com/ProtonMail/go-rfc5322 v0.11.0 github.com/ProtonMail/gopenpgp/v2 v2.4.10 github.com/PuerkitoBio/goquery v1.8.0 diff --git a/go.sum b/go.sum index fc239f74..d8656228 100644 --- a/go.sum +++ b/go.sum @@ -43,6 +43,8 @@ github.com/ProtonMail/go-mime v0.0.0-20220429130430-2192574d760f h1:4IWzKjHzZxdr github.com/ProtonMail/go-mime v0.0.0-20220429130430-2192574d760f/go.mod h1:qRZgbeASl2a9OwmsV85aWwRqic0NHPh+9ewGAzb4cgM= github.com/ProtonMail/go-proton-api v0.3.1-0.20230118091111-93ad9245e8ee h1:kXz09BKBbVLyzXgHztxIAMuvmSF0g8FgGpDaqi2IPiM= github.com/ProtonMail/go-proton-api v0.3.1-0.20230118091111-93ad9245e8ee/go.mod h1:JUo5IQG0hNuPRuDpOUsCOvtee6UjTEHHF1QN2i8RSos= +github.com/ProtonMail/go-proton-api v0.3.1-0.20230124064827-4a09eaa5d1bb h1:WSKNRN0p0rx1FXq1cGAor3RIoQkX9iD4jQeUlL2s+1o= +github.com/ProtonMail/go-proton-api v0.3.1-0.20230124064827-4a09eaa5d1bb/go.mod h1:JUo5IQG0hNuPRuDpOUsCOvtee6UjTEHHF1QN2i8RSos= github.com/ProtonMail/go-rfc5322 v0.11.0 h1:o5Obrm4DpmQEffvgsVqG6S4BKwC1Wat+hYwjIp2YcCY= github.com/ProtonMail/go-rfc5322 v0.11.0/go.mod h1:6oOKr0jXvpoE6pwTx/HukigQpX2J9WUf6h0auplrFTw= github.com/ProtonMail/go-srp v0.0.5 h1:xhUioxZgDbCnpo9JehyFhwwsn9JLWkUGfB0oiKXgiGg= diff --git a/internal/bridge/user_event_test.go b/internal/bridge/user_event_test.go index 5359c851..5e07f226 100644 --- a/internal/bridge/user_event_test.go +++ b/internal/bridge/user_event_test.go @@ -94,7 +94,42 @@ func TestBridge_User_BadEvents(t *testing.T) { }) } -func TestBridge_User_BadEvents_MessageLabelDeleted(t *testing.T) { +func TestBridge_User_NoBadEvent_SameMessageLabelCreated(t *testing.T) { + withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, storeKey []byte) { + // Create a user. + userID, addrID, err := s.CreateUser("user", password) + require.NoError(t, err) + + var messageIDs []string + + // Create 10 messages for the user. + withClient(ctx, t, s, "user", password, func(ctx context.Context, c *proton.Client) { + messageIDs = createNumMessages(ctx, t, c, addrID, proton.InboxLabel, 10) + }) + + // The initial user should be fully synced. + withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, _ *bridge.Mocks) { + syncCh, done := chToType[events.Event, events.SyncFinished](bridge.GetEvents(events.SyncFinished{})) + defer done() + + userID, err := bridge.LoginFull(ctx, "user", password, nil, nil) + require.NoError(t, err) + + require.Equal(t, userID, (<-syncCh).UserID) + }) + + labelID, err := s.CreateLabel(userID, "folder", "", proton.LabelTypeFolder) + require.NoError(t, err) + + // Add NOOP events + require.NoError(t, s.AddLabelCreatedEvent(userID, labelID)) + require.NoError(t, s.AddMessageCreatedEvent(userID, messageIDs[9])) + + userContinuEventProcess(ctx, t, s, netCtl, locator, storeKey) + }) +} + +func TestBridge_User_NoBadEvents_MessageLabelDeleted(t *testing.T) { withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, storeKey []byte) { // Create a user. userID, addrID, err := s.CreateUser("user", password) @@ -139,31 +174,42 @@ func TestBridge_User_BadEvents_MessageLabelDeleted(t *testing.T) { } }) - // The user will continue to process events and will not receive any bad request errors. - withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, _ *bridge.Mocks) { - info, err := bridge.QueryUserInfo("user") - require.NoError(t, err) - - client, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, bridge.GetIMAPPort())) - require.NoError(t, err) - require.NoError(t, client.Login(info.Addresses[0], string(info.BridgePass))) - defer func() { _ = client.Logout() }() - - // Create a new label. - withClient(ctx, t, s, "user", password, func(ctx context.Context, c *proton.Client) { - require.NoError(t, getErr(c.CreateLabel(ctx, proton.CreateLabelReq{ - Name: "blabla", - Color: "#f66", - Type: proton.LabelTypeLabel, - }))) - }) - - // Wait for the label to be created. - require.Eventually(t, func() bool { - return xslices.IndexFunc(clientList(client), func(mailbox *imap.MailboxInfo) bool { - return mailbox.Name == "Labels/blabla" - }) >= 0 - }, 10*time.Second, 100*time.Millisecond) - }) + userContinuEventProcess(ctx, t, s, netCtl, locator, storeKey) + }) +} + +// userContinuEventProcess checks that user will continue to process events and will not receive any bad request errors. +func userContinuEventProcess( + ctx context.Context, + t *testing.T, + s *server.Server, + netCtl *proton.NetCtl, + locator bridge.Locator, + storeKey []byte, +) { + withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, _ *bridge.Mocks) { + info, err := bridge.QueryUserInfo("user") + require.NoError(t, err) + + client, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, bridge.GetIMAPPort())) + require.NoError(t, err) + require.NoError(t, client.Login(info.Addresses[0], string(info.BridgePass))) + defer func() { _ = client.Logout() }() + + // Create a new label. + withClient(ctx, t, s, "user", password, func(ctx context.Context, c *proton.Client) { + require.NoError(t, getErr(c.CreateLabel(ctx, proton.CreateLabelReq{ + Name: "blabla", + Color: "#f66", + Type: proton.LabelTypeLabel, + }))) + }) + + // Wait for the label to be created. + require.Eventually(t, func() bool { + return xslices.IndexFunc(clientList(client), func(mailbox *imap.MailboxInfo) bool { + return mailbox.Name == "Labels/blabla" + }) >= 0 + }, 10*time.Second, 100*time.Millisecond) }) }