俺様サーバー構築記 - Bash de TAP 〜 Subversionサーバーの動作確認の自動化@デスクトップパソコン


俺様サーバー構築記 - 基本方針」以来構築を続けてきた俺様パソコン環境ですが、いよいよ実際のサービスのインストールが始まり、前回はSubversionサーバーを立てました

その動作確認は手で行った訳ですが、この手順の自動化を試みました。

テスト用シェルスクリプト

テストの形式は TAP (Test Anything Protocol) に従いました。これを bash で実施する為のフレームワークも無い訳では無いようですが、調べるとどうも大掛かりと言うか冗長と言うか… 私はもっと単純にしたいんです。

と言う訳で、フレームワークからすべて自力で書きました。と言ってもそれほど大したコードではありません。そう、大したコードじゃ無い筈なんですよね本来は。その為の簡素な仕様だったのではないかと思うんですけども。

/srv/svn/test.sh
#!/bin/bash

declare -a TAP_TESTS
declare -g TAP_EXPECTED_EXIT_CODE=0
declare -g TAP_EXIT_IF_ERROR

TAP_test() { TAP_TESTS+=( "$@" ); }

TAP_assert() {
    local testname="${FUNCNAME[1]}"
    local result    # "local" is a bash-command, thats exit-code $? is always 0
    result=$(diff -U0 \
            <("$@" 2>&1; echo "exit_code=$?")                --label "$testname" \
            <(cat; echo "exit_code=$TAP_EXPECTED_EXIT_CODE") --label "expected results" \
            2>&1)
    if [[ $? -eq 0 ]]; then # check the exit-code of "diff" command
        echo "ok $TAP_COUNT - $testname"
    else
        echo "$result" | head -n4 | tail -n1 | xargs echo "not ok $TAP_COUNT - $testname:"
        echo "$result" | sed -e"s/^/# /"
        [[ -n "$TAP_EXIT_IF_ERROR" ]] && exit
    fi
}

TAP_do_testing() {
    echo "1..${#TAP_TESTS[@]}"
    local TAP_COUNT=0
    beforeAll
    trap afterAll EXIT
    local t
    for t in ${TAP_TESTS[@]}; do
        let ++TAP_COUNT
        setup
        $t
        teardown
    done
}

beforeAll() {
    declare -g PROJECT="Subversion_project_for_the_automated_test"
    declare -g TEXT="Subversion test"
    declare -g T_HOME1=$(mktemp -d)
    declare -g T_HOME2=$(mktemp -d)
    declare -g T_USR T_PWD
    IFS="$IFS=" read T_USR T_PWD <<< $(grep = /srv/svn/conf/passwd | head -n1)
}

afterAll() {
    cd "$T_HOME1/.."
    rm -r "$T_HOME1" "$T_HOME2"
    cd /srv/svn/repo
    rm -r "$PROJECT"
}

setup()    { TAP_EXIT_IF_ERROR=1; }
teardown() { :; }

TAP_test svn_createprj
svn_createprj() {
    TAP_assert /srv/svn/createprj.sh "$PROJECT" <<-___
        Edit svnserve.conf and authz in the directory /srv/svn/repo/$PROJECT/conf as needed.
        The file passwd is in the directory /srv/svn/conf, edit it as needed, too.
    ___
}

TAP_test svn_checkout
svn_checkout() {
    cd "$T_HOME1"
    cmd() { svn co --username "$T_USR" --password "$T_PWD" svn://localhost/$PROJECT/; }
    TAP_assert cmd <<< "Checked out revision 0."
}

TAP_test svn_add
svn_add() {
    cd "$PROJECT"
    cmd() {
        echo "$TEXT" >document.txt
        svn add *
    }
    TAP_assert cmd <<< "A         document.txt"
}

TAP_test svn_commit 
svn_commit() {
    TAP_assert svn ci --password "$T_PWD" -m "first commit" <<-___
        Adding         document.txt
        Transmitting file data .done
        Committing transaction...
        Committed revision 1.
    ___
}

TAP_test svn_cat
svn_cat() {
    TAP_assert svn cat --password "$T_PWD" svn://localhost/$PROJECT/document.txt <<< "$TEXT"
}

TAP_test svn_checkout_datetime
svn_checkout_datetime() {
    cmd() {
        cd "$T_HOME2"
        svn co -q --username "$T_USR" --password "$T_PWD" svn://localhost/$PROJECT/
        cd "$PROJECT"
        A=$(date -u -r document.txt +"%FT%T.%6NZ")
        B=$(svn log --password "$T_PWD" * --xml | xmllint --xpath "/log/logentry/date/text()" -)
        [[ $A = $B ]]
        echo $?
    }
    TAP_assert cmd <<< 0
}

TAP_do_testing

実行結果

# /srv/svn/test.sh 
1..6
ok 1 - svn_createprj
ok 2 - svn_checkout
ok 3 - svn_add
ok 4 - svn_commit
ok 5 - svn_cat
ok 6 - svn_checkout_datetime

prove コマンドも使えますよ勿論。

# prove /srv/svn/test.sh
/srv/svn/test.sh .. ok   
All tests successful.
Files=1, Tests=6,  1 wallclock secs ( 0.03 usr  0.00 sys +  0.14 cusr  0.06 csys =  0.23 CPU)
Result: PASS

テスト失敗を含む場合

# /srv/svn/createprj.sh Subversion_project_for_the_automated_test
Edit svnserve.conf and authz in the directory /srv/svn/repo/Subversion_project_for_the_automated_test/conf as needed.
The file passwd is in the directory /srv/svn/conf, edit it as needed, too.
# prove /srv/svn/test.sh 
/srv/svn/test.sh .. Failed 6/6 subtests 

Test Summary Report
-------------------
/srv/svn/test.sh (Wstat: 0 Tests: 1 Failed: 1)
  Failed test:  1
  Parse errors: Bad plan.  You planned 6 tests but ran 1.
Files=1, Tests=1,  0 wallclock secs ( 0.04 usr  0.00 sys +  0.02 cusr  0.01 csys =  0.07 CPU)
Result: FAIL
# /srv/svn/createprj.sh Subversion_project_for_the_automated_test
Edit svnserve.conf and authz in the directory /srv/svn/repo/Subversion_project_for_the_automated_test/conf as needed.
The file passwd is in the directory /srv/svn/conf, edit it as needed, too.
# /srv/svn/test.sh 
1..6
not ok 1 - svn_createprj: -svnadmin: E165002: /zfs/tank/sub0/srv/svn/repo/Subversion_project_for_the_automated_test is an existing repository
# --- svn_createprj
# +++ expected results
# @@ -1,2 +1,3 @@
# -svnadmin: E165002: '/zfs/tank/sub0/srv/svn/repo/Subversion_project_for_the_automated_test' is an existing repository
# -exit_code=1
# +Edit svnserve.conf and authz in the directory /srv/svn/repo/Subversion_project_for_the_automated_test/conf as needed.
# +The file passwd is in the directory /srv/svn/conf, edit it as needed, too.
# +exit_code=0

このように、エラーが発生した場合には、テスト結果にコメントの形でエラー内容が表示されます。その為 prove コマンドでも仕様通りに集計され、問題無く出力されます。

以上、手作業による動作確認を bash スクリプトで自動化し TAP による集計可能出力を表示しましたが、良い感じです。
やったね