Skip to content

Commit

Permalink
feat(GODT-2522): Migration Errors
Browse files Browse the repository at this point in the history
Report Migration failed and invalid database as dedicated error types.
  • Loading branch information
LBeernaertProton committed Jun 27, 2023
1 parent 8258a0f commit c042847
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 6 deletions.
1 change: 1 addition & 0 deletions db/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "errors"
var ErrNotFound = errors.New("value not found")
var ErrTransactionFailed = errors.New("transaction failed")
var ErrMigrationFailed = errors.New("database migration failed")
var ErrInvalidDatabaseVersion = errors.New("invalid database version")

func IsErrNotFound(err error) bool {
if err == nil {
Expand Down
2 changes: 1 addition & 1 deletion internal/db_impl/sqlite3/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func (c *Client) Init(ctx context.Context, generator imap.UIDValidityGenerator)
}

if err := RunMigrations(ctx, qw, generator); err != nil {
return fmt.Errorf("%w: %v", db.ErrMigrationFailed, err)
return err
}

return nil
Expand Down
44 changes: 44 additions & 0 deletions internal/db_impl/sqlite3/migration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package sqlite3
import (
"context"
"database/sql"
"errors"
"fmt"
"github.com/ProtonMail/gluon/db"
"github.com/ProtonMail/gluon/imap"
Expand All @@ -17,6 +18,41 @@ import (
"time"
)

func TestMigration_VersionTooHigh(t *testing.T) {
testDir := t.TempDir()

setup := func() {
client, _, err := NewClient(testDir, "foo", false, false)
require.NoError(t, err)

ctx := context.Background()
require.NoError(t, client.Init(ctx, &imap.IncrementalUIDValidityGenerator{}))

defer func() {
require.NoError(t, client.Close())
}()

// For version to very high value
require.NoError(t, client.wrapTx(ctx, func(ctx context.Context, tx *sql.Tx, entry *logrus.Entry) error {
qw := utils.TXWrapper{TX: tx}
return updateDBVersion(ctx, qw, 999999)
}))
}

setup()

client, _, err := NewClient(testDir, "foo", false, false)
require.NoError(t, err)

defer func() {
require.NoError(t, client.Close())
}()

err = client.Init(context.Background(), imap.DefaultEpochUIDValidityGenerator())
require.Error(t, err)
require.True(t, errors.Is(err, db.ErrInvalidDatabaseVersion))
}

func TestRunMigrations(t *testing.T) {
logrus.SetLevel(logrus.DebugLevel)

Expand All @@ -29,6 +65,14 @@ func TestRunMigrations(t *testing.T) {
// Fill v0 database.
prepareV0Database(t, testDir, "foo", testData, uidGenerator)

// First run, incurs migration.
runAndValidateDB(t, testDir, "foo", testData, uidGenerator)

// Second run, no migration.
runAndValidateDB(t, testDir, "foo", testData, uidGenerator)
}

func runAndValidateDB(t *testing.T, testDir, user string, testData *testData, uidGenerator imap.UIDValidityGenerator) {
// create client and run all migrations.
client, _, err := NewClient(testDir, "foo", false, false)
require.NoError(t, err)
Expand Down
26 changes: 21 additions & 5 deletions internal/db_impl/sqlite3/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ func RunMigrations(ctx context.Context, tx utils.QueryWrapper, generator imap.UI
logrus.Debugf("Running migration for version %v", idx)

if err := m.Run(ctx, tx, generator); err != nil {
return fmt.Errorf("failed to run migration %v: %w", idx, err)
return fmt.Errorf("%w %v: %v", db.ErrMigrationFailed, idx, err)
}
}

if err := updateDBVersion(ctx, tx, len(migrationList)-1); err != nil {
return fmt.Errorf("failed to update db version:%w", err)
return fmt.Errorf("%w: failed to update db version: %v", db.ErrMigrationFailed, err)
}

logrus.Debug("Migrations completed")
Expand All @@ -50,16 +50,32 @@ func RunMigrations(ctx context.Context, tx utils.QueryWrapper, generator imap.UI

logrus.Debugf("DB Version is %v", dbVersion)

for i := dbVersion + 1; i < len(migrationList); i++ {
dbVersion = dbVersion + 1

if dbVersion == len(migrationList) {
logrus.Debugf("No migrations to run")
return nil
}

if dbVersion > len(migrationList) {
return fmt.Errorf(
"%w: database version is %v, but we only support up to %v",
db.ErrInvalidDatabaseVersion,
dbVersion,
len(migrationList),
)
}

for i := dbVersion; i < len(migrationList); i++ {
logrus.Debugf("Running migration for version %v", i)

if err := migrationList[i].Run(ctx, tx, generator); err != nil {
return err
return fmt.Errorf("%w %v: %v", db.ErrMigrationFailed, i, err)
}
}

if err := updateDBVersion(ctx, tx, len(migrationList)-1); err != nil {
return fmt.Errorf("failed to update db version:%w", err)
return fmt.Errorf("%w: failed to update db version: %v", db.ErrMigrationFailed, err)
}

logrus.Debug("Migrations completed")
Expand Down

0 comments on commit c042847

Please sign in to comment.