🚀

Launchable Advent Calendar 16日目 - Split Subset

2022/12/16に公開

Launchableの各機能の利用方法を紹介する Launchable Advent Calendar 16日目です。

はじめに

16日目はSplit Subsetについて説明します。(docs)

Split Subsetは並列でテスト実行するのを助ける機能です。
テストランナーに並列でテストを実行する機能が備わっていない場合でも並列でのテストが可能になります。複数台のマシンを利用して並列でテストする際のテストケースの重複や実行時間の偏りなどの煩わしさもありません。

Split Subset

使用する主なコマンドは launchable subset, launchable split-subset コマンドになります。
また、テスト結果のレポート時に launchable record tests コマンドで --subset-id オプションを使用します。

実行する流れとしては、今までと同じように launchable subset コマンドを使用しPredictive Test Selection(PTS) を行います。1つ異なるのが --split オプションを使用する点です。
このオプションを使用することでテストすべきリストを出力していたものが launchable split-subset--subset-id オプションに渡すSubset IDを出力するようになります。

出力されたSubset IDを使用して launchable split-subset を実行します。
その際 --bin オプション使用し、PTSの結果を何分割にするのか、分割したうちのどれを取得するのかを指定します。

こちらはPTSを4分割にし、1つ目を使用する例になります。

$ launchable subset --target 100% --split maven src/test/java
subset/397825
Launchable created subset 397825 for build ignore-new-tests-example (test session 1619454) in workspace konboi/advent-calendar-2022

|           |   Candidates |   Estimated duration (%) |   Estimated duration (min) |
|-----------|--------------|--------------------------|----------------------------|
| Subset    |            4 |                      100 |                  0.0983333 |
| Remainder |            0 |                        0 |                  0         |
|           |              |                          |                            |
| Total     |            4 |                      100 |                  0.0983333 |

Run `launchable inspect subset --subset-id 397825` to view full subset details

$ launchable split-subset --subset-id subset/397825 --bin 1/4 maven
example.MulTest

...

# テスト結果のレポート
$ launchable record tests --subset-id subset/397825 maven target/surefire-reports/TEST-example.*.xml

以下は1回目の実行ではPTSの結果を4分割にしたうちの2つ目を取得。2回目の実行では2分割したうちの1つ目、最後の実行では2分割したうちの2つ目を取得する。という例になります。

$ launchable split-subset --subset-id subset/397825 --bin 2/4 maven
example.DivTest

$ launchable split-subset --subset-id subset/397825 --bin 1/2 maven
example.MulTest
example.AddTest

$ launchable split-subset --subset-id subset/397825 --bin 2/2 maven
example.DivTest
example.SubTest

ちなみに、デフォルトではテスト実行時間が均等になるように分割されます。

GitHub Actions での例

Day 12の設定を元に4並列でテストを実行するように設定します。

primary-nodeで --split オプションを使用し launchable subset を実行。出力されたSubset IDをworker-node1から4へ渡します。
worker-node1から4では渡されたSubset IDを使用し launchable split-subset で4つに分割したPTSの結果をそれぞれ取得しテストを実行。その後結果をレポート。

という流れになっています。

ci.yaml
   primary-node:
     runs-on: ubuntu-latest
     outputs:
-      test_session:  ${{ steps.issue_test_session.outputs.test_session}}
+      subset_id:  ${{ steps.issue_subset_id.outputs.subset_id}}
     steps:
       - uses: actions/checkout@v3
         with:
...
         run: launchable verify
       - name: record build
         run: launchable record build --name ${GITHUB_RUN_ID}
-      - name: record session
-        id: issue_test_session
+      - name: subset
+        id: issue_subset_id
         run: |
-          launchable record session --build ${GITHUB_RUN_ID} > test_session.txt
-          test_session=$(cat test_session.txt)
-          echo "test_session=$test_session" >> $GITHUB_OUTPUT
-  worker-node:
+          launchable subset --target 100% --split maven src/test/java > launchable-subset-id.txt
+          subset_id=$(cat launchable-subset-id.txt)
+          echo "subset_id=$subset_id" >> $GITHUB_OUTPUT
+  worker-node1:
     runs-on: ubuntu-latest
     needs: [primary-node]
     steps:
...
       - uses: actions/setup-python@v4                                                                                                [35/12654]
         with:
           python-version: "3.10"
-      - name: Set up JDK 1.8
-        uses: actions/setup-java@v3
+      - name: Install launchable command
+        run: |
+          pip install launchable
+      - name: Restore subset-id
+        run: echo -n '${{needs.primary-node.outputs.subset_id}}' > launchable-subset-id.txt
+      - name: split subset
+        run: launchable split-subset --subset-id $(cat launchable-subset-id.txt) --bin 1/4 maven > launchable-subset.txt
+      - name: Run tests
+        run: mvn test -Dsurefire.includesFile=launchable-subset.txt
+      - name: launchable record tests
+        run: launchable record tests --subset-id $(cat launchable-subset-id.txt) maven target/surefire-reports/TEST-example.*.xml
+        if: always()
+ worker-node2:
+    runs-on: ubuntu-latest
+    needs: [primary-node]
+    steps:
+      - uses: actions/checkout@v3
+      - uses: actions/setup-python@v4
         with:
-          distribution: 'adopt'
-          java-version: '8'
+          python-version: "3.10"
       - name: Install launchable command
         run: |
           pip install launchable
-      - name: Restore test session
-        run: echo -n '${{needs.primary-node.outputs.test_session}}' > test_session.txt
-      - name: subset
-        run: launchable subset --session $(cat test_session.txt) --target 80% maven src/test/java > launchable-subset.txt
+      - name: Restore subset-id
+        run: echo -n '${{needs.primary-node.outputs.subset_id}}' > launchable-subset-id.txt
+      - name: split subset
+        run: launchable split-subset --subset-id $(cat launchable-subset-id.txt) --bin 2/4 maven > launchable-subset.txt
+      - name: Run tests
+        run: mvn test -Dsurefire.includesFile=launchable-subset.txt
+      - name: launchable record tests
+        run: launchable record tests --subset-id $(cat launchable-subset-id.txt) maven target/surefire-reports/TEST-example.*.xml
+        if: always()
+  worker-node3:
+    runs-on: ubuntu-latest
+    needs: [primary-node]
+    steps:
+      - uses: actions/checkout@v3
+      - uses: actions/setup-python@v4
+        with:
+          python-version: "3.10"
+      - name: Install launchable command
+        run: |
+          pip install launchable
+      - name: Restore subset-id
+        run: echo -n '${{needs.primary-node.outputs.subset_id}}' > launchable-subset-id.txt
+      - name: split subset
+        run: launchable split-subset --subset-id $(cat launchable-subset-id.txt) --bin 3/4 maven > launchable-subset.txt
+      - name: Run tests
+        run: mvn test -Dsurefire.includesFile=launchable-subset.txt
+      - name: launchable record tests
+        run: launchable record tests --subset-id $(cat launchable-subset-id.txt) maven target/surefire-reports/TEST-example.*.xml
+        if: always()
+  worker-node4:
+    runs-on: ubuntu-latest
+    needs: [primary-node]
+    steps:
+      - uses: actions/checkout@v3
+      - uses: actions/setup-python@v4
+        with:
+          python-version: "3.10"
+      - name: Install launchable command
+        run: |
+          pip install launchable
+      - name: Restore subset-id
+        run: echo -n '${{needs.primary-node.outputs.subset_id}}' > launchable-subset-id.txt
+      - name: split subset
+        run: launchable split-subset --subset-id $(cat launchable-subset-id.txt) --bin 4/4 maven > launchable-subset.txt
       - name: Run tests
         run: mvn test -Dsurefire.includesFile=launchable-subset.txt
       - name: launchable record tests
-        run: launchable record tests --session $(cat test_session.txt) maven target/surefire-reports/TEST-example.*.xml
+        run: launchable record tests --subset-id $(cat launchable-subset-id.txt) maven target/surefire-reports/TEST-example.*.xml
         if: always()

サンプルPR

問題なく設定しテストを実行するとこのようになります。

さいごに

本日は並列でテストを実行するSplit Subsetについて紹介しました。
明日はSplit Subsetのオプションである include/exclude オプションについて紹介します。

Discussion