Test::mysqld を別ウィンドウで立ち上げたら開発時の prove が快適過ぎる件

id:xaicron 氏が紹介なされていました make test で Test::mysqld を永続化させる方法 を早速導入していたのですが、make test は速くなって便利なのですが、prove で 1 つずつテストをするときは、相変わらず mysqld を毎回、起動・終了するので時間がかかって開発時のストレスになります。

そこで、開発時には別ウィンドウで mysqld を立ち上げておいて、そこに接続しに行くようにすれば大分快適になると思い、実装してみました。

#!/usr/bin/env perl
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/../lib";
use File::Spec;
use JSON;
use Test::MyApp::mysqld;

my $tempfile = File::Spec->catfile(File::Spec->tmpdir, 'test_mysqld.json');

$SIG{'INT'} = *purge;
END { purge(); }

print "Starting mysqld...";
my $mysqld = Test::MyApp::mysqld->setup;
my $log = File::Spec->catfile($mysqld->{'base_dir'}, qw/tmp mysqld.log/);
printf " started at %s\n", $mysqld->{'my_cnf'}{'socket'};
print "log file: $log\n";

{
    my $json = encode_json({ %$mysqld });
    open my $fh, '>', $tempfile or die $!;
    $fh->print($json);
    $fh->close;
}

sleep 3 while -e $tempfile;

sub purge {
    unlink $tempfile;
    print "Shutting down mysqld...\n";
    exit;
}

まず、こんな感じのスクリプトを t/script/mysqld_runner.pl に作っておいて

次に、xaicron 氏の Test::MyApp::mysql を以下のように書き換えます。

# 前略
my $tempfile = File::Spec->catfile(File::Spec->tmpdir, 'test_mysqld.json');

sub setup {
    my ($class, %config) = @_;

    my $mysqld;

    if ( -e $tempfile ) {
        open my $fh, '<', $tempfile or die $!;
        my $obj = decode_json(join '', <$fh>);
        $mysqld = bless $obj, 'Test::mysqld';
    }
    elsif ( my $json = $ENV{'TEST_MYSQLD'} ) {
        my $obj = decode_json($json);
        $mysqld = bless $obj, 'Test::mysqld';
    }
# 後略

あとは、ガリガリ開発してる間は、適当なウィンドウで先ほどの t/script/mysqld_runner.pl を起動しておけば、そこに繋ぎに行ってくれるので、起動に時間がかからなくて良い感じです。prove のたびに 6 秒以上かかっていたのが、0.02 秒に短縮されました。

ファイル名を固定にするために File::Temp は使っていません。TEMPLATE が X 指定しなくても使えれば便利なんですけどね。

あと、mysqld_runner.pl の標準出力にクエリログでも出せれば便利そうな気がするのですが、log-output とかで標準出力を指定する方法が分からなかったので、とりあえず放置しています。どなたか分かるかた教えて頂けると幸いです。