テスト時にstatusコードが0以外になってしまう場合の対処方法

ファイルシステムがRead-Only になってしまうとログの書き込みすらできないから大変な事になるので検出しようと思ってNet::SSHスクリプト書いたらstatusエラーに遭遇したが、テストを成功させるにはこうすればいいよ、という事を学んだ件です

結論から言うとこうするです

my $status = `echo $?`; 

Linuxの場合でしか確認してないです

そもそも何がしたかったのか


運用しているWEBサーバーなどがリクエストを受け付けてそれをジョブキューに投げたら、実はファイルシステムがHDD障害によってReadonlyになっていてみんな無言で死んでたらいやだよね、という対策をしたかった

で、これを真似をした。

http://github.com/tokuhirom/madeye/blob/master/lib/App/MadEye/Plugin/Agent/WriteDisk.pm

スクリプト

とりあえずこんなディレクトリつくります。

mkdir eg tmp

eg/try_write.plというファイルをつくります。中身は次のとおり

package Hoge;
use strict;
use warnings;
use Net::SSH ();
use Try::Tiny;

sub try_write {
    my ($class, $hostname, $dir)=@_;

    my $file = 'hogefuga.piyo';

    my $cmd = << "END_OF";
if [ -d $dir ]; then
    /bin/touch $dir/$file
    /bin/rm    $dir/$file
fi
END_OF

    my @errors = ();
    try { Net::SSH::ssh_cmd( $hostname, $cmd ) }
    catch { @errors = split "\n", $_; };

    return scalar @errors ? [@errors] : undef;
}

package main;
use strict;
use warnings;
use Test::More;
use FindBin qw/$Bin/;
use Path::Class ();

my $tmp_dir  = Path::Class::Dir->new( $Bin, '..', 'tmp' );

subtest 'touch ok' => sub {

    my $errors = Hoge->try_write( 'localhost', $tmp_dir );

    ok ! $errors;

=pod
    my $status = `echo $?`;
    chomp($status);

    is $status, 0;
=cut

    done_testing();
};

subtest 'touch not ok' => sub {

    chmod 0666, $tmp_dir->stringify or die $@;

    my $errors = Hoge->try_write( 'localhost', $tmp_dir );

    ok scalar @{$errors};
    diag(join "\n", @{$errors});

=pod
    my $status = `echo $?`;
    chomp($status);

    is $status, 256;
=cut

    chmod 0755, $tmp_dir->stringify or die $@;

    done_testing();
};

done_testing();

この状態だとtestが失敗します。exit(0)じゃないからです。

:!prove -vl eg/try_write.pl
eg/try_write.pl ..
    ok 1
    1..1
ok 1 - touch ok
    ok 1
    # /bin/touch: cannot touch `/home/okamura/eg/../tmp/hogefuga.piyo': 許可がありません
    # /bin/rm: cannot remove `/home/okamura/eg/../tmp/hogefuga.piyo': 許可がありません
    1..1
    # Looks like your test exited with 256 just after 1.
not ok 2 - touch not ok

#   Failed test 'touch not ok'
#   at eg/try_write.pl line 66.
1..2
# Looks like you failed 1 test of 2.
Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/2 subtests

Test Summary Report
-------------------
eg/try_write.pl (Wstat: 256 Tests: 2 Failed: 1)
  Failed test:  2
  Non-zero exit status: 1
Files=1, Tests=2,  0 wallclock secs ( 0.02 usr  0.00 sys +  0.04 cusr  0.02 csys =  0.08 CPU)
Result: FAIL

podをはずすとうまくいく

:!prove -vl eg/try_write.pl
eg/try_write.pl ..
    ok 1
    ok 2
    1..2
ok 1 - touch ok
    ok 1
    # /bin/touch: cannot touch `/home/okamura/eg/../tmp/hogefuga.piyo': 許可がありません
    # /bin/rm: cannot remove `/home/okamura/eg/../tmp/hogefuga.piyo': 許可がありません
    ok 2
    1..2
ok 2 - touch not ok
1..2
ok
All tests successful.
Files=1, Tests=2,  0 wallclock secs ( 0.01 usr  0.00 sys +  0.04 cusr  0.02 csys =  0.07 CPU)
Result: PASS

YES!!

ということで

あとはエラーがあったらMail送信をしたりするとたぶんうまくいくと思います。たぶんね。

ところで参考にしたmadeyeのlib/App/MadEye/Plugin/Agent/WriteDisk.pmで、ssh_cmdでtouchに失敗したときに例外をキャッチしてないようなのですが、問い合わせに失敗したらdeamonizeされたプロセスが途中で戦死してる気が、、、