Skip to content

Commit 79e5e80

Browse files
committed
Add unit tests for reading JVM options files (#52176)
This commit adds some unit tests to cover the reading of JVM options files.
1 parent 2a968f4 commit 79e5e80

File tree

2 files changed

+139
-18
lines changed

2 files changed

+139
-18
lines changed

distribution/tools/launchers/src/main/java/org/elasticsearch/tools/launchers/JvmOptionsParser.java

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
*/
5151
final class JvmOptionsParser {
5252

53-
private static class JvmOptionsFileParserException extends Exception {
53+
static class JvmOptionsFileParserException extends Exception {
5454

5555
private final Path jvmOptionsFile;
5656

@@ -126,6 +126,29 @@ private List<String> jvmOptions(final Path config, final String esJavaOpts, fina
126126
throws InterruptedException,
127127
IOException,
128128
JvmOptionsFileParserException {
129+
130+
final List<String> jvmOptions = readJvmOptionsFiles(config);
131+
132+
if (esJavaOpts != null) {
133+
jvmOptions.addAll(
134+
Arrays.stream(esJavaOpts.split("\\s+")).filter(s -> s.trim().isEmpty() == false).collect(Collectors.toList())
135+
);
136+
}
137+
138+
final List<String> substitutedJvmOptions = substitutePlaceholders(jvmOptions, Collections.unmodifiableMap(substitutions));
139+
final List<String> ergonomicJvmOptions = JvmErgonomics.choose(substitutedJvmOptions);
140+
final List<String> systemJvmOptions = SystemJvmOptions.systemJvmOptions();
141+
final List<String> finalJvmOptions = new ArrayList<>(
142+
systemJvmOptions.size() + substitutedJvmOptions.size() + ergonomicJvmOptions.size()
143+
);
144+
finalJvmOptions.addAll(systemJvmOptions); // add the system JVM options first so that they can be overridden
145+
finalJvmOptions.addAll(substitutedJvmOptions);
146+
finalJvmOptions.addAll(ergonomicJvmOptions);
147+
148+
return finalJvmOptions;
149+
}
150+
151+
List<String> readJvmOptionsFiles(final Path config) throws IOException, JvmOptionsFileParserException {
129152
final ArrayList<Path> jvmOptionsFiles = new ArrayList<>();
130153
jvmOptionsFiles.add(config.resolve("jvm.options"));
131154

@@ -154,23 +177,7 @@ private List<String> jvmOptions(final Path config, final String esJavaOpts, fina
154177
}
155178
}
156179

157-
if (esJavaOpts != null) {
158-
jvmOptions.addAll(
159-
Arrays.stream(esJavaOpts.split("\\s+")).filter(s -> s.trim().isEmpty() == false).collect(Collectors.toList())
160-
);
161-
}
162-
163-
final List<String> substitutedJvmOptions = substitutePlaceholders(jvmOptions, Collections.unmodifiableMap(substitutions));
164-
final List<String> ergonomicJvmOptions = JvmErgonomics.choose(substitutedJvmOptions);
165-
final List<String> systemJvmOptions = SystemJvmOptions.systemJvmOptions();
166-
final List<String> finalJvmOptions = new ArrayList<>(
167-
systemJvmOptions.size() + substitutedJvmOptions.size() + ergonomicJvmOptions.size()
168-
);
169-
finalJvmOptions.addAll(systemJvmOptions); // add the system JVM options first so that they can be overridden
170-
finalJvmOptions.addAll(substitutedJvmOptions);
171-
finalJvmOptions.addAll(ergonomicJvmOptions);
172-
173-
return finalJvmOptions;
180+
return jvmOptions;
174181
}
175182

176183
static List<String> substitutePlaceholders(final List<String> jvmOptions, final Map<String, String> substitutions) {

distribution/tools/launchers/src/test/java/org/elasticsearch/tools/launchers/JvmOptionsParserTests.java

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
import java.io.BufferedReader;
2323
import java.io.IOException;
2424
import java.io.StringReader;
25+
import java.nio.file.Files;
26+
import java.nio.file.NoSuchFileException;
27+
import java.nio.file.Path;
28+
import java.nio.file.StandardOpenOption;
2529
import java.util.Arrays;
2630
import java.util.Collections;
2731
import java.util.HashMap;
@@ -31,7 +35,10 @@
3135
import java.util.concurrent.atomic.AtomicBoolean;
3236

3337
import static org.hamcrest.Matchers.contains;
38+
import static org.hamcrest.Matchers.empty;
3439
import static org.hamcrest.Matchers.equalTo;
40+
import static org.hamcrest.Matchers.hasKey;
41+
import static org.hamcrest.Matchers.hasSize;
3542
import static org.junit.Assert.assertFalse;
3643
import static org.junit.Assert.assertNull;
3744
import static org.junit.Assert.assertThat;
@@ -149,6 +156,113 @@ public void testComplexOptions() throws IOException {
149156
}
150157
}
151158

159+
public void testMissingRootJvmOptions() throws IOException, JvmOptionsParser.JvmOptionsFileParserException {
160+
final Path config = newTempDir();
161+
try {
162+
final JvmOptionsParser parser = new JvmOptionsParser();
163+
parser.readJvmOptionsFiles(config);
164+
fail("expected no such file exception, the root jvm.options file does not exist");
165+
} catch (final NoSuchFileException expected) {
166+
// this is expected, the root JVM options file must exist
167+
}
168+
}
169+
170+
public void testReadRootJvmOptions() throws IOException, JvmOptionsParser.JvmOptionsFileParserException {
171+
final Path config = newTempDir();
172+
final Path rootJvmOptions = config.resolve("jvm.options");
173+
Files.write(
174+
rootJvmOptions,
175+
Arrays.asList("# comment", "-Xms256m", "-Xmx256m"),
176+
StandardOpenOption.CREATE_NEW,
177+
StandardOpenOption.APPEND
178+
);
179+
if (randomBoolean()) {
180+
// an empty jvm.options.d directory should be irrelevant
181+
Files.createDirectory(config.resolve("jvm.options.d"));
182+
}
183+
final JvmOptionsParser parser = new JvmOptionsParser();
184+
final List<String> jvmOptions = parser.readJvmOptionsFiles(config);
185+
assertThat(jvmOptions, contains("-Xms256m", "-Xmx256m"));
186+
}
187+
188+
public void testReadJvmOptionsDirectory() throws IOException, JvmOptionsParser.JvmOptionsFileParserException {
189+
final Path config = newTempDir();
190+
Files.createDirectory(config.resolve("jvm.options.d"));
191+
Files.write(
192+
config.resolve("jvm.options"),
193+
Arrays.asList("# comment", "-Xms256m", "-Xmx256m"),
194+
StandardOpenOption.CREATE_NEW,
195+
StandardOpenOption.APPEND
196+
);
197+
Files.write(
198+
config.resolve("jvm.options.d").resolve("heap.options"),
199+
Arrays.asList("# comment", "-Xms384m", "-Xmx384m"),
200+
StandardOpenOption.CREATE_NEW,
201+
StandardOpenOption.APPEND
202+
);
203+
final JvmOptionsParser parser = new JvmOptionsParser();
204+
final List<String> jvmOptions = parser.readJvmOptionsFiles(config);
205+
assertThat(jvmOptions, contains("-Xms256m", "-Xmx256m", "-Xms384m", "-Xmx384m"));
206+
}
207+
208+
public void testReadJvmOptionsDirectoryInOrder() throws IOException, JvmOptionsParser.JvmOptionsFileParserException {
209+
final Path config = newTempDir();
210+
Files.createDirectory(config.resolve("jvm.options.d"));
211+
Files.write(
212+
config.resolve("jvm.options"),
213+
Arrays.asList("# comment", "-Xms256m", "-Xmx256m"),
214+
StandardOpenOption.CREATE_NEW,
215+
StandardOpenOption.APPEND
216+
);
217+
Files.write(
218+
config.resolve("jvm.options.d").resolve("first.options"),
219+
Arrays.asList("# comment", "-Xms384m", "-Xmx384m"),
220+
StandardOpenOption.CREATE_NEW,
221+
StandardOpenOption.APPEND
222+
);
223+
Files.write(
224+
config.resolve("jvm.options.d").resolve("second.options"),
225+
Arrays.asList("# comment", "-Xms512m", "-Xmx512m"),
226+
StandardOpenOption.CREATE_NEW,
227+
StandardOpenOption.APPEND
228+
);
229+
final JvmOptionsParser parser = new JvmOptionsParser();
230+
final List<String> jvmOptions = parser.readJvmOptionsFiles(config);
231+
assertThat(jvmOptions, contains("-Xms256m", "-Xmx256m", "-Xms384m", "-Xmx384m", "-Xms512m", "-Xmx512m"));
232+
}
233+
234+
public void testReadJvmOptionsDirectoryIgnoresFilesNotNamedOptions() throws IOException,
235+
JvmOptionsParser.JvmOptionsFileParserException {
236+
final Path config = newTempDir();
237+
Files.createFile(config.resolve("jvm.options"));
238+
Files.createDirectory(config.resolve("jvm.options.d"));
239+
Files.write(
240+
config.resolve("jvm.options.d").resolve("heap.not-named-options"),
241+
Arrays.asList("# comment", "-Xms256m", "-Xmx256m"),
242+
StandardOpenOption.CREATE_NEW,
243+
StandardOpenOption.APPEND
244+
);
245+
final JvmOptionsParser parser = new JvmOptionsParser();
246+
final List<String> jvmOptions = parser.readJvmOptionsFiles(config);
247+
assertThat(jvmOptions, empty());
248+
}
249+
250+
public void testFileContainsInvalidLinesThrowsParserException() throws IOException {
251+
final Path config = newTempDir();
252+
final Path rootJvmOptions = config.resolve("jvm.options");
253+
Files.write(rootJvmOptions, Arrays.asList("XX:+UseG1GC"), StandardOpenOption.CREATE_NEW, StandardOpenOption.APPEND);
254+
try {
255+
final JvmOptionsParser parser = new JvmOptionsParser();
256+
parser.readJvmOptionsFiles(config);
257+
fail("expected JVM options file parser exception, XX:+UseG1GC is improperly formatted");
258+
} catch (final JvmOptionsParser.JvmOptionsFileParserException expected) {
259+
assertThat(expected.jvmOptionsFile(), equalTo(rootJvmOptions));
260+
assertThat(expected.invalidLines().entrySet(), hasSize(1));
261+
assertThat(expected.invalidLines(), hasKey(1));
262+
assertThat(expected.invalidLines().get(1), equalTo("XX:+UseG1GC"));
263+
}
264+
}
265+
152266
private void assertExpectedJvmOptions(final int javaMajorVersion, final BufferedReader br, final List<String> expectedJvmOptions)
153267
throws IOException {
154268
final Map<String, AtomicBoolean> seenJvmOptions = new HashMap<>();

0 commit comments

Comments
 (0)