From 55beb9227f756aa4295c8560bb8274ea3819f714 Mon Sep 17 00:00:00 2001 From: Jakub Date: Tue, 30 Nov 2021 13:53:49 +0100 Subject: [PATCH] GODT-1433 Adding first integration test for drafts. --- internal/store/mailbox_message.go | 2 +- test/api_actions_test.go | 20 ++++++++++++++ test/context/pmapi_controller.go | 1 + test/fakeapi/controller_control.go | 33 +++++++++++++++++++++++ test/features/imap/message/drafts.feature | 29 +++++++++++--------- test/imap_actions_messages_test.go | 9 ++++++- test/liveapi/messages.go | 4 +++ test/store_setup_test.go | 6 +++++ 8 files changed, 89 insertions(+), 15 deletions(-) diff --git a/internal/store/mailbox_message.go b/internal/store/mailbox_message.go index cbdda7c3..2bfab0ae 100644 --- a/internal/store/mailbox_message.go +++ b/internal/store/mailbox_message.go @@ -370,7 +370,7 @@ func (storeMailbox *Mailbox) txCreateOrUpdateMessages(tx *bolt.Tx, msgs []*pmapi // Draft bodies can change and bodies are not re-fetched by IMAP clients. // Every change has to be a new message; we need to delete the old one and always recreate it. - if msg.Type == pmapi.MessageTypeDraft { + if msg.Type == pmapi.MessageTypeDraft || msg.IsDraft() { if err := storeMailbox.txDeleteMessage(tx, msg.ID); err != nil { return errors.Wrap(err, "cannot delete old draft") } diff --git a/test/api_actions_test.go b/test/api_actions_test.go index 6d1de665..f08feb8f 100644 --- a/test/api_actions_test.go +++ b/test/api_actions_test.go @@ -27,6 +27,7 @@ func APIActionsFeatureContext(s *godog.ScenarioContext) { s.Step(`^the internet connection is lost$`, theInternetConnectionIsLost) s.Step(`^the internet connection is restored$`, theInternetConnectionIsRestored) s.Step(`^(\d+) second[s]? pass$`, secondsPass) + s.Step(`^the body of draft "([^"]*)" for "([^"]*)" has changed to "([^"]*)"$`, draftBodyChanged) } func theInternetConnectionIsLost() error { @@ -43,3 +44,22 @@ func secondsPass(seconds int) error { time.Sleep(time.Duration(seconds) * time.Second) return nil } + +func draftBodyChanged(bddMessageID, bddUserID, body string) error { + account := ctx.GetTestAccount(bddUserID) + if account == nil { + return godog.ErrPending + } + + messageID, err := ctx.GetAPIMessageID(account.Username(), bddMessageID) + if err != nil { + return internalError(err, "getting apiID for %s", bddMessageID) + } + + err = ctx.GetPMAPIController().SetDraftBody(account.Username(), messageID, body) + if err != nil { + return internalError(err, "cannot set body of %s", messageID) + } + + return nil +} diff --git a/test/context/pmapi_controller.go b/test/context/pmapi_controller.go index e32ca4c9..9ff36e8b 100644 --- a/test/context/pmapi_controller.go +++ b/test/context/pmapi_controller.go @@ -36,6 +36,7 @@ type PMAPIController interface { AddUserLabel(username string, label *pmapi.Label) error GetLabelIDs(username string, labelNames []string) ([]string, error) AddUserMessage(username string, message *pmapi.Message) (string, error) + SetDraftBody(username string, messageID string, body string) error GetMessages(username, labelID string) ([]*pmapi.Message, error) ReorderAddresses(user *pmapi.User, addressIDs []string) error PrintCalls() diff --git a/test/fakeapi/controller_control.go b/test/fakeapi/controller_control.go index 4a372366..d79bf8cc 100644 --- a/test/fakeapi/controller_control.go +++ b/test/fakeapi/controller_control.go @@ -157,6 +157,39 @@ func (ctl *Controller) AddUserMessage(username string, message *pmapi.Message) ( return message.ID, nil } +func (ctl *Controller) SetDraftBody(username string, messageID string, body string) error { + // change the body in fakeAPI + fakeUser, ok := ctl.usersByUsername[username] + if !ok { + return fmt.Errorf("user %s not found", username) + } + + fakeAPI := ctl.getFakeAPIForUser(fakeUser.user.ID) + if fakeAPI == nil { + return fmt.Errorf("fakeAPI %s not found", fakeUser.user.ID) + } + + message := fakeAPI.getMessage(messageID) + if message == nil { + return fmt.Errorf("fake message %s not found", messageID) + } + + message.Body = body + + // assuming this is draft we set following + // - Draft type (NOTE: Type is not part of pmapi.MessageEvent, but it's there on API) + // - It must not have FlagReceived and FlagSent + // - Standard labelsIDs NOTE:wrong behaviour once we will have edge case tests for drafts outside draft folder + message.Type = pmapi.MessageTypeDraft + message.Flags = pmapi.FlagE2E | pmapi.FlagInternal + message.LabelIDs = []string{pmapi.AllDraftsLabel, pmapi.AllMailLabel, pmapi.DraftLabel} + + // send draft update + fakeAPI.addEventMessage(pmapi.EventUpdate, message) + + return nil +} + func (ctl *Controller) getFakeAPIForUser(userID string) *FakePMAPI { for _, fakeAPI := range ctl.fakeAPIs { if fakeAPI.userID == userID { diff --git a/test/features/imap/message/drafts.feature b/test/features/imap/message/drafts.feature index d7f82077..6d01d5cb 100644 --- a/test/features/imap/message/drafts.feature +++ b/test/features/imap/message/drafts.feature @@ -1,25 +1,18 @@ Feature: IMAP operations with Drafts Background: Given there is connected user "user" + And there are messages in mailbox "Drafts" for "user" + | id | from | subject | body | + | msg1 | Lionel Richie | RE: Hello, is it me you looking for? | Nope | And there is IMAP client logged in as "user" And there is IMAP client selected in "Drafts" - And IMAP client imports message to "Drafts" - """ - To: Lionel Richie - Subject: RE: Hello, is it me you looking for? - - Nope. - - """ - And IMAP response is "OK" - And API mailbox "" for "user" has 1 message - Scenario: Draft subject updated on locally + Scenario: Draft subject updated locally - Scenario: Draft recipient updated on locally + Scenario: Draft recipient updated locally - Scenario: Draft body updated on locally + Scenario: Draft body updated locally @ignore-live Scenario: Draft subject updated on server side @@ -29,4 +22,14 @@ Feature: IMAP operations with Drafts @ignore-live Scenario: Draft body and size updated on server side + When IMAP client fetches body of UID "1" + Then IMAP response is "OK" + Then IMAP response contains "Nope" + Given the body of draft "msg1" for "user" has changed to "Yes I am" + And the event loop of "user" loops once + And mailbox "Drafts" for "user" has 1 messages + When IMAP client fetches body of UID "2" + Then IMAP response is "OK" + Then IMAP response contains "Yes I am" + Then IMAP response does not contain "Nope" diff --git a/test/imap_actions_messages_test.go b/test/imap_actions_messages_test.go index 7ec1f0dd..8413e24c 100644 --- a/test/imap_actions_messages_test.go +++ b/test/imap_actions_messages_test.go @@ -34,7 +34,8 @@ func IMAPActionsMessagesFeatureContext(s *godog.ScenarioContext) { s.Step(`^IMAP client sends command "([^"]*)"$`, imapClientSendsCommand) s.Step(`^IMAP client fetches "([^"]*)"$`, imapClientFetches) s.Step(`^IMAP client fetches header(?:s)? of "([^"]*)"$`, imapClientFetchesHeader) - s.Step(`^IMAP client fetches body "([^"]*)"$`, imapClientFetchesBody) + s.Step(`^IMAP client fetches bod(?:y|ies) "([^"]*)"$`, imapClientFetchesBody) + s.Step(`^IMAP client fetches bod(?:y|ies) of UID "([^"]*)"$`, imapClientFetchesUIDBody) s.Step(`^IMAP client fetches by UID "([^"]*)"$`, imapClientFetchesByUID) s.Step(`^IMAP client searches for "([^"]*)"$`, imapClientSearchesFor) s.Step(`^IMAP client copies message seq "([^"]*)" to "([^"]*)"$`, imapClientCopiesMessagesTo) @@ -98,6 +99,12 @@ func imapClientFetchesBody(fetchRange string) error { return nil } +func imapClientFetchesUIDBody(fetchRange string) error { + res := ctx.GetIMAPClient("imap").FetchUID(fetchRange, "BODY.PEEK[]") + ctx.SetIMAPLastResponse("imap", res) + return nil +} + func imapClientFetchesByUID(fetchRange string) error { res := ctx.GetIMAPClient("imap").FetchUID(fetchRange, "UID") ctx.SetIMAPLastResponse("imap", res) diff --git a/test/liveapi/messages.go b/test/liveapi/messages.go index 2487b568..ffdcec83 100644 --- a/test/liveapi/messages.go +++ b/test/liveapi/messages.go @@ -73,6 +73,10 @@ func (ctl *Controller) AddUserMessage(username string, message *pmapi.Message) ( return result.MessageID, nil } +func (ctl *Controller) SetDraftBody(username string, messageID string, body string) error { + return errors.New("set draft body is not implemented for live") +} + func (ctl *Controller) GetMessages(username, labelID string) ([]*pmapi.Message, error) { client, err := getPersistentClient(username) if err != nil { diff --git a/test/store_setup_test.go b/test/store_setup_test.go index d03dd4a1..c543ff6b 100644 --- a/test/store_setup_test.go +++ b/test/store_setup_test.go @@ -108,6 +108,7 @@ func thereAreMessagesInMailboxesForAddressOfUser(mailboxNames, bddAddressID, bdd if message.HasLabelID(pmapi.SentLabel) { message.Flags |= pmapi.FlagSent + message.Type = pmapi.MessageTypeSent } else { // some tests (Outlook move by DELETE EXPUNGE APPEND) imply creating hard copies of emails, // and the importMessage() function flags the email as Sent if the 'Received' key in not present in the @@ -115,6 +116,11 @@ func thereAreMessagesInMailboxesForAddressOfUser(mailboxNames, bddAddressID, bdd header.Add("Received", "from dummy.protonmail.com") } + if message.HasLabelID(pmapi.DraftLabel) { + message.Type = pmapi.MessageTypeDraft + message.Flags = pmapi.FlagInternal | pmapi.FlagE2E + } + bddMessageID := "" hasDeletedFlag := false