GODT-35: Finish all details and make tests pass

This commit is contained in:
Michal Horejsek
2021-03-11 14:37:15 +01:00
committed by Jakub
parent 2284e9ede1
commit 8109831c07
173 changed files with 4697 additions and 2897 deletions

View File

@ -96,17 +96,16 @@ type TestContext struct {
func New(app string) *TestContext {
setLogrusVerbosityFromEnv()
userAgent := useragent.New()
pmapiController, clientManager := newPMAPIController()
listener := listener.New()
pmapiController, clientManager := newPMAPIController(app, listener)
ctx := &TestContext{
t: &bddT{},
cache: newFakeCache(),
locations: newFakeLocations(),
settings: newFakeSettings(),
listener: listener.New(),
userAgent: userAgent,
listener: listener,
userAgent: useragent.New(),
pmapiController: pmapiController,
clientManager: clientManager,
testAccounts: newTestAccounts(),
@ -137,14 +136,6 @@ func New(app string) *TestContext {
return ctx
}
func getConfigName(app string) string {
if app == "ie" {
return "importExport"
}
return app
}
// Cleanup runs through all cleanup steps.
// This can be a deferred call so that it is run even if the test steps failed the test.
func (ctx *TestContext) Cleanup() *TestContext {

View File

@ -65,7 +65,6 @@ func (c *fakeCredStore) Add(userID, userName, uid, ref, mailboxPassword string,
BridgePassword: bridgePassword,
IsCombinedAddressMode: true, // otherwise by default starts in split mode
}
return c.Get(userID)
}
@ -74,12 +73,10 @@ func (c *fakeCredStore) Get(userID string) (*credentials.Credentials, error) {
}
func (c *fakeCredStore) SwitchAddressMode(userID string) (*credentials.Credentials, error) {
// FIXME(conman): Why is this empty?
return c.credentials[userID], nil
}
func (c *fakeCredStore) UpdateEmails(userID string, emails []string) (*credentials.Credentials, error) {
// FIXME(conman): Why is this empty?
return c.credentials[userID], nil
}

View File

@ -20,6 +20,8 @@ package context
import (
"os"
"github.com/ProtonMail/proton-bridge/internal/events"
"github.com/ProtonMail/proton-bridge/pkg/listener"
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
"github.com/ProtonMail/proton-bridge/test/fakeapi"
"github.com/ProtonMail/proton-bridge/test/liveapi"
@ -39,15 +41,26 @@ type PMAPIController interface {
GetCalls(method, path string) [][]byte
}
func newPMAPIController() (PMAPIController, pmapi.Manager) {
func newPMAPIController(app string, listener listener.Listener) (PMAPIController, pmapi.Manager) {
switch os.Getenv(EnvName) {
case EnvFake:
return fakeapi.NewController()
cntl, cm := fakeapi.NewController()
addConnectionObserver(cm, listener)
return cntl, cm
case EnvLive:
return liveapi.NewController()
cntl, cm := liveapi.NewController(app)
addConnectionObserver(cm, listener)
return cntl, cm
default:
panic("unknown env")
}
}
func addConnectionObserver(cm pmapi.Manager, listener listener.Listener) {
cm.AddConnectionObserver(pmapi.NewConnectionObserver(
func() { listener.Emit(events.InternetOffEvent, "") },
func() { listener.Emit(events.InternetOnEvent, "") },
))
}

View File

@ -1,65 +0,0 @@
package context
import (
"context"
"net/http"
"time"
"github.com/ProtonMail/gopenpgp/v2/crypto"
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
"github.com/go-resty/resty/v2"
)
func newLivePMAPIManager() pmapi.Manager {
return pmapi.New(pmapi.DefaultConfig)
}
func newFakePMAPIManager() pmapi.Manager {
return &fakePMAPIManager{}
}
type fakePMAPIManager struct{}
func (*fakePMAPIManager) NewClient(string, string, string, time.Time) pmapi.Client {
panic("TODO")
}
func (*fakePMAPIManager) NewClientWithRefresh(context.Context, string, string) (pmapi.Client, *pmapi.Auth, error) {
panic("TODO")
}
func (*fakePMAPIManager) NewClientWithLogin(context.Context, string, string) (pmapi.Client, *pmapi.Auth, error) {
panic("TODO")
}
func (*fakePMAPIManager) DownloadAndVerify(kr *crypto.KeyRing, url, sig string) ([]byte, error) {
panic("TODO")
}
func (*fakePMAPIManager) ReportBug(context.Context, pmapi.ReportBugReq) error {
panic("TODO")
}
func (*fakePMAPIManager) SendSimpleMetric(context.Context, string, string, string) error {
panic("TODO")
}
func (*fakePMAPIManager) SetLogger(resty.Logger) {
panic("TODO")
}
func (*fakePMAPIManager) SetTransport(http.RoundTripper) {
panic("TODO")
}
func (*fakePMAPIManager) SetCookieJar(http.CookieJar) {
panic("TODO")
}
func (*fakePMAPIManager) SetRetryCount(int) {
panic("TODO")
}
func (*fakePMAPIManager) AddConnectionObserver(pmapi.ConnectionObserver) {
panic("TODO")
}

View File

@ -26,7 +26,6 @@ import (
"github.com/ProtonMail/proton-bridge/internal/store"
"github.com/ProtonMail/proton-bridge/internal/users"
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
"github.com/ProtonMail/proton-bridge/pkg/srp"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
@ -46,8 +45,8 @@ func (ctx *TestContext) LoginUser(username, password, mailboxPassword string) er
return errors.Wrap(err, "failed to login")
}
if auth.TwoFA.Enabled == pmapi.TOTPEnabled {
if err := client.Auth2FA(context.TODO(), pmapi.Auth2FAReq{TwoFactorCode: "2fa code"}); err != nil {
if auth.HasTwoFactor() {
if err := client.Auth2FA(context.Background(), "2fa code"); err != nil {
return errors.Wrap(err, "failed to login with 2FA")
}
}

View File

@ -23,8 +23,8 @@ import (
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
)
func (api *FakePMAPI) Auth2FA(_ context.Context, req pmapi.Auth2FAReq) error {
if err := api.checkAndRecordCall(POST, "/auth/2fa", req); err != nil {
func (api *FakePMAPI) Auth2FA(_ context.Context, twoFactorCode string) error {
if err := api.checkAndRecordCall(POST, "/auth/2fa", twoFactorCode); err != nil {
return err
}
@ -50,7 +50,7 @@ func (api *FakePMAPI) AuthSalt(_ context.Context) (string, error) {
return "", nil
}
func (api *FakePMAPI) AddAuthHandler(handler pmapi.AuthHandler) {
func (api *FakePMAPI) AddAuthRefreshHandler(handler pmapi.AuthRefreshHandler) {
api.authHandlers = append(api.authHandlers, handler)
}

View File

@ -32,7 +32,7 @@ type Controller struct {
labelIDGenerator idGenerator
messageIDGenerator idGenerator
tokenGenerator idGenerator
clientManager pmapi.Manager
clientManager *fakePMAPIManager
// State controlled by test.
noInternetConnection bool

View File

@ -40,7 +40,7 @@ type fakeCall struct {
request []byte
}
func (ctl *Controller) recordCall(method method, path string, req interface{}) error {
func (ctl *Controller) checkAndRecordCall(method method, path string, req interface{}) error {
ctl.lock.Lock()
defer ctl.lock.Unlock()
@ -50,7 +50,7 @@ func (ctl *Controller) recordCall(method method, path string, req interface{}) e
var err error
if request, err = json.Marshal(req); err != nil {
return err
panic(err)
}
}

View File

@ -39,11 +39,17 @@ var systemLabelNameToID = map[string]string{ //nolint[gochecknoglobals]
func (ctl *Controller) TurnInternetConnectionOff() {
ctl.log.Warn("Turning OFF internet")
ctl.noInternetConnection = true
for _, observer := range ctl.clientManager.connectionObservers {
observer.OnDown()
}
}
func (ctl *Controller) TurnInternetConnectionOn() {
ctl.log.Warn("Turning ON internet")
ctl.noInternetConnection = false
for _, observer := range ctl.clientManager.connectionObservers {
observer.OnUp()
}
}
func (ctl *Controller) ReorderAddresses(user *pmapi.User, addressIDs []string) error {
@ -52,7 +58,7 @@ func (ctl *Controller) ReorderAddresses(user *pmapi.User, addressIDs []string) e
return errors.New("no such user")
}
return api.ReorderAddresses(context.TODO(), addressIDs)
return api.ReorderAddresses(context.Background(), addressIDs)
}
func (ctl *Controller) AddUser(user *pmapi.User, addresses *pmapi.AddressList, password string, twoFAEnabled bool) error {
@ -79,7 +85,7 @@ func (ctl *Controller) AddUserLabel(username string, label *pmapi.Label) error {
label.Exclusive = getLabelExclusive(label.Name)
prefix := "label"
if label.Exclusive == 1 {
if label.Exclusive {
prefix = "folder"
}
label.ID = ctl.labelIDGenerator.next(prefix)
@ -127,11 +133,8 @@ func getLabelNameWithoutPrefix(name string) string {
return name
}
func getLabelExclusive(name string) int {
if strings.HasPrefix(name, "Folders/") {
return 1
}
return 0
func getLabelExclusive(name string) pmapi.Boolean {
return pmapi.Boolean(strings.HasPrefix(name, "Folders/"))
}
func (ctl *Controller) AddUserMessage(username string, message *pmapi.Message) (string, error) {

View File

@ -43,13 +43,12 @@ func (api *FakePMAPI) getCounts(addressID string) []*pmapi.MessagesCount {
for _, labelID := range message.LabelIDs {
if counts, ok := allCounts[labelID]; ok {
counts.Total++
if message.Unread == 1 {
if message.Unread {
counts.Unread++
}
} else {
var unread int
if message.Unread == pmapi.True {
if message.Unread {
unread = 1
}

View File

@ -34,7 +34,7 @@ type FakePMAPI struct {
controller *Controller
eventIDGenerator idGenerator
authHandlers []pmapi.AuthHandler
authHandlers []pmapi.AuthRefreshHandler
user *pmapi.User
userKeyRing *crypto.KeyRing
addresses *pmapi.AddressList
@ -45,25 +45,13 @@ type FakePMAPI struct {
// uid represents the API UID. It is the unique session ID.
uid string
acc string // FIXME(conman): Check this is correct!
ref string // FIXME(conman): Check this is correct!
acc string
ref string
log *logrus.Entry
}
func newFakePMAPI(controller *Controller, userID, uid, acc, ref string) *FakePMAPI {
return &FakePMAPI{
controller: controller,
log: logrus.WithField("pkg", "fakeapi").WithField("uid", uid),
uid: uid,
acc: acc, // FIXME(conman): This should be checked!
ref: ref, // FIXME(conman): This should be checked!
userID: userID,
addrKeyRing: make(map[string]*crypto.KeyRing),
}
}
func NewFakePMAPI(controller *Controller, username, userID, uid, acc, ref string) (*FakePMAPI, error) {
func newFakePMAPI(controller *Controller, username, userID, uid, acc, ref string) (*FakePMAPI, error) {
user, ok := controller.usersByUsername[username]
if !ok {
return nil, fmt.Errorf("user %s does not exist", username)
@ -84,19 +72,28 @@ func NewFakePMAPI(controller *Controller, username, userID, uid, acc, ref string
messages = []*pmapi.Message{}
}
fakePMAPI := newFakePMAPI(controller, userID, uid, acc, ref)
fakePMAPI := &FakePMAPI{
username: username,
userID: userID,
controller: controller,
fakePMAPI.log = fakePMAPI.log.WithField("username", username)
fakePMAPI.username = username
fakePMAPI.user = user.user
fakePMAPI.addresses = addresses
fakePMAPI.labels = labels
fakePMAPI.messages = messages
user: user.user,
addresses: addresses,
labels: labels,
messages: messages,
uid: uid,
acc: acc,
ref: ref,
addrKeyRing: make(map[string]*crypto.KeyRing),
log: logrus.WithField("pkg", "fakeapi").WithField("uid", uid).WithField("username", username),
}
fakePMAPI.addEvent(&pmapi.Event{
EventID: fakePMAPI.eventIDGenerator.last("event"),
Refresh: 0,
More: 0,
More: false,
})
return fakePMAPI, nil
@ -112,13 +109,14 @@ func (api *FakePMAPI) checkAndRecordCall(method method, path string, request int
api.log.WithField(string(method), path).Trace("CALL")
if err := api.controller.recordCall(method, path, request); err != nil {
if err := api.controller.checkAndRecordCall(method, path, request); err != nil {
return err
}
// FIXME(conman): This needs to match conman behaviour. Should try auth refresh somehow.
if !api.controller.checkAccessToken(api.uid, api.acc) {
return pmapi.ErrUnauthorized
if err := api.authRefresh(); err != nil {
return err
}
}
if path != "/auth/2fa" && !api.controller.checkScope(api.uid) {
@ -128,6 +126,21 @@ func (api *FakePMAPI) checkAndRecordCall(method method, path string, request int
return nil
}
func (api *FakePMAPI) authRefresh() error {
if err := api.controller.checkAndRecordCall(POST, "/auth/refresh", []string{api.uid, api.ref}); err != nil {
return err
}
session, err := api.controller.refreshSessionIfAuthorized(api.uid, api.ref)
if err != nil {
return err
}
api.ref = session.ref
api.acc = session.acc
return nil
}
func (api *FakePMAPI) setUser(username string) error {
api.username = username
api.log = api.log.WithField("username", username)
@ -158,12 +171,3 @@ func (api *FakePMAPI) setUser(username string) error {
return nil
}
func (api *FakePMAPI) unsetUser() {
api.uid = ""
api.acc = "" // FIXME(conman): This should be checked!
api.user = nil
api.labels = nil
api.messages = nil
api.events = nil
}

View File

@ -27,7 +27,7 @@ import (
func (api *FakePMAPI) isLabelFolder(labelID string) bool {
for _, label := range api.labels {
if label.ID == labelID {
return label.Exclusive == 1
return bool(label.Exclusive)
}
}
return labelID == pmapi.InboxLabel || labelID == pmapi.ArchiveLabel || labelID == pmapi.SentLabel
@ -50,7 +50,7 @@ func (api *FakePMAPI) CreateLabel(_ context.Context, label *pmapi.Label) (*pmapi
}
}
prefix := "label"
if label.Exclusive == 1 {
if label.Exclusive {
prefix = "folder"
}
label.ID = api.controller.labelIDGenerator.next(prefix)

View File

@ -1,3 +1,20 @@
// Copyright (c) 2021 Proton Technologies AG
//
// This file is part of ProtonMail 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 fakeapi
import (
@ -8,27 +25,36 @@ import (
"github.com/ProtonMail/gopenpgp/v2/crypto"
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
"github.com/go-resty/resty/v2"
"github.com/sirupsen/logrus"
)
type fakePMAPIManager struct {
controller *Controller
controller *Controller
connectionObservers []pmapi.ConnectionObserver
}
func (m *fakePMAPIManager) NewClient(uid string, acc string, ref string, _ time.Time) pmapi.Client {
if uid == "" {
return &FakePMAPI{
controller: m.controller,
log: logrus.WithField("pkg", "fakeapi"),
addrKeyRing: make(map[string]*crypto.KeyRing),
}
}
session, ok := m.controller.sessionsByUID[uid]
if !ok {
return newFakePMAPI(m.controller, "", "", "", "")
panic("session " + uid + " is missing")
}
user, ok := m.controller.usersByUsername[session.username]
if !ok {
return newFakePMAPI(m.controller, "", "", "", "")
panic("user " + session.username + " from session " + uid + " is missing")
}
client, err := NewFakePMAPI(m.controller, session.username, user.user.ID, session.uid, session.acc, session.ref)
client, err := newFakePMAPI(m.controller, session.username, user.user.ID, session.uid, session.acc, session.ref)
if err != nil {
return newFakePMAPI(m.controller, "", "", "", "")
panic(err)
}
m.controller.fakeAPIs = append(m.controller.fakeAPIs, client)
@ -36,15 +62,8 @@ func (m *fakePMAPIManager) NewClient(uid string, acc string, ref string, _ time.
return client
}
func (m *fakePMAPIManager) NewClientWithRefresh(_ context.Context, uid, ref string) (pmapi.Client, *pmapi.Auth, error) {
if err := m.controller.recordCall(POST, "/auth/refresh", &pmapi.AuthRefreshReq{
UID: uid,
RefreshToken: ref,
ResponseType: "token",
GrantType: "refresh_token",
RedirectURI: "https://protonmail.ch",
State: "random_string",
}); err != nil {
func (m *fakePMAPIManager) NewClientWithRefresh(_ context.Context, uid, ref string) (pmapi.Client, *pmapi.AuthRefresh, error) {
if err := m.controller.checkAndRecordCall(POST, "/auth/refresh", []string{uid, ref}); err != nil {
return nil, nil, err
}
@ -58,31 +77,25 @@ func (m *fakePMAPIManager) NewClientWithRefresh(_ context.Context, uid, ref stri
return nil, nil, errWrongNameOrPassword
}
client, err := NewFakePMAPI(m.controller, session.username, user.user.ID, session.uid, session.acc, session.ref)
client, err := newFakePMAPI(m.controller, session.username, user.user.ID, session.uid, session.acc, session.ref)
if err != nil {
return nil, nil, err
}
m.controller.fakeAPIs = append(m.controller.fakeAPIs, client)
auth := &pmapi.Auth{
auth := &pmapi.AuthRefresh{
UID: session.uid,
AccessToken: session.acc,
RefreshToken: session.ref,
ExpiresIn: 86400, // seconds,
}
if user.has2FA {
auth.TwoFA = pmapi.TwoFAInfo{
Enabled: pmapi.TOTPEnabled,
}
}
return client, auth, nil
}
func (m *fakePMAPIManager) NewClientWithLogin(_ context.Context, username string, password string) (pmapi.Client, *pmapi.Auth, error) {
if err := m.controller.recordCall(POST, "/auth/info", &pmapi.GetAuthInfoReq{Username: username}); err != nil {
if err := m.controller.checkAndRecordCall(POST, "/auth/info", &pmapi.GetAuthInfoReq{Username: username}); err != nil {
return nil, nil, err
}
@ -93,7 +106,7 @@ func (m *fakePMAPIManager) NewClientWithLogin(_ context.Context, username string
return nil, nil, errWrongNameOrPassword
}
if err := m.controller.recordCall(POST, "/auth", &pmapi.AuthReq{Username: username}); err != nil {
if err := m.controller.checkAndRecordCall(POST, "/auth", &pmapi.AuthReq{Username: username}); err != nil {
return nil, nil, err
}
@ -102,7 +115,7 @@ func (m *fakePMAPIManager) NewClientWithLogin(_ context.Context, username string
return nil, nil, err
}
client, err := NewFakePMAPI(m.controller, username, user.user.ID, session.uid, session.acc, session.ref)
client, err := newFakePMAPI(m.controller, username, user.user.ID, session.uid, session.acc, session.ref)
if err != nil {
return nil, nil, err
}
@ -110,14 +123,17 @@ func (m *fakePMAPIManager) NewClientWithLogin(_ context.Context, username string
m.controller.fakeAPIs = append(m.controller.fakeAPIs, client)
auth := &pmapi.Auth{
UID: session.uid,
AccessToken: session.acc,
RefreshToken: session.ref,
ExpiresIn: 86400, // seconds,
UserID: user.user.ID,
AuthRefresh: pmapi.AuthRefresh{
UID: session.uid,
AccessToken: session.acc,
RefreshToken: session.ref,
ExpiresIn: 86400, // seconds,
},
}
if user.has2FA {
auth.TwoFA = pmapi.TwoFAInfo{
auth.TwoFA = &pmapi.TwoFAInfo{
Enabled: pmapi.TOTPEnabled,
}
}
@ -125,40 +141,46 @@ func (m *fakePMAPIManager) NewClientWithLogin(_ context.Context, username string
return client, auth, nil
}
func (*fakePMAPIManager) DownloadAndVerify(kr *crypto.KeyRing, url, sig string) ([]byte, error) {
panic("TODO")
func (m *fakePMAPIManager) DownloadAndVerify(kr *crypto.KeyRing, url, sig string) ([]byte, error) {
panic("Not implemented: not used by tests")
}
func (*fakePMAPIManager) ReportBug(context.Context, pmapi.ReportBugReq) error {
panic("TODO")
func (m *fakePMAPIManager) ReportBug(_ context.Context, bugReport pmapi.ReportBugReq) error {
return m.controller.checkAndRecordCall(POST, "/reports/bug", bugReport)
}
func (m *fakePMAPIManager) SendSimpleMetric(_ context.Context, cat string, act string, lab string) error {
v := url.Values{}
v.Set("Category", cat)
v.Set("Action", act)
v.Set("Label", lab)
return m.controller.recordCall(GET, "/metrics?"+v.Encode(), nil)
return m.controller.checkAndRecordCall(GET, "/metrics?"+v.Encode(), nil)
}
func (*fakePMAPIManager) SetLogger(resty.Logger) {
panic("TODO")
func (m *fakePMAPIManager) SetLogging(*logrus.Entry, bool) {
// NOOP
}
func (*fakePMAPIManager) SetTransport(http.RoundTripper) {
panic("TODO")
func (m *fakePMAPIManager) SetTransport(http.RoundTripper) {
// NOOP
}
func (*fakePMAPIManager) SetCookieJar(http.CookieJar) {
panic("TODO")
func (m *fakePMAPIManager) SetCookieJar(http.CookieJar) {
// NOOP
}
func (*fakePMAPIManager) SetRetryCount(int) {
panic("TODO")
func (m *fakePMAPIManager) SetRetryCount(int) {
// NOOP
}
func (*fakePMAPIManager) AddConnectionObserver(pmapi.ConnectionObserver) {
panic("TODO")
func (m *fakePMAPIManager) AddConnectionObserver(connectionObserver pmapi.ConnectionObserver) {
m.connectionObservers = append(m.connectionObservers, connectionObserver)
}
func (m *fakePMAPIManager) AllowProxy() {
// NOOP
}
func (m *fakePMAPIManager) DisallowProxy() {
// NOOP
}

View File

@ -132,15 +132,7 @@ func isMessageMatchingFilter(filter *pmapi.MessagesFilter, message *pmapi.Messag
return false
}
if filter.Unread != nil {
var wantUnread pmapi.Boolean
if *filter.Unread {
wantUnread = pmapi.True
} else {
wantUnread = pmapi.False
}
if message.Unread != wantUnread {
if bool(message.Unread) != *filter.Unread {
return false
}
}
@ -393,10 +385,10 @@ func (api *FakePMAPI) MarkMessagesRead(_ context.Context, apiIDs []string) error
return api.updateMessages(PUT, "/mail/v4/messages/read", &pmapi.MessagesActionReq{
IDs: apiIDs,
}, apiIDs, func(message *pmapi.Message) error {
if message.Unread == 0 {
if !message.Unread {
return errWasNotUpdated
}
message.Unread = 0
message.Unread = false
return nil
})
}
@ -405,10 +397,10 @@ func (api *FakePMAPI) MarkMessagesUnread(_ context.Context, apiIDs []string) err
err := api.updateMessages(PUT, "/mail/v4/messages/unread", &pmapi.MessagesActionReq{
IDs: apiIDs,
}, apiIDs, func(message *pmapi.Message) error {
if message.Unread == 1 {
if message.Unread {
return errWasNotUpdated
}
message.Unread = 1
message.Unread = true
return nil
})
if err != nil {

View File

@ -116,6 +116,12 @@ func (api *FakePMAPI) ReorderAddresses(_ context.Context, addressIDs []string) e
}
func (api *FakePMAPI) Addresses() pmapi.AddressList {
if api.controller.noInternetConnection {
return nil
}
if api.addresses == nil {
return pmapi.AddressList{}
}
return *api.addresses
}

View File

@ -16,7 +16,6 @@ Feature: Start bridge
And "user" has loaded store
And "user" has running event loop
@ignore
Scenario: Start with connected user, no database file and internet connection
Given there is connected user "user"
And there is no database file for "user"
@ -24,15 +23,20 @@ Feature: Start bridge
Then "user" is connected
And "user" has loaded store
And "user" has running event loop
And "user" is connected
@ignore
Scenario: Start with connected user, no database file and no internet connection
Given there is connected user "user"
And there is no database file for "user"
And there is no internet connection
When bridge starts
Then "user" is disconnected
Then "user" is connected
And "user" does not have loaded store
And "user" does not have running event loop
And the internet connection is restored
And 5 seconds pass
Then "user" is connected
And "user" has loaded store
And "user" has running event loop
Scenario: Start with disconnected user, database file and internet connection
Given there is disconnected user "user"
@ -51,7 +55,6 @@ Feature: Start bridge
And "user" has loaded store
And "user" does not have running event loop
@ignore
Scenario: Start with disconnected user, no database file and internet connection
Given there is disconnected user "user"
And there is no database file for "user"
@ -60,7 +63,6 @@ Feature: Start bridge
And "user" does not have loaded store
And "user" does not have running event loop
@ignore
Scenario: Start with disconnected user, no database file and no internet connection
Given there is disconnected user "user"
And there is no database file for "user"

View File

@ -44,7 +44,7 @@ func cleanup(client pmapi.Client, addresses *pmapi.AddressList) error {
func cleanSystemFolders(client pmapi.Client) error {
for _, labelID := range []string{pmapi.InboxLabel, pmapi.SentLabel, pmapi.ArchiveLabel, pmapi.AllMailLabel, pmapi.DraftLabel} {
for {
messages, total, err := client.ListMessages(context.TODO(), &pmapi.MessagesFilter{
messages, total, err := client.ListMessages(context.Background(), &pmapi.MessagesFilter{
PageSize: 150,
LabelID: labelID,
})
@ -61,7 +61,7 @@ func cleanSystemFolders(client pmapi.Client) error {
messageIDs = append(messageIDs, message.ID)
}
if err := client.DeleteMessages(context.TODO(), messageIDs); err != nil {
if err := client.DeleteMessages(context.Background(), messageIDs); err != nil {
return errors.Wrap(err, "failed to delete messages")
}
@ -74,7 +74,7 @@ func cleanSystemFolders(client pmapi.Client) error {
}
func cleanCustomLables(client pmapi.Client) error {
labels, err := client.ListLabels(context.TODO())
labels, err := client.ListLabels(context.Background())
if err != nil {
return errors.Wrap(err, "failed to list labels")
}
@ -83,7 +83,7 @@ func cleanCustomLables(client pmapi.Client) error {
if err := emptyFolder(client, label.ID); err != nil {
return errors.Wrap(err, "failed to empty label")
}
if err := client.DeleteLabel(context.TODO(), label.ID); err != nil {
if err := client.DeleteLabel(context.Background(), label.ID); err != nil {
return errors.Wrap(err, "failed to delete label")
}
}
@ -93,7 +93,7 @@ func cleanCustomLables(client pmapi.Client) error {
func cleanTrash(client pmapi.Client) error {
for {
_, total, err := client.ListMessages(context.TODO(), &pmapi.MessagesFilter{
_, total, err := client.ListMessages(context.Background(), &pmapi.MessagesFilter{
PageSize: 1,
LabelID: pmapi.TrashLabel,
})
@ -115,12 +115,12 @@ func cleanTrash(client pmapi.Client) error {
}
func emptyFolder(client pmapi.Client, labelID string) error {
err := client.EmptyFolder(context.TODO(), labelID, "")
err := client.EmptyFolder(context.Background(), labelID, "")
if err != nil {
return err
}
for {
_, total, err := client.ListMessages(context.TODO(), &pmapi.MessagesFilter{
_, total, err := client.ListMessages(context.Background(), &pmapi.MessagesFilter{
PageSize: 1,
LabelID: labelID,
})
@ -142,5 +142,5 @@ func reorderAddresses(client pmapi.Client, addresses *pmapi.AddressList) error {
addressIDs = append(addressIDs, address.ID)
}
return client.ReorderAddresses(context.TODO(), addressIDs)
return client.ReorderAddresses(context.Background(), addressIDs)
}

View File

@ -21,6 +21,7 @@ import (
"net/http"
"sync"
"github.com/ProtonMail/proton-bridge/internal/constants"
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
)
@ -36,19 +37,18 @@ type Controller struct {
noInternetConnection bool
}
func NewController() (*Controller, pmapi.Manager) {
func NewController(app string) (*Controller, pmapi.Manager) {
cm := pmapi.New(pmapi.NewConfig(getAppVersionName(app), constants.Version))
controller := &Controller{
lock: &sync.RWMutex{},
calls: []*fakeCall{},
pmapiByUsername: map[string]pmapi.Client{},
messageIDsByUsername: map[string][]string{},
clientManager: cm,
noInternetConnection: false,
}
// FIXME(conman): Set connect values here?
cm := pmapi.New(pmapi.DefaultConfig)
cm.SetTransport(&fakeTransport{
ctl: controller,
transport: http.DefaultTransport,
@ -56,3 +56,10 @@ func NewController() (*Controller, pmapi.Manager) {
return controller, cm
}
func getAppVersionName(app string) string {
if app == "ie" {
return "importExport"
}
return app
}

View File

@ -45,7 +45,7 @@ func (ctl *Controller) AddUserLabel(username string, label *pmapi.Label) error {
label.Exclusive = getLabelExclusive(label.Name)
label.Name = getLabelNameWithoutPrefix(label.Name)
label.Color = pmapi.LabelColors[0]
if _, err := client.CreateLabel(context.TODO(), label); err != nil {
if _, err := client.CreateLabel(context.Background(), label); err != nil {
return errors.Wrap(err, "failed to create label")
}
return nil
@ -73,7 +73,7 @@ func (ctl *Controller) getLabelID(username, labelName string) (string, error) {
return "", fmt.Errorf("user %s does not exist", username)
}
labels, err := client.ListLabels(context.TODO())
labels, err := client.ListLabels(context.Background())
if err != nil {
return "", errors.Wrap(err, "failed to list labels")
}
@ -98,9 +98,6 @@ func getLabelNameWithoutPrefix(name string) string {
return name
}
func getLabelExclusive(name string) int {
if strings.HasPrefix(name, "Folders/") {
return 1
}
return 0
func getLabelExclusive(name string) pmapi.Boolean {
return pmapi.Boolean(strings.HasPrefix(name, "Folders/"))
}

View File

@ -61,7 +61,7 @@ func (ctl *Controller) AddUserMessage(username string, message *pmapi.Message) (
Message: body,
}
results, err := client.Import(context.TODO(), pmapi.ImportMsgReqs{req})
results, err := client.Import(context.Background(), pmapi.ImportMsgReqs{req})
if err != nil {
return "", errors.Wrap(err, "failed to make an import")
}
@ -85,7 +85,7 @@ func (ctl *Controller) GetMessages(username, labelID string) ([]*pmapi.Message,
for {
// ListMessages returns empty result, not error, asking for page out of range.
pageMessages, _, err := client.ListMessages(context.TODO(), &pmapi.MessagesFilter{
pageMessages, _, err := client.ListMessages(context.Background(), &pmapi.MessagesFilter{
Page: page,
PageSize: 150,
LabelID: labelID,

View File

@ -48,9 +48,11 @@ func (t *fakeTransport) RoundTrip(req *http.Request) (*http.Response, error) {
if err != nil {
return nil, errors.Wrap(err, "failed to get body")
}
body, err = ioutil.ReadAll(bodyReader)
if err != nil {
return nil, errors.Wrap(err, "failed to read body")
if bodyReader != nil {
body, err = ioutil.ReadAll(bodyReader)
if err != nil {
return nil, errors.Wrap(err, "failed to read body")
}
}
}
t.ctl.recordCall(req.Method, req.URL.Path, body)

View File

@ -30,12 +30,12 @@ func (ctl *Controller) AddUser(user *pmapi.User, addresses *pmapi.AddressList, p
return godog.ErrPending
}
client, _, err := ctl.clientManager.NewClientWithLogin(context.TODO(), user.Name, password)
client, _, err := ctl.clientManager.NewClientWithLogin(context.Background(), user.Name, password)
if err != nil {
return errors.Wrap(err, "failed to create new client")
}
salt, err := client.AuthSalt(context.TODO())
salt, err := client.AuthSalt(context.Background())
if err != nil {
return errors.Wrap(err, "failed to get salt")
}
@ -45,7 +45,7 @@ func (ctl *Controller) AddUser(user *pmapi.User, addresses *pmapi.AddressList, p
return errors.Wrap(err, "failed to hash mailbox password")
}
if err := client.Unlock(context.TODO(), mailboxPassword); err != nil {
if err := client.Unlock(context.Background(), mailboxPassword); err != nil {
return errors.Wrap(err, "failed to unlock user")
}
@ -59,5 +59,5 @@ func (ctl *Controller) AddUser(user *pmapi.User, addresses *pmapi.AddressList, p
}
func (ctl *Controller) ReorderAddresses(user *pmapi.User, addressIDs []string) error {
return ctl.pmapiByUsername[user.Name].ReorderAddresses(context.TODO(), addressIDs)
return ctl.pmapiByUsername[user.Name].ReorderAddresses(context.Background(), addressIDs)
}

View File

@ -256,11 +256,10 @@ func messagesContainsMessageRow(account *accounts.TestAccount, allMessages []int
}
case "read":
var unread pmapi.Boolean
if cell.Value == "true" { //nolint[goconst]
unread = pmapi.False
unread = false
} else {
unread = pmapi.True
unread = true
}
if message.Unread != unread {
@ -299,7 +298,7 @@ func areAddressesSame(first, second string) bool {
func messagesInMailboxForUserIsMarkedAsRead(bddMessageIDs, mailboxName, bddUserID string) error {
return checkMessages(bddUserID, mailboxName, bddMessageIDs, func(message *store.Message) error {
if message.Message().Unread == 0 {
if !message.Message().Unread {
return nil
}
return fmt.Errorf("message %s \"%s\" is expected to be read but is not", message.ID(), message.Message().Subject)
@ -308,7 +307,7 @@ func messagesInMailboxForUserIsMarkedAsRead(bddMessageIDs, mailboxName, bddUserI
func messagesInMailboxForUserIsMarkedAsUnread(bddMessageIDs, mailboxName, bddUserID string) error {
return checkMessages(bddUserID, mailboxName, bddMessageIDs, func(message *store.Message) error {
if message.Message().Unread == 1 {
if message.Message().Unread {
return nil
}
return fmt.Errorf("message %s \"%s\" is expected to not be read but is", message.ID(), message.Message().Subject)

View File

@ -34,10 +34,6 @@ func UsersChecksFeatureContext(s *godog.Suite) {
s.Step(`^"([^"]*)" does not have loaded store$`, userDoesNotHaveLoadedStore)
s.Step(`^"([^"]*)" has running event loop$`, userHasRunningEventLoop)
s.Step(`^"([^"]*)" does not have running event loop$`, userDoesNotHaveRunningEventLoop)
// FIXME(conman): Write tests for new "auth" system.
// s.Step(`^"([^"]*)" does not have API auth$`, isNotAuthorized)
// s.Step(`^"([^"]*)" has API auth$`, isAuthorized)
}
func userHasAddressModeInMode(bddUserID, wantAddressMode string) error {
@ -158,36 +154,11 @@ func userDoesNotHaveRunningEventLoop(bddUserID string) error {
if err != nil {
return internalError(err, "getting store of %s", account.Username())
}
if store == nil {
return nil
}
a.Eventually(ctx.GetTestingT(), func() bool {
return store.TestGetEventLoop() == nil || !store.TestGetEventLoop().IsRunning()
}, 5*time.Second, 10*time.Millisecond)
return ctx.GetTestingError()
}
/*
func isAuthorized(bddUserID string) error {
account := ctx.GetTestAccount(bddUserID)
if account == nil {
return godog.ErrPending
}
user, err := ctx.GetUser(account.Username())
if err != nil {
return internalError(err, "getting user %s", account.Username())
}
a.Eventually(ctx.GetTestingT(), user.IsAuthorized, 5*time.Second, 10*time.Millisecond)
return ctx.GetTestingError()
}
func isNotAuthorized(bddUserID string) error {
account := ctx.GetTestAccount(bddUserID)
if account == nil {
return godog.ErrPending
}
user, err := ctx.GetUser(account.Username())
if err != nil {
return internalError(err, "getting user %s", account.Username())
}
a.Eventually(ctx.GetTestingT(), func() bool { return !user.IsAuthorized() }, 5*time.Second, 10*time.Millisecond)
return ctx.GetTestingError()
}
*/