Gradle test でOutOfMemoryError

SpringBootのテストをJenkinsで行っていたんですが、
ある日OutOfMemoryErrorで落ちて如何ともし難くなりました。かなしみ。

![OOM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38628/6a1ecbd2-edc8-84b9-d3b4-871979d0ca8d.png)

一応、何度かトライして復旧できたので、ログを残しておきます。

## 環境

- Java8
- CentOS7
- Jenkins
- JUnit5

## ①ヒープを増やす

```
java.lang.OutOfMemoryError: GC overhead limit exceeded
```
とあり、[Jenkins-SlaveでUnitTestがOutOfMemory](https://qiita.com/fake-deli-ca/items/b2cadce085595c57636d) (@fake-deli-ca) の記事によるとtestタスクはプロセスが別になって実行される（へー知らなかった）ということなので、そのプロセスのヒープサイズの割当を増やせば良さそうと。

> 23.13.1. テストの実行
テストの実行は別のJVMで行われ、メインのビルドプロセスからは分離されます。TestタスクのAPIを使って、テストの実行を制御できます。

http://gradle.monochromeroad.com/docs/userguide/java_plugin.html

なので、testタスクに以下の記述を追記して、再実行。

```
test {
  useJUnitPlatform()

  maxHeapSize = '2G'
}
```

OOMは発生しなくなったけど、テスト結果の保存に失敗。
設定は変えてないんですけどー

> BUILD SUCCESSFUL in 32m 45s
> 7 actionable tasks: 7 executed
> Build step 'Invoke Gradle script' changed build result to SUCCESS
> 成果物を保存中
> テスト結果を保存中
> ERROR: Step ‘JUnitテスト結果の集計’ failed: テストのレポートファイルが見つかりませんでした。設定ミス?

次に進む。

## ②テストプロセスの設定の追記

testタスクに『-i』つけて実行すると、以下のログが出てました。

> Successfully started process 'Gradle Test Executor 1'

> Gradle Test Executor 1 STANDARD_ERROR
    11 08, 2021 4:25:30 午後 org.junit.platform.launcher.core.DefaultLauncher handleThrowable
    警告: TestEngine with ID 'junit-jupiter' failed to discover tests
    java.lang.StackOverflowError
    	at org.junit.jupiter.engine.discovery.MethodOrderingVisitor.visit(MethodOrderingVisitor.java:55)
    	at org.junit.platform.engine.TestDescriptor.accept(TestDescriptor.java:249)
    	at org.junit.platform.engine.TestDescriptor.lambda$accept$0(TestDescriptor.java:251)
    	at java.lang.Iterable.forEach(Iterable.java:75)
    	at org.junit.platform.engine.TestDescriptor.accept(TestDescriptor.java:251)
    	at org.junit.platform.engine.TestDescriptor.lambda$accept$0(TestDescriptor.java:251)
    	at java.lang.Iterable.forEach(Iterable.java:75)
    	at org.junit.platform.engine.TestDescriptor.accept(TestDescriptor.java:251)
    	at org.junit.platform.engine.TestDescriptor.lambda$accept$0(TestDescriptor.java:251)

今度はStackOverflowですか。。でもヒープを上げて解消できる感じでもなさそうだしなぁと思い、プロセス周りで調べたところ
ここのサイトがわかりやすかったです。
[Gradleのユニットテストを早くするためにやったこと](https://hepokon365.hatenablog.com/entry/2021/09/12/184908)

設定値としては以下がある模様。
> maxParallelForks — default: 1
> You can run your tests in parallel by setting this property to a value greater than 1. This may make your test suites complete faster, particularly if you run them on a multi-core CPU. When using parallel test execution, make sure your tests are properly isolated from one another. Tests that interact with the filesystem are particularly prone to conflict, causing intermittent test failures.
> 
> Your tests can distinguish between parallel test processes by using the value of the org.gradle.test.worker property, which is unique for each process. You can use this for anything you want, but it’s particularly useful for filenames and other resource identifiers to prevent the kind of conflict we just mentioned.
> 
> forkEvery — default: 0 (no maximum)
> This property specifies the maximum number of test classes that Gradle should run on a test process before its disposed of and a fresh one created. This is mainly used as a way to manage leaky tests or frameworks that have static state that can’t be cleared or reset between tests.
> 
> Warning: a low value (other than 0) can severely hurt the performance of the tests

https://docs.gradle.org/current/userguide/java_testing.html#sec:test_execution

現在の設定値がなんのか、調べる術がわからなかったんですが、そんなにJenkinsやらGradleやらの設定を追加してるわけではないので、多分デフォルト値のはず。

## 最終的な記述

上記を踏まえて、以下の記述で通りました。
forkEveryもmaxHeapSizeもいらなかったような気もしなくはないですが、まああっても問題ないかと。

```build.gradle
test {
  useJUnitPlatform()

  maxParallelForks = Runtime.runtime.availableProcessors()
  forkEvery = 0L
  maxHeapSize = '2G'
}
```

あー解決してよかった。当分これで様子を見ます。