From 9c25f56fe6bad746e8169e3a7113821816328cdc Mon Sep 17 00:00:00 2001 From: Romain Le Jeune Date: Mon, 22 May 2023 11:16:56 +0000 Subject: [PATCH] test: fix flaky tests. --- .gitlab-ci.yml | 2 +- Makefile | 6 +- internal/bridge/bridge_test.go | 37 ++++++++--- internal/bridge/refresh_test.go | 5 +- internal/bridge/send_test.go | 13 ++-- internal/bridge/server_manager_test.go | 16 +++-- internal/bridge/sync_test.go | 8 +-- internal/bridge/user_event_test.go | 63 ++++++++++++------- tests/ctx_imap_test.go | 18 +++++- tests/ctx_test.go | 1 + tests/features/bridge/heartbeat.feature | 4 +- tests/features/imap/auth.feature | 4 +- tests/features/imap/id.feature | 4 +- tests/features/imap/mailbox/create.feature | 4 +- tests/features/imap/mailbox/delete.feature | 4 +- .../imap/mailbox/hide_all_mail.feature | 4 +- tests/features/imap/mailbox/info.feature | 4 +- tests/features/imap/mailbox/list.feature | 4 +- tests/features/imap/mailbox/rename.feature | 4 +- .../imap/mailbox/rename_hiearchy.feature | 4 +- tests/features/imap/mailbox/select.feature | 4 +- tests/features/imap/message/copy.feature | 4 +- tests/features/imap/message/create.feature | 4 +- tests/features/imap/message/delete.feature | 4 +- .../imap/message/delete_from_trash.feature | 1 + tests/features/imap/message/drafts.feature | 8 ++- tests/features/imap/message/fetch.feature | 4 +- tests/features/imap/message/import.feature | 4 +- tests/features/imap/message/move.feature | 4 +- .../imap/message/move_without_support.feature | 4 +- tests/features/imap/migration.feature | 3 +- tests/features/imap/ports.feature | 4 +- tests/features/smtp/auth.feature | 4 +- tests/features/smtp/init.feature | 6 +- tests/features/smtp/ports.feature | 6 +- tests/features/smtp/send/bcc.feature | 8 ++- .../smtp/send/embedded_message.feature | 4 +- tests/features/smtp/send/failures.feature | 4 +- tests/features/smtp/send/html.feature | 4 +- tests/features/smtp/send/html_att.feature | 4 +- tests/features/smtp/send/inline.feature | 4 +- tests/features/smtp/send/mixed_case.feature | 4 +- .../smtp/send/one_account_to_another.feature | 4 +- tests/features/smtp/send/plain.feature | 4 +- tests/features/smtp/send/plain_att.feature | 4 +- tests/features/smtp/send/same_message.feature | 3 +- tests/features/smtp/send/send_append.feature | 4 +- tests/features/smtp/send/send_reply.feature | 4 +- tests/features/smtp/send/two_messages.feature | 4 +- tests/features/user/addressmode.feature | 4 +- tests/features/user/delete.feature | 4 +- tests/features/user/login.feature | 6 +- tests/features/user/relogin.feature | 4 +- tests/features/user/revoke.feature | 4 +- tests/features/user/sync.feature | 4 +- tests/features/user/telemetry.feature | 4 +- tests/user_test.go | 12 +++- 57 files changed, 265 insertions(+), 109 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ddb16c05..ed1ab356 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -99,7 +99,7 @@ test-linux: - .rules-branch-manual-MR-and-devel-always - .after-script-code-coverage tags: - - medium + - large test-linux-race: extends: diff --git a/Makefile b/Makefile index 500e71e5..7d021279 100644 --- a/Makefile +++ b/Makefile @@ -228,13 +228,13 @@ change-copyright-year: ./utils/missing_license.sh change-year test: gofiles - go test -v -timeout=10m -p=1 -count=1 -coverprofile=/tmp/coverage.out -run=${TESTRUN} ./internal/... ./pkg/... + go test -v -timeout=20m -p=1 -count=1 -coverprofile=/tmp/coverage.out -run=${TESTRUN} ./internal/... ./pkg/... test-race: gofiles - go test -v -timeout=30m -p=1 -count=1 -race -failfast -run=${TESTRUN} ./internal/... ./pkg/... + go test -v -timeout=40m -p=1 -count=1 -race -failfast -run=${TESTRUN} ./internal/... ./pkg/... test-integration: gofiles - go test -v -timeout=30m -p=1 -count=1 github.com/ProtonMail/proton-bridge/v3/tests + go test -v -timeout=60m -p=1 -count=1 github.com/ProtonMail/proton-bridge/v3/tests test-integration-debug: gofiles dlv test github.com/ProtonMail/proton-bridge/v3/tests -- -test.v -test.timeout=10m -test.parallel=1 -test.count=1 diff --git a/internal/bridge/bridge_test.go b/internal/bridge/bridge_test.go index c9529e10..676eb612 100644 --- a/internal/bridge/bridge_test.go +++ b/internal/bridge/bridge_test.go @@ -50,7 +50,6 @@ import ( "github.com/ProtonMail/proton-bridge/v3/tests" "github.com/bradenaw/juniper/xslices" imapid "github.com/emersion/go-imap-id" - "github.com/emersion/go-imap/client" "github.com/stretchr/testify/require" ) @@ -182,14 +181,18 @@ func TestBridge_UserAgent_Persistence(t *testing.T) { imapWaiter := waitForIMAPServerReady(b) defer imapWaiter.Done() + smtpWaiter := waitForSMTPServerReady(b) + defer smtpWaiter.Done() + require.NoError(t, getErr(b.LoginFull(ctx, otherUser, otherPassword, nil, nil))) imapWaiter.Wait() + smtpWaiter.Wait() currentUserAgent := b.GetCurrentUserAgent() require.Contains(t, currentUserAgent, vault.DefaultUserAgent) - imapClient, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) + imapClient, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) require.NoError(t, err) defer func() { _ = imapClient.Logout() }() @@ -241,11 +244,15 @@ func TestBridge_UserAgentFromIMAPID(t *testing.T) { imapWaiter := waitForIMAPServerReady(b) defer imapWaiter.Done() + smtpWaiter := waitForSMTPServerReady(b) + defer smtpWaiter.Done() + require.NoError(t, getErr(b.LoginFull(ctx, otherUser, otherPassword, nil, nil))) imapWaiter.Wait() + smtpWaiter.Wait() - imapClient, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) + imapClient, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) require.NoError(t, err) defer func() { _ = imapClient.Logout() }() @@ -619,6 +626,9 @@ func TestBridge_LoginFailed(t *testing.T) { imapWaiter := waitForIMAPServerReady(bridge) defer imapWaiter.Done() + smtpWaiter := waitForSMTPServerReady(bridge) + defer smtpWaiter.Done() + failCh, done := chToType[events.Event, events.IMAPLoginFailed](bridge.GetEvents(events.IMAPLoginFailed{})) defer done() @@ -626,8 +636,9 @@ func TestBridge_LoginFailed(t *testing.T) { require.NoError(t, err) imapWaiter.Wait() + smtpWaiter.Wait() - imapClient, err := client.Dial(net.JoinHostPort(constants.Host, fmt.Sprint(bridge.GetIMAPPort()))) + imapClient, err := eventuallyDial(net.JoinHostPort(constants.Host, fmt.Sprint(bridge.GetIMAPPort()))) require.NoError(t, err) require.Error(t, imapClient.Login("badUser", "badPass")) @@ -657,6 +668,9 @@ func TestBridge_ChangeCacheDirectory(t *testing.T) { imapWaiter := waitForIMAPServerReady(b) defer imapWaiter.Done() + smtpWaiter := waitForSMTPServerReady(b) + defer smtpWaiter.Done() + // Login the user. syncCh, done := chToType[events.Event, events.SyncFinished](b.GetEvents(events.SyncFinished{})) defer done() @@ -691,8 +705,9 @@ func TestBridge_ChangeCacheDirectory(t *testing.T) { require.True(t, info.State == bridge.Connected) imapWaiter.Wait() + smtpWaiter.Wait() - client, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) + client, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) require.NoError(t, err) require.NoError(t, client.Login(info.Addresses[0], string(info.BridgePass))) defer func() { _ = client.Logout() }() @@ -732,7 +747,7 @@ func TestBridge_ChangeAddressOrder(t *testing.T) { require.NoError(t, err) require.True(t, info.State == bridge.Connected) - client, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) + client, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) require.NoError(t, err) require.NoError(t, client.Login(info.Addresses[0], string(info.BridgePass))) defer func() { _ = client.Logout() }() @@ -753,7 +768,7 @@ func TestBridge_ChangeAddressOrder(t *testing.T) { require.NoError(t, err) require.True(t, info.State == bridge.Connected) - client, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) + client, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) require.NoError(t, err) require.NoError(t, client.Login(info.Addresses[0], string(info.BridgePass))) defer func() { _ = client.Logout() }() @@ -990,6 +1005,14 @@ func waitForSMTPServerReady(b *bridge.Bridge) *eventWaiter { } } +func waitForSMTPServerStopped(b *bridge.Bridge) *eventWaiter { + evtCh, cancel := b.GetEvents(events.SMTPServerStopped{}) + return &eventWaiter{ + evtCh: evtCh, + cancel: cancel, + } +} + func waitForIMAPServerReady(b *bridge.Bridge) *eventWaiter { evtCh, cancel := b.GetEvents(events.IMAPServerReady{}) return &eventWaiter{ diff --git a/internal/bridge/refresh_test.go b/internal/bridge/refresh_test.go index ad4192f6..e8edcd7d 100644 --- a/internal/bridge/refresh_test.go +++ b/internal/bridge/refresh_test.go @@ -28,7 +28,6 @@ import ( "github.com/ProtonMail/proton-bridge/v3/internal/constants" "github.com/ProtonMail/proton-bridge/v3/internal/events" "github.com/bradenaw/juniper/iterator" - "github.com/emersion/go-imap/client" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -66,7 +65,7 @@ func TestBridge_Refresh(t *testing.T) { require.NoError(t, err) require.True(t, info.State == bridge.Connected) - client, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) + client, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) require.NoError(t, err) require.NoError(t, client.Login(info.Addresses[0], string(info.BridgePass))) defer func() { _ = client.Logout() }() @@ -99,7 +98,7 @@ func TestBridge_Refresh(t *testing.T) { require.NoError(t, err) require.True(t, info.State == bridge.Connected) - client, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) + client, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) require.NoError(t, err) require.NoError(t, client.Login(info.Addresses[0], string(info.BridgePass))) defer func() { _ = client.Logout() }() diff --git a/internal/bridge/send_test.go b/internal/bridge/send_test.go index 8015e4ea..a334db15 100644 --- a/internal/bridge/send_test.go +++ b/internal/bridge/send_test.go @@ -34,7 +34,6 @@ import ( "github.com/ProtonMail/proton-bridge/v3/internal/constants" "github.com/ProtonMail/proton-bridge/v3/internal/events" "github.com/emersion/go-imap" - "github.com/emersion/go-imap/client" "github.com/emersion/go-sasl" "github.com/emersion/go-smtp" "github.com/stretchr/testify/require" @@ -96,13 +95,13 @@ func TestBridge_Send(t *testing.T) { } // Connect the sender IMAP client. - senderIMAPClient, err := client.Dial(net.JoinHostPort(constants.Host, fmt.Sprint(bridge.GetIMAPPort()))) + senderIMAPClient, err := eventuallyDial(net.JoinHostPort(constants.Host, fmt.Sprint(bridge.GetIMAPPort()))) require.NoError(t, err) require.NoError(t, senderIMAPClient.Login(senderInfo.Addresses[0], string(senderInfo.BridgePass))) defer senderIMAPClient.Logout() //nolint:errcheck // Connect the recipient IMAP client. - recipientIMAPClient, err := client.Dial(net.JoinHostPort(constants.Host, fmt.Sprint(bridge.GetIMAPPort()))) + recipientIMAPClient, err := eventuallyDial(net.JoinHostPort(constants.Host, fmt.Sprint(bridge.GetIMAPPort()))) require.NoError(t, err) require.NoError(t, recipientIMAPClient.Login(recipientInfo.Addresses[0], string(recipientInfo.BridgePass))) defer recipientIMAPClient.Logout() //nolint:errcheck @@ -146,7 +145,7 @@ func TestBridge_SendDraftFlags(t *testing.T) { require.NoError(t, err) // Connect the sender IMAP client. - imapClient, err := client.Dial(net.JoinHostPort(constants.Host, fmt.Sprint(bridge.GetIMAPPort()))) + imapClient, err := eventuallyDial(net.JoinHostPort(constants.Host, fmt.Sprint(bridge.GetIMAPPort()))) require.NoError(t, err) require.NoError(t, imapClient.Login(userInfo.Addresses[0], string(userInfo.BridgePass))) defer imapClient.Logout() //nolint:errcheck @@ -256,7 +255,7 @@ func TestBridge_SendInvite(t *testing.T) { require.NoError(t, err) // Connect the sender IMAP client. - imapClient, err := client.Dial(net.JoinHostPort(constants.Host, fmt.Sprint(bridge.GetIMAPPort()))) + imapClient, err := eventuallyDial(net.JoinHostPort(constants.Host, fmt.Sprint(bridge.GetIMAPPort()))) require.NoError(t, err) require.NoError(t, imapClient.Login(userInfo.Addresses[0], string(userInfo.BridgePass))) defer imapClient.Logout() //nolint:errcheck @@ -454,13 +453,13 @@ SGVsbG8gd29ybGQK } // Connect the sender IMAP client. - senderIMAPClient, err := client.Dial(net.JoinHostPort(constants.Host, fmt.Sprint(bridge.GetIMAPPort()))) + senderIMAPClient, err := eventuallyDial(net.JoinHostPort(constants.Host, fmt.Sprint(bridge.GetIMAPPort()))) require.NoError(t, err) require.NoError(t, senderIMAPClient.Login(senderInfo.Addresses[0], string(senderInfo.BridgePass))) defer senderIMAPClient.Logout() //nolint:errcheck // Connect the recipient IMAP client. - recipientIMAPClient, err := client.Dial(net.JoinHostPort(constants.Host, fmt.Sprint(bridge.GetIMAPPort()))) + recipientIMAPClient, err := eventuallyDial(net.JoinHostPort(constants.Host, fmt.Sprint(bridge.GetIMAPPort()))) require.NoError(t, err) require.NoError(t, recipientIMAPClient.Login(recipientInfo.Addresses[0], string(recipientInfo.BridgePass))) defer recipientIMAPClient.Logout() //nolint:errcheck diff --git a/internal/bridge/server_manager_test.go b/internal/bridge/server_manager_test.go index 23a94a1d..47f799e9 100644 --- a/internal/bridge/server_manager_test.go +++ b/internal/bridge/server_manager_test.go @@ -27,14 +27,13 @@ import ( "github.com/ProtonMail/proton-bridge/v3/internal/bridge" "github.com/ProtonMail/proton-bridge/v3/internal/constants" "github.com/ProtonMail/proton-bridge/v3/internal/events" - "github.com/emersion/go-imap/client" "github.com/stretchr/testify/require" ) func TestServerManager_NoLoadedUsersNoServers(t *testing.T) { withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, storeKey []byte) { withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) { - _, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, bridge.GetIMAPPort())) + _, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, bridge.GetIMAPPort())) require.Error(t, err) }) }) @@ -113,7 +112,7 @@ func TestServerManager_ServersDoNotStopWhenThereIsStillOneActiveUser(t *testing. waitForEvent(t, evtCh, events.UserDeauth{}) - imapClient, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, bridge.GetIMAPPort())) + imapClient, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, bridge.GetIMAPPort())) require.NoError(t, err) require.NoError(t, imapClient.Logout()) }) @@ -138,7 +137,7 @@ func TestServerManager_ServersStartIfAtLeastOneUserIsLoggedIn(t *testing.T) { require.NoError(t, s.RevokeUser(userIDOther)) withBridgeWaitForServers(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) { - imapClient, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, bridge.GetIMAPPort())) + imapClient, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, bridge.GetIMAPPort())) require.NoError(t, err) require.NoError(t, imapClient.Logout()) }) @@ -151,21 +150,30 @@ func TestServerManager_NetworkLossStopsServers(t *testing.T) { imapWaiter := waitForIMAPServerReady(bridge) defer imapWaiter.Done() + smtpWaiter := waitForSMTPServerReady(bridge) + defer smtpWaiter.Done() + imapWaiterStop := waitForIMAPServerStopped(bridge) defer imapWaiterStop.Done() + smtpWaiterStop := waitForSMTPServerStopped(bridge) + defer smtpWaiterStop.Done() + _, err := bridge.LoginFull(ctx, username, password, nil, nil) require.NoError(t, err) imapWaiter.Wait() + smtpWaiter.Wait() netCtl.Disable() imapWaiterStop.Wait() + smtpWaiterStop.Wait() netCtl.Enable() imapWaiter.Wait() + smtpWaiter.Wait() }) }) } diff --git a/internal/bridge/sync_test.go b/internal/bridge/sync_test.go index c880f7b3..00a0105e 100644 --- a/internal/bridge/sync_test.go +++ b/internal/bridge/sync_test.go @@ -80,7 +80,7 @@ func TestBridge_Sync(t *testing.T) { require.NoError(t, err) require.True(t, info.State == bridge.Connected) - client, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) + client, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) require.NoError(t, err) require.NoError(t, client.Login(info.Addresses[0], string(info.BridgePass))) defer func() { _ = client.Logout() }() @@ -127,7 +127,7 @@ func TestBridge_Sync(t *testing.T) { require.NoError(t, err) require.True(t, info.State == bridge.Connected) - client, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) + client, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) require.NoError(t, err) require.NoError(t, client.Login(info.Addresses[0], string(info.BridgePass))) defer func() { _ = client.Logout() }() @@ -178,7 +178,7 @@ func _TestBridge_Sync_BadMessage(t *testing.T) { //nolint:unused,deadcode require.NoError(t, err) require.True(t, info.State == bridge.Connected) - client, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) + client, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) require.NoError(t, err) require.NoError(t, client.Login(info.Addresses[0], string(info.BridgePass))) defer func() { _ = client.Logout() }() @@ -293,7 +293,7 @@ func TestBridge_SyncWithOngoingEvents(t *testing.T) { require.NoError(t, err) require.True(t, info.State == bridge.Connected) - client, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) + client, err := eventuallyDial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) require.NoError(t, err) require.NoError(t, client.Login(info.Addresses[0], string(info.BridgePass))) defer func() { _ = client.Logout() }() diff --git a/internal/bridge/user_event_test.go b/internal/bridge/user_event_test.go index caae0134..e31ae675 100644 --- a/internal/bridge/user_event_test.go +++ b/internal/bridge/user_event_test.go @@ -444,14 +444,14 @@ func TestBridge_User_DropConn_NoBadEvent(t *testing.T) { info, err := bridge.QueryUserInfo("user") require.NoError(t, err) - client, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, bridge.GetIMAPPort())) + cli, err := eventuallyDial(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() }() + require.NoError(t, cli.Login(info.Addresses[0], string(info.BridgePass))) + defer func() { _ = cli.Logout() }() // The IMAP client will eventually see 20 messages. require.Eventually(t, func() bool { - status, err := client.Status("INBOX", []imap.StatusItem{imap.StatusMessages}) + status, err := cli.Status("INBOX", []imap.StatusItem{imap.StatusMessages}) return err == nil && status.Messages == 20 }, 10*time.Second, 100*time.Millisecond) }) @@ -645,12 +645,12 @@ func TestBridge_User_SendDraftRemoveDraftFlag(t *testing.T) { info, err := bridge.QueryUserInfo("user") require.NoError(t, err) - client, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, bridge.GetIMAPPort())) + cli, err := eventuallyDial(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() }() + require.NoError(t, cli.Login(info.Addresses[0], string(info.BridgePass))) + defer func() { _ = cli.Logout() }() - messages, err := clientFetch(client, "Drafts") + messages, err := clientFetch(cli, "Drafts") require.NoError(t, err) require.Len(t, messages, 1) require.Contains(t, messages[0].Flags, imap.DraftFlag) @@ -684,12 +684,12 @@ func TestBridge_User_SendDraftRemoveDraftFlag(t *testing.T) { info, err := bridge.QueryUserInfo("user") require.NoError(t, err) - client, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, bridge.GetIMAPPort())) + cli, err := eventuallyDial(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() }() + require.NoError(t, cli.Login(info.Addresses[0], string(info.BridgePass))) + defer func() { _ = cli.Logout() }() - messages, err := clientFetch(client, "Sent") + messages, err := clientFetch(cli, "Sent") require.NoError(t, err) require.Len(t, messages, 1) require.NotContains(t, messages[0].Flags, imap.DraftFlag) @@ -781,17 +781,21 @@ func TestBridge_User_HandleParentLabelRename(t *testing.T) { imapWaiter := waitForIMAPServerReady(bridge) defer imapWaiter.Done() + smtpWaiter := waitForSMTPServerReady(bridge) + defer smtpWaiter.Done() + require.NoError(t, getErr(bridge.LoginFull(ctx, username, password, nil, nil))) info, err := bridge.QueryUserInfo(username) require.NoError(t, err) imapWaiter.Wait() + smtpWaiter.Wait() - client, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, bridge.GetIMAPPort())) + cli, err := eventuallyDial(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() }() + require.NoError(t, cli.Login(info.Addresses[0], string(info.BridgePass))) + defer func() { _ = cli.Logout() }() withClient(ctx, t, s, username, password, func(ctx context.Context, c *proton.Client) { parentName := uuid.NewString() @@ -807,7 +811,7 @@ func TestBridge_User_HandleParentLabelRename(t *testing.T) { // Wait for the parent folder to be created. require.Eventually(t, func() bool { - return xslices.IndexFunc(clientList(client), func(mailbox *imap.MailboxInfo) bool { + return xslices.IndexFunc(clientList(cli), func(mailbox *imap.MailboxInfo) bool { return mailbox.Name == fmt.Sprintf("Folders/%v", parentName) }) >= 0 }, 100*user.EventPeriod, user.EventPeriod) @@ -824,7 +828,7 @@ func TestBridge_User_HandleParentLabelRename(t *testing.T) { // Wait for the parent folder to be created. require.Eventually(t, func() bool { - return xslices.IndexFunc(clientList(client), func(mailbox *imap.MailboxInfo) bool { + return xslices.IndexFunc(clientList(cli), func(mailbox *imap.MailboxInfo) bool { return mailbox.Name == fmt.Sprintf("Folders/%v/%v", parentName, childName) }) >= 0 }, 100*user.EventPeriod, user.EventPeriod) @@ -839,14 +843,14 @@ func TestBridge_User_HandleParentLabelRename(t *testing.T) { // Wait for the parent folder to be renamed. require.Eventually(t, func() bool { - return xslices.IndexFunc(clientList(client), func(mailbox *imap.MailboxInfo) bool { + return xslices.IndexFunc(clientList(cli), func(mailbox *imap.MailboxInfo) bool { return mailbox.Name == fmt.Sprintf("Folders/%v", newParentName) }) >= 0 }, 100*user.EventPeriod, user.EventPeriod) // Wait for the child folder to be renamed. require.Eventually(t, func() bool { - return xslices.IndexFunc(clientList(client), func(mailbox *imap.MailboxInfo) bool { + return xslices.IndexFunc(clientList(cli), func(mailbox *imap.MailboxInfo) bool { return mailbox.Name == fmt.Sprintf("Folders/%v/%v", newParentName, childName) }) >= 0 }, 100*user.EventPeriod, user.EventPeriod) @@ -898,10 +902,10 @@ func userContinueEventProcess( info, err := bridge.QueryUserInfo("user") require.NoError(t, err) - client, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, bridge.GetIMAPPort())) + cli, err := eventuallyDial(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() }() + require.NoError(t, cli.Login(info.Addresses[0], string(info.BridgePass))) + defer func() { _ = cli.Logout() }() randomLabel := uuid.NewString() @@ -916,8 +920,21 @@ func userContinueEventProcess( // Wait for the label to be created. require.Eventually(t, func() bool { - return xslices.IndexFunc(clientList(client), func(mailbox *imap.MailboxInfo) bool { + return xslices.IndexFunc(clientList(cli), func(mailbox *imap.MailboxInfo) bool { return mailbox.Name == "Labels/"+randomLabel }) >= 0 }, 100*user.EventPeriod, user.EventPeriod) } + +func eventuallyDial(addr string) (cli *client.Client, err error) { + var sleep = 1 * time.Second + for i := 0; i < 5; i++ { + cli, err := client.Dial(addr) + if err == nil { + return cli, nil + } + time.Sleep(sleep) + sleep *= 2 + } + return nil, fmt.Errorf("after 5 attempts, last error: %s", err) +} diff --git a/tests/ctx_imap_test.go b/tests/ctx_imap_test.go index 7f8b3d6a..13b590ad 100644 --- a/tests/ctx_imap_test.go +++ b/tests/ctx_imap_test.go @@ -19,6 +19,7 @@ package tests import ( "fmt" + "time" "github.com/ProtonMail/proton-bridge/v3/internal/constants" "github.com/emersion/go-imap/client" @@ -29,14 +30,14 @@ func (t *testCtx) newIMAPClient(userID, clientID string) error { } func (t *testCtx) newIMAPClientOnPort(userID, clientID string, imapPort int) error { - client, err := client.Dial(fmt.Sprintf("%v:%d", constants.Host, imapPort)) + cli, err := eventuallyDial(fmt.Sprintf("%v:%d", constants.Host, imapPort)) if err != nil { return err } t.imapClients[clientID] = &imapClient{ userID: userID, - client: client, + client: cli, } return nil @@ -45,3 +46,16 @@ func (t *testCtx) newIMAPClientOnPort(userID, clientID string, imapPort int) err func (t *testCtx) getIMAPClient(clientID string) (string, *client.Client) { return t.imapClients[clientID].userID, t.imapClients[clientID].client } + +func eventuallyDial(addr string) (cli *client.Client, err error) { + var sleep = 1 * time.Second + for i := 0; i < 5; i++ { + cli, err := client.Dial(addr) + if err == nil { + return cli, nil + } + time.Sleep(sleep) + sleep *= 2 + } + return nil, fmt.Errorf("after 5 attempts, last error: %s", err) +} diff --git a/tests/ctx_test.go b/tests/ctx_test.go index b37a0a99..f667c5f1 100644 --- a/tests/ctx_test.go +++ b/tests/ctx_test.go @@ -169,6 +169,7 @@ type testCtx struct { dummyListeners []net.Listener imapServerStarted bool + smtpServerStarted bool } type imapClient struct { diff --git a/tests/features/bridge/heartbeat.feature b/tests/features/bridge/heartbeat.feature index 9584f800..1288b7c5 100644 --- a/tests/features/bridge/heartbeat.feature +++ b/tests/features/bridge/heartbeat.feature @@ -1,7 +1,9 @@ Feature: Send Telemetry Heartbeat Background: Given there exists an account with username "[user:user1]" and password "password" - And bridge starts + Then it succeeds + When bridge starts + Then it succeeds Scenario: Send at first start - one user default settings diff --git a/tests/features/imap/auth.feature b/tests/features/imap/auth.feature index d839a3bc..c51539f4 100644 --- a/tests/features/imap/auth.feature +++ b/tests/features/imap/auth.feature @@ -4,9 +4,11 @@ Feature: A user can authenticate an IMAP client And there exists an account with username "[user:user2]" and password "password2" And the account "[user:user]" has additional address "[alias:alias]@[domain]" And the account "[user:user2]" has additional disabled address "[alias:alias2]@[domain]" - And bridge starts + Then it succeeds + When bridge starts And the user logs in with username "[user:user]" and password "password" And the user logs in with username "[user:user2]" and password "password2" + Then it succeeds Scenario: IMAP client can authenticate successfully When user "[user:user]" connects IMAP client "1" diff --git a/tests/features/imap/id.feature b/tests/features/imap/id.feature index a8653b9e..95d1ab83 100644 --- a/tests/features/imap/id.feature +++ b/tests/features/imap/id.feature @@ -1,8 +1,10 @@ Feature: The IMAP ID is propagated to bridge Background: Given there exists an account with username "[user:user]" and password "password" - And bridge starts + Then it succeeds + When bridge starts And the user logs in with username "[user:user]" and password "password" + Then it succeeds Scenario: Initial user agent before an IMAP client announces its ID When user "[user:user]" connects IMAP client "1" diff --git a/tests/features/imap/mailbox/create.feature b/tests/features/imap/mailbox/create.feature index e89ffc7c..c7617b43 100644 --- a/tests/features/imap/mailbox/create.feature +++ b/tests/features/imap/mailbox/create.feature @@ -7,10 +7,12 @@ Feature: IMAP create mailbox | f2 | folder | | l1 | label | | l2 | label | - And bridge starts + Then it succeeds + 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 it succeeds Scenario: Create folder When IMAP client "1" creates "Folders/mbox" diff --git a/tests/features/imap/mailbox/delete.feature b/tests/features/imap/mailbox/delete.feature index 01c664ae..0f269dda 100644 --- a/tests/features/imap/mailbox/delete.feature +++ b/tests/features/imap/mailbox/delete.feature @@ -6,10 +6,12 @@ Feature: IMAP delete mailbox | one | folder | | two | folder | | three | label | - And bridge starts + Then it succeeds + 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 it succeeds Scenario: Delete folder When IMAP client "1" deletes "Folders/one" diff --git a/tests/features/imap/mailbox/hide_all_mail.feature b/tests/features/imap/mailbox/hide_all_mail.feature index 9a450e8f..4009a1d9 100644 --- a/tests/features/imap/mailbox/hide_all_mail.feature +++ b/tests/features/imap/mailbox/hide_all_mail.feature @@ -1,10 +1,12 @@ Feature: IMAP Hide All Mail Background: Given there exists an account with username "[user:user]" and password "password" - And bridge starts + Then it succeeds + 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 it succeeds Scenario: Hide All Mail Mailbox Given IMAP client "1" eventually sees the following mailbox info: diff --git a/tests/features/imap/mailbox/info.feature b/tests/features/imap/mailbox/info.feature index 670f0936..bcf938a2 100644 --- a/tests/features/imap/mailbox/info.feature +++ b/tests/features/imap/mailbox/info.feature @@ -8,9 +8,11 @@ Feature: IMAP get mailbox info | from | to | subject | unread | | a@example.com | a@example.com | one | true | | b@example.com | b@example.com | two | false | - And bridge starts + Then it succeeds + When bridge starts And the user logs in with username "[user:user]" and password "password" And user "[user:user]" finishes syncing + Then it succeeds Scenario: Mailbox status reports correct name, total and unread When user "[user:user]" connects and authenticates IMAP client "1" diff --git a/tests/features/imap/mailbox/list.feature b/tests/features/imap/mailbox/list.feature index ac939363..d800019b 100644 --- a/tests/features/imap/mailbox/list.feature +++ b/tests/features/imap/mailbox/list.feature @@ -5,11 +5,13 @@ Feature: IMAP list mailboxes | name | type | | mbox1 | folder | | mbox2 | label | + Then it succeeds 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: + Then it succeeds + And IMAP client "1" eventually sees the following mailbox info: | name | | INBOX | | Drafts | diff --git a/tests/features/imap/mailbox/rename.feature b/tests/features/imap/mailbox/rename.feature index 5e88af5c..25f2bb04 100644 --- a/tests/features/imap/mailbox/rename.feature +++ b/tests/features/imap/mailbox/rename.feature @@ -5,10 +5,12 @@ Feature: IMAP get mailbox info | name | type | | f1 | folder | | l1 | label | - And bridge starts + Then it succeeds + 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 it succeeds Scenario: Rename folder When IMAP client "1" renames "Folders/f1" to "Folders/f2" diff --git a/tests/features/imap/mailbox/rename_hiearchy.feature b/tests/features/imap/mailbox/rename_hiearchy.feature index 7bb0de8d..4ca53036 100644 --- a/tests/features/imap/mailbox/rename_hiearchy.feature +++ b/tests/features/imap/mailbox/rename_hiearchy.feature @@ -5,10 +5,12 @@ Feature: IMAP get mailbox info | name | type | | f1 | folder | | f1/f2| folder | - And bridge starts + Then it succeeds + 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 it succeeds Scenario: Rename folder with subfolders When IMAP client "1" renames "Folders/f1" to "Folders/f3" diff --git a/tests/features/imap/mailbox/select.feature b/tests/features/imap/mailbox/select.feature index abfa1d9c..af3dfb3d 100644 --- a/tests/features/imap/mailbox/select.feature +++ b/tests/features/imap/mailbox/select.feature @@ -5,10 +5,12 @@ Feature: IMAP select mailbox | name | type | | mbox | folder | | label | label | - And bridge starts + Then it succeeds + 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 it succeeds Scenario: Select inbox When IMAP client "1" selects "INBOX" diff --git a/tests/features/imap/message/copy.feature b/tests/features/imap/message/copy.feature index 016fa323..4dd0b6c6 100644 --- a/tests/features/imap/message/copy.feature +++ b/tests/features/imap/message/copy.feature @@ -9,10 +9,12 @@ Feature: IMAP copy messages | from | to | subject | unread | | john.doe@mail.com | [user:user]@[domain] | foo | false | | jane.doe@mail.com | name@[domain] | bar | true | - And bridge starts + Then it succeeds + 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 it succeeds Scenario: Copy message to label When IMAP client "1" copies the message with subject "foo" from "INBOX" to "Labels/label" diff --git a/tests/features/imap/message/create.feature b/tests/features/imap/message/create.feature index 367197da..9b7305c4 100644 --- a/tests/features/imap/message/create.feature +++ b/tests/features/imap/message/create.feature @@ -2,10 +2,12 @@ Feature: IMAP create messages Background: Given there exists an account with username "[user:user]" and password "password" And the account "[user:user]" has additional address "[alias:alias]@[domain]" - And bridge starts + Then it succeeds + 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 it succeeds Scenario: Creates message to user's primary address When IMAP client "1" appends the following messages to "INBOX": diff --git a/tests/features/imap/message/delete.feature b/tests/features/imap/message/delete.feature index 72fcb288..b9247f19 100644 --- a/tests/features/imap/message/delete.feature +++ b/tests/features/imap/message/delete.feature @@ -7,10 +7,12 @@ Feature: IMAP remove messages from mailbox | 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 + Then it succeeds + 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 it succeeds Scenario: Mark message as deleted and EXPUNGE When IMAP client "1" selects "Folders/mbox" diff --git a/tests/features/imap/message/delete_from_trash.feature b/tests/features/imap/message/delete_from_trash.feature index fdc5105e..15446eed 100644 --- a/tests/features/imap/message/delete_from_trash.feature +++ b/tests/features/imap/message/delete_from_trash.feature @@ -5,6 +5,7 @@ Feature: IMAP remove messages from Trash | name | type | | mbox | folder | | label | label | + Then it succeeds Scenario Outline: Message in Trash and some other label is not permanently deleted Given the address "[user:user]@[domain]" of account "[user:user]" has the following messages in "Trash": diff --git a/tests/features/imap/message/drafts.feature b/tests/features/imap/message/drafts.feature index 2c8e6ae7..0d5f9729 100644 --- a/tests/features/imap/message/drafts.feature +++ b/tests/features/imap/message/drafts.feature @@ -1,7 +1,8 @@ Feature: IMAP Draft messages Background: Given there exists an account with username "[user:user]" and password "password" - And bridge starts + Then it succeeds + 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" @@ -11,12 +12,13 @@ Feature: IMAP Draft messages This is a dra """ - And it succeeds - Then IMAP client "1" eventually sees the following messages in "Drafts": + Then it succeeds + And IMAP client "1" eventually sees the following messages in "Drafts": | body | | This is a dra | And IMAP client "1" eventually sees 1 messages in "Drafts" + Scenario: Draft edited locally When IMAP client "1" marks message 1 as deleted And IMAP client "1" expunges diff --git a/tests/features/imap/message/fetch.feature b/tests/features/imap/message/fetch.feature index f72461b4..f1375c91 100644 --- a/tests/features/imap/message/fetch.feature +++ b/tests/features/imap/message/fetch.feature @@ -7,10 +7,12 @@ Feature: IMAP Fetch And the address "[user:user]@[domain]" of account "[user:user]" has the following messages in "Inbox": | from | to | subject | date | | john.doe@mail.com | [user:user]@[domain] | foo | 13 Jul 69 00:00 +0000 | - And bridge starts + Then it succeeds + 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 it succeeds Scenario: Fetch very old message Given IMAP client "1" eventually sees the following messages in "INBOX": diff --git a/tests/features/imap/message/import.feature b/tests/features/imap/message/import.feature index b70ad4c7..3608d133 100644 --- a/tests/features/imap/message/import.feature +++ b/tests/features/imap/message/import.feature @@ -1,10 +1,12 @@ Feature: IMAP import messages Background: Given there exists an account with username "[user:user]" and password "password" - And bridge starts + Then it succeeds + 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 it succeeds Scenario: Basic message import When IMAP client "1" appends the following message to "INBOX": diff --git a/tests/features/imap/message/move.feature b/tests/features/imap/message/move.feature index 33235de5..1434930f 100644 --- a/tests/features/imap/message/move.feature +++ b/tests/features/imap/message/move.feature @@ -19,10 +19,12 @@ Feature: IMAP move messages 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 + Then it succeeds + 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 it succeeds Scenario: Move message from folder to label (keeps in folder) When IMAP client "1" moves the message with subject "foo" from "INBOX" to "Labels/label" diff --git a/tests/features/imap/message/move_without_support.feature b/tests/features/imap/message/move_without_support.feature index ca81095e..0ef82762 100644 --- a/tests/features/imap/message/move_without_support.feature +++ b/tests/features/imap/message/move_without_support.feature @@ -4,11 +4,13 @@ Feature: IMAP move messages by append and delete (without MOVE support, e.g., Ou And the account "[user:user]" has the following custom mailboxes: | name | type | | mbox | folder | - And bridge starts + Then it succeeds + 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 "source" And user "[user:user]" connects and authenticates IMAP client "target" + Then it succeeds Scenario Outline: Move message from to by When IMAP client "source" appends the following message to "": diff --git a/tests/features/imap/migration.feature b/tests/features/imap/migration.feature index 4d6a11a9..485e966f 100644 --- a/tests/features/imap/migration.feature +++ b/tests/features/imap/migration.feature @@ -7,10 +7,11 @@ Feature: Bridge can fully sync an account | jane.doe@mail.com | name@[domain] | bar | true | And the account "[user:user]" has 20 custom folders And the account "[user:user]" has 60 custom labels + Then it succeeds When bridge starts And the user logs in with username "[user:user]" and password "password" And user "[user:user]" finishes syncing - When user "[user:user]" connects and authenticates IMAP client "1" + And user "[user:user]" connects and authenticates IMAP client "1" Then IMAP client "1" counts 20 mailboxes under "Folders" And IMAP client "1" counts 60 mailboxes under "Labels" diff --git a/tests/features/imap/ports.feature b/tests/features/imap/ports.feature index 11ff9e12..8a221cdc 100644 --- a/tests/features/imap/ports.feature +++ b/tests/features/imap/ports.feature @@ -1,9 +1,11 @@ Feature: A user can connect an IMAP client to custom ports Background: Given there exists an account with username "[user:user]" and password "password" - And bridge starts + Then it succeeds + When bridge starts And the user logs in with username "[user:user]" and password "password" And the user changes the IMAP port to 1144 + Then it succeeds Scenario: Authenticates successfully on custom port When user "[user:user]" connects IMAP client "1" on port 1144 diff --git a/tests/features/smtp/auth.feature b/tests/features/smtp/auth.feature index 540b291f..067b9321 100644 --- a/tests/features/smtp/auth.feature +++ b/tests/features/smtp/auth.feature @@ -6,10 +6,12 @@ Feature: A user can authenticate an SMTP client And the account "[user:user]" has additional address "[alias:alias]@[domain]" And the account "[user:user2]" has additional disabled address "[alias:alias2]@[domain]" And the account "[user:user3]" has additional address "[alias:alias3]@[domain]" - And bridge starts + Then it succeeds + When bridge starts And the user logs in with username "[user:user]" and password "password" And the user logs in with username "[user:user2]" and password "password2" And the user logs in with username "[user:user3]" and password "password3" + Then it succeeds Scenario: SMTP client can authenticate successfully When user "[user:user]" connects SMTP client "1" diff --git a/tests/features/smtp/init.feature b/tests/features/smtp/init.feature index 20fb9258..4d5ba114 100644 --- a/tests/features/smtp/init.feature +++ b/tests/features/smtp/init.feature @@ -1,9 +1,11 @@ Feature: SMTP initiation Background: Given there exists an account with username "[user:user]" and password "password" - And bridge starts + Then it succeeds + When bridge starts And the user logs in with username "[user:user]" and password "password" - When user "[user:user]" connects and authenticates SMTP client "1" + And user "[user:user]" connects and authenticates SMTP client "1" + Then it succeeds Scenario: Send without first announcing FROM and TO When SMTP client "1" sends DATA: diff --git a/tests/features/smtp/ports.feature b/tests/features/smtp/ports.feature index 82fd17ec..d117d968 100644 --- a/tests/features/smtp/ports.feature +++ b/tests/features/smtp/ports.feature @@ -1,10 +1,12 @@ Feature: A user can connect an SMTP client to custom ports Background: Given there exists an account with username "[user:user]" and password "password" - And bridge starts + Then it succeeds + When bridge starts And the user logs in with username "[user:user]" and password "password" - And the user changes the SMTP port to 1144 + Then it succeeds Scenario: Authenticates successfully on custom port + When the user changes the SMTP port to 1144 When user "[user:user]" connects SMTP client "1" on port 1144 Then SMTP client "1" can authenticate \ No newline at end of file diff --git a/tests/features/smtp/send/bcc.feature b/tests/features/smtp/send/bcc.feature index a41f60da..8ae2a770 100644 --- a/tests/features/smtp/send/bcc.feature +++ b/tests/features/smtp/send/bcc.feature @@ -1,12 +1,14 @@ Feature: SMTP with bcc Background: Given there exists an account with username "[user:user]" and password "password" - Given there exists an account with username "[user:to]" and password "password" - Given there exists an account with username "[user:bcc]" and password "password" - And bridge starts + And there exists an account with username "[user:to]" and password "password" + And there exists an account with username "[user:bcc]" and password "password" + Then it succeeds + When bridge starts And the user logs in with username "[user:user]" and password "password" And the user logs in with username "[user:bcc]" and password "password" And user "[user:user]" connects and authenticates SMTP client "1" + Then it succeeds Scenario: Send message to address in to and bcc When SMTP client "1" sends the following message from "[user:user]@[domain]" to "[user:to]@[domain], [user:bcc]@[domain]": diff --git a/tests/features/smtp/send/embedded_message.feature b/tests/features/smtp/send/embedded_message.feature index 3ab685c9..a7c94db3 100644 --- a/tests/features/smtp/send/embedded_message.feature +++ b/tests/features/smtp/send/embedded_message.feature @@ -2,10 +2,12 @@ Feature: SMTP sending embedded message Background: Given there exists an account with username "[user:user]" and password "password" And there exists an account with username "[user:to]" and password "password" - And bridge starts + Then it succeeds + When bridge starts And the user logs in with username "[user:user]" and password "password" And the user logs in with username "[user:to]" and password "password" And user "[user:user]" connects and authenticates SMTP client "1" + Then it succeeds @long-black Scenario: Send it diff --git a/tests/features/smtp/send/failures.feature b/tests/features/smtp/send/failures.feature index cd93f6a6..19c53538 100644 --- a/tests/features/smtp/send/failures.feature +++ b/tests/features/smtp/send/failures.feature @@ -2,9 +2,11 @@ Feature: SMTP wrong messages Background: Given there exists an account with username "[user:user]" and password "password" And there exists an account with username "[user:to]" and password "password" - And bridge starts + Then it succeeds + When bridge starts And the user logs in with username "[user:user]" and password "password" And user "[user:user]" connects and authenticates SMTP client "1" + Then it succeeds Scenario: Message with attachment and wrong boundaries When SMTP client "1" sends the following message from "[user:user]@[domain]" to "[user:to]@[domain]": diff --git a/tests/features/smtp/send/html.feature b/tests/features/smtp/send/html.feature index 0b120d93..5f2d28ea 100644 --- a/tests/features/smtp/send/html.feature +++ b/tests/features/smtp/send/html.feature @@ -2,9 +2,11 @@ Feature: SMTP sending of plain messages Background: Given there exists an account with username "[user:user]" and password "password" And there exists an account with username "[user:to]" and password "password" - And bridge starts + Then it succeeds + When bridge starts And the user logs in with username "[user:user]" and password "password" And user "[user:user]" connects and authenticates SMTP client "1" + Then it succeeds Scenario: HTML message to external account When SMTP client "1" sends the following message from "[user:user]@[domain]" to "pm.bridge.qa@gmail.com": diff --git a/tests/features/smtp/send/html_att.feature b/tests/features/smtp/send/html_att.feature index effb7989..5d0a547f 100644 --- a/tests/features/smtp/send/html_att.feature +++ b/tests/features/smtp/send/html_att.feature @@ -2,9 +2,11 @@ Feature: SMTP sending of plain messages Background: Given there exists an account with username "[user:user]" and password "password" And there exists an account with username "[user:to]" and password "password" - And bridge starts + Then it succeeds + When bridge starts And the user logs in with username "[user:user]" and password "password" And user "[user:user]" connects and authenticates SMTP client "1" + Then it succeeds Scenario: HTML message with attachment to internal account When SMTP client "1" sends the following message from "[user:user]@[domain]" to "[user:to]@[domain]": diff --git a/tests/features/smtp/send/inline.feature b/tests/features/smtp/send/inline.feature index 29d0fd17..97aab9e7 100644 --- a/tests/features/smtp/send/inline.feature +++ b/tests/features/smtp/send/inline.feature @@ -2,9 +2,11 @@ Feature: SMTP messages containing inlines Background: Given there exists an account with username "[user:user]" and password "password" And there exists an account with username "[user:to]" and password "password" - And bridge starts + Then it succeeds + When bridge starts And the user logs in with username "[user:user]" and password "password" And user "[user:user]" connects and authenticates SMTP client "1" + Then it succeeds Scenario: A message with inline attachment to internal account When SMTP client "1" sends the following message from "[user:user]@[domain]" to "[user:to]@[domain]": diff --git a/tests/features/smtp/send/mixed_case.feature b/tests/features/smtp/send/mixed_case.feature index dd6b918b..248b14df 100644 --- a/tests/features/smtp/send/mixed_case.feature +++ b/tests/features/smtp/send/mixed_case.feature @@ -2,9 +2,11 @@ Feature: SMTP sending with mixed case address Background: Given there exists an account with username "[user:user]" and password "password" And there exists an account with username "[user:to]" and password "password" - And bridge starts + Then it succeeds + When bridge starts And the user logs in with username "[user:user]" and password "password" And user "[user:user]" connects and authenticates SMTP client "1" + Then it succeeds Scenario: Mixed sender case in sender address When SMTP client "1" sends the following message from "[user:user]@[domain]" to "[user:to]@[domain]": diff --git a/tests/features/smtp/send/one_account_to_another.feature b/tests/features/smtp/send/one_account_to_another.feature index 62e20587..82b29568 100644 --- a/tests/features/smtp/send/one_account_to_another.feature +++ b/tests/features/smtp/send/one_account_to_another.feature @@ -2,9 +2,11 @@ Feature: SMTP sending two messages Background: Given there exists an account with username "[user:user]" and password "password" And there exists an account with username "[user:recp]" and password "password" - And bridge starts + Then it succeeds + When bridge starts And the user logs in with username "[user:user]" and password "password" And the user logs in with username "[user:recp]" and password "password" + Then it succeeds @long-black diff --git a/tests/features/smtp/send/plain.feature b/tests/features/smtp/send/plain.feature index 1dffe325..a8427333 100644 --- a/tests/features/smtp/send/plain.feature +++ b/tests/features/smtp/send/plain.feature @@ -3,9 +3,11 @@ Feature: SMTP sending of plain messages Given there exists an account with username "[user:user]" and password "password" And there exists an account with username "[user:to]" and password "password" And there exists an account with username "[user:cc]" and password "password" - And bridge starts + Then it succeeds + When bridge starts And the user logs in with username "[user:user]" and password "password" And user "[user:user]" connects and authenticates SMTP client "1" + Then it succeeds Scenario: Only from and to headers to internal account When SMTP client "1" sends the following message from "[user:user]@[domain]" to "[user:to]@[domain]": diff --git a/tests/features/smtp/send/plain_att.feature b/tests/features/smtp/send/plain_att.feature index 41a9112f..009e6d8c 100644 --- a/tests/features/smtp/send/plain_att.feature +++ b/tests/features/smtp/send/plain_att.feature @@ -2,9 +2,11 @@ Feature: SMTP sending of plain messages Background: Given there exists an account with username "[user:user]" and password "password" And there exists an account with username "[user:to]" and password "password" - And bridge starts + Then it succeeds + When bridge starts And the user logs in with username "[user:user]" and password "password" And user "[user:user]" connects and authenticates SMTP client "1" + Then it succeeds Scenario: Basic message with attachment to internal account When SMTP client "1" sends the following message from "[user:user]@[domain]" to "[user:to]@[domain]": diff --git a/tests/features/smtp/send/same_message.feature b/tests/features/smtp/send/same_message.feature index 394b28d3..f877f659 100644 --- a/tests/features/smtp/send/same_message.feature +++ b/tests/features/smtp/send/same_message.feature @@ -2,7 +2,8 @@ Feature: SMTP sending the same message twice Background: Given there exists an account with username "[user:user]" and password "password" And there exists an account with username "[user:to]" and password "password" - And bridge starts + Then it succeeds + When bridge starts And the user logs in with username "[user:user]" and password "password" And the user logs in with username "[user:to]" and password "password" And user "[user:user]" connects and authenticates SMTP client "1" diff --git a/tests/features/smtp/send/send_append.feature b/tests/features/smtp/send/send_append.feature index 1d475360..57e5b443 100644 --- a/tests/features/smtp/send/send_append.feature +++ b/tests/features/smtp/send/send_append.feature @@ -2,10 +2,12 @@ Feature: SMTP sending with APPENDing to Sent Background: Given there exists an account with username "[user:user]" and password "password" And there exists an account with username "[user:to]" and password "password" - And bridge starts + Then it succeeds + When bridge starts And the user logs in with username "[user:user]" and password "password" And user "[user:user]" connects and authenticates SMTP client "1" And user "[user:user]" connects and authenticates IMAP client "1" + Then it succeeds Scenario: Send message and append to Sent # First do sending. diff --git a/tests/features/smtp/send/send_reply.feature b/tests/features/smtp/send/send_reply.feature index 095b5749..4727e1bc 100644 --- a/tests/features/smtp/send/send_reply.feature +++ b/tests/features/smtp/send/send_reply.feature @@ -3,11 +3,13 @@ Feature: SMTP send reply Background: Given there exists an account with username "[user:user1]" and password "password" And there exists an account with username "[user:user2]" and password "password" - And bridge starts + Then it succeeds + When bridge starts And the user logs in with username "[user:user1]" and password "password" And user "[user:user1]" finishes syncing And user "[user:user1]" connects and authenticates SMTP client "1" And user "[user:user1]" connects and authenticates IMAP client "1" + Then it succeeds @long-black Scenario: Reply with In-Reply-To but no References diff --git a/tests/features/smtp/send/two_messages.feature b/tests/features/smtp/send/two_messages.feature index 509c848c..e484a566 100644 --- a/tests/features/smtp/send/two_messages.feature +++ b/tests/features/smtp/send/two_messages.feature @@ -4,10 +4,12 @@ Feature: SMTP sending two messages And there exists an account with username "[user:multi]" and password "password" And the account "[user:multi]" has additional address "[user:multi-alias]@[domain]" And there exists an account with username "[user:to]" and password "password" - And bridge starts + Then it succeeds + When bridge starts And the user logs in with username "[user:user]" and password "password" And the user logs in with username "[user:multi]" and password "password" And the user sets the address mode of user "[user:multi]" to "split" + Then it succeeds Scenario: Send two messages in one connection When user "[user:user]" connects and authenticates SMTP client "1" diff --git a/tests/features/user/addressmode.feature b/tests/features/user/addressmode.feature index 714e2e3c..026c3205 100644 --- a/tests/features/user/addressmode.feature +++ b/tests/features/user/addressmode.feature @@ -14,9 +14,11 @@ Feature: Address mode | from | to | subject | unread | | c@[domain] | c@[domain] | three | true | | d@[domain] | d@[domain] | four | false | - And bridge starts + Then it succeeds + When bridge starts And the user logs in with username "[user:user]" and password "password" And user "[user:user]" finishes syncing + Then it succeeds Scenario: The user is in combined mode When user "[user:user]" connects and authenticates IMAP client "1" with address "[user:user]@[domain]" diff --git a/tests/features/user/delete.feature b/tests/features/user/delete.feature index e4027df4..2d586a79 100644 --- a/tests/features/user/delete.feature +++ b/tests/features/user/delete.feature @@ -1,8 +1,10 @@ Feature: A user can be deleted Background: Given there exists an account with username "[user:user]" and password "password" - And bridge starts + Then it succeeds + When bridge starts And the user logs in with username "[user:user]" and password "password" + Then it succeeds Scenario: Delete a connected user When user "[user:user]" is deleted diff --git a/tests/features/user/login.feature b/tests/features/user/login.feature index 1e512431..e38d74fc 100644 --- a/tests/features/user/login.feature +++ b/tests/features/user/login.feature @@ -1,9 +1,11 @@ Feature: A user can login Background: Given there exists an account with username "[user:user]" and password "password" - Given there exists an account with username "[user:MixedCaps]" and password "password" - Given there exists a disabled account with username "[user:disabled]" and password "password" + And there exists an account with username "[user:MixedCaps]" and password "password" + And there exists a disabled account with username "[user:disabled]" and password "password" + Then it succeeds And bridge starts + Then it succeeds Scenario: Login to account When the user logs in with username "[user:user]" and password "password" diff --git a/tests/features/user/relogin.feature b/tests/features/user/relogin.feature index faf5f5cd..cf1b5a9e 100644 --- a/tests/features/user/relogin.feature +++ b/tests/features/user/relogin.feature @@ -1,8 +1,10 @@ Feature: A logged out user can login again Background: Given there exists an account with username "[user:user]" and password "password" - And bridge starts + Then it succeeds + When bridge starts And the user logs in with username "[user:user]" and password "password" + Then it succeeds Scenario: Login to disconnected account When user "[user:user]" logs out diff --git a/tests/features/user/revoke.feature b/tests/features/user/revoke.feature index f0d59055..1eb984ac 100644 --- a/tests/features/user/revoke.feature +++ b/tests/features/user/revoke.feature @@ -1,8 +1,10 @@ Feature: A logged in user is logged out when its auth is revoked. Background: Given there exists an account with username "[user:user]" and password "password" - And bridge starts + Then it succeeds + When bridge starts And the user logs in with username "[user:user]" and password "password" + Then it succeeds Scenario: The auth is revoked while bridge is running When the auth of user "[user:user]" is revoked diff --git a/tests/features/user/sync.feature b/tests/features/user/sync.feature index 260eea3d..a939c1b8 100644 --- a/tests/features/user/sync.feature +++ b/tests/features/user/sync.feature @@ -14,7 +14,9 @@ Feature: Bridge can fully sync an account | from | to | subject | unread | | a@[domain] | a@[domain] | one | true | | b@[domain] | b@[domain] | two | false | - And bridge starts + Then it succeeds + When bridge starts + Then it succeeds Scenario: The account is synced when the user logs in and persists across bridge restarts When the user logs in with username "[user:user]" and password "password" diff --git a/tests/features/user/telemetry.feature b/tests/features/user/telemetry.feature index ff98029b..d1120acc 100644 --- a/tests/features/user/telemetry.feature +++ b/tests/features/user/telemetry.feature @@ -2,7 +2,9 @@ Feature: Bridge send usage metrics Background: Given there exists an account with username "[user:user1]" and password "password" And there exists an account with username "[user:user2]" and password "password" - And bridge starts + Then it succeeds + When bridge starts + Then it succeeds Scenario: Telemetry availability - No user diff --git a/tests/user_test.go b/tests/user_test.go index f1dffda8..a6b31636 100644 --- a/tests/user_test.go +++ b/tests/user_test.go @@ -332,8 +332,10 @@ func (s *scenario) drafAtIndexWasMovedToTrashForAddressOfAccount(draftIndex int, } func (s *scenario) userLogsInWithUsernameAndPassword(username, password string) error { - evtCh, cancel := s.t.bridge.GetEvents(events.SMTPServerReady{}) - defer cancel() + smtpEvtCh, cancelSMTP := s.t.bridge.GetEvents(events.SMTPServerReady{}) + defer cancelSMTP() + imapEvtCh, cancelIMAP := s.t.bridge.GetEvents(events.IMAPServerReady{}) + defer cancelIMAP() userID, err := s.t.bridge.LoginFull(context.Background(), username, []byte(password), nil, nil) if err != nil { @@ -342,9 +344,13 @@ func (s *scenario) userLogsInWithUsernameAndPassword(username, password string) // We need to wait for server to be up or we won't be able to connect. It should only happen once to avoid // blocking on multiple Logins. if !s.t.imapServerStarted { - <-evtCh + <-imapEvtCh s.t.imapServerStarted = true } + if !s.t.smtpServerStarted { + <-smtpEvtCh + s.t.smtpServerStarted = true + } if userID != s.t.getUserByName(username).getUserID() { return errors.New("user ID mismatch")