diff --git a/go.mod b/go.mod index b48da270..b5cc2c68 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/0xAX/notificator v0.0.0-20220220101646-ee9b8921e557 github.com/Masterminds/semver/v3 v3.1.1 - github.com/ProtonMail/gluon v0.14.2-0.20230106095250-7e99ea4da61e + github.com/ProtonMail/gluon v0.14.2-0.20230111132924-ace48198e45a github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a github.com/ProtonMail/go-proton-api v0.2.4-0.20230112102613-6ad201cdb337 github.com/ProtonMail/go-rfc5322 v0.11.0 diff --git a/go.sum b/go.sum index 85b2db5b..4f134c84 100644 --- a/go.sum +++ b/go.sum @@ -28,8 +28,8 @@ github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf h1:yc9daCCYUefEs github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf/go.mod h1:o0ESU9p83twszAU8LBeJKFAAMX14tISa0yk4Oo5TOqo= github.com/ProtonMail/docker-credential-helpers v1.1.0 h1:+kvUIpwWcbtP3WFv5sSvkFn/XLzSqPOB5AAthuk9xPk= github.com/ProtonMail/docker-credential-helpers v1.1.0/go.mod h1:mK0aBveCxhnQ756AmaTfXMZDeULvheYVhF/MWMErN5g= -github.com/ProtonMail/gluon v0.14.2-0.20230106095250-7e99ea4da61e h1://xRNjGTAMXw2U91MtqPc4krUtxQmt2+4z1oYrBaOWU= -github.com/ProtonMail/gluon v0.14.2-0.20230106095250-7e99ea4da61e/go.mod h1:z2AxLIiBCT1K+0OBHyaDI7AEaO5qI6/BEC2TE42vs4Q= +github.com/ProtonMail/gluon v0.14.2-0.20230111132924-ace48198e45a h1:yx/1F4jGMLVTUVeycIGwe90l5YQWrvoTbPOYWC4FLkY= +github.com/ProtonMail/gluon v0.14.2-0.20230111132924-ace48198e45a/go.mod h1:z2AxLIiBCT1K+0OBHyaDI7AEaO5qI6/BEC2TE42vs4Q= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a h1:D+aZah+k14Gn6kmL7eKxoo/4Dr/lK3ChBcwce2+SQP4= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4= github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= diff --git a/internal/bridge/bridge.go b/internal/bridge/bridge.go index 6772d727..2073e4e4 100644 --- a/internal/bridge/bridge.go +++ b/internal/bridge/bridge.go @@ -221,8 +221,14 @@ func newBridge( return nil, fmt.Errorf("failed to get Gluon directory: %w", err) } + gluonDBDir, err := locator.ProvideGluonPath() + if err != nil { + return nil, fmt.Errorf("failed to get Gluon Database directory: %w", err) + } + imapServer, err := newIMAPServer( gluonDir, + gluonDBDir, curVersion, tlsConfig, reporter, diff --git a/internal/bridge/bridge_test.go b/internal/bridge/bridge_test.go index 9aaa6f2d..79be477c 100644 --- a/internal/bridge/bridge_test.go +++ b/internal/bridge/bridge_test.go @@ -23,7 +23,7 @@ import ( "fmt" "net/http" "os" - "runtime" + "path/filepath" "sync" "testing" "time" @@ -35,6 +35,7 @@ import ( "github.com/ProtonMail/gopenpgp/v2/crypto" "github.com/ProtonMail/proton-bridge/v3/internal/bridge" "github.com/ProtonMail/proton-bridge/v3/internal/certs" + "github.com/ProtonMail/proton-bridge/v3/internal/constants" "github.com/ProtonMail/proton-bridge/v3/internal/cookies" "github.com/ProtonMail/proton-bridge/v3/internal/events" "github.com/ProtonMail/proton-bridge/v3/internal/focus" @@ -45,6 +46,7 @@ import ( "github.com/ProtonMail/proton-bridge/v3/internal/vault" "github.com/ProtonMail/proton-bridge/v3/tests" "github.com/bradenaw/juniper/xslices" + "github.com/emersion/go-imap/client" "github.com/stretchr/testify/require" ) @@ -349,7 +351,7 @@ func TestBridge_BadVaultKey(t *testing.T) { }) } -func TestBridge_MissingGluonDir(t *testing.T) { +func TestBridge_MissingGluonStore(t *testing.T) { withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, vaultKey []byte) { var gluonDir string @@ -361,13 +363,36 @@ func TestBridge_MissingGluonDir(t *testing.T) { require.NoError(t, bridge.SetGluonDir(ctx, t.TempDir())) // Get the gluon dir. - gluonDir = bridge.GetGluonDir() + gluonDir = bridge.GetGluonCacheDir() }) // The user removes the gluon dir while bridge is not running. require.NoError(t, os.RemoveAll(gluonDir)) - // Bridge starts but can't find the gluon dir; there should be no error. + // Bridge starts but can't find the gluon store dir; there should be no error. + withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) { + // ... + }) + }) +} + +func TestBridge_MissingGluonDatabase(t *testing.T) { + withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, vaultKey []byte) { + var gluonDir string + + withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) { + _, err := bridge.LoginFull(context.Background(), username, password, nil, nil) + require.NoError(t, err) + + // Get the gluon dir. + gluonDir, err = bridge.GetGluonConfigDir() + require.NoError(t, err) + }) + + // The user removes the gluon dir while bridge is not running. + require.NoError(t, os.RemoveAll(gluonDir)) + + // Bridge starts but can't find the gluon database dir; there should be no error. withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) { // ... }) @@ -456,41 +481,80 @@ func TestBridge_FactoryReset(t *testing.T) { }) } -func TestBridge_ChangeCacheDirectoryFailsBetweenDifferentVolumes(t *testing.T) { - if runtime.GOOS != "windows" { - t.Skip("Test only necessary on windows") - } +func TestBridge_InitGluonDirectory(t *testing.T) { withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, vaultKey []byte) { - withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) { - // Change directory - err := bridge.SetGluonDir(ctx, "XX:\\") - require.Error(t, err) + withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(b *bridge.Bridge, mocks *bridge.Mocks) { + configDir, err := b.GetGluonConfigDir() + require.NoError(t, err) + + _, err = os.ReadDir(bridge.ApplyGluonCachePathSuffix(b.GetGluonCacheDir())) + require.False(t, os.IsNotExist(err)) + + _, err = os.ReadDir(bridge.ApplyGluonDBPathSuffix(configDir)) + require.False(t, os.IsNotExist(err)) }) }) } func TestBridge_ChangeCacheDirectory(t *testing.T) { withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, vaultKey []byte) { - withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) { + userID, addrID, err := s.CreateUser("imap", password) + require.NoError(t, err) + + labelID, err := s.CreateLabel(userID, "folder", "", proton.LabelTypeFolder) + require.NoError(t, err) + + withClient(ctx, t, s, "imap", password, func(ctx context.Context, c *proton.Client) { + createNumMessages(ctx, t, c, addrID, labelID, 10) + }) + + withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(b *bridge.Bridge, mocks *bridge.Mocks) { newCacheDir := t.TempDir() - currentCacheDir := bridge.GetGluonDir() + currentCacheDir := b.GetGluonCacheDir() + configDir, err := b.GetGluonConfigDir() + require.NoError(t, err) // Login the user. - userID, err := bridge.LoginFull(ctx, username, password, nil, nil) + syncCh, done := chToType[events.Event, events.SyncFinished](b.GetEvents(events.SyncFinished{})) + defer done() + userID, err := b.LoginFull(ctx, "imap", password, nil, nil) require.NoError(t, err) + require.Equal(t, userID, (<-syncCh).UserID) // The user is now connected. - require.Equal(t, []string{userID}, bridge.GetUserIDs()) - require.Equal(t, []string{userID}, getConnectedUserIDs(t, bridge)) + require.Equal(t, []string{userID}, b.GetUserIDs()) + require.Equal(t, []string{userID}, getConnectedUserIDs(t, b)) // Change directory - err = bridge.SetGluonDir(ctx, newCacheDir) + err = b.SetGluonDir(ctx, newCacheDir) require.NoError(t, err) - _, err = os.ReadDir(currentCacheDir) + // Old store should no more exists. + _, err = os.ReadDir(bridge.ApplyGluonCachePathSuffix(currentCacheDir)) require.True(t, os.IsNotExist(err)) + // Database should not have changed. + _, err = os.ReadDir(bridge.ApplyGluonDBPathSuffix(configDir)) + require.False(t, os.IsNotExist(err)) - require.Equal(t, newCacheDir, bridge.GetGluonDir()) + // New path should have Gluon sub-folder. + require.Equal(t, filepath.Join(newCacheDir, "gluon"), b.GetGluonCacheDir()) + // And store should be inside it. + _, err = os.ReadDir(bridge.ApplyGluonCachePathSuffix(b.GetGluonCacheDir())) + require.False(t, os.IsNotExist(err)) + + // We should be able to fetch. + info, err := b.GetUserInfo(userID) + require.NoError(t, err) + require.True(t, info.State == bridge.Connected) + + client, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) + require.NoError(t, err) + require.NoError(t, client.Login(info.Addresses[0], string(info.BridgePass))) + defer func() { _ = client.Logout() }() + + status, err := client.Select(`Folders/folder`, false) + require.NoError(t, err) + require.Equal(t, uint32(10), status.Messages) }) }) } diff --git a/internal/bridge/files.go b/internal/bridge/files.go index 7301872c..475b1925 100644 --- a/internal/bridge/files.go +++ b/internal/bridge/files.go @@ -18,6 +18,8 @@ package bridge import ( + "fmt" + "io" "os" "path/filepath" ) @@ -62,3 +64,75 @@ func moveFile(from, to string) error { return nil } + +func copyDir(from, to string) error { + entries, err := os.ReadDir(from) + if err != nil { + return err + } + if err := createIfNotExists(to, 0o700); err != nil { + return err + } + for _, entry := range entries { + sourcePath := filepath.Join(from, entry.Name()) + destPath := filepath.Join(to, entry.Name()) + + if entry.IsDir() { + if err := copyDir(sourcePath, destPath); err != nil { + return err + } + } else { + if err := copyFile(sourcePath, destPath); err != nil { + return err + } + } + } + return nil +} + +func copyFile(srcFile, dstFile string) error { + out, err := os.Create(filepath.Clean(dstFile)) + defer func(out *os.File) { + _ = out.Close() + }(out) + + if err != nil { + return err + } + + in, err := os.Open(filepath.Clean(srcFile)) + defer func(in *os.File) { + _ = in.Close() + }(in) + + if err != nil { + return err + } + + _, err = io.Copy(out, in) + if err != nil { + return err + } + + return nil +} + +func exists(filePath string) bool { + if _, err := os.Stat(filePath); os.IsNotExist(err) { + return false + } + + return true +} + +func createIfNotExists(dir string, perm os.FileMode) error { + if exists(dir) { + return nil + } + + if err := os.MkdirAll(dir, perm); err != nil { + return fmt.Errorf("failed to create directory: '%s', error: '%s'", dir, err.Error()) + } + + return nil +} diff --git a/internal/bridge/imap.go b/internal/bridge/imap.go index 67a98b41..9922bbfa 100644 --- a/internal/bridge/imap.go +++ b/internal/bridge/imap.go @@ -199,13 +199,13 @@ func (bridge *Bridge) handleIMAPEvent(event imapEvents.Event) { } func getGluonDir(encVault *vault.Vault) (string, error) { - empty, exists, err := isEmpty(encVault.GetGluonDir()) + empty, exists, err := isEmpty(encVault.GetGluonCacheDir()) if err != nil { return "", fmt.Errorf("failed to check if gluon dir is empty: %w", err) } if !exists { - if err := os.MkdirAll(encVault.GetGluonDir(), 0o700); err != nil { + if err := os.MkdirAll(encVault.GetGluonCacheDir(), 0o700); err != nil { return "", fmt.Errorf("failed to create gluon dir: %w", err) } } @@ -218,12 +218,20 @@ func getGluonDir(encVault *vault.Vault) (string, error) { } } - return encVault.GetGluonDir(), nil + return encVault.GetGluonCacheDir(), nil +} + +func ApplyGluonCachePathSuffix(basePath string) string { + return filepath.Join(basePath, "backend", "store") +} + +func ApplyGluonDBPathSuffix(basePath string) string { + return filepath.Join(basePath, "backend", "db") } // nolint:funlen func newIMAPServer( - gluonDir string, + gluonCacheDir, gluonDBDir string, version *semver.Version, tlsConfig *tls.Config, reporter reporter.Reporter, @@ -231,11 +239,15 @@ func newIMAPServer( eventCh chan<- imapEvents.Event, tasks *async.Group, ) (*gluon.Server, error) { + gluonCacheDir = ApplyGluonCachePathSuffix(gluonCacheDir) + gluonDBDir = ApplyGluonDBPathSuffix(gluonDBDir) + logrus.WithFields(logrus.Fields{ - "gluonDir": gluonDir, - "version": version, - "logClient": logClient, - "logServer": logServer, + "gluonStore": gluonCacheDir, + "gluonDB": gluonDBDir, + "version": version, + "logClient": logClient, + "logServer": logServer, }).Info("Creating IMAP server") if logClient || logServer { @@ -263,7 +275,8 @@ func newIMAPServer( imapServer, err := gluon.New( gluon.WithTLS(tlsConfig), - gluon.WithDataDir(gluonDir), + gluon.WithDataDir(gluonCacheDir), + gluon.WithDatabaseDir(gluonDBDir), gluon.WithStoreBuilder(new(storeBuilder)), gluon.WithLogger(imapClientLog, imapServerLog), getGluonVersionInfo(version), diff --git a/internal/bridge/settings.go b/internal/bridge/settings.go index 64efe88b..a0771ffe 100644 --- a/internal/bridge/settings.go +++ b/internal/bridge/settings.go @@ -21,6 +21,7 @@ import ( "context" "fmt" "net" + "os" "path/filepath" "github.com/Masterminds/semver/v3" @@ -114,38 +115,47 @@ func (bridge *Bridge) SetSMTPSSL(newSSL bool) error { return bridge.restartSMTP() } -func (bridge *Bridge) GetGluonDir() string { - return bridge.vault.GetGluonDir() +func (bridge *Bridge) GetGluonCacheDir() string { + return bridge.vault.GetGluonCacheDir() +} + +func (bridge *Bridge) GetGluonConfigDir() (string, error) { + return bridge.locator.ProvideGluonPath() } func (bridge *Bridge) SetGluonDir(ctx context.Context, newGluonDir string) error { return safe.RLockRet(func() error { - currentGluonDir := bridge.GetGluonDir() + currentGluonDir := bridge.GetGluonCacheDir() + newGluonDir = filepath.Join(newGluonDir, "gluon") if newGluonDir == currentGluonDir { return fmt.Errorf("new gluon dir is the same as the old one") } - currentVolumeName := filepath.VolumeName(currentGluonDir) - newVolumeName := filepath.VolumeName(newGluonDir) + if err := bridge.stopEventLoops(); err != nil { + return err + } + defer func() { + err := bridge.startEventLoops(ctx) + if err != nil { + panic(err) + } + }() - if currentVolumeName != newVolumeName { - return fmt.Errorf("it's currently not possible to move the cache between different volumes") + if err := bridge.moveGluonCacheDir(currentGluonDir, newGluonDir); err != nil { + logrus.WithError(err).Error("failed to move GluonCacheDir") + if err := bridge.vault.SetGluonDir(currentGluonDir); err != nil { + panic(err) + } } - if err := bridge.closeIMAP(context.Background()); err != nil { - return fmt.Errorf("failed to close IMAP: %w", err) - } - - if err := moveDir(bridge.GetGluonDir(), newGluonDir); err != nil { - return fmt.Errorf("failed to move gluon dir: %w", err) - } - - if err := bridge.vault.SetGluonDir(newGluonDir); err != nil { - return fmt.Errorf("failed to set new gluon dir: %w", err) + gluonDBDir, err := bridge.GetGluonConfigDir() + if err != nil { + panic(fmt.Errorf("failed to get Gluon Database directory: %w", err)) } imapServer, err := newIMAPServer( - bridge.vault.GetGluonDir(), + bridge.vault.GetGluonCacheDir(), + gluonDBDir, bridge.curVersion, bridge.tlsConfig, bridge.reporter, @@ -155,25 +165,60 @@ func (bridge *Bridge) SetGluonDir(ctx context.Context, newGluonDir string) error bridge.tasks, ) if err != nil { - return fmt.Errorf("failed to create new IMAP server: %w", err) + panic(fmt.Errorf("failed to create new IMAP server: %w", err)) } bridge.imapServer = imapServer - for _, user := range bridge.users { - if err := bridge.addIMAPUser(ctx, user); err != nil { - return fmt.Errorf("failed to add users to new IMAP server: %w", err) - } - } - - if err := bridge.serveIMAP(); err != nil { - return fmt.Errorf("failed to serve IMAP: %w", err) - } - return nil }, bridge.usersLock) } +func (bridge *Bridge) moveGluonCacheDir(oldGluonDir, newGluonDir string) error { + logrus.Infof("gluon cache moving from %s to %s", oldGluonDir, newGluonDir) + oldCacheDir := ApplyGluonCachePathSuffix(oldGluonDir) + if err := copyDir(oldCacheDir, ApplyGluonCachePathSuffix(newGluonDir)); err != nil { + return fmt.Errorf("failed to copy gluon dir: %w", err) + } + + if err := bridge.vault.SetGluonDir(newGluonDir); err != nil { + return fmt.Errorf("failed to set new gluon cache dir: %w", err) + } + + if err := os.RemoveAll(oldCacheDir); err != nil { + logrus.WithError(err).Error("failed to remove old gluon cache dir") + } + return nil +} + +func (bridge *Bridge) stopEventLoops() error { + if err := bridge.closeIMAP(context.Background()); err != nil { + return fmt.Errorf("failed to close IMAP: %w", err) + } + + if err := bridge.closeSMTP(); err != nil { + return fmt.Errorf("failed to close SMTP: %w", err) + } + return nil +} + +func (bridge *Bridge) startEventLoops(ctx context.Context) error { + for _, user := range bridge.users { + if err := bridge.addIMAPUser(ctx, user); err != nil { + return fmt.Errorf("failed to add users to new IMAP server: %w", err) + } + } + + if err := bridge.serveIMAP(); err != nil { + panic(fmt.Errorf("failed to serve IMAP: %w", err)) + } + + if err := bridge.serveSMTP(); err != nil { + panic(fmt.Errorf("failed to serve SMTP: %w", err)) + } + return nil +} + func (bridge *Bridge) GetProxyAllowed() bool { return bridge.vault.GetProxyAllowed() } diff --git a/internal/bridge/sync_test.go b/internal/bridge/sync_test.go index 8c4c449c..4bdaf37f 100644 --- a/internal/bridge/sync_test.go +++ b/internal/bridge/sync_test.go @@ -399,6 +399,9 @@ func createMessages(ctx context.Context, t *testing.T, c *proton.Client, addrID, _, addrKRs, err := proton.Unlock(user, addr, keyPass) require.NoError(t, err) + _, ok := addrKRs[addrID] + require.True(t, ok) + res, err := stream.Collect(ctx, c.ImportMessages( ctx, addrKRs[addrID], diff --git a/internal/frontend/cli/system.go b/internal/frontend/cli/system.go index 262be120..c92df83f 100644 --- a/internal/frontend/cli/system.go +++ b/internal/frontend/cli/system.go @@ -196,7 +196,7 @@ func (f *frontendCLI) showAllMail(c *ishell.Context) { } func (f *frontendCLI) setGluonLocation(c *ishell.Context) { - if gluonDir := f.bridge.GetGluonDir(); gluonDir != "" { + if gluonDir := f.bridge.GetGluonCacheDir(); gluonDir != "" { f.Println("The current message cache location is:", gluonDir) } diff --git a/internal/frontend/grpc/service_methods.go b/internal/frontend/grpc/service_methods.go index 3b3016ce..6beecaf3 100644 --- a/internal/frontend/grpc/service_methods.go +++ b/internal/frontend/grpc/service_methods.go @@ -591,7 +591,7 @@ func (s *Service) IsAutomaticUpdateOn(ctx context.Context, _ *emptypb.Empty) (*w func (s *Service) DiskCachePath(ctx context.Context, _ *emptypb.Empty) (*wrapperspb.StringValue, error) { s.log.Debug("DiskCachePath") - return wrapperspb.String(s.bridge.GetGluonDir()), nil + return wrapperspb.String(s.bridge.GetGluonCacheDir()), nil } func (s *Service) SetDiskCachePath(ctx context.Context, newPath *wrapperspb.StringValue) (*emptypb.Empty, error) { @@ -609,14 +609,14 @@ func (s *Service) SetDiskCachePath(ctx context.Context, newPath *wrapperspb.Stri path = path[1:] } - if path != s.bridge.GetGluonDir() { + if path != s.bridge.GetGluonCacheDir() { if err := s.bridge.SetGluonDir(context.Background(), path); err != nil { s.log.WithError(err).Error("The local cache location could not be changed.") _ = s.SendEvent(NewDiskCacheErrorEvent(DiskCacheErrorType_CANT_MOVE_DISK_CACHE_ERROR)) return } - _ = s.SendEvent(NewDiskCachePathChangedEvent(s.bridge.GetGluonDir())) + _ = s.SendEvent(NewDiskCachePathChangedEvent(s.bridge.GetGluonCacheDir())) } }() diff --git a/internal/vault/migrate_test.go b/internal/vault/migrate_test.go index a92bb57e..32af3a19 100644 --- a/internal/vault/migrate_test.go +++ b/internal/vault/migrate_test.go @@ -57,7 +57,7 @@ func TestMigrate(t *testing.T) { require.False(t, corrupt) // Check the migrated vault. - require.Equal(t, "v2.3.x-gluon-dir", s.GetGluonDir()) + require.Equal(t, "v2.3.x-gluon-dir", s.GetGluonCacheDir()) require.Equal(t, 1234, s.GetIMAPPort()) require.Equal(t, 5678, s.GetSMTPPort()) diff --git a/internal/vault/settings.go b/internal/vault/settings.go index 1b2752b9..434cabb5 100644 --- a/internal/vault/settings.go +++ b/internal/vault/settings.go @@ -70,8 +70,8 @@ func (vault *Vault) SetSMTPSSL(ssl bool) error { }) } -// GetGluonDir sets the directory where the gluon should store its data. -func (vault *Vault) GetGluonDir() string { +// GetGluonCacheDir sets the directory where the gluon should store its data. +func (vault *Vault) GetGluonCacheDir() string { return vault.get().Settings.GluonDir } diff --git a/internal/vault/settings_test.go b/internal/vault/settings_test.go index f75b64d8..8e5cec9b 100644 --- a/internal/vault/settings_test.go +++ b/internal/vault/settings_test.go @@ -67,13 +67,13 @@ func TestVault_Settings_GluonDir(t *testing.T) { require.False(t, corrupt) // Check the default gluon dir. - require.Equal(t, "/path/to/gluon", s.GetGluonDir()) + require.Equal(t, "/path/to/gluon", s.GetGluonCacheDir()) // Modify the gluon dir. require.NoError(t, s.SetGluonDir("/tmp/gluon")) // Check the new gluon dir. - require.Equal(t, "/tmp/gluon", s.GetGluonDir()) + require.Equal(t, "/tmp/gluon", s.GetGluonCacheDir()) } func TestVault_Settings_UpdateChannel(t *testing.T) { diff --git a/internal/vault/vault_test.go b/internal/vault/vault_test.go index bf478f69..07b2b329 100644 --- a/internal/vault/vault_test.go +++ b/internal/vault/vault_test.go @@ -89,7 +89,7 @@ func TestVault_Reset(t *testing.T) { require.Equal(t, 5678, s.GetSMTPPort()) // Reset. - require.NoError(t, s.Reset(s.GetGluonDir())) + require.NoError(t, s.Reset(s.GetGluonCacheDir())) // The data is gone. require.Equal(t, 1143, s.GetIMAPPort()) diff --git a/tests/features/imap/migration.feature b/tests/features/imap/migration.feature index 58e113ed..136257f1 100644 --- a/tests/features/imap/migration.feature +++ b/tests/features/imap/migration.feature @@ -1,6 +1,10 @@ Feature: Bridge can fully sync an account Background: Given there exists an account with username "[user:user]" and password "password" + And the address "[user:user]@[domain]" of account "[user:user]" has the following messages in "Inbox": + | from | to | subject | unread | + | john.doe@mail.com | [user:user]@[domain] | foo | false | + | jane.doe@mail.com | name@[domain] | bar | true | And the account "[user:user]" has 20 custom folders And the account "[user:user]" has 60 custom labels When bridge starts @@ -13,5 +17,9 @@ Feature: Bridge can fully sync an account Scenario: The user changes the gluon path When the user changes the gluon path And user "[user:user]" connects and authenticates IMAP client "2" - Then IMAP client "2" counts 20 mailboxes under "Folders" + Then IMAP client "2" sees the following messages in "INBOX": + | from | to | subject | unread | + | john.doe@mail.com | [user:user]@[domain] | foo | false | + | jane.doe@mail.com | name@[domain] | bar | true | + And IMAP client "2" counts 20 mailboxes under "Folders" And IMAP client "2" counts 60 mailboxes under "Labels" \ No newline at end of file