Test::Perl::Critic その3

Test::Perl::Criticは、Perlベストプラクティスのポリシーをどのていど厳格に守るのか設定が可能。
設定は、Perl::Criticと同じようにできる。
今回のエントリーは、その設定項目について。

設定方法

useにリストとして指定

use Test::Perl::Critic ( -profile => 't/perlcriticrc' );

または、importの引数として指定

Test::Perl::Critic->import( -profile => 't/perlcriticrc' );

-profile

コンフィグファイルへのパスを指定する。
もし、指定されたファイルがない場合はカレントディレクトリから.perlcriticrcを探す。

-severity

厳格さを数値もしくは、厳格さを反映した名前で設定する。
数値の場合、5が最も緩く、1が最も厳しい。デフォルトでは5が設定される。
gentleを指定した場合は、重大な違反のみを報告する。
brutalを指定した場合は、最も軽微な違反も報告する。

数値 名前
5 gentle *1
4 stern *2
3 harsh *3
2 cruel *4
1 brutal *5
Test::Perl::Critic->import( -severity => 'gentle' );

-theme

指定したテーマについてポリシーを適用する。

  • severityが指定されていない場合、-severityには1が設定される。

&&演算子や、||演算子を使い複雑なテーマの設定が可能。
使える演算子は、&&, ||, !, and, or, not。
演算子の優先順位はPerlのコードと同じ。

なお、テーマは大文字と小文字を区別されない。
また、テーマを指定しない場合はすべてのポリシーが適用される。

以下の例では、'bugs'と'pbp'のテーマを持っているポリシーが適用される。

Test::Perl::Critic->import( -theme => 'bugs && pbp' );
テーマとは

ポリシーには、1つ以上のテーマが設定されている。
これにより、テーマを設定することで好みのポリシーでPerl::Criticを走らせることができる。

テーマ 内容
core Perl::Criticのすべてのポリシー
pbp "Perl Best Practices"由来のポリシー
bugs バグを防止または、明らかにするポリシー
maintenance コードの長期的な健全さに影響するポリシー
cosmetic Policies that only have a superficial effect*6
complexity コードの複雑さに関するポリシー
security セキュリティ問題に関するポリシー
tests テストプログラムのためのポリシー

以下のコマンドで使用可能なポリシーとそれに関連付けられているテーマを確認することができる。

$ perlcritic -list

-include

適用させるポリシーを、文字列のリストリファレンスとして指定する。
指定した文字列がixmsオプション付きのパターンマッチにヒットした場合、ポリシーは適用される。
このとき、-severityで設定した厳格さ以上のポリシーも適用される。

Test::Perl::Critic->import(-include => ['layout'] -severity => 4);

-exclude

除外するポリシーを、文字列のリストリファレンスとして指定する。
指定した文字列がixmsオプション付きのパターンマッチにヒットした場合、ポリシーは除外される。

なお、-includeと共に使用した場合、-excludeで設定した項目が優先される。

-single-policy

指定した文字列がimxsオプション付きのパターンマッチに一致する1つのポリシーのみが適用される。
(複数のポリシーに一致しても、適用されるのは1つのみ)
この設定は、-severity, -theme, -include, -exclude, -only よりも優先される。

-top

表示される違反の最大数を設定する。
表示される違反はファイルで発生した順。
severityが指定されない場合は、最も厳格な1が設定される。

-force

コード内の"## no critic"を無視するかどうかの設定値。
真となる値を設定した場合、Perl::Criticはすべてのコードを分析する。
偽となる値を設定した場合は、"## no critic"がつけられたタグを無視する。

-verbose

1から11までの正の整数。もしくは、リテラルで書式を設定できる。
CPAN本によると、8がちょうどいいらしい。

*1:優しい、穏やかな

*2:厳格な、厳しい、断固たる、容赦のない、人を寄せ付けない、いかめしい

*3:厳しい、手厳しい、とげとげしい、辛辣な

*4:残酷な、むごい、残虐な、無慈悲な、非情な

*5:残忍な、厳しい、荒々しい

*6:コードの見た目に関するポリシーの模様

Test::Perl::Critic その2

今日はサブルーチンについて。

critic_ok( $FILE [, $TEST_NAME ] )

# t/991_perlcritic.t
use strict;
use Test::More;

eval { require Test::Perl::Critic; Test::Perl::Critic->import(-profile => "t/perlcriticrc") };
plan skip_all => "Test::Perl::Critic is not installed." if $@;

critic_ok( 'bin/get_tweet.pl' );

done_testing;
$ perl t/991_perlcritic.t
ok 1 - Test::Perl::Critic for "bin/get_tweet.pl"
1..1

ファイルを指定してテストする場合に使う。
複数のファイルを指定することはできない模様。


最も気をつけるべき点は、テスト数を明示して上げる必要がある。もしくはdone_testing;を記述する。


なお、第二引数にテスト名を指定することが可能。
デフォルトでは、"Perl::Critic test for $FILE"。
テスト名を'MyTest'とした場合は、以下のようになる。

perl t/991_perlcritic.t
ok 1 - MyTest
1..1

all_critic_ok( [ @DIRECTORIES ] )

# t/992_perlcriti_all_critic_ok.t
use strict;
use Test::More;

eval { require Test::Perl::Critic; Test::Perl::Critic->import(-profile => "t/perlcriticrc") };
plan skip_all => "Test::Perl::Critic is not installed." if $@;

all_critic_ok();

指定したディレクトリ内のPerlファイルに対してテストを実行する。
ディレクトリが指定されなかった場合はblib以下ののPerlファイルを、
blibが存在しない場合は、lib以下のPerlファイルに対してテストを行う。


その1で書いたとおり、このサブルーチンを使用する場合はテスト数を明示する必要がない。

all_code_files ( [@DIRECTORIES] )

非推奨!
[12/7追記]
そもそもimportされないのでパッケージ名から指定しないと使えません。


Perlファイルのリストを返す。
ディレクトリを指定しない場合、blib以下から、
blibが存在しない場合は、lib以下から。
CVSSubversionディレクトリ内のファイルはスキップされる。


ソースコードを見てみると、all_critic_okから呼び出されている。
また、このサブルーチン自体はディレクトリの設定をしてPerl::Critic::Utils::all_perl_filesを呼び出しているだけ。
したがって、このサブルーチンを使いたい場合は、ドキュメントに書いてあるとおりPerl::Critic::Utils::all_perl_filesを使うべき。


なお、Perlファイルの判断条件は以下の2つ

  1. 拡張子が .PL .pl .pm .t
  2. シバンに'perl'を含む

Test::Perl::Critic その1

社内勉強会で発表するためのメモその1

概要

Test::Perl::Critic wraps the Perl::Critic engine in a convenient subroutine suitable for test programs written using the Test::More framework.

Test::Perl::Critic - Use Perl::Critic in test programs - metacpan.org

(超意訳)Test::Perl::CriticはTest::More向けの、Perl::Criticのラッパーだよ!

このモジュールはテスト対象のコードがPBPに準拠しているかどうかをテストしてくれるモジュールです。 PBPとはDamian Conway氏の提唱するPerl Best PracticesというPerlのコードを書く際のスタイルです。

第4回 Test::Perl::Critic, Test::Pod, Test::Pod::Coverage, Test::Exception, Test::Warn, Devel::Coverの紹介:Happy Testing Perl|gihyo.jp … 技術評論社

使ってみる

# t/99_perlcritic.t
use strict;
use Test::More;

eval { require Test::Perl::Critic; Test::Perl::Critic->import(-profile => "t/perlcriticrc") };
plan skip_all => "Test::Perl::Critic is not installed." if $@;

all_critic_ok( qw/ bin lib /);

はじめ、done_testingをつけて実行したところ、テスト数が合わないと言われパスしなかった。
ドキュメントを見てみると、Test::Moreのテスト数はTest::Perl::Criticが設定してくれる云々と書いてある。


また、t/perlcriticrcを作ってない場合は、空ファイルでいいので作らないとパスしない。
もしくは、以下のようにコードを変更するか。

#eval { require Test::Perl::Critic; Test::Perl::Critic->import(-profile => "t/perlcriticrc") };
eval { require Test::Perl::Critic; Test::Perl::Critic->import };


とりあえず、自分が書いたコードでテストしてみたが、なんとパスした。
ちょっと驚いた。それほど難しいことしてないためだろうが。

/bin/shの実体

シェルスクリプトはエレガントでなければならない (1/2):スマートな紳士のためのシェルスクリプト(1) - @ITを読むまで、/bin/shの実体は各OSによって違うと知らなかった。

記事中に明記されていない、CentOS5.7で調べてみるとやはりbashへのシンボリックリンクが貼られていた。

$ cat /etc/redhat-release
CentOS release 5.7 (Final)
$ ls -al /bin/sh
lrwxrwxrwx 1 root root 4 Nov 19 21:52 /bin/sh -> bash

今後、自分が書くシェルスクリプトのシバンには/bin/shをではなく、実体のシェルを書くようにしようと思った。

オペレーションミス

転職して、アプリケーション構築だけでなく、サーバのソフトウェアインストールや設定などオペレーション作業も行わせていただけるようになりました。
貴重な経験を積むことができる機会を与えて頂き、ありがたく思っています。


しかし、本日オペレーションミスをしてしまいました。

覚悟はしていたか

すでにサービスを開始しているアプリケーションが動作しているサーバ上での作業でした。
したがって、作業中に何かミスをしてしまった場合、サービスに影響が起る事、最悪実害が発生する事も把握していました。
ですので、少なくとも作業開始前は今から行う作業への覚悟はありました。

ですが、結果的にミスを犯しました。
今振り返ると、作業を進める中で自分が実行しようとするコマンドがどのような結果になるのか、
どのサーバで作業を行なっているのか、といった事への注意が疎かになっていったと思っています。

自分には向いていないのではないか

自分は確認や注意する事への意識が足りない、長続きしない性格だと思います。
ですので、適性的にはあまりオペレーション作業には向いていないと思っています。

しかし、業務を投げ出すことはできません。
また、自分勝手な思いですが、オペレーション作業をもっと習得していきたいと思っています。
ですので、今回のミスを見直し、まとめることで今後同じミスを起こなさいための戒めとします。

今日の作業を振り返る

自分は、オペレーションの作業内容を予め作業手順としてまとめ、手順通りに作業を進めるようしていましたが、作業中に想定していないエラーが発生してしまいました。

ここで自分は、rootで作業中のコンソールをそのままに、エラー原因の調査を開始。
その結果、調査のために立ち上げた複数のコンソールの中に、作業対象サーバにrootで接続されたコンソールが存在する状態となってしまいました。

そして、ミスを犯します。
開発環境で実行・確認するつもりで、作業対象サーバにてコマンドを発行してしまいました。

何が問題だったのか

1. 作業から調査への移行

調査を始める段階でrootで作業していたコンソールを閉じていなかったことが問題。
作業対象のサーバを調査する必要があったとしても、rootのままでいる必要はなかった。

2. コマンドの実行サーバの確認不足

現在自分がどのサーバで作業をやっており、どのようなコマンドを実行しようとしているのか確認することが疎かになっていた。

3. そもそもの知識不足、確認手段の安易な選択

「2」でのコマンドは本当に実行し確認する必要はあったのか。
(調べれば|聞けば)分かることではなかったのか。

今後の対策

「1. 作業から調査への移行」への対策

作業を中断する必要な状態になった場合は、作業中のコンソールは落としてしまう。

「2. コマンドの実行サーバの確認不足」 への対策

現在作業しているサーバがどのサーバなのか分かりやすい環境を構築することにする。

「3. そもそもの知識不足、確認手段の安易な選択」 への対策

勉強する。自分の知識不足をもっと認め、自尊心を捨て周りに聞く。

だが、しかし

現状、すべてが後手に回ってしまっています。
ミスを起こしてしまってから、反省、改善を行なってもミスが起きた事実は変わらないので、
自分の性格をもっと自覚し、ミスが起こりにくい環境の構築をもっと積極的に行うべきだと考えています。
また、オペレーションに関する知識をこれまで以上にもっと深めていくことも必須だと考えています。

明日から

今日は落ち込みました。
この気持が風化してしまう前に、こうやってエントリーとして残しておきたいと考えちょっと頑張ってみました。
明日からは改めて業務を行いたいと思います。
そして、今後、オペレーション作業を行う際は、この記事を見なおし気を引き締め取り組むつもりです。

/etc/init.d/mysql start が失敗する。

xtrabackupでバックアップしたMySQLデータベースをリストアした後に、起動しようとるすが失敗した。

原因を調べていくと、起動できるコマンドとできないコマンドがあることが分かった。

以下、そのコマンドになる。

なお、いずれもrootユーザで実行。

失敗するコマンド
  • /etc/init.d/mysql start
成功するコマンド
  • su -x /etc/init.d/mysql start
  • /usr/bin/mysqld_safe --datadir='/var/lib/mysql' --pid-file='/var/lib/mysql/www8196u.sakura.ne.jp.pid' >/dev/null 2>&1 & *1

現状わかっていること

  • 失敗する場合、/usr/bin/mysqld_safe の748行目でbreakされ、mysqld_safeのデーモンは終了している
  • 分岐条件は、if test ! -f "$pid_file"なので、mysqldの起動に失敗していると思われる
  • エラーログは、"mysqld_safe mysqld from pid file /var/lib/mysql/localhost.pid ended" のみ
  • リストアする前のデータディレクトリに戻すことで問題なく起動できる

環境情報など

会社で構築した環境下での出来事なので、改めて追記します。

*1:/etc/init.d/mysql start で呼び出されるコマンド