forked from Silverfish/proton-bridge
GODT-1177: remove Import-Export from repo
This commit is contained in:
@ -1,10 +1,9 @@
|
||||
.PHONY: check-go check-godog install-godog test test-bridge test-ie test-live test-live-bridge test-live-ie test-stage test-debug test-live-debug bench
|
||||
.PHONY: check-go check-godog install-godog test test-bridge test-live test-live-bridge test-stage test-debug test-live-debug bench
|
||||
|
||||
export GO111MODULE=on
|
||||
export BRIDGE_VERSION:=1.8.12+integrationtests
|
||||
export VERBOSITY?=fatal
|
||||
export TEST_DATA=testdata
|
||||
export TEST_APP?=bridge
|
||||
|
||||
# Tests do not run in parallel. This will overrule user settings.
|
||||
MAKEFLAGS=-j1
|
||||
@ -16,23 +15,17 @@ check-godog:
|
||||
install-godog: check-go
|
||||
go get github.com/cucumber/godog/cmd/godog@v0.12.1
|
||||
|
||||
test: test-bridge test-ie
|
||||
test-bridge: FEATURES ?= features/bridge
|
||||
test: test-bridge
|
||||
test-bridge: FEATURES ?= features
|
||||
test-bridge: check-godog
|
||||
TEST_APP=bridge TEST_ENV=fake TEST_ACCOUNTS=accounts/fake.json godog --tags="~@ignore" $(FEATURES)
|
||||
test-ie: FEATURES ?= features/ie
|
||||
test-ie: check-godog
|
||||
TEST_APP=ie TEST_ENV=fake TEST_ACCOUNTS=accounts/fake.json godog --tags="~@ignore" $(FEATURES)
|
||||
TEST_ENV=fake TEST_ACCOUNTS=accounts/fake.json godog --tags="~@ignore" $(FEATURES)
|
||||
|
||||
# Doesn't work in parallel!
|
||||
# Provide TEST_ACCOUNTS with your accounts.
|
||||
test-live: test-live-bridge test-live-ie
|
||||
test-live-bridge: FEATURES ?= features/bridge
|
||||
test-live-bridge: FEATURES ?= features
|
||||
test-live-bridge: check-godog
|
||||
TEST_APP=bridge TEST_ENV=live godog --tags="~@ignore && ~@ignore-live" $(FEATURES)
|
||||
test-live-ie: FEATURES ?= features/ie
|
||||
test-live-ie: check-godog
|
||||
TEST_APP=ie TEST_ENV=live godog --tags="~@ignore && ~@ignore-live" $(FEATURES)
|
||||
TEST_ENV=live godog --tags="~@ignore && ~@ignore-live" $(FEATURES)
|
||||
|
||||
# Doesn't work in parallel!
|
||||
# Provide TEST_ACCOUNTS with your accounts.
|
||||
@ -47,12 +40,6 @@ test-debug:
|
||||
test-live-debug:
|
||||
TEST_ENV=live dlv test -- $(FEATURES)
|
||||
|
||||
test-ie-debug:
|
||||
TEST_APP=ie TEST_ENV=fake TEST_ACCOUNTS=accounts/fake.json dlv test -- $(FEATURES)
|
||||
|
||||
test-live-ie-debug:
|
||||
TEST_APP=ie TEST_ENV=live dlv test -- $(FEATURES)
|
||||
|
||||
# -run flag is not working anyway, but lets keep it there to note we really do not want to run tests.
|
||||
# To properly benchmark sync/fetch, we need everything empty. For that is better to start everything
|
||||
# again and safest way is to run only one loop per run.
|
||||
|
||||
@ -19,7 +19,6 @@ package tests
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
testContext "github.com/ProtonMail/proton-bridge/test/context"
|
||||
"github.com/cucumber/godog"
|
||||
@ -60,10 +59,6 @@ func ScenarioInitializer(s *godog.ScenarioContext) {
|
||||
StoreChecksFeatureContext(s)
|
||||
StoreSetupFeatureContext(s)
|
||||
|
||||
TransferActionsFeatureContext(s)
|
||||
TransferChecksFeatureContext(s)
|
||||
TransferSetupFeatureContext(s)
|
||||
|
||||
UsersActionsFeatureContext(s)
|
||||
UsersSetupFeatureContext(s)
|
||||
UsersChecksFeatureContext(s)
|
||||
@ -72,9 +67,7 @@ func ScenarioInitializer(s *godog.ScenarioContext) {
|
||||
var ctx *testContext.TestContext //nolint[gochecknoglobals]
|
||||
|
||||
func beforeScenario(scenarioCtx context.Context, _ *godog.Scenario) (context.Context, error) {
|
||||
// NOTE(GODT-219) It would be possible to optimised the usage of godog with our context.
|
||||
app := os.Getenv("TEST_APP")
|
||||
ctx = testContext.New(app)
|
||||
ctx = testContext.New()
|
||||
return scenarioCtx, nil
|
||||
}
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@ import (
|
||||
)
|
||||
|
||||
func benchTestContext() (*context.TestContext, *mocks.IMAPClient) {
|
||||
ctx := context.New("bridge")
|
||||
ctx := context.New()
|
||||
|
||||
username := "user"
|
||||
account := ctx.GetTestAccount(username)
|
||||
|
||||
@ -23,8 +23,6 @@ import (
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/internal/bridge"
|
||||
"github.com/ProtonMail/proton-bridge/internal/config/useragent"
|
||||
"github.com/ProtonMail/proton-bridge/internal/importexport"
|
||||
"github.com/ProtonMail/proton-bridge/internal/transfer"
|
||||
"github.com/ProtonMail/proton-bridge/internal/users"
|
||||
"github.com/ProtonMail/proton-bridge/pkg/listener"
|
||||
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
|
||||
@ -55,11 +53,10 @@ type TestContext struct {
|
||||
clientManager pmapi.Manager
|
||||
|
||||
// Core related variables.
|
||||
bridge *bridge.Bridge
|
||||
importExport *importexport.ImportExport
|
||||
users *users.Users
|
||||
credStore users.CredentialsStorer
|
||||
lastError error
|
||||
bridge *bridge.Bridge
|
||||
users *users.Users
|
||||
credStore users.CredentialsStorer
|
||||
lastError error
|
||||
|
||||
// IMAP related variables.
|
||||
imapAddr string
|
||||
@ -75,13 +72,6 @@ type TestContext struct {
|
||||
smtpLastResponses map[string]*mocks.SMTPResponse
|
||||
smtpResponseLocker sync.Locker
|
||||
|
||||
// Transfer related variables.
|
||||
transferLocalRootForImport string
|
||||
transferLocalRootForExport string
|
||||
transferRemoteIMAPServer *mocks.IMAPServer
|
||||
transferProgress *transfer.Progress
|
||||
transferSkipEncryptedMessages bool
|
||||
|
||||
// Store releated variables.
|
||||
bddMessageIDsToAPIIDs map[string]string
|
||||
|
||||
@ -93,9 +83,11 @@ type TestContext struct {
|
||||
}
|
||||
|
||||
// New returns a new test TestContext.
|
||||
func New(app string) *TestContext {
|
||||
func New() *TestContext {
|
||||
setLogrusVerbosityFromEnv()
|
||||
|
||||
listener := listener.New()
|
||||
pmapiController, clientManager := newPMAPIController(app, listener)
|
||||
pmapiController, clientManager := newPMAPIController(listener)
|
||||
|
||||
ctx := &TestContext{
|
||||
t: &bddT{},
|
||||
@ -121,15 +113,8 @@ func New(app string) *TestContext {
|
||||
// Ensure that the config is cleaned up after the test is over.
|
||||
ctx.addCleanupChecked(ctx.locations.Clear, "Cleaning bridge config data")
|
||||
|
||||
// Create bridge or import-export instance under test.
|
||||
switch app {
|
||||
case "bridge":
|
||||
ctx.withBridgeInstance()
|
||||
case "ie":
|
||||
ctx.withImportExportInstance()
|
||||
default:
|
||||
panic("unknown app: " + app)
|
||||
}
|
||||
// Create bridge instance under test.
|
||||
ctx.withBridgeInstance()
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
@ -1,50 +0,0 @@
|
||||
// Copyright (c) 2021 Proton Technologies AG
|
||||
//
|
||||
// This file is part of ProtonMail Bridge.Bridge.
|
||||
//
|
||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package context
|
||||
|
||||
import (
|
||||
"github.com/ProtonMail/proton-bridge/internal/importexport"
|
||||
"github.com/ProtonMail/proton-bridge/internal/users"
|
||||
"github.com/ProtonMail/proton-bridge/pkg/listener"
|
||||
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
|
||||
)
|
||||
|
||||
// GetImportExport returns import-export instance.
|
||||
func (ctx *TestContext) GetImportExport() *importexport.ImportExport {
|
||||
return ctx.importExport
|
||||
}
|
||||
|
||||
// withImportExportInstance creates a import-export instance for use in the test.
|
||||
// TestContext has this by default once called with env variable TEST_APP=ie.
|
||||
func (ctx *TestContext) withImportExportInstance() {
|
||||
ctx.importExport = newImportExportInstance(ctx.t, ctx.locations, ctx.cache, ctx.credStore, ctx.listener, ctx.clientManager)
|
||||
ctx.users = ctx.importExport.Users
|
||||
}
|
||||
|
||||
// newImportExportInstance creates a new import-export instance configured to use the given config/credstore.
|
||||
func newImportExportInstance(
|
||||
t *bddT,
|
||||
locations importexport.Locator,
|
||||
cache importexport.Cacher,
|
||||
credStore users.CredentialsStorer,
|
||||
eventListener listener.Listener,
|
||||
clientManager pmapi.Manager,
|
||||
) *importexport.ImportExport {
|
||||
panicHandler := &panicHandler{t: t}
|
||||
return importexport.New(locations, cache, panicHandler, eventListener, clientManager, credStore)
|
||||
}
|
||||
@ -46,7 +46,7 @@ type PMAPIController interface {
|
||||
UnlockEvents()
|
||||
}
|
||||
|
||||
func newPMAPIController(app string, listener listener.Listener) (PMAPIController, pmapi.Manager) {
|
||||
func newPMAPIController(listener listener.Listener) (PMAPIController, pmapi.Manager) {
|
||||
switch os.Getenv(EnvName) {
|
||||
case EnvFake:
|
||||
cntl, cm := fakeapi.NewController()
|
||||
@ -54,7 +54,7 @@ func newPMAPIController(app string, listener listener.Listener) (PMAPIController
|
||||
return cntl, cm
|
||||
|
||||
case EnvLive:
|
||||
cntl, cm := liveapi.NewController(app)
|
||||
cntl, cm := liveapi.NewController()
|
||||
addConnectionObserver(cm, listener)
|
||||
return cntl, cm
|
||||
|
||||
|
||||
@ -1,101 +0,0 @@
|
||||
// Copyright (c) 2021 Proton Technologies AG
|
||||
//
|
||||
// This file is part of ProtonMail Bridge.Bridge.
|
||||
//
|
||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package context
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/internal/transfer"
|
||||
"github.com/ProtonMail/proton-bridge/test/mocks"
|
||||
)
|
||||
|
||||
// SetTransferProgress sets transfer progress.
|
||||
func (ctx *TestContext) SetTransferProgress(progress *transfer.Progress) {
|
||||
ctx.transferProgress = progress
|
||||
}
|
||||
|
||||
// GetTransferProgress returns transfer progress.
|
||||
func (ctx *TestContext) GetTransferProgress() *transfer.Progress {
|
||||
return ctx.transferProgress
|
||||
}
|
||||
|
||||
// SetTransferSkipEncryptedMessages sets whether encrypted messages will be skipped.
|
||||
func (ctx *TestContext) SetTransferSkipEncryptedMessages(value bool) {
|
||||
ctx.transferSkipEncryptedMessages = value
|
||||
}
|
||||
|
||||
// GetTransferSkipEncryptedMessages gets whether encrypted messages will be skipped.
|
||||
func (ctx *TestContext) GetTransferSkipEncryptedMessages() bool {
|
||||
return ctx.transferSkipEncryptedMessages
|
||||
}
|
||||
|
||||
// GetTransferLocalRootForImport creates temporary root for importing
|
||||
// if it not exists yet, and returns its path.
|
||||
func (ctx *TestContext) GetTransferLocalRootForImport() string {
|
||||
if ctx.transferLocalRootForImport != "" {
|
||||
return ctx.transferLocalRootForImport
|
||||
}
|
||||
root := ctx.createLocalRoot()
|
||||
ctx.transferLocalRootForImport = root
|
||||
return root
|
||||
}
|
||||
|
||||
// GetTransferLocalRootForExport creates temporary root for exporting
|
||||
// if it not exists yet, and returns its path.
|
||||
func (ctx *TestContext) GetTransferLocalRootForExport() string {
|
||||
if ctx.transferLocalRootForExport != "" {
|
||||
return ctx.transferLocalRootForExport
|
||||
}
|
||||
root := ctx.createLocalRoot()
|
||||
ctx.transferLocalRootForExport = root
|
||||
return root
|
||||
}
|
||||
|
||||
func (ctx *TestContext) createLocalRoot() string {
|
||||
root, err := ioutil.TempDir("", "transfer")
|
||||
if err != nil {
|
||||
panic("failed to create temp transfer root: " + err.Error())
|
||||
}
|
||||
|
||||
ctx.addCleanupChecked(func() error {
|
||||
return os.RemoveAll(root)
|
||||
}, "Cleaning transfer data")
|
||||
|
||||
return root
|
||||
}
|
||||
|
||||
// GetTransferRemoteIMAPServer creates mocked IMAP server if it not created yet, and returns it.
|
||||
func (ctx *TestContext) GetTransferRemoteIMAPServer() *mocks.IMAPServer {
|
||||
if ctx.transferRemoteIMAPServer != nil {
|
||||
return ctx.transferRemoteIMAPServer
|
||||
}
|
||||
|
||||
port := 21300 + rand.Intn(100) //nolint[gosec] It is OK to use weaker rand generator here
|
||||
ctx.transferRemoteIMAPServer = mocks.NewIMAPServer("user", "pass", "127.0.0.1", strconv.Itoa(port))
|
||||
|
||||
ctx.transferRemoteIMAPServer.Start()
|
||||
ctx.addCleanupChecked(func() error {
|
||||
ctx.transferRemoteIMAPServer.Stop()
|
||||
return nil
|
||||
}, "Cleaning transfer IMAP server")
|
||||
|
||||
return ctx.transferRemoteIMAPServer
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
Feature: Export to EML files
|
||||
Background:
|
||||
Given there is connected user "user"
|
||||
And there is "user" with mailbox "Folders/Foo"
|
||||
And there are messages in mailbox "INBOX" for "user"
|
||||
| from | to | subject | time |
|
||||
| bridgetest@pm.test | test@protonmail.com | hello | 2020-01-01T12:00:00 |
|
||||
And there are messages in mailbox "Folders/Foo" for "user"
|
||||
| from | to | subject | time |
|
||||
| foo@example.com | bridgetest@protonmail.com | one | 2020-01-01T12:00:00 |
|
||||
| bar@example.com | bridgetest@protonmail.com | two | 2020-01-01T13:00:00 |
|
||||
| bar@example.com | bridgetest@protonmail.com | three | 2020-01-01T12:30:00 |
|
||||
|
||||
Scenario: Export all
|
||||
When user "user" exports to EML files
|
||||
Then progress result is "OK"
|
||||
# Every message is also in All Mail.
|
||||
And transfer exported 8 messages
|
||||
And transfer imported 8 messages
|
||||
And transfer failed for 0 messages
|
||||
And transfer exported messages
|
||||
| folder | from | to | subject | time |
|
||||
| Inbox | bridgetest@pm.test | test@protonmail.com | hello | 2020-01-01T12:00:00 |
|
||||
| Foo | foo@example.com | bridgetest@protonmail.com | one | 2020-01-01T12:00:00 |
|
||||
| Foo | bar@example.com | bridgetest@protonmail.com | two | 2020-01-01T13:00:00 |
|
||||
| Foo | bar@example.com | bridgetest@protonmail.com | three | 2020-01-01T12:30:00 |
|
||||
| All Mail | bridgetest@pm.test | test@protonmail.com | hello | 2020-01-01T12:00:00 |
|
||||
| All Mail | foo@example.com | bridgetest@protonmail.com | one | 2020-01-01T12:00:00 |
|
||||
| All Mail | bar@example.com | bridgetest@protonmail.com | two | 2020-01-01T13:00:00 |
|
||||
| All Mail | bar@example.com | bridgetest@protonmail.com | three | 2020-01-01T12:30:00 |
|
||||
|
||||
Scenario: Export only Foo with time limit
|
||||
When user "user" exports to EML files with rules
|
||||
| source | target | from | to |
|
||||
| Foo | | 2020-01-01T12:10:00 | 2020-01-01T13:00:00 |
|
||||
Then progress result is "OK"
|
||||
And transfer exported 2 messages
|
||||
And transfer imported 2 messages
|
||||
And transfer failed for 0 messages
|
||||
And transfer exported messages
|
||||
| folder | from | to | subject | time |
|
||||
| Foo | bar@example.com | bridgetest@protonmail.com | two | 2020-01-01T13:00:00 |
|
||||
| Foo | bar@example.com | bridgetest@protonmail.com | three | 2020-01-01T12:30:00 |
|
||||
@ -1,43 +0,0 @@
|
||||
Feature: Export to MBOX files
|
||||
Background:
|
||||
Given there is connected user "user"
|
||||
And there is "user" with mailbox "Folders/Foo"
|
||||
And there are messages in mailbox "INBOX" for "user"
|
||||
| from | to | subject | time |
|
||||
| bridgetest@pm.test | test@protonmail.com | hello | 2020-01-01T12:00:00 |
|
||||
And there are messages in mailbox "Folders/Foo" for "user"
|
||||
| from | to | subject | time |
|
||||
| foo@example.com | bridgetest@protonmail.com | one | 2020-01-01T12:00:00 |
|
||||
| bar@example.com | bridgetest@protonmail.com | two | 2020-01-01T13:00:00 |
|
||||
| bar@example.com | bridgetest@protonmail.com | three | 2020-01-01T12:30:00 |
|
||||
|
||||
Scenario: Export all
|
||||
When user "user" exports to MBOX files
|
||||
Then progress result is "OK"
|
||||
# Every message is also in All Mail.
|
||||
And transfer exported 8 messages
|
||||
And transfer imported 8 messages
|
||||
And transfer failed for 0 messages
|
||||
And transfer exported messages
|
||||
| folder | from | to | subject | time |
|
||||
| Inbox | bridgetest@pm.test | test@protonmail.com | hello | 2020-01-01T12:00:00 |
|
||||
| Foo | foo@example.com | bridgetest@protonmail.com | one | 2020-01-01T12:00:00 |
|
||||
| Foo | bar@example.com | bridgetest@protonmail.com | two | 2020-01-01T13:00:00 |
|
||||
| Foo | bar@example.com | bridgetest@protonmail.com | three | 2020-01-01T12:30:00 |
|
||||
| All Mail | bridgetest@pm.test | test@protonmail.com | hello | 2020-01-01T12:00:00 |
|
||||
| All Mail | foo@example.com | bridgetest@protonmail.com | one | 2020-01-01T12:00:00 |
|
||||
| All Mail | bar@example.com | bridgetest@protonmail.com | two | 2020-01-01T13:00:00 |
|
||||
| All Mail | bar@example.com | bridgetest@protonmail.com | three | 2020-01-01T12:30:00 |
|
||||
|
||||
Scenario: Export only Foo with time limit
|
||||
When user "user" exports to MBOX files with rules
|
||||
| source | target | from | to |
|
||||
| Foo | | 2020-01-01T12:10:00 | 2020-01-01T13:00:00 |
|
||||
Then progress result is "OK"
|
||||
And transfer exported 2 messages
|
||||
And transfer imported 2 messages
|
||||
And transfer failed for 0 messages
|
||||
And transfer exported messages
|
||||
| folder | from | to | subject | time |
|
||||
| Foo | bar@example.com | bridgetest@protonmail.com | two | 2020-01-01T13:00:00 |
|
||||
| Foo | bar@example.com | bridgetest@protonmail.com | three | 2020-01-01T12:30:00 |
|
||||
@ -1,24 +0,0 @@
|
||||
Feature: Import from EML files
|
||||
Background:
|
||||
Given there is connected user "user"
|
||||
|
||||
Scenario: Import draft without from fallbacks to primary address
|
||||
Given there is EML file "Drafts/one.eml"
|
||||
"""
|
||||
Subject: no from yet
|
||||
To: Internal Bridge <test@protonmail.com>
|
||||
Received: by 2002:0:0:0:0:0:0:0 with SMTP id 0123456789abcdef; Wed, 30 Dec 2020 01:23:45 0000
|
||||
|
||||
hello
|
||||
|
||||
"""
|
||||
When user "user" imports local files with rules
|
||||
| source | target |
|
||||
| Drafts | Drafts |
|
||||
Then progress result is "OK"
|
||||
And transfer exported 1 messages
|
||||
And transfer imported 1 messages
|
||||
And transfer failed for 0 messages
|
||||
And API mailbox "Drafts" for "user" has messages
|
||||
| from | to | subject |
|
||||
| [userAddress] | test@protonmail.com | no from yet |
|
||||
@ -1,43 +0,0 @@
|
||||
Feature: Import embedded message
|
||||
Background:
|
||||
Given there is connected user "user"
|
||||
And there is EML file "Inbox/hello.eml"
|
||||
"""
|
||||
From: Foo <foo@example.com>
|
||||
To: Bridge Test <bridgetest@pm.test>
|
||||
Subject: Embedded message
|
||||
Content-Type: multipart/mixed; boundary="boundary"
|
||||
Received: by 2002:0:0:0:0:0:0:0 with SMTP id 0123456789abcdef; Wed, 30 Dec 2020 01:23:45 0000
|
||||
|
||||
This is a multi-part message in MIME format.
|
||||
--boundary
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
Content-Transfer-Encoding: 7bit
|
||||
|
||||
|
||||
--boundary
|
||||
Content-Type: message/rfc822; name="embedded.eml"
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Content-Disposition: attachment; filename="embedded.eml"
|
||||
|
||||
From: Bar <bar@example.com>
|
||||
To: Bridge Test <bridgetest@pm.test>
|
||||
Subject: (No Subject)
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
|
||||
hello
|
||||
|
||||
--boundary--
|
||||
|
||||
"""
|
||||
|
||||
Scenario: Import it
|
||||
When user "user" imports local files
|
||||
Then progress result is "OK"
|
||||
And transfer exported 1 messages
|
||||
And transfer imported 1 messages
|
||||
And transfer failed for 0 messages
|
||||
And API mailbox "INBOX" for "user" has messages
|
||||
| from | to | subject |
|
||||
| foo@example.com | bridgetest@pm.test | Embedded message |
|
||||
@ -1,61 +0,0 @@
|
||||
Feature: Import from EML files
|
||||
Background:
|
||||
Given there is connected user "user"
|
||||
And there is "user" with mailbox "Folders/Foo"
|
||||
And there is "user" with mailbox "Folders/Bar"
|
||||
And there are EML files
|
||||
| file | from | to | subject | time |
|
||||
| Foo/one.eml | foo@example.com | bridgetest@protonmail.com | one | 2020-01-01T12:00:00 |
|
||||
| Foo/two.eml | bar@example.com | bridgetest@protonmail.com | two | 2020-01-01T13:00:00 |
|
||||
| Sub/Foo/three.eml | bar@example.com | bridgetest@protonmail.com | three | 2020-01-01T12:30:00 |
|
||||
And there is EML file "Inbox/hello.eml"
|
||||
"""
|
||||
Subject: hello
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
To: Internal Bridge <test@protonmail.com>
|
||||
Received: by 2002:0:0:0:0:0:0:0 with SMTP id 0123456789abcdef; Wed, 30 Dec 2020 01:23:45 0000
|
||||
|
||||
hello
|
||||
|
||||
"""
|
||||
|
||||
Scenario: Import all
|
||||
When user "user" imports local files
|
||||
Then progress result is "OK"
|
||||
And transfer exported 4 messages
|
||||
And transfer imported 4 messages
|
||||
And transfer failed for 0 messages
|
||||
And API mailbox "INBOX" for "user" has messages
|
||||
| from | to | subject |
|
||||
| bridgetest@pm.test | test@protonmail.com | hello |
|
||||
And API mailbox "Folders/Foo" for "user" has messages
|
||||
| from | to | subject |
|
||||
| foo@example.com | bridgetest@protonmail.com | one |
|
||||
| bar@example.com | bridgetest@protonmail.com | two |
|
||||
| bar@example.com | bridgetest@protonmail.com | three |
|
||||
|
||||
Scenario: Import only Foo to Bar with time limit
|
||||
When user "user" imports local files with rules
|
||||
| source | target | from | to |
|
||||
| Foo | Bar | 2020-01-01T12:10:00 | 2020-01-01T13:00:00 |
|
||||
Then progress result is "OK"
|
||||
And transfer exported 2 messages
|
||||
And transfer imported 2 messages
|
||||
And transfer failed for 0 messages
|
||||
And API mailbox "Folders/Bar" for "user" has messages
|
||||
| from | to | subject |
|
||||
| bar@example.com | bridgetest@protonmail.com | two |
|
||||
| bar@example.com | bridgetest@protonmail.com | three |
|
||||
|
||||
Scenario: Import broken EML message
|
||||
Given there is EML file "Broken/broken.eml"
|
||||
"""
|
||||
Content-type: multipart/mixed
|
||||
"""
|
||||
When user "user" imports local files with rules
|
||||
| source | target |
|
||||
| Broken | Foo |
|
||||
Then progress result is "OK"
|
||||
And transfer exported 1 messages
|
||||
And transfer imported 0 messages
|
||||
And transfer failed for 1 messages
|
||||
@ -1,188 +0,0 @@
|
||||
Feature: Import from EML files
|
||||
Background:
|
||||
Given there is connected user "user"
|
||||
And there is EML file "Inbox/clear.eml"
|
||||
"""
|
||||
Subject: clear
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
To: Internal Bridge <test@protonmail.com>
|
||||
Received: by 2002:0:0:0:0:0:0:0 with SMTP id 0123456789abcdef; Wed, 30 Dec 2020 01:23:45 0000
|
||||
|
||||
secret
|
||||
"""
|
||||
And there is EML file "Inbox/encrypted.eml"
|
||||
"""
|
||||
Subject: encrypted
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
To: Internal Bridge <test@protonmail.com>
|
||||
Received: by 2002:0:0:0:0:0:0:0 with SMTP id 0123456789abcdef; Wed, 30 Dec 2020 01:23:45 0000
|
||||
|
||||
-----BEGIN PGP MESSAGE-----
|
||||
|
||||
hQEMA7hGUUsYs0fEAQgA10NwJSNTLm3vpxVtoYBaA9AjFI5H4hKuV3/f2NHbWb2s
|
||||
k5enK3tEIOYdFdrO+NLrV6weHq3Dgu4er3URTQ62tFwjSJyeXxmY0d9J+JdxibJg
|
||||
wqZubuSHYzQHpFqJgoUUWEVEsv0Ao8yQo8BE9iybCKoZf6KojROUuE748oxlxJnV
|
||||
m1XuaVIzgw4xN0GUA5sLLuWeL94b2dZe5SDDQE5POzDgueZ7faefX8U1pGErCRJ0
|
||||
sO6FSw3SF4NpvrxVESWgCmsG5pcuxE2JqB0UoHnNDcqsW8w1Q+GabAPo6UqHhgIg
|
||||
56MRCWeou2djHIIj9TMUIVFzSG/HvTYQWVS+i4Z7AdJJAXr53GgbZQznO80Qxwcb
|
||||
FFdlwOXHuaXqhqCb338jlQWnbcnUsuJWxBAxkHrlP/nluFqPdIBOglC38kdYSBed
|
||||
3YwuEB9sXV/fcw==
|
||||
=B05V
|
||||
-----END PGP MESSAGE-----
|
||||
"""
|
||||
And there is EML file "Inbox/encrypted-mime.eml"
|
||||
"""
|
||||
Subject: encrypted mime
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
To: Internal Bridge <test@protonmail.com>
|
||||
Received: by 2002:0:0:0:0:0:0:0 with SMTP id 0123456789abcdef; Wed, 30 Dec 2020 01:23:45 0000
|
||||
MIME-Version: 1.0
|
||||
Content-Type: multipart/encrypted; protocol="application/pgp-encrypted"; boundary="WLjzd46aUAiOcuNXjWTJItBZonI56MuAk"
|
||||
|
||||
--WLjzd46aUAiOcuNXjWTJItBZonI56MuAk
|
||||
Content-Type: application/pgp-encrypted
|
||||
Content-Description: PGP/MIME version identification
|
||||
|
||||
|
||||
--WLjzd46aUAiOcuNXjWTJItBZonI56MuAk
|
||||
Content-Type: application/octet-stream; name="encrypted.asc"
|
||||
Content-Description: OpenPGP encrypted message
|
||||
Content-Disposition: inline; filename="encrypted.asc"
|
||||
|
||||
-----BEGIN PGP MESSAGE-----
|
||||
|
||||
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
|
||||
=4M3l
|
||||
-----END PGP MESSAGE-----
|
||||
|
||||
--WLjzd46aUAiOcuNXjWTJItBZonI56MuAk--
|
||||
"""
|
||||
And there is EML file "Inbox/signed.eml"
|
||||
"""
|
||||
Subject: signed
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
To: Internal Bridge <test@protonmail.com>
|
||||
Received: by 2002:0:0:0:0:0:0:0 with SMTP id 0123456789abcdef; Wed, 30 Dec 2020 01:23:45 0000
|
||||
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA256
|
||||
|
||||
secret
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQEzBAEBCAAdFiEENaE2ZPemenI4pZah/SJcGo7SJWIFAl+cCAgACgkQ/SJcGo7S
|
||||
JWKsOQf/YakNXkMNjZIu8Hf1WflxtiDXVzTugOicC05k5W64oIqSHt0xNaFKE37k
|
||||
//3eDMWbHvqHKFVdg7qcLsVPeVBaW3bdZUiexGM24OiGgyEitufnHQLOtEDTound
|
||||
JyH5nUeHpvpBKIIOJZNBDM0HsRYnwKwrOWk3N2VRwog4J8J3cmJ/f9bPWNI/0OPT
|
||||
qmtVGRVg6Ge83nZn51Vof//jFzkO4wGYCsE0aF0Ywc7nISZuyKQzmu/qgmwzDG50
|
||||
PjpvIQ/ygisRPNdRlylXEqyoIDCQ+v0AnxhhwX/5dbt6xMuMMOxBrFSC94Zce1Vj
|
||||
x2ssXlT4ONPnkI/YWwhtQPLU628IMg==
|
||||
=GiS3
|
||||
-----END PGP SIGNATURE-----
|
||||
"""
|
||||
And there is EML file "Inbox/encrypted-signed.eml"
|
||||
"""
|
||||
Subject: encrypted and signed
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
To: Internal Bridge <test@protonmail.com>
|
||||
Received: by 2002:0:0:0:0:0:0:0 with SMTP id 0123456789abcdef; Wed, 30 Dec 2020 01:23:45 0000
|
||||
|
||||
-----BEGIN PGP MESSAGE-----
|
||||
|
||||
hQEMA7hGUUsYs0fEAQf/dppHciWIf+o4l0gEfHeyHV/HVhG4es0aVQYrwFQlSWVx
|
||||
estMuyLBSMfrsQXLago7Q9ZNo/XnKszzprCXxxYH52hAg64oAsjKB3jgRmVizs8b
|
||||
8lj0BRf003wUluS/0msV9SiEZBGeL8jGq6Te9vaM8OHHhIVzVjGnRdTSC0jBE6cS
|
||||
vy8IBHXYe0LfdZiPojPDPGQdSej+H3uu7eZGBvVHTDeQLPDel4k7Ykdr0qlNXs6O
|
||||
5XpM5YG4w+t0aG+YROPH+BUj8PpPojQ/lrv/yFISTRbHlEd8N50w8BNTnBet+9Vm
|
||||
oPcyvN+RQxBlvRuPpDjUmREvmtObKZV6+m6gocemx9LAzQEeVLcpjO/hJhl8gX72
|
||||
MNz3McU7aXf5sSoOPdHDNx8T2NON/2bwG5FE+PRMuVywTKhCB7o8VAsJpGMQ8xRM
|
||||
5WCNhow0AI7kni8yZA+GbvspnJWfit9tCTR5MIFHCSH9J3kJJnWkxQSN04GGpBcd
|
||||
n43GWn7O7ufA4lMMZiGXMdi/J1iV9waAsIfMPk29BMq6xK0/jJYdHqQS+vNsSnF5
|
||||
xL/Ir4RYq4SFFA06A/E7HpXr2ruZhBQCkzaIIdrVJR/Lp2VLJIVulTBQK8y2AFtj
|
||||
JeeKS0kIuC/7UPF2O624kwNr8dmIhDJYusFs6ZeED/nAKwDO/vP2CSwVC3sUjn3N
|
||||
u+sWqQUTxSmjhRVf9b0+VyTh0mXCovJQXomL6Zz6lxXuJqqzELIOfCxYD1z9GwTG
|
||||
cT08Aa2eEpf3agdLCTxvjO3iq9FksMHvIN+LSCQ6Pw+aTByjrk0oMmvGbANAogTk
|
||||
yrplG/iRVlmq0p/Cfl5UEjKqT/nt5j9zbpeuYXmhjiBT9SBE07oUVLY1VT7ihcY=
|
||||
=qYnL
|
||||
-----END PGP MESSAGE-----
|
||||
"""
|
||||
|
||||
Scenario: Import encrypted
|
||||
Given there is skip encrypted messages set to "false"
|
||||
When user "user" imports local files
|
||||
Then progress result is "OK"
|
||||
And transfer failed for 0 messages
|
||||
And transfer exported 5 messages
|
||||
And transfer imported 5 messages
|
||||
And transfer skipped 0 messages
|
||||
And API mailbox "INBOX" for "user" has messages
|
||||
| from | to | subject |
|
||||
| bridgetest@pm.test | test@protonmail.com | clear |
|
||||
| bridgetest@pm.test | test@protonmail.com | encrypted |
|
||||
| bridgetest@pm.test | test@protonmail.com | encrypted mime |
|
||||
| bridgetest@pm.test | test@protonmail.com | signed |
|
||||
| bridgetest@pm.test | test@protonmail.com | encrypted and signed |
|
||||
|
||||
Scenario: Skip encrypted
|
||||
Given there is skip encrypted messages set to "true"
|
||||
When user "user" imports local files
|
||||
Then progress result is "OK"
|
||||
And transfer failed for 0 messages
|
||||
And transfer exported 5 messages
|
||||
And transfer imported 2 messages
|
||||
And transfer skipped 3 messages
|
||||
And API mailbox "INBOX" for "user" has messages
|
||||
| from | to | subject |
|
||||
| bridgetest@pm.test | test@protonmail.com | clear |
|
||||
| bridgetest@pm.test | test@protonmail.com | signed |
|
||||
@ -1,49 +0,0 @@
|
||||
Feature: Import-Export app
|
||||
Background:
|
||||
Given there is connected user "user"
|
||||
And there is "user" with mailbox "Folders/Foo"
|
||||
And there is "user" with mailbox "Folders/Bar"
|
||||
|
||||
Scenario: EML -> PM -> EML
|
||||
Given there are EML files
|
||||
| file | from | to | subject | time |
|
||||
| Inbox/hello.eml | bridgetest@pm.test | test@protonmail.com | hello | 2020-01-01T12:00:00 |
|
||||
| Foo/one.eml | foo@example.com | bridgetest@protonmail.com | one | 2020-01-01T12:00:00 |
|
||||
| Foo/two.eml | bar@example.com | bridgetest@protonmail.com | two | 2020-01-01T13:00:00 |
|
||||
| Sub/Foo/three.eml | bar@example.com | bridgetest@protonmail.com | three | 2020-01-01T12:30:00 |
|
||||
|
||||
When user "user" imports local files
|
||||
Then progress result is "OK"
|
||||
And transfer failed for 0 messages
|
||||
And transfer imported 4 messages
|
||||
|
||||
When user "user" exports to EML files
|
||||
Then progress result is "OK"
|
||||
And transfer failed for 0 messages
|
||||
# Every message is also in All Mail.
|
||||
And transfer imported 8 messages
|
||||
|
||||
And exported messages match the original ones
|
||||
|
||||
Scenario: MBOX -> PM -> MBOX
|
||||
Given there is MBOX file "Inbox.mbox" with messages
|
||||
| from | to | subject | time |
|
||||
| bridgetest@pm.test | test@protonmail.com | hello | 2020-01-01T12:00:00 |
|
||||
And there is MBOX file "Foo.mbox" with messages
|
||||
| from | to | subject | time |
|
||||
| foo@example.com | bridgetest@protonmail.com | one | 2020-01-01T12:00:00 |
|
||||
| bar@example.com | bridgetest@protonmail.com | two | 2020-01-01T13:00:00 |
|
||||
| bar@example.com | bridgetest@protonmail.com | three | 2020-01-01T12:30:00 |
|
||||
|
||||
When user "user" imports local files
|
||||
Then progress result is "OK"
|
||||
And transfer failed for 0 messages
|
||||
And transfer imported 4 messages
|
||||
|
||||
When user "user" exports to MBOX files
|
||||
Then progress result is "OK"
|
||||
And transfer failed for 0 messages
|
||||
# Every message is also in All Mail.
|
||||
And transfer imported 8 messages
|
||||
|
||||
And exported messages match the original ones
|
||||
@ -1,80 +0,0 @@
|
||||
Feature: Import from IMAP server
|
||||
Background:
|
||||
Given there is connected user "user"
|
||||
And there is "user" with mailbox "Folders/Foo"
|
||||
And there is "user" with mailbox "Folders/Bar"
|
||||
And there are IMAP mailboxes
|
||||
| name |
|
||||
| Inbox |
|
||||
| Foo |
|
||||
| Broken |
|
||||
And there are IMAP messages
|
||||
| mailbox | seqnum | uid | from | to | subject | time |
|
||||
| Foo | 1 | 12 | foo@example.com | bridgetest@protonmail.com | one | 2020-01-01T12:00:00 |
|
||||
| Foo | 2 | 14 | bar@example.com | bridgetest@protonmail.com | two | 2020-01-01T13:00:00 |
|
||||
| Foo | 3 | 15 | bar@example.com | bridgetest@protonmail.com | three | 2020-01-01T12:30:00 |
|
||||
And there is IMAP message in mailbox "Inbox" with seq 1, uid 42, time "2020-01-01T12:34:56" and subject "hello"
|
||||
"""
|
||||
Subject: hello
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
To: Internal Bridge <test@protonmail.com>
|
||||
Received: by 2002:0:0:0:0:0:0:0 with SMTP id 0123456789abcdef; Wed, 30 Dec 2020 01:23:45 0000
|
||||
|
||||
hello
|
||||
|
||||
"""
|
||||
|
||||
Scenario: Import all
|
||||
When user "user" imports remote messages
|
||||
Then progress result is "OK"
|
||||
And transfer exported 4 messages
|
||||
And transfer imported 4 messages
|
||||
And transfer failed for 0 messages
|
||||
And API mailbox "INBOX" for "user" has messages
|
||||
| from | to | subject |
|
||||
| bridgetest@pm.test | test@protonmail.com | hello |
|
||||
And API mailbox "Folders/Foo" for "user" has messages
|
||||
| from | to | subject |
|
||||
| foo@example.com | bridgetest@protonmail.com | one |
|
||||
| bar@example.com | bridgetest@protonmail.com | two |
|
||||
| bar@example.com | bridgetest@protonmail.com | three |
|
||||
|
||||
Scenario: Import only Foo to Bar with time limit
|
||||
When user "user" imports remote messages with rules
|
||||
| source | target | from | to |
|
||||
| Foo | Bar | 2020-01-01T12:10:00 | 2020-01-01T13:00:00 |
|
||||
Then progress result is "OK"
|
||||
And transfer exported 2 messages
|
||||
And transfer imported 2 messages
|
||||
And transfer failed for 0 messages
|
||||
And API mailbox "Folders/Bar" for "user" has messages
|
||||
| from | to | subject |
|
||||
| bar@example.com | bridgetest@protonmail.com | two |
|
||||
| bar@example.com | bridgetest@protonmail.com | three |
|
||||
|
||||
# Note we need to have message which we can parse and use in go-imap
|
||||
# but which has problem on our side. Used example with missing boundary
|
||||
# is real example which we want to solve one day. Probabl this test
|
||||
# can be removed once we import any time of message or switch is to
|
||||
# something we will never allow.
|
||||
Scenario: Import broken message
|
||||
Given there is IMAP message in mailbox "Broken" with seq 1, uid 42, time "2020-01-01T12:34:56" and subject "broken"
|
||||
"""
|
||||
Subject: missing boundary end
|
||||
Content-Type: multipart/related; boundary=boundary
|
||||
|
||||
--boundary
|
||||
Content-Disposition: inline
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
|
||||
body
|
||||
|
||||
"""
|
||||
When user "user" imports remote messages with rules
|
||||
| source | target |
|
||||
| Broken | Foo |
|
||||
Then progress result is "OK"
|
||||
And transfer exported 1 messages
|
||||
And transfer imported 0 messages
|
||||
And transfer failed for 1 messages
|
||||
@ -1,65 +0,0 @@
|
||||
Feature: Import from MBOX files
|
||||
Background:
|
||||
Given there is connected user "user"
|
||||
And there is "user" with mailbox "Folders/Foo"
|
||||
And there is "user" with mailbox "Folders/Bar"
|
||||
And there is MBOX file "Foo.mbox" with messages
|
||||
| from | to | subject | time |
|
||||
| foo@example.com | bridgetest@protonmail.com | one | 2020-01-01T12:00:00 |
|
||||
| bar@example.com | bridgetest@protonmail.com | two | 2020-01-01T13:00:00 |
|
||||
And there is MBOX file "Sub/Foo.mbox" with messages
|
||||
| from | to | subject | time |
|
||||
| bar@example.com | bridgetest@protonmail.com | three | 2020-01-01T12:30:00 |
|
||||
And there is MBOX file "Inbox.mbox"
|
||||
"""
|
||||
From bridgetest@pm.test Thu Feb 20 20:20:20 2020
|
||||
Subject: hello
|
||||
From: Bridge Test <bridgetest@pm.test>
|
||||
To: Internal Bridge <test@protonmail.com>
|
||||
Received: by 2002:0:0:0:0:0:0:0 with SMTP id 0123456789abcdef; Wed, 30 Dec 2020 01:23:45 0000
|
||||
|
||||
hello
|
||||
|
||||
"""
|
||||
|
||||
Scenario: Import all
|
||||
When user "user" imports local files
|
||||
Then progress result is "OK"
|
||||
And transfer exported 4 messages
|
||||
And transfer imported 4 messages
|
||||
And transfer failed for 0 messages
|
||||
And API mailbox "INBOX" for "user" has messages
|
||||
| from | to | subject |
|
||||
| bridgetest@pm.test | test@protonmail.com | hello |
|
||||
And API mailbox "Folders/Foo" for "user" has messages
|
||||
| from | to | subject |
|
||||
| foo@example.com | bridgetest@protonmail.com | one |
|
||||
| bar@example.com | bridgetest@protonmail.com | two |
|
||||
| bar@example.com | bridgetest@protonmail.com | three |
|
||||
|
||||
Scenario: Import only Foo to Bar with time limit
|
||||
When user "user" imports local files with rules
|
||||
| source | target | from | to |
|
||||
| Foo | Bar | 2020-01-01T12:10:00 | 2020-01-01T13:00:00 |
|
||||
Then progress result is "OK"
|
||||
And transfer exported 2 messages
|
||||
And transfer imported 2 messages
|
||||
And transfer failed for 0 messages
|
||||
And API mailbox "Folders/Bar" for "user" has messages
|
||||
| from | to | subject |
|
||||
| bar@example.com | bridgetest@protonmail.com | two |
|
||||
| bar@example.com | bridgetest@protonmail.com | three |
|
||||
|
||||
Scenario: Import broken message
|
||||
Given there is MBOX file "Broken.mbox"
|
||||
"""
|
||||
From bridgetest@pm.test Thu Feb 20 20:20:20 2020
|
||||
Content-type: multipart/mixed
|
||||
"""
|
||||
When user "user" imports local files with rules
|
||||
| source | target |
|
||||
| Broken | Foo |
|
||||
Then progress result is "OK"
|
||||
And transfer exported 1 messages
|
||||
And transfer imported 0 messages
|
||||
And transfer failed for 1 messages
|
||||
@ -1,98 +0,0 @@
|
||||
Feature: Import to sent
|
||||
Background:
|
||||
Given there is connected user "user"
|
||||
And there is "user" with mailbox "Labels/label"
|
||||
And there is EML file "Sent/one.eml"
|
||||
"""
|
||||
Subject: one
|
||||
From: Foo <foo@example.com>
|
||||
To: Bridge Test <bridgetest@pm.test>
|
||||
Message-ID: one.integrationtest
|
||||
|
||||
one
|
||||
|
||||
"""
|
||||
And there is EML file "Sent/two.eml"
|
||||
"""
|
||||
Subject: two
|
||||
From: Bar <bar@example.com>
|
||||
To: Bridge Test <bridgetest@pm.test>
|
||||
Message-ID: two.integrationtest
|
||||
|
||||
two
|
||||
|
||||
"""
|
||||
|
||||
Scenario: Import sent only
|
||||
When user "user" imports local files
|
||||
Then progress result is "OK"
|
||||
And transfer exported 2 messages
|
||||
And transfer imported 2 messages
|
||||
And transfer failed for 0 messages
|
||||
And API mailbox "INBOX" for "user" has 0 message
|
||||
And API mailbox "Sent" for "user" has messages
|
||||
| from | to | subject |
|
||||
| foo@example.com | bridgetest@pm.test | one |
|
||||
| bar@example.com | bridgetest@pm.test | two |
|
||||
|
||||
# Messages imported to label only are added automatically to Archive folder.
|
||||
# Then it depends on the order: if the message is first imported to Sent
|
||||
# folder and later to that label with importing to Archive, message will not
|
||||
# be in Sent but Archive. The order is semi-random for the big messages,
|
||||
# e.g., it will do alphabetical order of mailboxes, but for under ten small
|
||||
# messages the order is random every time (because we are importing in
|
||||
# batches of up to ten messages and iterating through map we use to collect
|
||||
# messages is random). So we cannot for this test ensure the same output
|
||||
# every time.
|
||||
@ignore-live
|
||||
Scenario: Import to sent and custom label
|
||||
And there is EML file "Label/one.eml"
|
||||
"""
|
||||
Subject: one
|
||||
From: Foo <foo@example.com>
|
||||
To: Bridge Test <bridgetest@pm.test>
|
||||
Message-ID: one.integrationtest
|
||||
|
||||
one
|
||||
|
||||
"""
|
||||
When user "user" imports local files
|
||||
Then progress result is "OK"
|
||||
And transfer exported 3 messages
|
||||
And transfer imported 3 messages
|
||||
And transfer failed for 0 messages
|
||||
# We had an issue that moving message to Sent automatically added
|
||||
# the message also into Inbox if the message was in some custom label.
|
||||
And API mailbox "INBOX" for "user" has 0 message
|
||||
And API mailbox "Labels/label" for "user" has messages
|
||||
| from | to | subject |
|
||||
| foo@example.com | bridgetest@pm.test | one |
|
||||
And API mailbox "Sent" for "user" has messages
|
||||
| from | to | subject |
|
||||
| foo@example.com | bridgetest@pm.test | one |
|
||||
| bar@example.com | bridgetest@pm.test | two |
|
||||
|
||||
Scenario: Import to sent and inbox is in both mailboxes
|
||||
And there is EML file "Inbox/one.eml"
|
||||
"""
|
||||
Subject: one
|
||||
From: Foo <foo@example.com>
|
||||
To: Bridge Test <bridgetest@pm.test>
|
||||
Message-ID: one.integrationtest
|
||||
Received: by 2002:0:0:0:0:0:0:0 with SMTP id 0123456789abcdef; Wed, 30 Dec 2020 01:23:45 0000
|
||||
|
||||
one
|
||||
|
||||
"""
|
||||
When user "user" imports local files
|
||||
Then progress result is "OK"
|
||||
And transfer exported 3 messages
|
||||
And transfer imported 3 messages
|
||||
And transfer failed for 0 messages
|
||||
And API mailbox "INBOX" for "user" has messages
|
||||
| from | to | subject |
|
||||
| foo@example.com | bridgetest@pm.test | one |
|
||||
And API mailbox "Sent" for "user" has messages
|
||||
| from | to | subject |
|
||||
| foo@example.com | bridgetest@pm.test | one |
|
||||
| bar@example.com | bridgetest@pm.test | two |
|
||||
@ -1,20 +0,0 @@
|
||||
Feature: Delete user
|
||||
Scenario: Deleting connected user
|
||||
Given there is connected user "user"
|
||||
When user deletes "user"
|
||||
Then last response is "OK"
|
||||
|
||||
Scenario: Deleting connected user with cache
|
||||
Given there is connected user "user"
|
||||
When user deletes "user" with cache
|
||||
Then last response is "OK"
|
||||
|
||||
Scenario: Deleting disconnected user
|
||||
Given there is disconnected user "user"
|
||||
When user deletes "user"
|
||||
Then last response is "OK"
|
||||
|
||||
Scenario: Deleting disconnected user with cache
|
||||
Given there is disconnected user "user"
|
||||
When user deletes "user" with cache
|
||||
Then last response is "OK"
|
||||
@ -1,58 +0,0 @@
|
||||
Feature: Login for the first time
|
||||
Scenario: Normal login
|
||||
Given there is user "user"
|
||||
When "user" logs in
|
||||
Then last response is "OK"
|
||||
And "user" is connected
|
||||
|
||||
@ignore-live
|
||||
Scenario: Login with bad username
|
||||
When "user" logs in with bad password
|
||||
Then last response is "failed to login: Incorrect login credentials. Please try again"
|
||||
|
||||
@ignore-live
|
||||
Scenario: Login with bad password
|
||||
Given there is user "user"
|
||||
When "user" logs in with bad password
|
||||
Then last response is "failed to login: Incorrect login credentials. Please try again"
|
||||
|
||||
Scenario: Login without internet connection
|
||||
Given there is no internet connection
|
||||
When "user" logs in
|
||||
Then last response is "failed to login: no internet connection"
|
||||
|
||||
@ignore-live
|
||||
Scenario: Login user with 2FA
|
||||
Given there is user "user2fa"
|
||||
When "user2fa" logs in
|
||||
Then last response is "OK"
|
||||
And "user2fa" is connected
|
||||
|
||||
Scenario: Login user with capital letters in address
|
||||
Given there is user "userAddressWithCapitalLetter"
|
||||
When "userAddressWithCapitalLetter" logs in
|
||||
Then last response is "OK"
|
||||
And "userAddressWithCapitalLetter" is connected
|
||||
|
||||
Scenario: Login user with more addresses
|
||||
Given there is user "userMoreAddresses"
|
||||
When "userMoreAddresses" logs in
|
||||
Then last response is "OK"
|
||||
And "userMoreAddresses" is connected
|
||||
|
||||
@ignore-live
|
||||
Scenario: Login user with disabled primary address
|
||||
Given there is user "userDisabledPrimaryAddress"
|
||||
When "userDisabledPrimaryAddress" logs in
|
||||
Then last response is "OK"
|
||||
And "userDisabledPrimaryAddress" is connected
|
||||
|
||||
Scenario: Login two users
|
||||
Given there is user "user"
|
||||
And there is user "userMoreAddresses"
|
||||
When "user" logs in
|
||||
Then last response is "OK"
|
||||
And "user" is connected
|
||||
When "userMoreAddresses" logs in
|
||||
Then last response is "OK"
|
||||
And "userMoreAddresses" is connected
|
||||
@ -1,12 +0,0 @@
|
||||
Feature: Re-login
|
||||
Scenario: Re-login with connected user
|
||||
Given there is connected user "user"
|
||||
When "user" logs in
|
||||
Then last response is "failed to finish login: user is already connected"
|
||||
And "user" is connected
|
||||
|
||||
Scenario: Re-login with disconnected user
|
||||
Given there is disconnected user "user"
|
||||
When "user" logs in
|
||||
Then last response is "OK"
|
||||
And "user" is connected
|
||||
30
test/features/no_internet.feature
Normal file
30
test/features/no_internet.feature
Normal file
@ -0,0 +1,30 @@
|
||||
Feature: Servers are closed when no internet
|
||||
|
||||
Scenario: All connection are closed and then restored multiple times
|
||||
Given there is connected user "user"
|
||||
And there is IMAP client "i1" logged in as "user"
|
||||
And there is SMTP client "s1" logged in as "user"
|
||||
When there is no internet connection
|
||||
And 1 second pass
|
||||
Then IMAP client "i1" is logged out
|
||||
And SMTP client "s1" is logged out
|
||||
Given the internet connection is restored
|
||||
And 1 second pass
|
||||
And there is IMAP client "i2" logged in as "user"
|
||||
And there is SMTP client "s2" logged in as "user"
|
||||
When IMAP client "i2" gets info of "INBOX"
|
||||
When SMTP client "s2" sends "HELO example.com"
|
||||
Then IMAP response to "i2" is "OK"
|
||||
Then SMTP response to "s2" is "OK"
|
||||
When there is no internet connection
|
||||
And 1 second pass
|
||||
Then IMAP client "i2" is logged out
|
||||
And SMTP client "s2" is logged out
|
||||
Given the internet connection is restored
|
||||
And 1 second pass
|
||||
And there is IMAP client "i3" logged in as "user"
|
||||
And there is SMTP client "s3" logged in as "user"
|
||||
When IMAP client "i3" gets info of "INBOX"
|
||||
When SMTP client "s3" sends "HELO example.com"
|
||||
Then IMAP response to "i3" is "OK"
|
||||
Then SMTP response to "s3" is "OK"
|
||||
@ -38,7 +38,7 @@ type Controller struct {
|
||||
noInternetConnection bool
|
||||
}
|
||||
|
||||
func NewController(_ string) (*Controller, pmapi.Manager) {
|
||||
func NewController() (*Controller, pmapi.Manager) {
|
||||
controller := &Controller{
|
||||
log: logrus.WithField("pkg", "live-controller"),
|
||||
lock: &sync.RWMutex{},
|
||||
|
||||
@ -1,227 +0,0 @@
|
||||
// Copyright (c) 2021 Proton Technologies AG
|
||||
//
|
||||
// This file is part of ProtonMail Bridge.Bridge.
|
||||
//
|
||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package tests
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/internal/transfer"
|
||||
"github.com/cucumber/godog"
|
||||
)
|
||||
|
||||
func TransferActionsFeatureContext(s *godog.ScenarioContext) {
|
||||
s.Step(`^user "([^"]*)" imports local files$`, userImportsLocalFiles)
|
||||
s.Step(`^user "([^"]*)" imports local files with rules$`, userImportsLocalFilesWithRules)
|
||||
s.Step(`^user "([^"]*)" imports local files to address "([^"]*)"$`, userImportsLocalFilesToAddress)
|
||||
s.Step(`^user "([^"]*)" imports local files to address "([^"]*)" with rules$`, userImportsLocalFilesToAddressWithRules)
|
||||
s.Step(`^user "([^"]*)" imports remote messages$`, userImportsRemoteMessages)
|
||||
s.Step(`^user "([^"]*)" imports remote messages with rules$`, userImportsRemoteMessagesWithRules)
|
||||
s.Step(`^user "([^"]*)" imports remote messages to address "([^"]*)"$`, userImportsRemoteMessagesToAddress)
|
||||
s.Step(`^user "([^"]*)" imports remote messages to address "([^"]*)" with rules$`, userImportsRemoteMessagesToAddressWithRules)
|
||||
s.Step(`^user "([^"]*)" exports to EML files$`, userExportsToEMLFiles)
|
||||
s.Step(`^user "([^"]*)" exports to EML files with rules$`, userExportsToEMLFilesWithRules)
|
||||
s.Step(`^user "([^"]*)" exports address "([^"]*)" to EML files$`, userExportsAddressToEMLFiles)
|
||||
s.Step(`^user "([^"]*)" exports address "([^"]*)" to EML files with rules$`, userExportsAddressToEMLFilesWithRules)
|
||||
s.Step(`^user "([^"]*)" exports to MBOX files$`, userExportsToMBOXFiles)
|
||||
s.Step(`^user "([^"]*)" exports to MBOX files with rules$`, userExportsToMBOXFilesWithRules)
|
||||
s.Step(`^user "([^"]*)" exports address "([^"]*)" to MBOX files$`, userExportsAddressToMBOXFiles)
|
||||
s.Step(`^user "([^"]*)" exports address "([^"]*)" to MBOX files with rules$`, userExportsAddressToMBOXFilesWithRules)
|
||||
}
|
||||
|
||||
// Local import.
|
||||
|
||||
func userImportsLocalFiles(bddUserID string) error {
|
||||
return userImportsLocalFilesToAddressWithRules(bddUserID, "", nil)
|
||||
}
|
||||
|
||||
func userImportsLocalFilesWithRules(bddUserID string, rules *godog.Table) error {
|
||||
return userImportsLocalFilesToAddressWithRules(bddUserID, "", rules)
|
||||
}
|
||||
|
||||
func userImportsLocalFilesToAddress(bddUserID, bddAddressID string) error {
|
||||
return userImportsLocalFilesToAddressWithRules(bddUserID, bddAddressID, nil)
|
||||
}
|
||||
|
||||
func userImportsLocalFilesToAddressWithRules(bddUserID, bddAddressID string, rules *godog.Table) error {
|
||||
return doTransfer(bddUserID, bddAddressID, rules, func(username, address string) (*transfer.Transfer, error) {
|
||||
path := ctx.GetTransferLocalRootForImport()
|
||||
return ctx.GetImportExport().GetLocalImporter(username, address, path)
|
||||
})
|
||||
}
|
||||
|
||||
// Remote import.
|
||||
|
||||
func userImportsRemoteMessages(bddUserID string) error {
|
||||
return userImportsRemoteMessagesToAddressWithRules(bddUserID, "", nil)
|
||||
}
|
||||
|
||||
func userImportsRemoteMessagesWithRules(bddUserID string, rules *godog.Table) error {
|
||||
return userImportsRemoteMessagesToAddressWithRules(bddUserID, "", rules)
|
||||
}
|
||||
|
||||
func userImportsRemoteMessagesToAddress(bddUserID, bddAddressID string) error {
|
||||
return userImportsRemoteMessagesToAddressWithRules(bddUserID, bddAddressID, nil)
|
||||
}
|
||||
|
||||
func userImportsRemoteMessagesToAddressWithRules(bddUserID, bddAddressID string, rules *godog.Table) error {
|
||||
return doTransfer(bddUserID, bddAddressID, rules, func(username, address string) (*transfer.Transfer, error) {
|
||||
imapServer := ctx.GetTransferRemoteIMAPServer()
|
||||
return ctx.GetImportExport().GetRemoteImporter(username, address, imapServer.Username, imapServer.Password, imapServer.Host, imapServer.Port)
|
||||
})
|
||||
}
|
||||
|
||||
// EML export.
|
||||
|
||||
func userExportsToEMLFiles(bddUserID string) error {
|
||||
return userExportsAddressToEMLFilesWithRules(bddUserID, "", nil)
|
||||
}
|
||||
|
||||
func userExportsToEMLFilesWithRules(bddUserID string, rules *godog.Table) error {
|
||||
return userExportsAddressToEMLFilesWithRules(bddUserID, "", rules)
|
||||
}
|
||||
|
||||
func userExportsAddressToEMLFiles(bddUserID, bddAddressID string) error {
|
||||
return userExportsAddressToEMLFilesWithRules(bddUserID, bddAddressID, nil)
|
||||
}
|
||||
|
||||
func userExportsAddressToEMLFilesWithRules(bddUserID, bddAddressID string, rules *godog.Table) error {
|
||||
return doTransfer(bddUserID, bddAddressID, rules, func(username, address string) (*transfer.Transfer, error) {
|
||||
path := ctx.GetTransferLocalRootForExport()
|
||||
return ctx.GetImportExport().GetEMLExporter(username, address, path)
|
||||
})
|
||||
}
|
||||
|
||||
// MBOX export.
|
||||
|
||||
func userExportsToMBOXFiles(bddUserID string) error {
|
||||
return userExportsAddressToMBOXFilesWithRules(bddUserID, "", nil)
|
||||
}
|
||||
|
||||
func userExportsToMBOXFilesWithRules(bddUserID string, rules *godog.Table) error {
|
||||
return userExportsAddressToMBOXFilesWithRules(bddUserID, "", rules)
|
||||
}
|
||||
|
||||
func userExportsAddressToMBOXFiles(bddUserID, bddAddressID string) error {
|
||||
return userExportsAddressToMBOXFilesWithRules(bddUserID, bddAddressID, nil)
|
||||
}
|
||||
|
||||
func userExportsAddressToMBOXFilesWithRules(bddUserID, bddAddressID string, rules *godog.Table) error {
|
||||
return doTransfer(bddUserID, bddAddressID, rules, func(username, address string) (*transfer.Transfer, error) {
|
||||
path := ctx.GetTransferLocalRootForExport()
|
||||
return ctx.GetImportExport().GetMBOXExporter(username, address, path)
|
||||
})
|
||||
}
|
||||
|
||||
// Helpers.
|
||||
|
||||
func doTransfer(bddUserID, bddAddressID string, rules *godog.Table, getTransferrer func(string, string) (*transfer.Transfer, error)) error {
|
||||
account := ctx.GetTestAccountWithAddress(bddUserID, bddAddressID)
|
||||
if account == nil {
|
||||
return godog.ErrPending
|
||||
}
|
||||
transferrer, err := getTransferrer(account.Username(), account.Address())
|
||||
if err != nil {
|
||||
return internalError(err, "failed to init transfer")
|
||||
}
|
||||
if err := setRules(transferrer, rules); err != nil {
|
||||
return internalError(err, "failed to set rules")
|
||||
}
|
||||
transferrer.SetSkipEncryptedMessages(ctx.GetTransferSkipEncryptedMessages())
|
||||
progress := transferrer.Start()
|
||||
ctx.SetTransferProgress(progress)
|
||||
return nil
|
||||
}
|
||||
|
||||
func setRules(transferrer *transfer.Transfer, rules *godog.Table) error {
|
||||
if rules == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
transferrer.ResetRules()
|
||||
|
||||
allSourceMailboxes, err := transferrer.SourceMailboxes()
|
||||
if err != nil {
|
||||
return internalError(err, "failed to get source mailboxes")
|
||||
}
|
||||
allTargetMailboxes, err := transferrer.TargetMailboxes()
|
||||
if err != nil {
|
||||
return internalError(err, "failed to get target mailboxes")
|
||||
}
|
||||
|
||||
head := rules.Rows[0].Cells
|
||||
for _, row := range rules.Rows[1:] {
|
||||
source := ""
|
||||
target := ""
|
||||
fromTime := int64(0)
|
||||
toTime := int64(0)
|
||||
for n, cell := range row.Cells {
|
||||
switch head[n].Value {
|
||||
case "source":
|
||||
source = cell.Value
|
||||
case "target":
|
||||
target = cell.Value
|
||||
case "from":
|
||||
date, err := time.Parse(timeFormat, cell.Value)
|
||||
if err != nil {
|
||||
return internalError(err, "failed to parse from time")
|
||||
}
|
||||
fromTime = date.Unix()
|
||||
case "to":
|
||||
date, err := time.Parse(timeFormat, cell.Value)
|
||||
if err != nil {
|
||||
return internalError(err, "failed to parse to time")
|
||||
}
|
||||
toTime = date.Unix()
|
||||
default:
|
||||
return fmt.Errorf("unexpected column name: %s", head[n].Value)
|
||||
}
|
||||
}
|
||||
|
||||
sourceMailbox, err := getMailboxByName(allSourceMailboxes, source)
|
||||
if err != nil {
|
||||
return internalError(err, "failed to match source mailboxes")
|
||||
}
|
||||
|
||||
// Empty target means the same as source. Useful for exports.
|
||||
targetMailboxes := []transfer.Mailbox{}
|
||||
if target == "" {
|
||||
targetMailboxes = append(targetMailboxes, sourceMailbox)
|
||||
} else {
|
||||
targetMailbox, err := getMailboxByName(allTargetMailboxes, target)
|
||||
if err != nil {
|
||||
return internalError(err, "failed to match target mailboxes")
|
||||
}
|
||||
targetMailboxes = append(targetMailboxes, targetMailbox)
|
||||
}
|
||||
|
||||
if err := transferrer.SetRule(sourceMailbox, targetMailboxes, fromTime, toTime); err != nil {
|
||||
return internalError(err, "failed to set rule")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getMailboxByName(mailboxes []transfer.Mailbox, name string) (transfer.Mailbox, error) {
|
||||
for _, mailbox := range mailboxes {
|
||||
if mailbox.Name == name {
|
||||
return mailbox, nil
|
||||
}
|
||||
}
|
||||
return transfer.Mailbox{}, fmt.Errorf("mailbox %s not found", name)
|
||||
}
|
||||
@ -1,277 +0,0 @@
|
||||
// Copyright (c) 2021 Proton Technologies AG
|
||||
//
|
||||
// This file is part of ProtonMail Bridge.Bridge.
|
||||
//
|
||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package tests
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ProtonMail/go-rfc5322"
|
||||
"github.com/cucumber/godog"
|
||||
"github.com/emersion/go-mbox"
|
||||
"github.com/emersion/go-message"
|
||||
"github.com/pkg/errors"
|
||||
a "github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TransferChecksFeatureContext(s *godog.ScenarioContext) {
|
||||
s.Step(`^progress result is "([^"]*)"$`, progressFinishedWith)
|
||||
s.Step(`^transfer exported (\d+) messages$`, transferExportedNumberOfMessages)
|
||||
s.Step(`^transfer imported (\d+) messages$`, transferImportedNumberOfMessages)
|
||||
s.Step(`^transfer skipped (\d+) messages$`, transferSkippedNumberOfMessages)
|
||||
s.Step(`^transfer failed for (\d+) messages$`, transferFailedForNumberOfMessages)
|
||||
s.Step(`^transfer exported messages$`, transferExportedMessages)
|
||||
s.Step(`^exported messages match the original ones$`, exportedMessagesMatchTheOriginalOnes)
|
||||
}
|
||||
|
||||
func progressFinishedWith(wantResponse string) error {
|
||||
progress := ctx.GetTransferProgress()
|
||||
// Wait till transport is finished.
|
||||
updateCh := progress.GetUpdateChannel()
|
||||
if updateCh != nil {
|
||||
for range updateCh {
|
||||
}
|
||||
}
|
||||
|
||||
err := progress.GetFatalError()
|
||||
if wantResponse == "OK" {
|
||||
a.NoError(ctx.GetTestingT(), err)
|
||||
} else {
|
||||
a.EqualError(ctx.GetTestingT(), err, wantResponse)
|
||||
}
|
||||
return ctx.GetTestingError()
|
||||
}
|
||||
|
||||
func transferExportedNumberOfMessages(wantCount int) error {
|
||||
progress := ctx.GetTransferProgress()
|
||||
counts := progress.GetCounts()
|
||||
a.Equal(ctx.GetTestingT(), uint(wantCount), counts.Exported)
|
||||
return ctx.GetTestingError()
|
||||
}
|
||||
|
||||
func transferImportedNumberOfMessages(wantCount int) error {
|
||||
progress := ctx.GetTransferProgress()
|
||||
counts := progress.GetCounts()
|
||||
a.Equal(ctx.GetTestingT(), uint(wantCount), counts.Imported)
|
||||
return ctx.GetTestingError()
|
||||
}
|
||||
|
||||
func transferSkippedNumberOfMessages(wantCount int) error {
|
||||
progress := ctx.GetTransferProgress()
|
||||
counts := progress.GetCounts()
|
||||
a.Equal(ctx.GetTestingT(), uint(wantCount), counts.Skipped)
|
||||
return ctx.GetTestingError()
|
||||
}
|
||||
|
||||
func transferFailedForNumberOfMessages(wantCount int) error {
|
||||
progress := ctx.GetTransferProgress()
|
||||
failedMessages := progress.GetFailedMessages()
|
||||
a.Equal(ctx.GetTestingT(), wantCount, len(failedMessages), "failed messages: %v", failedMessages)
|
||||
return ctx.GetTestingError()
|
||||
}
|
||||
|
||||
func transferExportedMessages(messages *godog.Table) error {
|
||||
expectedMessages := map[string][]MessageAttributes{}
|
||||
|
||||
head := messages.Rows[0].Cells
|
||||
for _, row := range messages.Rows[1:] {
|
||||
folder := ""
|
||||
msg := MessageAttributes{}
|
||||
|
||||
for n, cell := range row.Cells {
|
||||
switch head[n].Value {
|
||||
case "folder":
|
||||
folder = cell.Value
|
||||
case "subject":
|
||||
msg.subject = cell.Value
|
||||
case "from":
|
||||
msg.from = cell.Value
|
||||
case "to":
|
||||
msg.to = []string{cell.Value}
|
||||
case "time":
|
||||
date, err := time.Parse(timeFormat, cell.Value)
|
||||
if err != nil {
|
||||
return internalError(err, "failed to parse time")
|
||||
}
|
||||
msg.date = date.Unix()
|
||||
default:
|
||||
return fmt.Errorf("unexpected column name: %s", head[n].Value)
|
||||
}
|
||||
}
|
||||
|
||||
expectedMessages[folder] = append(expectedMessages[folder], msg)
|
||||
sort.Sort(BySubject(expectedMessages[folder]))
|
||||
}
|
||||
|
||||
exportRoot := ctx.GetTransferLocalRootForExport()
|
||||
exportedMessages, err := readMessages(exportRoot)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "scanning exported messages")
|
||||
}
|
||||
|
||||
a.Equal(ctx.GetTestingT(), expectedMessages, exportedMessages)
|
||||
return ctx.GetTestingError()
|
||||
}
|
||||
|
||||
func exportedMessagesMatchTheOriginalOnes() error {
|
||||
importRoot := ctx.GetTransferLocalRootForImport()
|
||||
exportRoot := ctx.GetTransferLocalRootForExport()
|
||||
|
||||
importMessages, err := readMessages(importRoot)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "scanning messages for import")
|
||||
}
|
||||
exportMessages, err := readMessages(exportRoot)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "scanning exported messages")
|
||||
}
|
||||
delete(exportMessages, "All Mail") // Ignore All Mail.
|
||||
|
||||
a.Equal(ctx.GetTestingT(), importMessages, exportMessages)
|
||||
return ctx.GetTestingError()
|
||||
}
|
||||
|
||||
func readMessages(root string) (map[string][]MessageAttributes, error) {
|
||||
files, err := ioutil.ReadDir(root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
messagesPerLabel := map[string][]MessageAttributes{}
|
||||
for _, file := range files {
|
||||
if !file.IsDir() {
|
||||
fileReader, err := os.Open(filepath.Join(root, file.Name()))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "opening file")
|
||||
}
|
||||
|
||||
if filepath.Ext(file.Name()) == ".eml" {
|
||||
label := filepath.Base(root)
|
||||
msg, err := readMessageAttributes(fileReader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
messagesPerLabel[label] = append(messagesPerLabel[label], msg)
|
||||
sort.Sort(BySubject(messagesPerLabel[label]))
|
||||
} else if filepath.Ext(file.Name()) == ".mbox" {
|
||||
label := strings.TrimSuffix(file.Name(), ".mbox")
|
||||
mboxReader := mbox.NewReader(fileReader)
|
||||
for {
|
||||
msgReader, err := mboxReader.NextMessage()
|
||||
if err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
return nil, errors.Wrap(err, "reading next message")
|
||||
}
|
||||
msg, err := readMessageAttributes(msgReader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
messagesPerLabel[label] = append(messagesPerLabel[label], msg)
|
||||
}
|
||||
sort.Sort(BySubject(messagesPerLabel[label]))
|
||||
}
|
||||
} else {
|
||||
subfolderRoot := filepath.Join(root, file.Name())
|
||||
subfolderMessagesPerLabel, err := readMessages(subfolderRoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for key, value := range subfolderMessagesPerLabel {
|
||||
messagesPerLabel[key] = append(messagesPerLabel[key], value...)
|
||||
sort.Sort(BySubject(messagesPerLabel[key]))
|
||||
}
|
||||
}
|
||||
}
|
||||
return messagesPerLabel, nil
|
||||
}
|
||||
|
||||
type MessageAttributes struct {
|
||||
subject string
|
||||
from string
|
||||
to []string
|
||||
date int64
|
||||
}
|
||||
|
||||
func readMessageAttributes(fileReader io.Reader) (MessageAttributes, error) {
|
||||
entity, err := message.Read(fileReader)
|
||||
if err != nil {
|
||||
return MessageAttributes{}, errors.Wrap(err, "reading file")
|
||||
}
|
||||
date, err := parseTime(entity.Header.Get("date"))
|
||||
if err != nil {
|
||||
return MessageAttributes{}, errors.Wrap(err, "parsing date")
|
||||
}
|
||||
from, err := parseAddress(entity.Header.Get("from"))
|
||||
if err != nil {
|
||||
return MessageAttributes{}, errors.Wrap(err, "parsing from")
|
||||
}
|
||||
to, err := parseAddresses(entity.Header.Get("to"))
|
||||
if err != nil {
|
||||
return MessageAttributes{}, errors.Wrap(err, "parsing to")
|
||||
}
|
||||
return MessageAttributes{
|
||||
subject: entity.Header.Get("subject"),
|
||||
from: from,
|
||||
to: to,
|
||||
date: date.Unix(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parseTime(input string) (time.Time, error) {
|
||||
for _, format := range []string{time.RFC1123, time.RFC1123Z} {
|
||||
t, err := time.Parse(format, input)
|
||||
if err == nil {
|
||||
return t, nil
|
||||
}
|
||||
}
|
||||
return time.Time{}, errors.New("Unrecognized time format")
|
||||
}
|
||||
|
||||
func parseAddresses(input string) ([]string, error) {
|
||||
addresses, err := rfc5322.ParseAddressList(input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := []string{}
|
||||
for _, address := range addresses {
|
||||
result = append(result, address.Address)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func parseAddress(input string) (string, error) {
|
||||
address, err := rfc5322.ParseAddressList(input)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return address[0].Address, nil
|
||||
}
|
||||
|
||||
// BySubject implements sort.Interface based on the subject field.
|
||||
type BySubject []MessageAttributes
|
||||
|
||||
func (a BySubject) Len() int { return len(a) }
|
||||
func (a BySubject) Less(i, j int) bool { return a[i].subject < a[j].subject }
|
||||
func (a BySubject) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
@ -1,275 +0,0 @@
|
||||
// Copyright (c) 2021 Proton Technologies AG
|
||||
//
|
||||
// This file is part of ProtonMail Bridge.Bridge.
|
||||
//
|
||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package tests
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/textproto"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/pkg/message"
|
||||
"github.com/cucumber/godog"
|
||||
"github.com/cucumber/messages-go/v16"
|
||||
"github.com/emersion/go-imap"
|
||||
"github.com/emersion/go-mbox"
|
||||
)
|
||||
|
||||
func TransferSetupFeatureContext(s *godog.ScenarioContext) {
|
||||
s.Step(`^there are EML files$`, thereAreEMLFiles)
|
||||
s.Step(`^there is EML file "([^"]*)"$`, thereIsEMLFile)
|
||||
s.Step(`^there is MBOX file "([^"]*)" with messages$`, thereIsMBOXFileWithMessages)
|
||||
s.Step(`^there is MBOX file "([^"]*)"$`, thereIsMBOXFile)
|
||||
s.Step(`^there are IMAP mailboxes$`, thereAreIMAPMailboxes)
|
||||
s.Step(`^there are IMAP messages$`, thereAreIMAPMessages)
|
||||
s.Step(`^there is IMAP message in mailbox "([^"]*)" with seq (\d+), uid (\d+), time "([^"]*)" and subject "([^"]*)"$`, thereIsIMAPMessage)
|
||||
s.Step(`^there is skip encrypted messages set to "([^"]*)"$`, thereIsSkipEncryptedMessagesSetTo)
|
||||
}
|
||||
|
||||
func thereAreEMLFiles(messages *godog.Table) error {
|
||||
head := messages.Rows[0].Cells
|
||||
for _, row := range messages.Rows[1:] {
|
||||
fileName := ""
|
||||
for n, cell := range row.Cells {
|
||||
switch head[n].Value {
|
||||
case "file":
|
||||
fileName = cell.Value
|
||||
case "from", "to", "subject", "time", "body":
|
||||
default:
|
||||
return fmt.Errorf("unexpected column name: %s", head[n].Value)
|
||||
}
|
||||
}
|
||||
|
||||
body := getBodyFromDataRow(head, row)
|
||||
if err := createFile(fileName, body); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func thereIsEMLFile(fileName string, message *godog.DocString) error {
|
||||
return createFile(fileName, message.Content)
|
||||
}
|
||||
|
||||
func thereIsMBOXFileWithMessages(fileName string, messages *godog.Table) error {
|
||||
mboxBuffer := &bytes.Buffer{}
|
||||
mboxWriter := mbox.NewWriter(mboxBuffer)
|
||||
|
||||
head := messages.Rows[0].Cells
|
||||
for _, row := range messages.Rows[1:] {
|
||||
from := ""
|
||||
for n, cell := range row.Cells {
|
||||
switch head[n].Value {
|
||||
case "from":
|
||||
from = cell.Value
|
||||
case "to", "subject", "time", "body":
|
||||
default:
|
||||
return fmt.Errorf("unexpected column name: %s", head[n].Value)
|
||||
}
|
||||
}
|
||||
|
||||
body := getBodyFromDataRow(head, row)
|
||||
|
||||
messageWriter, err := mboxWriter.CreateMessage(from, time.Now())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = messageWriter.Write([]byte(body))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return createFile(fileName, mboxBuffer.String())
|
||||
}
|
||||
|
||||
func thereIsMBOXFile(fileName string, messages *godog.DocString) error {
|
||||
return createFile(fileName, messages.Content)
|
||||
}
|
||||
|
||||
func thereAreIMAPMailboxes(mailboxes *godog.Table) error {
|
||||
imapServer := ctx.GetTransferRemoteIMAPServer()
|
||||
head := mailboxes.Rows[0].Cells
|
||||
for _, row := range mailboxes.Rows[1:] {
|
||||
mailboxName := ""
|
||||
for n, cell := range row.Cells {
|
||||
switch head[n].Value {
|
||||
case "name":
|
||||
mailboxName = cell.Value
|
||||
default:
|
||||
return fmt.Errorf("unexpected column name: %s", head[n].Value)
|
||||
}
|
||||
}
|
||||
imapServer.AddMailbox(mailboxName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func thereAreIMAPMessages(messages *godog.Table) (err error) {
|
||||
imapServer := ctx.GetTransferRemoteIMAPServer()
|
||||
head := messages.Rows[0].Cells
|
||||
for _, row := range messages.Rows[1:] {
|
||||
mailboxName := ""
|
||||
date := time.Now()
|
||||
subject := ""
|
||||
seqNum := 0
|
||||
uid := 0
|
||||
for n, cell := range row.Cells {
|
||||
switch head[n].Value {
|
||||
case "mailbox":
|
||||
mailboxName = cell.Value
|
||||
case "uid":
|
||||
uid, err = strconv.Atoi(cell.Value)
|
||||
if err != nil {
|
||||
return internalError(err, "failed to parse uid")
|
||||
}
|
||||
case "seqnum":
|
||||
seqNum, err = strconv.Atoi(cell.Value)
|
||||
if err != nil {
|
||||
return internalError(err, "failed to parse seqnum")
|
||||
}
|
||||
case "time":
|
||||
date, err = time.Parse(timeFormat, cell.Value)
|
||||
if err != nil {
|
||||
return internalError(err, "failed to parse time")
|
||||
}
|
||||
case "subject":
|
||||
subject = cell.Value
|
||||
case "from", "to", "body":
|
||||
default:
|
||||
return fmt.Errorf("unexpected column name: %s", head[n].Value)
|
||||
}
|
||||
}
|
||||
|
||||
body := getBodyFromDataRow(head, row)
|
||||
imapMessage, err := getIMAPMessage(seqNum, uid, date, subject, body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
imapServer.AddMessage(mailboxName, imapMessage)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func thereIsIMAPMessage(mailboxName string, seqNum, uid int, dateValue, subject string, message *godog.DocString) error {
|
||||
imapServer := ctx.GetTransferRemoteIMAPServer()
|
||||
|
||||
date, err := time.Parse(timeFormat, dateValue)
|
||||
if err != nil {
|
||||
return internalError(err, "failed to parse time")
|
||||
}
|
||||
|
||||
imapMessage, err := getIMAPMessage(seqNum, uid, date, subject, message.Content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
imapServer.AddMessage(mailboxName, imapMessage)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getBodyFromDataRow(head []*messages.PickleTableCell, row *messages.PickleTableRow) string {
|
||||
body := "hello"
|
||||
headers := textproto.MIMEHeader{}
|
||||
headers.Set("Received", "by 2002:0:0:0:0:0:0:0 with SMTP id 0123456789abcdef; Wed, 30 Dec 2020 01:23:45 0000")
|
||||
for n, cell := range row.Cells {
|
||||
switch head[n].Value {
|
||||
case "from":
|
||||
headers.Set("from", cell.Value)
|
||||
case "to":
|
||||
headers.Set("to", cell.Value)
|
||||
case "subject":
|
||||
headers.Set("subject", cell.Value)
|
||||
case "time":
|
||||
date, err := time.Parse(timeFormat, cell.Value)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
headers.Set("date", date.Format(time.RFC1123))
|
||||
case "body":
|
||||
body = cell.Value
|
||||
}
|
||||
}
|
||||
|
||||
buffer := &bytes.Buffer{}
|
||||
_ = message.WriteHeader(buffer, headers)
|
||||
return buffer.String() + body + "\n\n"
|
||||
}
|
||||
|
||||
func getIMAPMessage(seqNum, uid int, date time.Time, subject, body string) (*imap.Message, error) {
|
||||
reader := bytes.NewBufferString(body)
|
||||
bodyStructure, err := message.NewBodyStructure(reader)
|
||||
if err != nil {
|
||||
return nil, internalError(err, "failed to parse body structure")
|
||||
}
|
||||
imapBodyStructure, err := bodyStructure.IMAPBodyStructure([]int{})
|
||||
if err != nil {
|
||||
return nil, internalError(err, "failed to parse body structure")
|
||||
}
|
||||
bodySection, _ := imap.ParseBodySectionName("BODY[]")
|
||||
|
||||
return &imap.Message{
|
||||
SeqNum: uint32(seqNum),
|
||||
Uid: uint32(uid),
|
||||
Size: uint32(len(body)),
|
||||
Envelope: &imap.Envelope{
|
||||
Date: date,
|
||||
Subject: subject,
|
||||
},
|
||||
BodyStructure: imapBodyStructure,
|
||||
Body: map[*imap.BodySectionName]imap.Literal{
|
||||
bodySection: bytes.NewBufferString(body),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func createFile(fileName, body string) error {
|
||||
root := ctx.GetTransferLocalRootForImport()
|
||||
filePath := filepath.Join(root, fileName)
|
||||
|
||||
dirPath := filepath.Dir(filePath)
|
||||
err := os.MkdirAll(dirPath, os.ModePerm)
|
||||
if err != nil {
|
||||
return internalError(err, "failed to create dir")
|
||||
}
|
||||
|
||||
f, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
return internalError(err, "failed to create file")
|
||||
}
|
||||
defer f.Close() //nolint
|
||||
|
||||
_, err = f.WriteString(body)
|
||||
return internalError(err, "failed to write to file")
|
||||
}
|
||||
|
||||
func thereIsSkipEncryptedMessagesSetTo(value string) error {
|
||||
switch value {
|
||||
case "true":
|
||||
ctx.SetTransferSkipEncryptedMessages(true)
|
||||
case "false":
|
||||
ctx.SetTransferSkipEncryptedMessages(false)
|
||||
default:
|
||||
return fmt.Errorf("expected either true or false, was %v", value)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user