4.5 KiB
QA: MySQL/MariaDB database driver
Backend only. Go tests in test/, black-box, no live server by default.
Decisions: separate DB_* vars, new DATA_DIR (DB_FILE ignored under mysql), pure-Go logical dump backup, task test:mysql against mysql:8.4 and mariadb:11, SQLite-to-MySQL data migration documented as manual export/import only.
Automated, no server (task test)
- Registry: Connect with Driver "sqlite" works against a temp file; Driver "oracle" returns
unsupported database driver "oracle"; the registry contains sqlite and mysql. - Env validation: table-driven over the Driver selection and Missing MySQL variable scenarios. SQLite needs no DB_* vars. DB_DRIVER defaults to sqlite. An invalid DB_TLS or a non-numeric pool var returns an error naming the variable.
- DSN builder: table-driven over the DSN scenario. Assert host:port, database, parseTime, loc=UTC, charset=utf8mb4, clientFoundRows, tls. Assert that the redacted form used in errors never contains the password.
- Settings.DataDir: table-driven (DB_FILE only, DATA_DIR overrides).
- Fail fast without a server: point mysql at a closed local port with a 1s timeout. Assert the error mentions the host and port, and not the password.
- Pool settings: assert sql.DB stats MaxOpenConnections via a stub opener, or via the real mysql test below.
- SQLite regression: build a database file using the pre-change schema (a fixture created with the old model definitions), run Migrate, and assert that the schema (sqlite_master) and the rows are unchanged. The existing suite must pass unchanged.
- Backup (SQLite): existing tests unchanged.
- Dump writer: unit-test the SQL dump formatter with a fake row source (quoting, NULL, time, bool, binary-safe strings, 3-file retention, existing-file handling, failure leaves no partial file).
Automated, real server (task test:mysql)
Setup: the task runs docker run for mysql:8.4 and, in a second pass, mariadb:11, waits for readiness, exports RENEWCMS_TEST_MYSQL_DSN, runs go test -tags nofrontend ./test/... -run MySQL -count=1, then removes the container. Tests call t.Skip when the var is unset, so task test skips them. The repository tests are parameterised over both drivers (SQLite temp file and the MySQL DSN, each with a fresh database), and run the "Repository behaviour is the same on both drivers" Examples.
10. Migrate on an empty database; table and index existence via information_schema; the backfill role rules.
11. User create/read, case-sensitive username and email, duplicate email, ErrUserNotFound.
12. Invite accept twice, accept with a taken username (invite stays unaccepted), renew with unchanged values.
13. Image duplicates grouping and counts, search with % and _, filename backfill listing.
14. Article body 1 MB, title lookup, online filter.
15. API key unique hashed_key, revoke, last_used.
16. Zero-time round trip, UTC times.
17. Purge settings upsert.
18. Backup: run on a populated MySQL database, assert the .sql file, the 3-file retention, a replay into a second empty database giving identical rows, and that the file contains no password.
19. Wrong password and missing database fail with the "Unable to open the database" prefix and no password in the message.
Build and lint
task lint:goandtask testpass.task test:mysqlpasses on MySQL 8.4 and MariaDB 11 (record both; NOT RUN if Docker is unavailable).CGO_ENABLED=0 go build -tags nofrontend ./...passes. Cross-compile the 6task releasetargets (e.g.GOOS=linux GOARCH=arm64) with CGO_ENABLED=0.task mutateimpact: none, because it only targets useCases. No change.- No comment lines in the added Go files (the hook enforces this).
Manual (needs Compose and real SMTP)
- docker-compose.mysql.yml example: renewcms plus a mysql service with a named volume and a healthcheck,
depends_on: condition: service_healthy, DB_DRIVER=mysql, DB_HOST=mysql, DATA_DIR=/data.docker compose up: /healthz returns 200, register, log in, create an article, restart the stack, and the data persists. - Stop the mysql container and start renewcms: it exits with a clear error and no password in the logs. docker.env.example holds placeholders only.
- In the Docker image (non-root uid 10001), trigger the backup path and confirm the .sql file lands under /data/backups.
- Docs: configuration.md, docker.md, deployment.md,
.env.example,docker.env.exampleand the architecture.md "Storage and database seams" section list the new vars and the manual SQLite to MySQL export/import note. - Verify the SQLite default end to end with no new vars set: same behaviour as before.