Documentation
¶
Overview ¶
Package testutils contains some common utilities used exclusively by the test suite.
Index ¶
- func CreateUniqueTestDatabase(t *testing.T) (string, *sql.DB)
- func DSN() string
- func DSNForDatabase(dbName string) string
- func EvenOddHasher(colAny any) (uint64, error)
- func RequireNoEffectiveTLS(t *testing.T, dsn, description string)
- func RunSQL(t *testing.T, stmt string)
- func RunSQLInDatabase(t *testing.T, dbName, stmt string)
- func RunSQLInDatabaseAsRoot(t *testing.T, dbName, stmt string)
- func SanitizeIdentifier(s string) string
- func SkipBeforeMySQLVersion(t *testing.T, minVersion, reason string)
- func SkipFromMySQLVersion(t *testing.T, fromVersion, reason string)
- func SkipUnlessVectorSupported(t *testing.T)
- func WaitForReplicaHealthy(t *testing.T, dsn string, timeout time.Duration)
- type OnLogHandler
- type TestTable
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CreateUniqueTestDatabase ¶
CreateUniqueTestDatabase creates a unique database for a test and returns both the database name and a *sql.DB connection scoped to that database. The connection and database are automatically cleaned up when the test finishes.
func DSNForDatabase ¶
DSNForDatabase returns a DSN for a specific database name
func EvenOddHasher ¶ added in v0.10.2
EvenOddHasher is a test hash function that shards assuming -80 and 80- shards. even goes to -80, odd goes to 80-
func RequireNoEffectiveTLS ¶ added in v0.18.0
RequireNoEffectiveTLS asserts that a DSN yields a connection with no TLS.
It deliberately does not assert the DSN omits "tls=". DISABLED writes tls=false, because the driver applies verified TLS to an RDS address whenever the DSN asks for nothing — so an omitted parameter is how DISABLED silently becomes a TLS connection, while an explicit "false" is how it stays off. What matters is the setting the driver ends up with, which is what this reads.
It lives here rather than in dbconn's tests because pkg/migration asserts the same property, and two copies of "what counts as no TLS" would let one of them be strengthened while the other silently stayed weak.
func RunSQLInDatabase ¶
RunSQLInDatabase runs SQL in a specific database
func RunSQLInDatabaseAsRoot ¶ added in v0.18.0
RunSQLInDatabaseAsRoot runs SQL in a specific database as the root user, with the password from MYSQL_DSN (CI gives root and the test user the same password). Use it for statements the test user is not granted, such as CREATE VIEW or CREATE ROUTINE (compose/bootstrap.sql lists its grants).
func SanitizeIdentifier ¶ added in v0.18.0
SanitizeIdentifier lowercases s and replaces every character outside [a-z0-9_] with '_', so the result can be used as a MySQL identifier without quoting. Use it to derive schema or table names from t.Name().
func SkipBeforeMySQLVersion ¶ added in v0.18.0
SkipBeforeMySQLVersion skips the test when the server's version() is older than minVersion (e.g. "8.0.33"), giving reason in the skip message. Use it for behavior an old server gets wrong and that is not worth special-casing, not to hide a failure a supported server should pass.
func SkipFromMySQLVersion ¶ added in v0.18.0
SkipFromMySQLVersion skips the test when the server's version() is fromVersion (e.g. "9.7.0") or newer, giving reason in the skip message. Use it for behavior a newer server changed or gets wrong and that is not worth special-casing, not to hide a failure a supported server should pass.
func SkipUnlessVectorSupported ¶ added in v0.17.0
SkipUnlessVectorSupported skips the test unless the server understands the VECTOR data type (MySQL 9.7+). It probes for the feature rather than parsing version(), so a fork or a future version that renames itself still gets the coverage. The probe result is cached for the life of the test binary.
Only an "unknown function" answer from the server counts as unsupported. Anything else — an unreachable host, a bad DSN, an auth failure, any other server error — fails the test instead, so a broken environment cannot masquerade as a whole suite of quietly skipped tests.
func WaitForReplicaHealthy ¶ added in v0.13.0
WaitForReplicaHealthy polls SHOW REPLICA STATUS until both the IO and SQL threads report Yes, or the timeout elapses. On timeout it fails the test with an infra-attribution message so a broken CI replica setup is clearly distinguishable from a Spirit migration bug.
Types ¶
type OnLogHandler ¶ added in v0.18.0
OnLogHandler wraps a slog.Handler and calls fn, once, the first time a record with message msg is handled, before passing the record on. Tests use it to act at a precise point in code that has no other hook, such as the log line a runner writes as Run starts.
func NewOnLogHandler ¶ added in v0.18.0
func NewOnLogHandler(h slog.Handler, msg string, fn func()) *OnLogHandler
NewOnLogHandler returns an OnLogHandler that wraps h.
func (*OnLogHandler) Handle ¶ added in v0.18.0
Handle calls fn the first time msg is logged, then passes rec on. fn runs on the logging goroutine and may itself log.
type TestTable ¶ added in v0.13.0
TestTable manages a test table's lifecycle: creation, cleanup, and provides a DB connection for verification queries after migration.
func NewTestTable ¶ added in v0.13.0
NewTestTable creates a test table and registers cleanup to drop it and all Spirit artifacts (_new, _old, _chkpnt) when the test finishes.
Example:
tt := testutils.NewTestTable(t, "mytable",
`CREATE TABLE mytable (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL
)`)
// Use tt.DB for verification queries after migration
var count int
tt.DB.QueryRowContext(t.Context(), "SELECT COUNT(*) FROM mytable").Scan(&count)
func (*TestTable) SeedRows ¶ added in v0.13.0
SeedRows populates the table by doubling rows until reaching approximately targetRows. The insertSelectSQL should be an INSERT INTO ... SELECT statement WITHOUT a FROM clause. SeedRows appends "FROM dual" for the initial insert, then "FROM <table>" for each doubling iteration.
Example:
// Simple seeding — produces ~4096 identical rows (different auto-increment IDs) tt.SeedRows(t, "INSERT INTO mytable (name, val) SELECT 'seed', 1", 4096) // With SQL functions — each row gets unique random data tt.SeedRows(t, "INSERT INTO mytable (pad) SELECT RANDOM_BYTES(1024)", 100000)