func LockDBAndMigrate(logger lager.Logger, sqlDriver string, sqlDataSource string) (db.Conn, error) { var err error var dbLockConn db.Conn var dbConn db.Conn for { dbLockConn, err = db.WrapWithError(sql.Open(sqlDriver, sqlDataSource)) if err != nil { if strings.Contains(err.Error(), " dial ") { logger.Error("failed-to-open-db-retrying", err) time.Sleep(5 * time.Second) continue } return nil, err } break } lockName := crc32.ChecksumIEEE([]byte(sqlDriver + sqlDataSource)) for { _, err = dbLockConn.Exec(`select pg_advisory_lock($1)`, lockName) if err != nil { logger.Error("failed-to-acquire-lock-retrying", err) time.Sleep(5 * time.Second) continue } logger.Info("migration-lock-acquired") migrations := Translogrifier(logger, Migrations) dbConn, err = db.WrapWithError(migration.OpenWith(sqlDriver, sqlDataSource, migrations, safeGetVersion, safeSetVersion)) if err != nil { logger.Fatal("failed-to-run-migrations", err) } _, err = dbLockConn.Exec(`select pg_advisory_unlock($1)`, lockName) if err != nil { logger.Error("failed-to-release-lock", err) } dbLockConn.Close() break } return dbConn, nil }
It("returns the return values from the underlying connection", func() { underlyingConn.PingReturns(errors.New("disaster")) err := countingConn.Ping() Expect(err).To(MatchError("disaster")) }) Describe("query counting", func() { It("increments the global (;_;) counter", func() { _, err := countingConn.Query("SELECT $1::int", 1) Expect(err).NotTo(HaveOccurred()) Expect(metric.DatabaseQueries.Max()).To(Equal(1)) _, err = countingConn.Exec("SELECT $1::int", 1) Expect(err).NotTo(HaveOccurred()) Expect(metric.DatabaseQueries.Max()).To(Equal(2)) countingConn.QueryRow("SELECT $1::int", 1) Expect(metric.DatabaseQueries.Max()).To(Equal(3)) By("working in transactions") underlyingTx := &fakes.FakeTx{} underlyingConn.BeginReturns(underlyingTx, nil) tx, err := countingConn.Begin() Expect(err).NotTo(HaveOccurred())
}) It("logs the output of the explain", func() { var i int err := explainConn.QueryRow("SELECT $1::int", 1).Scan(&i) Ω(err).ShouldNot(HaveOccurred()) Expect(logger).To(gbytes.Say("Result")) Expect(logger).To(gbytes.Say("cost=")) Expect(logger).To(gbytes.Say("SELECT")) }) }) Describe("Exec()", func() { It("EXPLAINs the query", func() { _, err := explainConn.Exec("SELECT $1::int", 1) Ω(err).ShouldNot(HaveOccurred()) Ω(underlyingConn.ExecCallCount()).Should(Equal(1)) Ω(underlyingConn.QueryCallCount()).Should(Equal(1)) query, args := underlyingConn.ExecArgsForCall(0) Ω(query).Should(Equal("SELECT $1::int")) Ω(args).Should(Equal(varargs(1))) query, args = underlyingConn.QueryArgsForCall(0) Ω(query).Should(Equal("EXPLAIN SELECT $1::int")) Ω(args).Should(Equal(varargs(1))) }) It("logs the output of the explain", func() {