rig_mysql
A MySQL container for your Dart tests, storing the password under the authentication plugin you actually asked for.
import 'package:rig_mysql/rig_mysql.dart';
import 'package:test/test.dart';
void main() {
final my = useMySql();
test('connects', () async {
// mysql://test:test@127.0.0.1:<port>/<this suite's own database>.
// Hand it to whatever driver you are testing; this package deliberately
// depends on no MySQL client.
expect(my.url, startsWith('mysql://'));
expect(my.database, isNot('test_db'));
});
}
Suites that ask for the same configuration share one container and, by default, each get their own database inside it — see Isolation below to change that.
MySQL 8.0 and 8.4 are the only versions this package is tested against and
supports; the default is '8.4'.
Auth modes
MySqlAuth picks the plugin the server stores — and authenticates — the
password under:
cachingSha2(the default) — SHA-256 based, with a cache on the server. MySQL's own default since 8.0.nativePassword— the pre-8.0 default, still widely deployed, and not loaded by default in 8.4. Ask for it withuseMySql(auth: MySqlAuth.nativePassword).
Naming a mode is not enough on its own. The official image stores the
password during initialisation under whatever the server's default plugin
happened to be at that moment, and changing the default afterwards does not
re-hash what is already stored — so a container could quietly go on
authenticating with a plugin the test never asked for. useMySql re-stores
the password again once the server is up, under the plugin auth: actually
names, which is what turns the auth mode into something a test asserts
rather than hopes for.
TLS
MySqlTls has two states:
MySqlTls.serverDefault()(the default) — MySQL's own behaviour: a self-signed certificate generated at initialisation, and TLS accepted with it.MySqlTls.off()— no TLS at all.
caching_sha2_password sends the password in the clear over TLS, but needs
the server's public key to do the same without one — and the only way to
exercise that second path is a server that speaks no TLS to begin with.
MySQL enables TLS by default, so a container with none has to be asked for
explicitly with MySqlTls.off().
Isolation
MySqlIsolation picks how much of the container a suite gets:
database(the default) — a database of this suite's own, inside a container other suites share.none— connect straight to the container's own database; suites sharing the container see each other's tables.
Why there is a rootPassword
MYSQL_USER is not a superuser, unlike the user the Postgres image creates.
A test that needs to create a schema, grant a privilege, or read
mysql.user has to connect as root, and rootPassword (default 'root') is
what makes that connection possible.
flushAuthCache()
caching_sha2_password has two paths: a client the server's cache already
knows proves itself with a fast SHA-256 scramble, and one it does not has to
fall back to sending the password in a form the server can recover — in the
clear over TLS, or encrypted with the server's public key without it. By the
second connection, the server's cache already knows the client, so testing
that fallback path at all means being able to empty the cache first.
my.flushAuthCache() does that. It lives on the lease rather than in the
test because the client under test is exactly the thing whose connection is
being asserted on — asking it to run FLUSH PRIVILEGES before proving it
can connect is circular.
What this does to a container you share
A shared container (the default) is reused by any suite whose configuration
hashes the same, and is never removed by a test run — the next run
reuses it instead of paying for startup again. Nothing in this package stops
or removes it; only rig prune does.
Inside a shared container, each suite gets a database of its own named
test_<project>_<minute>_<token>. A sweep runs before each suite creates its
database and drops other suites' test_* databases that are old enough (an
hour, by default) and that no marker still claims — this is what keeps a
long-lived shared container from accumulating databases from crashed runs
forever. The container's own database is never one of them, since its name
never has the shape a suite's own database is given. Unlike the Postgres
sibling, MySQL's DROP DATABASE succeeds even while something is still
connected, so the marker is the only thing standing between a live suite and
the sweep, not a second line of defence.
Ask for lifetime: Lifetime.dedicated when a suite would disturb others
sharing the container — connection limits, restarts, or assertions that
depend on the authentication cache being warm. Every suite that joins a
shared container re-stores the password in its own setUpAll (see Auth
modes above), and that statement cools the cache for whoever else is
connected to it.
Installing
dart pub add dev:rig_mysql
It brings rig with it. Containers are left
running on purpose, so you will also want
rig_cli for the rig command that
removes them.
Testing
dart test runs everything, integration suites included, so it needs a
running Docker daemon.
dart test # everything — needs Docker
dart test -t integration # only the integration suites
A full run exercises two versions and two auth modes, plus a TLS-off
container, so it leaves five shared containers running — deliberately, see
above — each holding roughly 200 MB of tmpfs. That is more than the siblings
leave running, so plan on rig prune once you are done.
Libraries
- rig_mysql
- A MySQL container for your Dart tests.