テスト失敗してるのにActionsがSuccessって言ってくる話
Github Actions上で、docker-composeを使ってRobotframeworkでのテストを行うコンテナを起動させる、というWorkflowを作成していたところ、 テストが失敗しているのにGithub ActionsがSuccessで終了する、という現象に出会ったので、それを調べた時のメモです
先に結論
docker-compose up
をそのまま使用していたのが今回の敗因。 docker-compose run
か、 docker-compose up --exit-code-from [service]
を使用していれば起きなかった
原因
どうやら、 docker-compose up
をそのまま実行すると、composeは個別のサービスの exit code
は返さず、サービスの起動自体は正常終了させたで、っていう意味での exit code 0
を返す、という妥当な内容だった。なるほど。Actionsは、このcomposeの exit code 0
を受け取って、「正常終了」と判別していたのが原因らしい。
検証してみる: ソースコード
ただ exit 1
するだけのコンテナを作成して動作確認します
1 | $ cat Dockerfile |
composeもビルドにまつわる記述以外は無し
1 | $ cat docker-compose.yml |
以上のソースコードは、こちらにも置いてます
1 | // ビルドもごく普通 |
検証してみる: docker run
まずは docker run
で実験。コンテナ内部の終了コードをそのまま認識している
1 | $ docker run --rm failure |
検証してみる: docker-compose run
次に、 docker-compose run
で実験。こちらも、コンテナ内部の終了コードをそのまま認識している
1 | $ docker-compose run --rm failure |
検証してみる: docker-compose up
次に、 docker-compose up
で実験。こちらは、コンテナ内部の終了コードではなく、 docker-compose
自体の終了コードを認識しています。また、 failure_failure_1 exited with code 1
の表示から、 failure
サービス自体は、正しく exit code 1
を返した事が確認出来ます
1 | $ docker-compose up failure |
考えた: docker-compose up
この検証ではコンテナが1つしかないため違和感があるが、これが複数のサービスになった場合(もとい、composeはそういうアレなので)、1つ以上のサービスが exit code 1
を返したからといって、compose自体の終了コードは 1
と扱わないようになっている模様。
とはいえ、今回のようにActions上で、アプリケーションとテストのコンテナを2つ起動し、テストが失敗した場合(=テストのコンテナが exit code 1
を返した場合)に、Slackに通知するなり、CI/CDを止めるなり、何らかの処理を行わないといけないので、それを検知出来ないとなるととても困る。
解決策: docker-compose up –exit-code-from を使う
こういう時のために、特定のサービスの exit code
を取得し、それを返すオプション --exit-code-from
が、docker-composeに用意されてた。
1 | // 抜粋 |
--exit-code-from SERVICE
を指定すると、SERVICE
に指定したサービスの終了コードを正しく実行側にかえしてくれるようになる、との事。そうそうこれ欲しかってん- そして、
--exit-code-from
オプションを使用すると、 暗黙で--abort-on-container-exit
オプションが有効になります、との事。 --abort-on-container-exit
は、 いずれかのコンテナが停止した場合、すべてのコンテナを停止するオプション、との事。
検証してみる: docker-compose up –exit-code-from
さっそく試してみる。例えばさっきのdocker-compose.ymlに、nginxを追加してみて、
1 | services: |
試しに、nginxを3つ起動する( --exit-code-from
付きで)
1 | $ docker-compose up --exit-code-from failure --scale nginx=3 |
期待通りの結果になり、nginxもすべて停止。
そして、 --exit-code-from
を使用した場合、肝心の exit code
はどうなっているのかというと
1 | // 異常終了 |
期待通り、異常終了を得ることが出来ました(おわり)
これって、例えば、複数のコンテナの exit code
を取得して、「両方 1
なら」みたいな条件ってどうやるんだろう