You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by ds...@apache.org on 2022/04/13 19:24:35 UTC

[geode] branch develop updated: GEODE-10235: fix --maxHeap for java 17 (#7585)

This is an automated email from the ASF dual-hosted git repository.

dschneider pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git


The following commit(s) were added to refs/heads/develop by this push:
     new 08c32c386a GEODE-10235: fix --maxHeap for java 17 (#7585)
08c32c386a is described below

commit 08c32c386aa2a6bc9e10d9a30815d9397ab3466b
Author: Darrel Schneider <da...@vmware.com>
AuthorDate: Wed Apr 13 12:24:29 2022 -0700

    GEODE-10235: fix --maxHeap for java 17 (#7585)
    
    * --maxHeap no longer forces CMS if the java version is 14 or later. It was in 14 that CMS was dropped from the JVM.
    
    * product code now uses SystemUtils to determine java version instead of system property
    tests now use junit5 EnabledForJreRange to determine java version instead of system property
    fixed some other tests that were broken in jdk17 by this change
---
 .../cli/commands/StartLocatorCommandTest.java      |   5 +-
 .../cli/commands/StartServerCommandTest.java       |   5 +-
 geode-gfsh/build.gradle                            |   1 +
 .../cli/commands/StartMemberUtilsTest.java         | 106 ++++++++++++---------
 .../internal/cli/commands/MemberJvmOptions.java    |  22 +++++
 .../internal/cli/commands/StartMemberUtils.java    |  12 +--
 .../cli/commands/MemberJvmOptionsTest.java         |  29 +++++-
 7 files changed, 118 insertions(+), 62 deletions(-)

diff --git a/geode-assembly/src/test/java/org/apache/geode/management/internal/cli/commands/StartLocatorCommandTest.java b/geode-assembly/src/test/java/org/apache/geode/management/internal/cli/commands/StartLocatorCommandTest.java
index b5c7f42418..bff8c58cc4 100644
--- a/geode-assembly/src/test/java/org/apache/geode/management/internal/cli/commands/StartLocatorCommandTest.java
+++ b/geode-assembly/src/test/java/org/apache/geode/management/internal/cli/commands/StartLocatorCommandTest.java
@@ -14,12 +14,14 @@
  */
 package org.apache.geode.management.internal.cli.commands;
 
+import static java.util.Collections.emptyList;
 import static java.util.stream.Collectors.toSet;
 import static org.apache.geode.distributed.ConfigurationProperties.DISABLE_AUTO_RECONNECT;
 import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_BIND_ADDRESS;
 import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
 import static org.apache.geode.distributed.ConfigurationProperties.STATISTIC_SAMPLE_RATE;
 import static org.apache.geode.distributed.LocatorLauncher.Command.START;
+import static org.apache.geode.management.internal.cli.commands.MemberJvmOptions.getGcJvmOptions;
 import static org.apache.geode.management.internal.cli.commands.MemberJvmOptions.getMemberJvmOptions;
 import static org.apache.geode.management.internal.cli.commands.VerifyCommandLine.verifyCommandLine;
 import static org.apache.geode.util.internal.GeodeGlossary.GEMFIRE_PREFIX;
@@ -252,8 +254,7 @@ class StartLocatorCommandTest {
       final String heapSize = "1024m";
       expectedJvmOptions.add("-Xms" + heapSize);
       expectedJvmOptions.add("-Xmx" + heapSize);
-      expectedJvmOptions.add("-XX:+UseConcMarkSweepGC");
-      expectedJvmOptions.add("-XX:CMSInitiatingOccupancyFraction=60");
+      expectedJvmOptions.addAll(getGcJvmOptions(emptyList()));
 
       String[] commandLine =
           startLocatorCommand.createStartLocatorCommandLine(locatorLauncher,
diff --git a/geode-assembly/src/test/java/org/apache/geode/management/internal/cli/commands/StartServerCommandTest.java b/geode-assembly/src/test/java/org/apache/geode/management/internal/cli/commands/StartServerCommandTest.java
index 90dc854046..c3a1a1ceb1 100644
--- a/geode-assembly/src/test/java/org/apache/geode/management/internal/cli/commands/StartServerCommandTest.java
+++ b/geode-assembly/src/test/java/org/apache/geode/management/internal/cli/commands/StartServerCommandTest.java
@@ -15,6 +15,7 @@
 
 package org.apache.geode.management.internal.cli.commands;
 
+import static java.util.Collections.emptyList;
 import static java.util.stream.Collectors.toSet;
 import static org.apache.geode.distributed.ConfigurationProperties.DISABLE_AUTO_RECONNECT;
 import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_BIND_ADDRESS;
@@ -25,6 +26,7 @@ import static org.apache.geode.distributed.ServerLauncher.Command.START;
 import static org.apache.geode.internal.lang.SystemUtils.IBM_J9_JVM_NAME;
 import static org.apache.geode.internal.lang.SystemUtils.JAVA_HOTSPOT_JVM_NAME;
 import static org.apache.geode.internal.lang.SystemUtils.ORACLE_JROCKIT_JVM_NAME;
+import static org.apache.geode.management.internal.cli.commands.MemberJvmOptions.getGcJvmOptions;
 import static org.apache.geode.management.internal.cli.commands.MemberJvmOptions.getMemberJvmOptions;
 import static org.apache.geode.management.internal.cli.commands.StartServerCommand.addJvmOptionsForOutOfMemoryErrors;
 import static org.apache.geode.management.internal.cli.commands.VerifyCommandLine.verifyCommandLine;
@@ -403,8 +405,7 @@ class StartServerCommandTest {
       final String heapSize = "1024m";
       expectedJvmOptions.add("-Xms" + heapSize);
       expectedJvmOptions.add("-Xmx" + heapSize);
-      expectedJvmOptions.add("-XX:+UseConcMarkSweepGC");
-      expectedJvmOptions.add("-XX:CMSInitiatingOccupancyFraction=60");
+      expectedJvmOptions.addAll(getGcJvmOptions(emptyList()));
 
       final String[] customJvmOptions = {
           "-verbose:gc",
diff --git a/geode-gfsh/build.gradle b/geode-gfsh/build.gradle
index f682de7ec6..859b05fd88 100644
--- a/geode-gfsh/build.gradle
+++ b/geode-gfsh/build.gradle
@@ -48,6 +48,7 @@ dependencies {
   integrationTestImplementation(project(':geode-dunit'))
   integrationTestImplementation('pl.pragmatists:JUnitParams')
   integrationTestRuntimeOnly('org.apache.derby:derby')
+  integrationTestImplementation('org.junit.jupiter:junit-jupiter-migrationsupport')
 
   distributedTestImplementation(project(':geode-dunit'))
   distributedTestImplementation('pl.pragmatists:JUnitParams')
diff --git a/geode-gfsh/src/integrationTest/java/org/apache/geode/management/internal/cli/commands/StartMemberUtilsTest.java b/geode-gfsh/src/integrationTest/java/org/apache/geode/management/internal/cli/commands/StartMemberUtilsTest.java
index 5bc9ffbe08..ec9f801143 100644
--- a/geode-gfsh/src/integrationTest/java/org/apache/geode/management/internal/cli/commands/StartMemberUtilsTest.java
+++ b/geode-gfsh/src/integrationTest/java/org/apache/geode/management/internal/cli/commands/StartMemberUtilsTest.java
@@ -17,8 +17,8 @@ package org.apache.geode.management.internal.cli.commands;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.condition.JRE.JAVA_13;
+import static org.junit.jupiter.api.condition.JRE.JAVA_14;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
@@ -26,6 +26,7 @@ import java.io.File;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.nio.file.FileSystems;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
@@ -34,17 +35,20 @@ import java.util.List;
 
 import org.apache.commons.io.FileUtils;
 import org.junit.Rule;
-import org.junit.Test;
 import org.junit.contrib.java.lang.system.RestoreSystemProperties;
-import org.junit.rules.TemporaryFolder;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledForJreRange;
+import org.junit.jupiter.api.io.TempDir;
+import org.junit.jupiter.migrationsupport.rules.EnableRuleMigrationSupport;
 
 import org.apache.geode.internal.GemFireVersion;
 import org.apache.geode.internal.util.IOUtils;
 
+@EnableRuleMigrationSupport
 public class StartMemberUtilsTest {
 
-  @Rule
-  public TemporaryFolder temporaryFolder = new TemporaryFolder();
+  @TempDir
+  private File temporaryFolder;
 
   @Rule
   public RestoreSystemProperties restorer = new RestoreSystemProperties();
@@ -68,8 +72,8 @@ public class StartMemberUtilsTest {
   }
 
   @Test
-  public void workingDirGetsCreatedIfNecessary() throws Exception {
-    File workingDir = temporaryFolder.newFolder("foo");
+  public void workingDirGetsCreatedIfNecessary() {
+    File workingDir = new File(temporaryFolder, "foo");
     FileUtils.deleteQuietly(workingDir);
     String workingDirString = workingDir.getAbsolutePath();
     String resolvedWorkingDir =
@@ -79,7 +83,7 @@ public class StartMemberUtilsTest {
   }
 
   @Test
-  public void testWorkingDirWithRelativePath() throws Exception {
+  public void testWorkingDirWithRelativePath() {
     Path relativePath = Paths.get("some").resolve("relative").resolve("path");
     assertThat(relativePath.isAbsolute()).isFalse();
     String resolvedWorkingDir =
@@ -87,19 +91,27 @@ public class StartMemberUtilsTest {
     assertThat(resolvedWorkingDir).isEqualTo(relativePath.toAbsolutePath().toString());
   }
 
+  private static final int EXPECTED_PID = 12345;
+
   @Test
   public void testReadPid() throws IOException {
-    final int expectedPid = 12345;
-    File folder = temporaryFolder.newFolder();
-    File pidFile = new File(folder, "my.pid");
+    File pidFile = new File(temporaryFolder, "my.pid");
 
-    assertTrue(pidFile.createNewFile());
+    assertThat(pidFile.createNewFile()).isTrue();
 
     pidFile.deleteOnExit();
-    writePid(pidFile, expectedPid);
+    writePid(pidFile);
 
     final int actualPid = StartMemberUtils.readPid(pidFile);
-    assertEquals(expectedPid, actualPid);
+    assertThat(actualPid).isEqualTo(EXPECTED_PID);
+  }
+
+  private void writePid(final File pidFile) throws IOException {
+    final FileWriter fileWriter = new FileWriter(pidFile, false);
+    fileWriter.write(String.valueOf(EXPECTED_PID));
+    fileWriter.write("\n");
+    fileWriter.flush();
+    IOUtils.close(fileWriter);
   }
 
   /**
@@ -121,10 +133,10 @@ public class StartMemberUtilsTest {
     final String customGeodeCore = FileSystems.getDefault().getPath(customGeodeJarPATH.toString())
         .toAbsolutePath().toString();
 
-    currentClasspath = prependToClasspath("java.class.path", customGeodeCore, currentClasspath);
+    currentClasspath = prependToClasspath(customGeodeCore, currentClasspath);
     currentClasspath =
-        prependToClasspath("java.class.path", prependJar2.toString(), currentClasspath);
-    prependToClasspath("java.class.path", prependJar1.toString(), currentClasspath);
+        prependToClasspath(prependJar2.toString(), currentClasspath);
+    prependToClasspath(prependJar1.toString(), currentClasspath);
 
     String[] otherJars = new String[] {
         FileSystems.getDefault().getPath(otherJar1.toString()).toAbsolutePath().toString(),
@@ -137,10 +149,10 @@ public class StartMemberUtilsTest {
     assertThat(gemfireClasspath).startsWith(customGeodeCore);
   }
 
-  private String prependToClasspath(String systemPropertyKey, String prependJarPath,
+  private String prependToClasspath(String prependJarPath,
       String currentClasspath) {
-    System.setProperty(systemPropertyKey, prependJarPath + File.pathSeparator + currentClasspath);
-    return System.getProperty(systemPropertyKey);
+    System.setProperty("java.class.path", prependJarPath + File.pathSeparator + currentClasspath);
+    return System.getProperty("java.class.path");
   }
 
   @Test
@@ -151,51 +163,59 @@ public class StartMemberUtilsTest {
     assertThat(gemfireClasspath).doesNotContain("extensions");
 
     // when there is a `test.jar` in `extensions` directory
-    File folder = temporaryFolder.newFolder("extensions");
+    File folder = new File(temporaryFolder, "extensions");
+    Files.createDirectories(folder.toPath());
     File jarFile = new File(folder, "test.jar");
-    jarFile.createNewFile();
+    assertThat(jarFile.createNewFile()).isTrue();
     gemfireClasspath = StartMemberUtils.toClasspath(true, new String[] {jarFile.getAbsolutePath()});
     assertThat(gemfireClasspath).contains(jarFile.getName());
 
   }
 
+  @EnabledForJreRange(max = JAVA_13)
   @Test
-  public void testAddMaxHeap() {
+  public void testAddMaxHeapWithCMS() {
     List<String> baseCommandLine = new ArrayList<>();
 
     // Empty Max Heap Option
     StartMemberUtils.addMaxHeap(baseCommandLine, null);
-    assertThat(baseCommandLine.size()).isEqualTo(0);
+    assertThat(baseCommandLine).isEmpty();
 
     StartMemberUtils.addMaxHeap(baseCommandLine, "");
-    assertThat(baseCommandLine.size()).isEqualTo(0);
+    assertThat(baseCommandLine).isEmpty();
 
     // Only Max Heap Option Set
     StartMemberUtils.addMaxHeap(baseCommandLine, "32g");
-    assertThat(baseCommandLine.size()).isEqualTo(3);
     assertThat(baseCommandLine).containsExactly("-Xmx32g", "-XX:+UseConcMarkSweepGC",
-        "-XX:CMSInitiatingOccupancyFraction=" + StartMemberUtils.CMS_INITIAL_OCCUPANCY_FRACTION);
+        "-XX:CMSInitiatingOccupancyFraction=" + MemberJvmOptions.CMS_INITIAL_OCCUPANCY_FRACTION);
 
     // All Options Set
     List<String> customCommandLine = new ArrayList<>(
         Arrays.asList("-XX:+UseConcMarkSweepGC", "-XX:CMSInitiatingOccupancyFraction=30"));
     StartMemberUtils.addMaxHeap(customCommandLine, "16g");
-    assertThat(customCommandLine.size()).isEqualTo(3);
     assertThat(customCommandLine).containsExactly("-XX:+UseConcMarkSweepGC",
         "-XX:CMSInitiatingOccupancyFraction=30", "-Xmx16g");
   }
 
-  private void writePid(final File pidFile, final int pid) throws IOException {
-    final FileWriter fileWriter = new FileWriter(pidFile, false);
-    fileWriter.write(String.valueOf(pid));
-    fileWriter.write("\n");
-    fileWriter.flush();
-    IOUtils.close(fileWriter);
+  @EnabledForJreRange(min = JAVA_14)
+  @Test
+  public void testAddMaxHeapWithoutCMS() {
+    List<String> baseCommandLine = new ArrayList<>();
+
+    // Empty Max Heap Option
+    StartMemberUtils.addMaxHeap(baseCommandLine, null);
+    assertThat(baseCommandLine).isEmpty();
+
+    StartMemberUtils.addMaxHeap(baseCommandLine, "");
+    assertThat(baseCommandLine).isEmpty();
+
+    // Only Max Heap Option Set
+    StartMemberUtils.addMaxHeap(baseCommandLine, "32g");
+    assertThat(baseCommandLine).containsExactly("-Xmx32g");
   }
 
   @Test
-  public void whenResolveWorkingDirectoryIsCalledWithTwoNonEmptyStrings_thenTheUserSpecifiedDirectoryIsReturned()
-      throws Exception {
+  public void whenResolveWorkingDirectoryIsCalledWithTwoNonEmptyStrings_thenTheUserSpecifiedDirectoryIsReturned() {
     String userSpecifiedDir = "locator1Directory";
     String memberNameDir = "member1";
     assertThat(StartMemberUtils.resolveWorkingDirectory(userSpecifiedDir, memberNameDir))
@@ -203,16 +223,14 @@ public class StartMemberUtilsTest {
   }
 
   @Test
-  public void whenResolveWorkingDirectoryIsCalledWithNullUserSpecifiedDir_thenTheMemberNameDirectoryIsReturned()
-      throws Exception {
+  public void whenResolveWorkingDirectoryIsCalledWithNullUserSpecifiedDir_thenTheMemberNameDirectoryIsReturned() {
     String memberNameDir = "member1";
     assertThat(StartMemberUtils.resolveWorkingDirectory(null, memberNameDir))
         .isEqualTo(new File(memberNameDir).getAbsolutePath());
   }
 
   @Test
-  public void whenResolveWorkingDirectoryIsCalledWithEmptyUserSpecifiedDir_thenTheMemberNameDirectoryIsReturned()
-      throws Exception {
+  public void whenResolveWorkingDirectoryIsCalledWithEmptyUserSpecifiedDir_thenTheMemberNameDirectoryIsReturned() {
     String userSpecifiedDir = "";
     String memberNameDir = "member1";
     assertThat(StartMemberUtils.resolveWorkingDirectory(userSpecifiedDir, memberNameDir))
@@ -220,8 +238,7 @@ public class StartMemberUtilsTest {
   }
 
   @Test
-  public void whenResolveWorkingDirectoryIsCalledWithUserSpecifiedDirAsDot_thenTheUserSpecifiedDirectoryIsReturned()
-      throws Exception {
+  public void whenResolveWorkingDirectoryIsCalledWithUserSpecifiedDirAsDot_thenTheUserSpecifiedDirectoryIsReturned() {
     String userSpecifiedDir = ".";
     String memberNameDir = "member1";
     assertThat(StartMemberUtils.resolveWorkingDirectory(userSpecifiedDir, memberNameDir))
@@ -230,8 +247,7 @@ public class StartMemberUtilsTest {
   }
 
   @Test
-  public void whenResolveWorkingDirectoryIsCalledWithUserSpecifiedDirAsAbsolutePath_thenTheUserSpecifiedDirectoryIsReturned()
-      throws Exception {
+  public void whenResolveWorkingDirectoryIsCalledWithUserSpecifiedDirAsAbsolutePath_thenTheUserSpecifiedDirectoryIsReturned() {
     String userSpecifiedDir = new File(System.getProperty("user.dir")).getAbsolutePath();
     String memberNameDir = "member1";
     assertThat(StartMemberUtils.resolveWorkingDirectory(userSpecifiedDir, memberNameDir))
diff --git a/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/MemberJvmOptions.java b/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/MemberJvmOptions.java
index 9d02d8c1cd..542aa0f8cb 100644
--- a/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/MemberJvmOptions.java
+++ b/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/MemberJvmOptions.java
@@ -17,13 +17,17 @@
 package org.apache.geode.management.internal.cli.commands;
 
 import static org.apache.commons.lang3.JavaVersion.JAVA_11;
+import static org.apache.commons.lang3.JavaVersion.JAVA_13;
 import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
+import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
 public class MemberJvmOptions {
+  static final int CMS_INITIAL_OCCUPANCY_FRACTION = 60;
   private static final List<String> JAVA_11_OPTIONS = Arrays.asList(
       "--add-exports=java.base/sun.nio.ch=ALL-UNNAMED",
       "--add-exports=java.management/com.sun.jmx.remote.security=ALL-UNNAMED");
@@ -34,4 +38,22 @@ public class MemberJvmOptions {
     }
     return Collections.emptyList();
   }
+
+  public static List<String> getGcJvmOptions(List<String> commandLine) {
+    if (isJavaVersionAtMost(JAVA_13)) {
+      List<String> cmsOptions = new ArrayList<>();
+      String collectorKey = "-XX:+UseConcMarkSweepGC";
+      if (!commandLine.contains(collectorKey)) {
+        cmsOptions.add(collectorKey);
+      }
+      String occupancyFractionKey = "-XX:CMSInitiatingOccupancyFraction=";
+      if (commandLine.stream().noneMatch(s -> s.contains(occupancyFractionKey))) {
+        cmsOptions.add(occupancyFractionKey + CMS_INITIAL_OCCUPANCY_FRACTION);
+      }
+      return cmsOptions;
+    } else {
+      // TODO: configure ZGC?
+      return Collections.emptyList();
+    }
+  }
 }
diff --git a/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/StartMemberUtils.java b/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/StartMemberUtils.java
index 9686d6fb9e..ee931696ee 100644
--- a/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/StartMemberUtils.java
+++ b/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/StartMemberUtils.java
@@ -50,7 +50,6 @@ class StartMemberUtils {
   static final String GEODE_HOME = System.getenv("GEODE_HOME");
 
   private static final String JAVA_HOME = System.getProperty("java.home");
-  static final int CMS_INITIAL_OCCUPANCY_FRACTION = 60;
   @Immutable
   private static final ThreePhraseGenerator nameGenerator = new ThreePhraseGenerator();
 
@@ -138,16 +137,7 @@ class StartMemberUtils {
   static void addMaxHeap(final List<String> commandLine, final String maxHeap) {
     if (StringUtils.isNotBlank(maxHeap)) {
       commandLine.add("-Xmx" + maxHeap);
-
-      String collectorKey = "-XX:+UseConcMarkSweepGC";
-      if (!commandLine.contains(collectorKey)) {
-        commandLine.add(collectorKey);
-      }
-
-      String occupancyFractionKey = "-XX:CMSInitiatingOccupancyFraction=";
-      if (commandLine.stream().noneMatch(s -> s.contains(occupancyFractionKey))) {
-        commandLine.add(occupancyFractionKey + CMS_INITIAL_OCCUPANCY_FRACTION);
-      }
+      commandLine.addAll(MemberJvmOptions.getGcJvmOptions(commandLine));
     }
   }
 
diff --git a/geode-gfsh/src/test/java/org/apache/geode/management/internal/cli/commands/MemberJvmOptionsTest.java b/geode-gfsh/src/test/java/org/apache/geode/management/internal/cli/commands/MemberJvmOptionsTest.java
index 71f2d4a440..4a76ad6ea5 100644
--- a/geode-gfsh/src/test/java/org/apache/geode/management/internal/cli/commands/MemberJvmOptionsTest.java
+++ b/geode-gfsh/src/test/java/org/apache/geode/management/internal/cli/commands/MemberJvmOptionsTest.java
@@ -16,10 +16,14 @@
 
 package org.apache.geode.management.internal.cli.commands;
 
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+import static org.apache.geode.management.internal.cli.commands.MemberJvmOptions.CMS_INITIAL_OCCUPANCY_FRACTION;
+import static org.apache.geode.management.internal.cli.commands.MemberJvmOptions.getGcJvmOptions;
 import static org.apache.geode.management.internal.cli.commands.MemberJvmOptions.getMemberJvmOptions;
 import static org.assertj.core.api.Assertions.assertThat;
 
-import java.util.Arrays;
 import java.util.List;
 
 import org.junit.jupiter.api.Test;
@@ -38,11 +42,32 @@ class MemberJvmOptionsTest {
   @Test
   @EnabledForJreRange(min = JRE.JAVA_11)
   void java11Options() {
-    List<String> expectedOptions = Arrays.asList(
+    List<String> expectedOptions = asList(
         "--add-exports=java.base/sun.nio.ch=ALL-UNNAMED",
         "--add-exports=java.management/com.sun.jmx.remote.security=ALL-UNNAMED");
 
     assertThat(getMemberJvmOptions())
         .containsExactlyElementsOf(expectedOptions);
   }
+
+  @Test
+  @EnabledForJreRange(max = JRE.JAVA_13)
+  void cmsOptions() {
+    assertThat(getGcJvmOptions(emptyList())).containsExactly("-XX:+UseConcMarkSweepGC",
+        "-XX:CMSInitiatingOccupancyFraction=" + CMS_INITIAL_OCCUPANCY_FRACTION);
+    List<String> commandLine = singletonList("-XX:+UseConcMarkSweepGC");
+    assertThat(getGcJvmOptions(commandLine))
+        .containsExactly("-XX:CMSInitiatingOccupancyFraction=" + CMS_INITIAL_OCCUPANCY_FRACTION);
+    commandLine = singletonList("-XX:CMSInitiatingOccupancyFraction=");
+    assertThat(getGcJvmOptions(commandLine)).containsExactly("-XX:+UseConcMarkSweepGC");
+    commandLine = asList("-XX:+UseConcMarkSweepGC", "-XX:CMSInitiatingOccupancyFraction=");
+    assertThat(getGcJvmOptions(commandLine)).isEmpty();
+  }
+
+  @Test
+  @EnabledForJreRange(min = JRE.JAVA_14)
+  void noCmsOptions() {
+    assertThat(getGcJvmOptions(emptyList())).isEmpty();
+  }
+
 }