Groongaでは、これまでもGitHub Actionsを使ってパッケージの作成を自動化したり、テストの自動化を実施してきました。 いままで自動化してきたテストは、リポジトリーにpushされたソースコードに対してビルド、テストするものでした。 これらの自動化により、リリース前に初めて問題が発覚することが少なくなり、問題が発生した段階で対処を進めることができています。
ただ、リポジトリーにpushされたソースコードに対するテストだと、各OS向けに作成したパッケージがちゃんとインストールできるか、 パッケージからインストールした環境で動作するかは確認できていませんでした。 そのため、パッケージの作成に失敗していた場合には、リリース後、パッケージからGroongaをインストールする段階にならないと問題に気がつけない状態でした。
リリース後にパッケージに問題があるとわかった場合は、再リリースすることになり、余計な時間がかかってしまいます。 そこで、リポジトリーにソースコードがpushされた段階でパッケージのインストールとパッケージからインストールしたGroongaのテストを実行するようにしました。
この記事は、作成したパッケージをインストール、テストする方法を説明したものです。 Groongaに固有の部分もありますが、各OS向けにパッケージを提供しているプロジェクトにとって参考になる情報もあると思います。
パッケージのテスト環境の構築
パッケージをテストするためには、当然テスト対象のパッケージを作成する必要がありますが、Groongaでは、既に自動化されています。 パッケージは既にできているので、この記事では、作成されたパッケージを取得するところから説明します。
前述の通りGroongaでは、リポジトリーにソースコードがpushされるたびにパッケージの作成が実行されるので、パッケージ作成後にテストを実行します。
パッケージの作成とパッケージのテストのジョブを分けても良いのですが、そのようにすると、パッケージを作成するジョブでartifacts
にパッケージを保存し、
パッケージをテストするジョブでは、artifacts
から必要なパッケージをダウンロードする操作が必要になり煩雑です。
(GitHub Actionsでは、パッケージ等のワークフローの成果物をartifacts
として保持できます。)
そのため、Groongaではパッケージの作成とパッケージのテストは同一のジョブで実行しています。
具体的には、以下のようにしています。
-
Docker上にホストのディレクトリをマウント
-
テスト用のイメージ、テストスクリプトを指定
# Test
- name: Test
run: |
docker run \
--rm \
--tty \
--volume ${PWD}:/groonga:ro \
${{ matrix.test-docker-image }} \
/groonga/${{ matrix.test-script }}
上記設定は、 https://github.com/groonga/groonga/blob/v10.0.2/.github/workflows/package.yml#L158 に記載されています。
1. Docker上にホストのディレクトリをマウント
docker run
の--volume
オプションを使って、ホストのディレクトリをDocker上にマウントできます。
上記では、--volume ${PWD}:/groonga:ro
と指定されているので、現在居るディレクトリをDcoker上の/groonga
にマウントしています。
2. テスト用のイメージ、テストスクリプトを指定
${{ matrix.test-docker-image }}
で実行するイメージを指定し、/groonga/${{ matrix.test-script }}
で実行するテストスクリプトを指定しています。
GitHub Actions上で作成しているパッケージは、CentOS向けとDebian向けのものなので、この2つのOSのイメージを使用します。
複数のバージョンがあるので、matrix
を使用し、バージョンごとにイメージを変更してテストしています。
${{ matrix.test-docker-image }}
は以下のように定義されているので、Debian stretch、Debian buster、CentOS6、CentOS7、CentOS8のイメージを使用するようになっています。
テストに使用するスクリプトもOSによって異なるので、${{ matrix.test-script }}
としてそれぞれのパスを指定しています。
include:
- label: Debian GNU/Linux stretch amd64
id: debian-stretch-amd64
test-docker-image: debian:stretch
test-script: packages/apt/test.sh
- label: Debian GNU/Linux stretch i386
id: debian-stretch-i386
test-docker-image: i386/debian:stretch
test-script: packages/apt/test.sh
- label: Debian GNU/Linux buster amd64
id: debian-buster-amd64
test-docker-image: debian:buster
test-script: packages/apt/test.sh
- label: Debian GNU/Linux buster i386
id: debian-buster-i386
test-docker-image: i386/debian:buster
test-script: packages/apt/test.sh
- label: CentOS 6
id: centos-6
test-docker-image: centos:6
test-script: packages/yum/test.sh
- label: CentOS 7
id: centos-7
test-docker-image: centos:7
test-script: packages/yum/test.sh
- label: CentOS 8
id: centos-8
test-docker-image: centos:8
test-script: packages/yum/test.sh
また、テストに使用するイメージは既存のイメージを再利用せず、新規に作るのが良いです。 新規の環境でテストしないと依存ライブラリーが足りない等の問題に気がつけない可能性があるためです。
ここまでで、それぞれのDockerイメージ上でテストを実行する準備が整いました。 次は、パッケージのインストールとテストを実施します。 パッケージのインストールとテストは、テストスクリプト内で実施しています。
パッケージのインストールとテストの実施
Debian向け、CentOS向けのパッケージのテストスクリプトは、以下の場所にあります。 ここからは、これらのスクリプトの内容を説明し、どのような流れでパッケージのインストールとテストを行っているかを説明します。
Debian向け: https://github.com/groonga/groonga/blob/v10.0.2/packages/apt/test.sh
CentOS向け: https://github.com/groonga/groonga/blob/v10.0.2/packages/yum/test.sh
基本的な流れはどちらのスクリプトも同じで、それぞれのOSのパッケージ管理システム(Debianならapt
、CentOS6,7ならyum
、CentOS8ならdnf
)を使って
ホストからマウントしたディレクトリにある、パッケージをインストールし、その後grntest
(Groonga用のテストツール)を使ってGroongaのテストを実行しています。
ただ、CentOS6,7はRubyのバージョンが古く、grntest
を使ったテストができないので、パッケージのインストールのみを確認しています。
また、CentOS8は、CentOS8向けのMessagePackのパッケージが無いため、現状ではテストを実行せずにスクリプトを終了しています。
(MessagePackがないとすべてのテストを実行できないためです。)
Debian向けパッケージのインストール、テストの流れ
まず、テストスクリプトの以下の箇所でOSのコードネームとアーキテクチャを取得します。 これらは、インストールするパッケージのパスに使用します。
code_name
には、stretch
やbuster
等のDebianの各バージョンのコードネームが入ります。
architecture
には、amd64
やi386
等のCPUアーキテクチャが入ります。
code_name=$(lsb_release --codename --short)
architecture=$(dpkg --print-architecture)
次にインストールするパッケージのパスを指定してapt
コマンドでパッケージをインストールします。
apt
コマンドは、APTリポジトリを用意しなくても、以下のようにローカルに保存されているパッケージを直接指定してインストールできます。
repositories_dir=/groonga/packages/apt/repositories
apt install -V -y \
${repositories_dir}/debian/pool/${code_name}/main/*/*/*_{${architecture},all}.deb
インストール後、インストールが成功しているかを、groonga
コマンドを使って確認します。
groonga --version
次にテスト用のディレクトリを作成し、テストスクリプトを移動します。 この段階で、i386の環境では動作しないテストを削除します。
mkdir -p /test
cd /test
cp -a /groonga/test/command ./
if [ "${architecture}" = "i386" ]; then
rm command/suite/ruby/eval/convert/string_to_time/over_int32.test
# TODO: debug this
rm command/suite/select/filter/geo_in_circle/no_index/north_east.test
fi
最後にgem
でgrntest
をインストールし、テストを実行しています。
apt install -V -y \
gcc \
make \
ruby-dev
gem install grntest
export TZ=Asia/Tokyo
grntest_options=()
grntest_options+=(--base-directory=command)
grntest_options+=(--n-retries=3)
grntest_options+=(--n-workers=$(nproc))
grntest_options+=(--reporter=mark)
grntest_options+=(command/suite)
grntest "${grntest_options[@]}"
grntest "${grntest_options[@]}" --interface http
grntest "${grntest_options[@]}" --interface http --testee groonga-httpd
CentOS向けパッケージのインストール、テストの流れ
まず、テストスクリプトの以下の箇所でOSのバージョンを取得します。
これは、パッケージのパスを指定するのとパッケージ管理システムのコマンドを指定するのに使います。
(CentOSのパッケージ管理は、CentOS6,7では、yum
コマンドで実行しますが、CentOS8では、dnf
コマンドで実行するためです。)
version=$(cut -d: -f5 /etc/system-release-cpe)
以下の箇所でバージョン毎にパッケージ管理システムのコマンドを指定します。
case ${version} in
6|7)
DNF=yum
;;
*)
DNF="dnf --enablerepo=PowerTools"
;;
esac
以下の箇所でGroongaの公開鍵のインポートを行い、RPMパッケージをインストールします。
yum
やdnf
コマンドもapt
コマンドと同様、YUMリポジトリを用意しなくても、以下のようにローカルに保存されているパッケージを直接指定してインストールできます。
${DNF} install -y \
https://packages.groonga.org/centos/groonga-release-latest.noarch.rpm
repositories_dir=/groonga/packages/yum/repositories
${DNF} install -y \
${repositories_dir}/centos/${version}/x86_64/Packages/*.rpm
インストールが成功しているかを、groonga
コマンドを使って確認します。
groonga --version
CentOS6,7はRubyのバージョンが古くgrntest
が動作しないためここでスクリプトを終了します。
case ${version} in
6|7)
exit 0
;;
*)
;;
esac
CentOS8は、以下の箇所でgrntest
をインストール後テストを実行します。
ただ、前述の通り現在は、CentOS8向けのMessagePackのパッケージが無いため、テスト実行前にexit 0
でスクリプトを終了しています。
# TODO: Require msgpack for testing normalizer options
exit 0
${DNF} install -y \
gcc \
make \
redhat-rpm-config \
ruby-devel
gem install grntest
export TZ=Asia/Tokyo
grntest_options=()
grntest_options+=(--base-directory=/groonga/test/command)
grntest_options+=(--n-retries=3)
grntest_options+=(--n-workers=$(nproc))
grntest_options+=(--reporter=mark)
grntest_options+=(/groonga/test/command/suite)
grntest "${grntest_options[@]}"
grntest "${grntest_options[@]}" --interface http
grntest "${grntest_options[@]}" --interface http --testee groonga-httpd
以上のようにして、Groongaではリポジトリへのpushをトリガーとして、パッケージの作成、インストール、テストまでを自動で実行しています。 こうすることで、作成したパッケージがインストールできないといった問題を未然に防げるようになり、より安定したものをリリースできます。
各OSに向けのパッケージを配布しているプロジェクトは、上記のようなやり方を参考にして、パッケージのテストも自動化してみてはいかがでしょうか?