Skip to main content
Testereiro - Test Engine Toolkit for Go
Go Docs GitHub Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

v0.6.0

Summary

The test-database lifecycle is no longer MySQL-only. DBLifecycle became a public extension point with MySQL, PostgreSQL and SQLite implementations in the box, and identifier quoting moved out of fmt.Sprintf.

Breaking Changes

WithConnectionFactory lost its executeDbCreateStmt bool parameter. The flag selected between MySQL DDL and doing nothing, which is what tied the library to one engine.

1
2
3
4
5
6
7
8
9
// before
puppetest.WithConnectionFactory(mySQLPerformer, true)
puppetest.WithConnectionFactory(sqlitePerformer, false)

// after
puppetest.WithConnectionFactory(mySQLPerformer),
puppetest.WithDatabaseLifecycle(puppetest.MySQLLifecycle),

puppetest.WithConnectionFactory(sqlitePerformer), // no lifecycle, as before

Core Library (puppetest)

  • DBLifecycle and DBLifecycleBuilder are exported, so a consumer can implement create/drop for an engine puppetest does not ship.
  • WithDatabaseLifecycle(...) selects the lifecycle. Option order does not matter: it is built after every option has run, over the root connection WithConnectionFactory opened.
  • MySQLLifecycle keeps the previous CREATE/DROP DATABASE IF [NOT] EXISTS behaviour with backtick quoting.
  • PostgresLifecycle checks pg_database instead of the IF NOT EXISTS PostgreSQL does not have, treats SQLSTATE 42P04 as success, and terminates live backends before dropping so teardown does not fail intermittently. It works on servers older than 13, which lack DROP DATABASE ... WITH (FORCE).
  • SQLiteLifecycle(pathFor) manages the database file and its -wal/-shm sidecars, since SQLite has no CREATE DATABASE.
  • QuoteIdentifier(name, quote) escapes an identifier by doubling the quote rune, and rejects an empty name or one holding a null byte. Database names reach a lifecycle from the caller, so this replaces interpolating them straight into a statement.

Placeholder Style

Engine.Seed hardcoded ? bind markers, which are a syntax error on PostgreSQL. The style is now pluggable and still defaults to ?.

  • WithPlaceholderStyle(...) on the engine factory, with QuestionPlaceholder (default) and OrdinalPlaceholder ($1, $2) shipped.
  • bancoche.NewMapQuery(...) takes bancoche.WithPlaceholderStyle(...), since it is built from a *sql.DB and never sees the engine. NewRawQuery is unchanged; that SQL belongs to the caller.
  • Markers are GENERATED, never rewritten, so no SQL is parsed and no string literal or comment can be corrupted by the substitution.

Connection Timeout

WithConnectionTimeout(d) replaces the hardcoded one-second budget, which covered dial, auth and ping with no way to change it. The default is unchanged. The budget is shared by the ConnectionPerformer and the ping, so it could not be extended from the call site.

Fixes

  • NewDatabase drops the database it just created when the follow-up connection fails, instead of stranding it on the server; ConnectionPerformer.Execute closes the connection when its ping fails; the engine factory’s lazy provider store no longer races under concurrent access.

Notes

puppetest still has no third-party dependencies. PostgresLifecycle reads the duplicate-database SQLSTATE through an interface{ SQLState() string } rather than importing a driver.

That structural read is what makes concurrent creation of the same database name safe, so the guarantee depends on the driver: pgx’s *pgconn.PgError satisfies it, lib/pq’s *pq.Error does not. On lib/pq, two tests racing to create one database name are not protected and one fails. Under go test -p N that is the main path rather than an edge case.