Debugging SQL Tests
Overview
Sometimes, when refactoring or changing code, you get an unexpected
sql error, like sql: transaction has already been committed or rolled
back
. Below is one technique for figuring out what is going on.
Database Setup
Each of our tests should run in a transaction, which means trying to figure out the state of the database after the tests finish is hard since it is reset. Each package runs its tests in a clone of the database.
After you run make server_test_setup
, you should see a docker
container running with the name milmove-db-test
$ docker docker ps -f name=milmove-db-test
You can connect to that docker container and see the databases. Something like
$ docker exec -it milmove-db-test psql -U postgres -l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+----------+----------+------------+------------+-----------------------
postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 |
template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres +
| | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres +
| | | | | postgres=CTc/postgres
test_db | postgres | UTF8 | en_US.utf8 | en_US.utf8 |
(4 rows)
The test_db
is the template database. Now, run your failing test
(and only your failing test).
Something like
$ go test ./pkg/handlers/internalapi/ -testify.m TestCancelMoveHandler
ok github.com/transcom/mymove/pkg/handlers/internalapi 0.929s
Now look at your databases again
docker exec -it milmove-db-test psql -U postgres -l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+----------+----------+------------+------------+-----------------------
postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 |
template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres +
| | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres +
| | | | | postgres=CTc/postgres
test_db | postgres | UTF8 | en_US.utf8 | en_US.utf8 |
test_db_1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 |
(5 rows)
Note the test_db_1
database, which is a clone of the pristine
test_db
instance and is what is used for your test.
Log All SQL Statements
Now, we are going to tell postgres to log every single SQL statement:
docker exec -it milmove-db-test psql -U postgres \
-c "ALTER DATABASE test_db_1 SET log_statement = 'all'"
In one terminal window, let's watch the logs
$ docker logs -f milmove-db-test
...
2022-03-30 19:35:05.603 UTC [149] STATEMENT: ALTER DATABASE test_db_1 SET log_statment = 'all'
Ok! Now we can run our test again (in another terminal window)
$ go test ./pkg/handlers/internalapi/ -testify.m TestCancelMoveHandler
ok github.com/transcom/mymove/pkg/handlers/internalapi 0.929s
You can see every single SQL statement!
If you want to try and figure out which SQL statement is being called where, add something like ...
_, err = appCtx.DB().Store.Exec("SET LOCAL drew.foo = 'after function foo'")
if err != nil {
// return the error, abort, or something
return err
}
Now you can run your test again and look for that in the logs.