19709: Test schema_migrations vs. db/migrate/*.rb.
authorTom Clegg <tom@curii.com>
Mon, 12 Dec 2022 21:46:03 +0000 (16:46 -0500)
committerTom Clegg <tom@curii.com>
Mon, 12 Dec 2022 21:46:03 +0000 (16:46 -0500)
Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom@curii.com>

lib/boot/rails_db.go
lib/boot/rails_db_test.go [new file with mode: 0644]

index 44ceb263c370f04b9cb5897d3f10c72d18a22fa8..ad9124d7dcb1ca54b7f130581ff768e175a946e9 100644 (file)
@@ -6,6 +6,7 @@ package boot
 
 import (
        "context"
+       "fmt"
        "io/fs"
        "os"
        "path/filepath"
@@ -47,28 +48,10 @@ func (runner railsDatabase) Run(ctx context.Context, fail func(error), super *Su
        // there are no new migrations, that would add ~2s to startup
        // time / downtime during service restart.
 
-       todo := map[string]bool{}
-
-       // list versions in db/migrate/{version}_{name}.rb
-       fs.WalkDir(os.DirFS(appdir), "db/migrate", func(path string, d fs.DirEntry, err error) error {
-               fnm := d.Name()
-               if !strings.HasSuffix(fnm, ".rb") {
-                       return nil
-               }
-               for i, c := range fnm {
-                       if i > 0 && c == '_' {
-                               todo[fnm[:i]] = true
-                               break
-                       }
-                       if c < '0' || c > '9' {
-                               // non-numeric character before the
-                               // first '_' means this is not a
-                               // migration
-                               break
-                       }
-               }
-               return nil
-       })
+       todo, err := migrationList(appdir)
+       if err != nil {
+               return err
+       }
 
        // read schema_migrations table (list of migrations already
        // applied) and remove those entries from todo
@@ -113,3 +96,35 @@ func (runner railsDatabase) Run(ctx context.Context, fail func(error), super *Su
        defer dblock.RailsMigrations.Unlock()
        return super.RunProgram(ctx, appdir, runOptions{env: railsEnv}, "bundle", "exec", "rake", "db:migrate")
 }
+
+func migrationList(dir string) (map[string]bool, error) {
+       todo := map[string]bool{}
+
+       // list versions in db/migrate/{version}_{name}.rb
+       err := fs.WalkDir(os.DirFS(dir), "db/migrate", func(path string, d fs.DirEntry, err error) error {
+               if d.IsDir() {
+                       return nil
+               }
+               fnm := d.Name()
+               if !strings.HasSuffix(fnm, ".rb") {
+                       return fmt.Errorf("unexpected file in db/migrate dir: %s", fnm)
+               }
+               for i, c := range fnm {
+                       if i > 0 && c == '_' {
+                               todo[fnm[:i]] = true
+                               break
+                       }
+                       if c < '0' || c > '9' {
+                               // non-numeric character before the
+                               // first '_' means this is not a
+                               // migration
+                               return fmt.Errorf("unexpected file in db/migrate dir: %s", fnm)
+                       }
+               }
+               return nil
+       })
+       if err != nil {
+               return nil, err
+       }
+       return todo, nil
+}
diff --git a/lib/boot/rails_db_test.go b/lib/boot/rails_db_test.go
new file mode 100644 (file)
index 0000000..ac78a3c
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+package boot
+
+import (
+       "git.arvados.org/arvados.git/lib/config"
+       "git.arvados.org/arvados.git/sdk/go/arvadostest"
+       "git.arvados.org/arvados.git/sdk/go/ctxlog"
+       "gopkg.in/check.v1"
+)
+
+type railsDBSuite struct{}
+
+var _ = check.Suite(&railsDBSuite{})
+
+// Check services/api/db/migrate/*.rb match schema_migrations
+func (s *railsDBSuite) TestMigrationList(c *check.C) {
+       todo, err := migrationList("../../services/api")
+       c.Check(err, check.IsNil)
+       c.Check(todo["20220804133317"], check.Equals, true)
+
+       cfg, err := config.NewLoader(nil, ctxlog.TestLogger(c)).Load()
+       c.Assert(err, check.IsNil)
+       cluster, err := cfg.GetCluster("")
+       c.Assert(err, check.IsNil)
+       db := arvadostest.DB(c, cluster)
+       rows, err := db.Query(`SELECT version FROM schema_migrations`)
+       for rows.Next() {
+               var v string
+               err = rows.Scan(&v)
+               c.Assert(err, check.IsNil)
+               if !todo[v] {
+                       c.Errorf("version is in schema_migrations but not services/api/db/migrate/: %q", v)
+               }
+               delete(todo, v)
+       }
+       err = rows.Close()
+       c.Assert(err, check.IsNil)
+
+       // In the test suite, the database should be fully migrated.
+       // So, if there's anything left in todo here, there is
+       // something wrong with our "db/migrate/*.rb ==
+       // schema_migrations" reasoning.
+       c.Check(todo, check.HasLen, 0)
+}