Launcher, app/base, sentry, update service

This commit is contained in:
James Houlahan
2020-11-23 11:56:57 +01:00
parent 6fffb460b8
commit dc3f61acee
164 changed files with 5368 additions and 4039 deletions

View File

@ -21,7 +21,6 @@ import (
"time"
"github.com/ProtonMail/proton-bridge/internal/bridge"
"github.com/ProtonMail/proton-bridge/internal/preferences"
"github.com/ProtonMail/proton-bridge/internal/users"
"github.com/ProtonMail/proton-bridge/pkg/listener"
)
@ -34,7 +33,7 @@ func (ctx *TestContext) GetBridge() *bridge.Bridge {
// withBridgeInstance creates a bridge instance for use in the test.
// TestContext has this by default once called with env variable TEST_APP=bridge.
func (ctx *TestContext) withBridgeInstance() {
ctx.bridge = newBridgeInstance(ctx.t, ctx.cfg, ctx.credStore, ctx.listener, ctx.clientManager)
ctx.bridge = newBridgeInstance(ctx.t, ctx.locations, ctx.cache, ctx.settings, ctx.credStore, ctx.listener, ctx.clientManager)
ctx.users = ctx.bridge.Users
ctx.addCleanupChecked(ctx.bridge.ClearData, "Cleaning bridge data")
}
@ -61,12 +60,13 @@ func (ctx *TestContext) RestartBridge() error {
// newBridgeInstance creates a new bridge instance configured to use the given config/credstore.
func newBridgeInstance(
t *bddT,
cfg *fakeConfig,
locations bridge.Locator,
cache bridge.Cacher,
settings *fakeSettings,
credStore users.CredentialsStorer,
eventListener listener.Listener,
clientManager users.ClientManager,
) *bridge.Bridge {
panicHandler := &panicHandler{t: t}
pref := preferences.New(cfg)
return bridge.New(cfg, pref, panicHandler, eventListener, clientManager, credStore)
return bridge.New(locations, cache, settings, panicHandler, eventListener, clientManager, credStore)
}

55
test/context/cache.go Normal file
View File

@ -0,0 +1,55 @@
// Copyright (c) 2020 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"
"path/filepath"
)
type fakeCache struct {
dir string
}
// newFakeCache creates a temporary folder for files.
// It's expected the test calls `ClearData` before finish to remove it from the file system.
func newFakeCache() *fakeCache {
dir, err := ioutil.TempDir("", "test-cache")
if err != nil {
panic(err)
}
return &fakeCache{
dir: dir,
}
}
// GetDBDir returns folder for db files.
func (c *fakeCache) GetDBDir() string {
return c.dir
}
// GetIMAPCachePath returns path to file with IMAP status.
func (c *fakeCache) GetIMAPCachePath() string {
return filepath.Join(c.dir, "user_info.json")
}
// GetTransferDir returns folder for import-export rules files.
func (c *fakeCache) GetTransferDir() string {
return c.dir
}

View File

@ -1,103 +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"
"path/filepath"
"github.com/ProtonMail/proton-bridge/pkg/config"
"github.com/ProtonMail/proton-bridge/pkg/constants"
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
"github.com/sirupsen/logrus"
)
type fakeConfig struct {
dir string
}
// newFakeConfig creates a temporary folder for files.
// It's expected the test calls `ClearData` before finish to remove it from the file system.
func newFakeConfig() *fakeConfig {
dir, err := ioutil.TempDir("", "example")
if err != nil {
panic(err)
}
cfg := &fakeConfig{
dir: dir,
}
// We must generate cert.pem and key.pem to prevent errors when attempting to open them.
if _, err = config.GenerateTLSConfig(cfg.GetTLSCertPath(), cfg.GetTLSKeyPath()); err != nil {
logrus.WithError(err).Fatal()
}
return cfg
}
func (c *fakeConfig) ClearData() error {
return os.RemoveAll(c.dir)
}
func (c *fakeConfig) GetAPIConfig() *pmapi.ClientConfig {
return &pmapi.ClientConfig{
AppVersion: "Bridge_" + constants.Version,
ClientID: "bridge",
}
}
func (c *fakeConfig) GetDBDir() string {
return c.dir
}
func (c *fakeConfig) GetVersion() string {
return constants.Version
}
func (c *fakeConfig) GetLogDir() string {
return c.dir
}
func (c *fakeConfig) GetLogPrefix() string {
return "test"
}
func (c *fakeConfig) GetPreferencesPath() string {
return filepath.Join(c.dir, "prefs.json")
}
func (c *fakeConfig) GetTransferDir() string {
return c.dir
}
func (c *fakeConfig) GetTLSCertPath() string {
return filepath.Join(c.dir, "cert.pem")
}
func (c *fakeConfig) GetTLSKeyPath() string {
return filepath.Join(c.dir, "key.pem")
}
func (c *fakeConfig) GetEventsPath() string {
return filepath.Join(c.dir, "events.json")
}
func (c *fakeConfig) GetIMAPCachePath() string {
return filepath.Join(c.dir, "user_info.json")
}
func (c *fakeConfig) GetDefaultAPIPort() int {
return 21042
}
func (c *fakeConfig) GetDefaultIMAPPort() int {
return 21100 + rand.Intn(100)
}
func (c *fakeConfig) GetDefaultSMTPPort() int {
return 21200 + rand.Intn(100)
}

View File

@ -41,7 +41,9 @@ type server interface {
type TestContext struct {
// Base setup for the whole bridge (core & imap & smtp).
t *bddT
cfg *fakeConfig
cache *fakeCache
locations *fakeLocations
settings *fakeSettings
listener listener.Listener
testAccounts *accounts.TestAccounts
@ -92,13 +94,13 @@ type TestContext struct {
func New(app string) *TestContext {
setLogrusVerbosityFromEnv()
cfg := newFakeConfig()
cm := pmapi.NewClientManager(cfg.GetAPIConfig())
cm := pmapi.NewClientManager(pmapi.GetAPIConfig("TODO", "TODO"))
ctx := &TestContext{
t: &bddT{},
cfg: cfg,
cache: newFakeCache(),
locations: newFakeLocations(),
settings: newFakeSettings(),
listener: listener.New(),
pmapiController: newPMAPIController(cm),
clientManager: cm,
@ -115,7 +117,7 @@ func New(app string) *TestContext {
}
// Ensure that the config is cleaned up after the test is over.
ctx.addCleanupChecked(cfg.ClearData, "Cleaning bridge config data")
ctx.addCleanupChecked(ctx.locations.Clear, "Cleaning bridge config data")
// Create bridge or import-export instance under test.
switch app {
@ -144,6 +146,11 @@ func (ctx *TestContext) GetPMAPIController() PMAPIController {
return ctx.pmapiController
}
// GetClientManager returns client manager being used for testing.
func (ctx *TestContext) GetClientManager() *pmapi.ClientManager {
return ctx.clientManager
}
// GetTestingT returns testing.T compatible struct.
func (ctx *TestContext) GetTestingT() *bddT { //nolint[golint]
return ctx.t

View File

@ -22,9 +22,9 @@ import (
"time"
"github.com/ProtonMail/proton-bridge/internal/bridge"
"github.com/ProtonMail/proton-bridge/internal/config/settings"
"github.com/ProtonMail/proton-bridge/internal/config/tls"
"github.com/ProtonMail/proton-bridge/internal/imap"
"github.com/ProtonMail/proton-bridge/internal/preferences"
"github.com/ProtonMail/proton-bridge/pkg/config"
"github.com/ProtonMail/proton-bridge/test/mocks"
"github.com/stretchr/testify/require"
)
@ -53,12 +53,12 @@ func (ctx *TestContext) withIMAPServer() {
return
}
settingsPath, _ := ctx.locations.ProvideSettingsPath()
ph := newPanicHandler(ctx.t)
pref := preferences.New(ctx.cfg)
port := pref.GetInt(preferences.IMAPPortKey)
tls, _ := config.GetTLSConfig(ctx.cfg)
port := ctx.settings.GetInt(settings.IMAPPortKey)
tls, _ := tls.New(settingsPath).GetConfig()
backend := imap.NewIMAPBackend(ph, ctx.listener, ctx.cfg, ctx.bridge)
backend := imap.NewIMAPBackend(ph, ctx.listener, ctx.cache, ctx.bridge)
server := imap.NewIMAPServer(true, true, port, tls, backend, ctx.listener)
go server.ListenAndServe()

View File

@ -31,18 +31,19 @@ func (ctx *TestContext) GetImportExport() *importexport.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.cfg, ctx.credStore, ctx.listener, ctx.clientManager)
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,
cfg importexport.Configer,
locations importexport.Locator,
cache importexport.Cacher,
credStore users.CredentialsStorer,
eventListener listener.Listener,
clientManager users.ClientManager,
) *importexport.ImportExport {
panicHandler := &panicHandler{t: t}
return importexport.New(cfg, panicHandler, eventListener, clientManager, credStore)
return importexport.New(locations, cache, panicHandler, eventListener, clientManager, credStore)
}

50
test/context/locations.go Normal file
View File

@ -0,0 +1,50 @@
// Copyright (c) 2020 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"
"os"
)
type fakeLocations struct {
dir string
}
func newFakeLocations() *fakeLocations {
dir, err := ioutil.TempDir("", "test-cache")
if err != nil {
panic(err)
}
return &fakeLocations{
dir: dir,
}
}
func (l *fakeLocations) ProvideLogsPath() (string, error) {
return l.dir, nil
}
func (l *fakeLocations) ProvideSettingsPath() (string, error) {
return l.dir, nil
}
func (l *fakeLocations) Clear() error {
return os.RemoveAll(l.dir)
}

50
test/context/settings.go Normal file
View File

@ -0,0 +1,50 @@
// Copyright (c) 2020 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"
"github.com/ProtonMail/proton-bridge/internal/config/settings"
)
type fakeSettings struct {
*settings.Settings
dir string
}
// newFakeSettings creates a temporary folder for files.
// It's expected the test calls `ClearData` before finish to remove it from the file system.
func newFakeSettings() *fakeSettings {
dir, err := ioutil.TempDir("", "test-settings")
if err != nil {
panic(err)
}
s := &fakeSettings{
Settings: settings.New(dir),
dir: dir,
}
// We should use nonstandard ports to not conflict with bridge.
s.SetInt(settings.IMAPPortKey, 21100+rand.Intn(100))
s.SetInt(settings.SMTPPortKey, 21200+rand.Intn(100))
return s
}

View File

@ -22,9 +22,9 @@ import (
"time"
"github.com/ProtonMail/proton-bridge/internal/bridge"
"github.com/ProtonMail/proton-bridge/internal/preferences"
"github.com/ProtonMail/proton-bridge/internal/config/settings"
"github.com/ProtonMail/proton-bridge/internal/config/tls"
"github.com/ProtonMail/proton-bridge/internal/smtp"
"github.com/ProtonMail/proton-bridge/pkg/config"
"github.com/ProtonMail/proton-bridge/test/mocks"
"github.com/stretchr/testify/require"
)
@ -53,13 +53,13 @@ func (ctx *TestContext) withSMTPServer() {
return
}
settingsPath, _ := ctx.locations.ProvideSettingsPath()
ph := newPanicHandler(ctx.t)
pref := preferences.New(ctx.cfg)
tls, _ := config.GetTLSConfig(ctx.cfg)
port := pref.GetInt(preferences.SMTPPortKey)
useSSL := pref.GetBool(preferences.SMTPSSLKey)
tls, _ := tls.New(settingsPath).GetConfig()
port := ctx.settings.GetInt(settings.SMTPPortKey)
useSSL := ctx.settings.GetBool(settings.SMTPSSLKey)
backend := smtp.NewSMTPBackend(ph, ctx.listener, pref, ctx.bridge)
backend := smtp.NewSMTPBackend(ph, ctx.listener, ctx.settings, ctx.bridge)
server := smtp.NewSMTPServer(true, port, useSSL, tls, backend, ctx.listener)
go server.ListenAndServe()

View File

@ -96,7 +96,7 @@ func (ctx *TestContext) GetStoreMailbox(username, addressID, mailboxName string)
func (ctx *TestContext) GetDatabaseFilePath(userID string) string {
// We cannot use store to get information because we need to check db file also when user is deleted from bridge.
fileName := fmt.Sprintf("mailbox-%v.db", userID)
return filepath.Join(ctx.cfg.GetDBDir(), fileName)
return filepath.Join(ctx.cache.GetDBDir(), fileName)
}
// WaitForSync waits for sync to be done.