Skip to content

Commit

Permalink
Merge pull request juju#17124 from SimonRichardson/include-sql-statem…
Browse files Browse the repository at this point in the history
…ents

juju#17124

Whilst debugging a test failure, including the SQL being executed helped diagnose the problem. Ideally, we would add a new flag for everyone to check against, but that requires a lot of reworking of the tests. Instead, for now, we can just set an envvar whilst running the tests and it spews out what it ran and how it got stuck.

This only works with super verbose mode i.e. check.vv.

It will also dump out valid SQL now, so you can dump it into a db without modifications.

## Checklist

<!-- If an item is not applicable, use `~strikethrough~`. -->

- [x] Code style: imports ordered, good names, simple structure, etc
- [x] Comments saying why design decisions were made
- [x] Go unit tests, with comments saying what you're testing

## QA steps

```sh
$ INCLUDE_SQL_OUTPUT=1 go test -v ./domain/schema -check.vv
```

## Links

**Jira card:** JUJU-
  • Loading branch information
jujubot authored Apr 2, 2024
2 parents 89fc93c + 6dd0259 commit 96cb1c7
Show file tree
Hide file tree
Showing 11 changed files with 46 additions and 20 deletions.
2 changes: 1 addition & 1 deletion core/database/schema/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ func ensurePatchesAreApplied(ctx context.Context, tx *sql.Tx, current int, patch
return errors.Trace(err)
}

if err := hook(current); err != nil {
if err := hook(current, patch.stmt); err != nil {
return errors.Annotatef(err, "failed to execute hook (version %d)", current)
}

Expand Down
2 changes: 1 addition & 1 deletion core/database/schema/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func (s *querySuite) TestEnsurePatches(c *gc.C) {

var called bool
err := s.TxnRunner().StdTxn(context.Background(), func(ctx context.Context, tx *sql.Tx) error {
return ensurePatchesAreApplied(context.Background(), tx, 0, patches, func(i int) error {
return ensurePatchesAreApplied(context.Background(), tx, 0, patches, func(i int, statement string) error {
called = true
c.Check(i, gc.Equals, 0)
return nil
Expand Down
6 changes: 4 additions & 2 deletions core/database/schema/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type Schema struct {
type Patch struct {
run func(context.Context, Tx) error
hash string
stmt string
}

// MakePatch returns a patch that applies the given SQL statement with the given
Expand All @@ -40,11 +41,12 @@ func MakePatch(statement string, args ...any) Patch {
return errors.Trace(err)
},
hash: computeHash(statement),
stmt: statement,
}
}

// Hook is a callback that gets fired when a update gets applied.
type Hook func(int) error
type Hook func(int, string) error

// New creates a new schema Schema with the given patches.
func New(patches ...Patch) *Schema {
Expand Down Expand Up @@ -122,4 +124,4 @@ func (s *Schema) Ensure(ctx context.Context, runner database.TxnRunner) (ChangeS
}

// omitHook always returns a nil, omitting the error.
func omitHook(int) error { return nil }
func omitHook(int, string) error { return nil }
10 changes: 6 additions & 4 deletions domain/schema/schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,12 @@ func readEntityNames(c *gc.C, db *sql.DB, entity_type string) []string {
}

func (s *schemaSuite) applyDDL(c *gc.C, ddl *schema.Schema) {
ddl.Hook(func(i int) error {
c.Log("Applying schema change", i)
return nil
})
if s.Verbose {
ddl.Hook(func(i int, statement string) error {
c.Logf("-- Applying schema change %d\n%s\n", i, statement)
return nil
})
}
changeSet, err := ddl.Ensure(context.Background(), s.TxnRunner())
c.Assert(err, jc.ErrorIsNil)
c.Check(changeSet.Current, gc.Equals, 0)
Expand Down
3 changes: 2 additions & 1 deletion domain/schema/testing/controllermodelsuite.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ type ControllerModelSuite struct {
func (s *ControllerModelSuite) ModelTxnRunner(c *gc.C, modelUUID string) coredatabase.TxnRunner {
txnRunner, _ := s.DqliteSuite.OpenDBForNamespace(c, modelUUID)
s.DqliteSuite.ApplyDDLForRunner(c, &SchemaApplier{
Schema: schema.ModelDDL(),
Schema: schema.ModelDDL(),
Verbose: s.Verbose,
}, txnRunner)
return txnRunner
}
6 changes: 4 additions & 2 deletions domain/schema/testing/controllersuite.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ func (s *ControllerSuite) ControllerTxnRunner() coredatabase.TxnRunner {
func (s *ControllerSuite) SetUpTest(c *gc.C) {
s.DqliteSuite.SetUpTest(c)
s.DqliteSuite.ApplyDDL(c, &SchemaApplier{
Schema: schema.ControllerDDL(),
Schema: schema.ControllerDDL(),
Verbose: s.Verbose,
})
err := database.InsertControllerNodeID(context.Background(), s.DqliteSuite.TxnRunner(), 0x2dc171858c3155be)
c.Assert(err, jc.ErrorIsNil)
Expand All @@ -41,7 +42,8 @@ func (s *ControllerSuite) SetUpTest(c *gc.C) {
// given database.
func (s *ControllerSuite) ApplyDDLForRunner(c *gc.C, runner coredatabase.TxnRunner) {
s.DqliteSuite.ApplyDDLForRunner(c, &SchemaApplier{
Schema: schema.ControllerDDL(),
Schema: schema.ControllerDDL(),
Verbose: s.Verbose,
}, runner)
err := database.InsertControllerNodeID(context.Background(), runner, 0x2dc171858c3155be)
c.Assert(err, jc.ErrorIsNil)
Expand Down
3 changes: 2 additions & 1 deletion domain/schema/testing/modelsuite.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ func (s *ModelSuite) SetUpTest(c *gc.C) {

s.DqliteSuite.SetUpTest(c)
s.DqliteSuite.ApplyDDL(c, &SchemaApplier{
Schema: schema.ModelDDL(),
Schema: schema.ModelDDL(),
Verbose: s.Verbose,
})
}

Expand Down
14 changes: 9 additions & 5 deletions domain/schema/testing/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,18 @@ import (
)

type SchemaApplier struct {
Schema *schema.Schema
Schema *schema.Schema
Verbose bool
}

func (s *SchemaApplier) Apply(c *gc.C, ctx context.Context, runner database.TxnRunner) {
s.Schema.Hook(func(i int) error {
//c.Log("Applying schema change", i)
return nil
})
if s.Verbose {
s.Schema.Hook(func(i int, statement string) error {
c.Logf("-- Applying schema change %d\n%s\n", i, statement)
return nil
})
}

changeSet, err := s.Schema.Ensure(ctx, runner)
c.Assert(err, gc.IsNil)
c.Check(changeSet.Post, gc.Equals, s.Schema.Len())
Expand Down
3 changes: 2 additions & 1 deletion internal/changestream/stream/package_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ type baseSuite struct {
func (s *baseSuite) SetUpTest(c *gc.C) {
s.DqliteSuite.SetUpTest(c)
s.DqliteSuite.ApplyDDL(c, &domaintesting.SchemaApplier{
Schema: schema.ControllerDDL(),
Schema: schema.ControllerDDL(),
Verbose: s.Verbose,
})
}

Expand Down
11 changes: 11 additions & 0 deletions internal/database/testing/dqlitesuite.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ import (
"github.com/juju/juju/internal/database/pragma"
)

// includeSQLOutput is used to enable the output of all SQL queries hitting the
// database.
var includeSQLOutput = os.Getenv("INCLUDE_SQL_OUTPUT")

// SchemaApplier is an interface that can be used to apply a schema to a
// database.
type SchemaApplier interface {
Expand All @@ -41,6 +45,10 @@ type SchemaApplier interface {
type DqliteSuite struct {
testing.IsolationSuite

// Verbose indicates whether the suite should print all the sql
// hitting the db.
Verbose bool

dbPath string
rootPath string
uniqueID int64
Expand Down Expand Up @@ -97,6 +105,9 @@ func (s *DqliteSuite) SetUpTest(c *gc.C) {
)
c.Assert(err, jc.ErrorIsNil)

// Enable super verbose mode.
s.Verbose = verbose && includeSQLOutput != ""

err = s.dqlite.Ready(context.Background())
c.Assert(err, jc.ErrorIsNil)

Expand Down
6 changes: 4 additions & 2 deletions internal/worker/changestreampruner/package_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,17 @@ type baseSuite struct {
func (s *baseSuite) SetUpTest(c *gc.C) {
s.DqliteSuite.SetUpTest(c)
s.DqliteSuite.ApplyDDL(c, &domaintesting.SchemaApplier{
Schema: schema.ControllerDDL(),
Schema: schema.ControllerDDL(),
Verbose: s.Verbose,
})
}

// ApplyDDLForRunner is responsible for applying the controller schema to the
// given database.
func (s *baseSuite) ApplyDDLForRunner(c *gc.C, runner coredatabase.TxnRunner) {
s.DqliteSuite.ApplyDDLForRunner(c, &domaintesting.SchemaApplier{
Schema: schema.ControllerDDL(),
Schema: schema.ControllerDDL(),
Verbose: s.Verbose,
}, runner)
}

Expand Down

0 comments on commit 96cb1c7

Please sign in to comment.