Kentaro Kuribayashi's blog

Software Engineering, Management, Books, and Daily Journal.

Test::TCPでgearman workerのテストを書く

この項、必ず追記を参照のこと。

Gearmanを使ったジョブの処理を書いていて、

  1. gearmandを起動
  2. workerプロセスを起動
  3. clientがジョブを投げ、先に起動したworkerがそれを処理
  4. 返ってきた結果を検証
  5. テスト終了時には、gearmand/workerをシャットダウン

ってのを全部いっぺんにできないかなーってんで、Test::TCPでやってみました。workerプロセスはlistenする必要がないので、

no warnings 'redefine';
local *Test::TCP::wait_port = sub {};

とかしちゃってるところが「ヒャー」って感じですが、まあいいかな、と。。。他にいい方法があったら教えてください!!1

use strict;
use warnings;
use Test::TCP;
use Test::More;

use Gearman::Worker;
use Gearman::Client;

test_tcp(
    client => sub {
        my $port = shift;

        no warnings 'redefine';
        local *Test::TCP::wait_port = sub {};

        test_tcp(
            client => sub {
                my $client = Gearman::Client->new;
                $client->job_servers("127.0.0.1:$port");
                my $result = $client->do_task('test');
                is $$result, 1;
            },
            server => sub {
                my $worker = Gearman::Worker->new;
                $worker->job_servers("127.0.0.1:$port");

                # 例のため適当なsubrefを登録しているが、実際には、
                # テストを行うfunctionをregisterする
                $worker->register_function(test => sub { 1 });
                $worker->work while 1;
            },
        )
    },
    server => sub {
        my $port = shift;
        exec 'gearmand', '-p', $port;
    }
);

done_testing;

追記

id:tokuhiromにツッコミいただきました(「それ Proc::Guard 0.04 でできるよっていう話」)。ありがとうございます!!1

というわけで、Proc::Guardを使って以下のようにすればより良いです。

use strict;
use warnings;
use Test::TCP;
use Test::More;
use Proc::Guard 0.04 qw/proc_guard/;

use Gearman::Worker;
use Gearman::Client;

test_tcp(
    client => sub {
        my $port = shift;

        my $worker_guard = proc_guard(sub {
            my $worker = Gearman::Worker->new;
            $worker->job_servers("127.0.0.1:$port");
            # 例のため適当なsubrefを登録しているが、実際には、
            # テストを行うfunctionをregisterする
            $worker->register_function(test => sub { 1 });
            $worker->work while 1;
        });

        my $client = Gearman::Client->new;
        $client->job_servers("127.0.0.1:$port");
        my $result = $client->do_task('test');
        is $$result, 1;
    },
    server => sub {
        my $port = shift;
        exec 'gearmand', '-p', $port;
    }
);

done_testing;