feat(GODT-1264): constraint on Scheduled mailbox in connector + Integration tests.

This commit is contained in:
Xavier Michelon
2023-02-15 07:37:09 +00:00
parent 13db1b0db8
commit 08dab2d115
8 changed files with 74 additions and 66 deletions

2
go.mod
View File

@ -7,7 +7,7 @@ require (
github.com/Masterminds/semver/v3 v3.1.1
github.com/ProtonMail/gluon v0.14.2-0.20230207142445-9f98ae47a031
github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a
github.com/ProtonMail/go-proton-api v0.4.0
github.com/ProtonMail/go-proton-api v0.4.1-0.20230214130336-4056d48a12e1
github.com/ProtonMail/go-rfc5322 v0.11.0
github.com/ProtonMail/gopenpgp/v2 v2.4.10
github.com/PuerkitoBio/goquery v1.8.0

6
go.sum
View File

@ -41,8 +41,10 @@ github.com/ProtonMail/go-message v0.0.0-20210611055058-fabeff2ec753/go.mod h1:NB
github.com/ProtonMail/go-mime v0.0.0-20220302105931-303f85f7fe0f/go.mod h1:NYt+V3/4rEeDuaev/zw1zCq8uqVEuPHzDPo3OZrlGJ4=
github.com/ProtonMail/go-mime v0.0.0-20220429130430-2192574d760f h1:4IWzKjHzZxdrW9k4zl/qCwenOVHDbVDADPPHFLjs0Oc=
github.com/ProtonMail/go-mime v0.0.0-20220429130430-2192574d760f/go.mod h1:qRZgbeASl2a9OwmsV85aWwRqic0NHPh+9ewGAzb4cgM=
github.com/ProtonMail/go-proton-api v0.4.0 h1:Tw8Ieuc355ljPqpIzh/uttpE+5ia0z8GA/ca5iyl/9w=
github.com/ProtonMail/go-proton-api v0.4.0/go.mod h1:JUo5IQG0hNuPRuDpOUsCOvtee6UjTEHHF1QN2i8RSos=
github.com/ProtonMail/go-proton-api v0.4.1-0.20230214112101-944a29edf66a h1:/31/wWgxpBWREaRGRMVH4AVgQGpPtTK9BsLjt1a8uwc=
github.com/ProtonMail/go-proton-api v0.4.1-0.20230214112101-944a29edf66a/go.mod h1:JUo5IQG0hNuPRuDpOUsCOvtee6UjTEHHF1QN2i8RSos=
github.com/ProtonMail/go-proton-api v0.4.1-0.20230214130336-4056d48a12e1 h1:AjdiuiUwDz9ADIzEccii+D91YYz0w0doGXZs12j4XcY=
github.com/ProtonMail/go-proton-api v0.4.1-0.20230214130336-4056d48a12e1/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=

View File

@ -24,7 +24,6 @@ import (
"os"
"path/filepath"
"runtime"
"strings"
"sync/atomic"
"testing"
"time"
@ -44,8 +43,6 @@ import (
"github.com/stretchr/testify/require"
)
const scheduled = "Scheduled"
func TestBridge_Sync(t *testing.T) {
numMsg := 1 << 8
@ -471,45 +468,3 @@ func countBytesRead(ctl *proton.NetCtl, fn func()) uint64 {
return read
}
func TestBridge_ScheduledLabel(t *testing.T) {
withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, storeKey []byte) {
hasScheduledSystemLabel := func(imapClient *client.Client) bool {
return xslices.Any(clientList(imapClient), func(mailboxInfo *imap.MailboxInfo) bool { return mailboxInfo.Name == scheduled })
}
_, _, err := s.CreateUser(username, password)
require.NoError(t, err)
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(b *bridge.Bridge, _ *bridge.Mocks) {
// Perform initial sync
syncCh, done := chToType[events.Event, events.SyncFinished](b.GetEvents(events.SyncFinished{}))
defer done()
userID, err := b.LoginFull(ctx, username, password, nil, nil)
require.NoError(t, err)
require.Equal(t, userID, (<-syncCh).UserID)
// connect an IMAP client
info, err := b.GetUserInfo(userID)
require.NoError(t, err)
imapClient, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort()))
require.NoError(t, err)
require.NoError(t, imapClient.Login(info.Addresses[0], string(info.BridgePass)))
defer func() { _ = imapClient.Logout() }()
// Scheduled mailbox is empty. It's not listed.
require.False(t, hasScheduledSystemLabel(imapClient))
// Add a message to the Schedule mailbox. It's now listed.
require.NoError(t, imapClient.Append(scheduled, []string{}, time.Now(), strings.NewReader("To: no_reply@pm.me")))
require.True(t, hasScheduledSystemLabel(imapClient))
// delete message from Scheduled. The mailbox is now empty and not listed anymore
_, err = imapClient.Select(scheduled, false)
require.NoError(t, err)
require.NoError(t, clientStore(imapClient, 1, 1, true, imap.FormatFlagsOp(imap.AddFlags, true), imap.DeletedFlag))
require.NoError(t, imapClient.Expunge(nil))
require.False(t, hasScheduledSystemLabel(imapClient))
})
})
}

View File

@ -380,7 +380,7 @@ func (conn *imapConnector) GetMessageLiteral(ctx context.Context, id imap.Messag
func (conn *imapConnector) AddMessagesToMailbox(ctx context.Context, messageIDs []imap.MessageID, mailboxID imap.MailboxID) error {
defer conn.goPollAPIEvents(false)
if mailboxID == proton.AllMailLabel {
if isAllMailOrScheduled(mailboxID) {
return fmt.Errorf("not allowed")
}
@ -391,7 +391,7 @@ func (conn *imapConnector) AddMessagesToMailbox(ctx context.Context, messageIDs
func (conn *imapConnector) RemoveMessagesFromMailbox(ctx context.Context, messageIDs []imap.MessageID, mailboxID imap.MailboxID) error {
defer conn.goPollAPIEvents(false)
if mailboxID == proton.AllMailLabel {
if isAllMailOrScheduled(mailboxID) {
return fmt.Errorf("not allowed")
}
@ -440,8 +440,8 @@ func (conn *imapConnector) MoveMessages(ctx context.Context, messageIDs []imap.M
if (labelFromID == proton.InboxLabel && labelToID == proton.SentLabel) ||
(labelFromID == proton.SentLabel && labelToID == proton.InboxLabel) ||
labelFromID == proton.AllMailLabel ||
labelToID == proton.AllMailLabel {
isAllMailOrScheduled(labelFromID) ||
isAllMailOrScheduled(labelToID) {
return false, fmt.Errorf("not allowed")
}
@ -691,3 +691,7 @@ func toIMAPMailbox(label proton.Label, flags, permFlags, attrs imap.FlagSet) ima
Attributes: attrs,
}
}
func isAllMailOrScheduled(mailboxID imap.MailboxID) bool {
return (mailboxID == proton.AllMailLabel) || (mailboxID == proton.AllScheduledLabel)
}

View File

@ -36,4 +36,27 @@ Feature: IMAP list mailboxes
Then IMAP client "1" counts 20 mailboxes under "Folders"
And IMAP client "1" counts 60 mailboxes under "Labels"
Then IMAP client "2" counts 20 mailboxes under "Folders"
And IMAP client "2" counts 60 mailboxes under "Labels"
And IMAP client "2" counts 60 mailboxes under "Labels"
Scenario: List with scheduled mail
Given there exists an account with username "[user:user]" and password "password"
And the address "[user:user]@[domain]" of account "[user:user]" has the following messages in "Scheduled":
| from | to | subject | unread |
| john.doe@mail.com | [user:user]@[domain] | sch | false |
When bridge starts
And the user logs in with username "[user:user]" and password "password"
And user "[user:user]" finishes syncing
And user "[user:user]" connects and authenticates IMAP client "1"
Then IMAP client "1" eventually sees the following mailbox info:
| name | total |
| INBOX | 0 |
| Drafts | 0 |
| Sent | 0 |
| Starred | 0 |
| Archive | 0 |
| Spam | 0 |
| Trash | 0 |
| All Mail | 1 |
| Folders | 0 |
| Labels | 0 |
| Scheduled | 1 |

View File

@ -6,6 +6,7 @@ Feature: IMAP remove messages from mailbox
| mbox | folder |
| label | label |
And the address "[user:user]@[domain]" of account "[user:user]" has 10 messages in "Folders/mbox"
And the address "[user:user]@[domain]" of account "[user:user]" has 1 messages in "Scheduled"
And bridge starts
And the user logs in with username "[user:user]" and password "password"
And user "[user:user]" finishes syncing
@ -44,4 +45,11 @@ Feature: IMAP remove messages from mailbox
And IMAP client "1" marks message 2 as deleted
And it succeeds
And IMAP client "1" expunges
Then it fails
Then it fails
Scenario: Not possible to delete from Scheduled and expunge does nothing
When IMAP client "1" selects "Scheduled"
And IMAP client "1" marks message 1 as deleted
Then it succeeds
And IMAP client "1" expunges
Then it fails

View File

@ -16,6 +16,9 @@ Feature: IMAP move messages
And the address "[user:user]@[domain]" of account "[user:user]" has the following messages in "Sent":
| from | to | subject | unread |
| john.doe@mail.com | [user:user]@[domain] | bax | false |
And the address "[user:user]@[domain]" of account "[user:user]" has the following messages in "Scheduled":
| from | to | subject | unread |
| john.doe@mail.com | [user:user]@[domain] | sch | false |
And bridge starts
And the user logs in with username "[user:user]" and password "password"
And user "[user:user]" finishes syncing
@ -96,8 +99,17 @@ Feature: IMAP move messages
| jane.doe@mail.com | name@[domain] | bar | true |
| john.doe@mail.com | [user:user]@[domain] | baz | false |
| john.doe@mail.com | [user:user]@[domain] | bax | false |
| john.doe@mail.com | [user:user]@[domain] | sch | false |
Scenario: Move message from Inbox to Sent is not possible
Scenario: Move message from Scheduled is not possible
Given test skips reporter checks
When IMAP client "1" moves the message with subject "sch" from "Scheduled" to "Inbox"
Then it fails
And IMAP client "1" eventually sees the following messages in "Scheduled":
| from | to | subject | unread |
| john.doe@mail.com | [user:user]@[domain] | sch | false |
Scenario: Move message from Inbox to Sent is not possible
Given test skips reporter checks
When IMAP client "1" moves the message with subject "bar" from "Inbox" to "Sent"
Then it fails
@ -105,4 +117,4 @@ Feature: IMAP move messages
Scenario: Move message from Sent to Inbox is not possible
Given test skips reporter checks
When IMAP client "1" moves the message with subject "bax" from "Sent" to "Inbox"
Then it fails
Then it fails

View File

@ -193,14 +193,6 @@ func (s *scenario) theAddressOfAccountHasTheFollowingMessagesInMailbox(address,
return err
}
var messageFlags proton.MessageFlag
if !strings.EqualFold(mailbox, "Sent") {
messageFlags = proton.MessageFlagReceived
} else {
messageFlags = proton.MessageFlagSent
}
return s.t.createMessages(ctx, username, addrID, xslices.Map(wantMessages, func(message Message) proton.ImportReq {
return proton.ImportReq{
@ -208,7 +200,7 @@ func (s *scenario) theAddressOfAccountHasTheFollowingMessagesInMailbox(address,
AddressID: addrID,
LabelIDs: []string{mboxID},
Unread: proton.Bool(message.Unread),
Flags: messageFlags,
Flags: flagsForMailbox(mailbox),
},
Message: message.Build(),
}
@ -228,7 +220,7 @@ func (s *scenario) theAddressOfAccountHasMessagesInMailbox(address, username str
Metadata: proton.ImportMetadata{
AddressID: addrID,
LabelIDs: []string{mboxID},
Flags: proton.MessageFlagReceived,
Flags: flagsForMailbox(mailbox),
},
Message: Message{
Subject: fmt.Sprintf("%d", idx),
@ -240,6 +232,18 @@ func (s *scenario) theAddressOfAccountHasMessagesInMailbox(address, username str
})))
}
func flagsForMailbox(mailboxName string) proton.MessageFlag {
if strings.EqualFold(mailboxName, "Sent") {
return proton.MessageFlagSent
}
if strings.EqualFold(mailboxName, "Scheduled") {
return proton.MessageFlagScheduledSend
}
return proton.MessageFlagReceived
}
// accountDraftChanged changes the draft attributes, where draftIndex is
// similar to sequential ID i.e. 1 represents the first message of draft folder
// sorted by API creation time.