1 /*
2  * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /*
25  * @test
26  * @bug 8061999 8135195 8136552
27  * @summary Test "-XX:VMOptionsFile" VM option
28  * @library /test/lib
29  * @modules java.base/jdk.internal.misc
30  * @modules jdk.management
31  * @run main TestVMOptionsFile
32  */
33 
34 import java.io.File;
35 import java.io.FileWriter;
36 import java.io.IOException;
37 import java.nio.file.Files;
38 import java.nio.file.Paths;
39 import java.nio.file.Path;
40 import java.nio.file.attribute.PosixFilePermissions;
41 import java.nio.file.attribute.AclEntry;
42 import java.nio.file.attribute.AclEntryPermission;
43 import java.nio.file.attribute.AclEntryType;
44 import java.nio.file.attribute.AclFileAttributeView;
45 import java.nio.file.attribute.UserPrincipal;
46 import java.nio.file.StandardCopyOption;
47 import java.util.ArrayList;
48 import java.util.Arrays;
49 import java.util.LinkedHashSet;
50 import java.util.List;
51 import java.util.Properties;
52 import java.util.Set;
53 import jdk.test.lib.Asserts;
54 import jdk.test.lib.management.DynamicVMOption;
55 import jdk.test.lib.process.OutputAnalyzer;
56 import jdk.test.lib.process.ProcessTools;
57 
58 public class TestVMOptionsFile {
59 
60     /* Various valid VM Option files */
61     private static final String VM_OPTION_FILE_EMPTY = "optionfile_empty";
62     private static final String VM_OPTION_FILE_TABS_AND_SPACES = "optionfile_only_tabsandspaces";
63     private static final String VM_OPTION_FILE_1 = "optionfile_1";
64     private static final String VM_OPTION_FILE_2 = "optionFILE_2";
65     private static final String VM_OPTION_FILE_3 = "optionfile_3";
66     private static final String VM_OPTION_FILE_QUOTE = "optionfile_quote";
67     private static final String VM_OPTION_FILE_BIG = "optionfile_big";
68     private static final int REPEAT_COUNT = 512;
69     /* Name of the file with flags for VM_OPTION_FILE_2 Option file */
70     private static final String FLAGS_FILE = "flags_file";
71     /* VM Option file with a lot of options with quote on separate lines */
72     private static final String VM_OPTION_FILE_LOT_OF_OPTIONS_QUOTE = "optionfile_lot_of_options_quote";
73     /* Number of properties defined in VM_OPTION_FILE_LOT_OF_OPTIONS_QUOTE */
74     private static final int NUM_OF_PROP_IN_FILE_LOT_OF_OPTIONS_QUOTE = 70;
75     /* VM Option file with long property */
76     private static final String VM_OPTION_FILE_WITH_LONG_PROPERTY = "optionfile_long_property";
77     private static final String LONG_PROPERTY_NAME = "veryl'" + String.format("%1536s", "").replace(' ', 'o') + "ng'name";
78     private static final String LONG_PROPERTY_VALUE = String.format("%2096s", "").replaceAll("    ", "long");
79     /* 2 VM Option files with unmatched quotes */
80     private static final String VM_OPTION_FILE_UNMATCHED_QUOTE_1 = "optionfile_unmatched_quote_1";
81     private static final String VM_OPTION_FILE_UNMATCHED_QUOTE_2 = "optionfile_unmatched_quote_2";
82     /* VM Option file with bad option in it */
83     private static final String VM_OPTION_FILE_WITH_BAD_OPTION = "optionfile_bad_option";
84     /* VM Option file with "-XX:VMOptionsFile=" option in it */
85     private static final String VM_OPTION_FILE_WITH_VM_OPTION_FILE = "optionfile_with_optionfile";
86     /* VM Option file with "-XX:VMOptionsFile=" option in it, where file is the same option file */
87     private static final String VM_OPTION_FILE_WITH_SAME_VM_OPTION_FILE = "optionfile_with_same_optionfile";
88     /* VM Option file without read permissions(not accessible) */
89     private static final String VM_OPTION_FILE_WITHOUT_READ_PERMISSIONS = "optionfile_wo_read_perm";
90     /* VM Option file which does not exist */
91     private static final String NOT_EXISTING_FILE = "not_exist_junk2123";
92 
93     /* JAVA_TOOL_OPTIONS environment variable */
94     private static final String JAVA_TOOL_OPTIONS = "JAVA_TOOL_OPTIONS";
95     /* _JAVA_OPTIONS environment variable */
96     private static final String JAVA_OPTIONS = "_JAVA_OPTIONS";
97 
98     /* Exit code for JVM, zero - for success, non-zero for failure */
99     private static final int JVM_SUCCESS = 0;
100     private static final int JVM_FAIL_WITH_EXIT_CODE_1 = 1;
101 
102     /* Current working directory */
103     private static final String CURRENT_DIR = System.getProperty("user.dir");
104 
105     /* Source directory */
106     private static final String SOURCE_DIR = System.getProperty("test.src", ".");
107 
108     /* VM Options which are passed to the JVM */
109     private static final List<String> VMParams = new ArrayList<>();
110     /* Argument passed to the PrintPropertyAndOptions.main */
111     private static final Set<String> appParams = new LinkedHashSet<>();
112 
113     private static OutputAnalyzer output;
114 
115     private static final String PRINT_PROPERTY_FORMAT = "Property %s=%s";
116     private static final String PRINT_VM_OPTION_FORMAT = "Virtual Machine option %s=%s";
117 
118     /*
119      * Get absoulte path to file from folder with sources
120      */
getAbsolutePathFromSource(String fileName)121     private static String getAbsolutePathFromSource(String fileName) {
122         return SOURCE_DIR + File.separator + fileName;
123     }
124 
125     /*
126      * Make file non-readable by modifying its permissions.
127      * If file supports "posix" attributes, then modify it.
128      * Otherwise check for "acl" attributes.
129      */
makeFileNonReadable(String file)130     private static void makeFileNonReadable(String file) throws IOException {
131         Path filePath = Paths.get(file);
132         Set<String> supportedAttr = filePath.getFileSystem().supportedFileAttributeViews();
133 
134         if (supportedAttr.contains("posix")) {
135             Files.setPosixFilePermissions(filePath, PosixFilePermissions.fromString("-w--w----"));
136         } else if (supportedAttr.contains("acl")) {
137             UserPrincipal fileOwner = Files.getOwner(filePath);
138 
139             AclFileAttributeView view = Files.getFileAttributeView(filePath, AclFileAttributeView.class);
140 
141             AclEntry entry = AclEntry.newBuilder()
142                     .setType(AclEntryType.DENY)
143                     .setPrincipal(fileOwner)
144                     .setPermissions(AclEntryPermission.READ_DATA)
145                     .build();
146 
147             List<AclEntry> acl = view.getAcl();
148             acl.add(0, entry);
149             view.setAcl(acl);
150         }
151     }
152 
copyFromSource(String fileName)153     private static void copyFromSource(String fileName) throws IOException {
154         Files.copy(Paths.get(getAbsolutePathFromSource(fileName)),
155                 Paths.get(fileName), StandardCopyOption.REPLACE_EXISTING);
156     }
157 
createOptionFiles()158     private static void createOptionFiles() throws IOException {
159         FileWriter fw = new FileWriter(VM_OPTION_FILE_WITH_VM_OPTION_FILE);
160 
161         /* Create VM option file with following parameters "-XX:VMOptionFile=<absolute_path_to_the_VM_option_file> */
162         fw.write("-XX:VMOptionsFile=" + getAbsolutePathFromSource(VM_OPTION_FILE_1));
163         fw.close();
164 
165         /* Create VM option file with following parameters "-XX:MinHeapFreeRatio=12 -XX:VMOptionFile=<absolute_path_to_the_same_VM_option_file> */
166         fw = new FileWriter(VM_OPTION_FILE_WITH_SAME_VM_OPTION_FILE);
167         fw.write("-XX:MinHeapFreeRatio=12 -XX:VMOptionsFile=" + (new File(VM_OPTION_FILE_WITH_SAME_VM_OPTION_FILE)).getCanonicalPath());
168         fw.close();
169 
170         /* Create VM option file with long property */
171         fw = new FileWriter(VM_OPTION_FILE_WITH_LONG_PROPERTY);
172         fw.write("-D" + LONG_PROPERTY_NAME + "=" + LONG_PROPERTY_VALUE);
173         fw.close();
174 
175         /* Create big VM option file */
176         fw = new FileWriter(VM_OPTION_FILE_BIG);
177         fw.write("-XX:MinHeapFreeRatio=17\n");
178         for (int i = 0; i < REPEAT_COUNT; i++) {
179             if (i == REPEAT_COUNT / 2) {
180                 fw.write("-XX:+PrintVMOptions ");
181             }
182             fw.write("-Dmy.property=value" + (i + 1) + "\n");
183         }
184         fw.write("-XX:MaxHeapFreeRatio=85\n");
185         fw.close();
186 
187         /* Copy valid VM option file and change its permission to make it not accessible */
188         Files.copy(Paths.get(getAbsolutePathFromSource(VM_OPTION_FILE_1)),
189                 Paths.get(VM_OPTION_FILE_WITHOUT_READ_PERMISSIONS),
190                 StandardCopyOption.REPLACE_EXISTING);
191 
192         makeFileNonReadable(VM_OPTION_FILE_WITHOUT_READ_PERMISSIONS);
193 
194         /* Copy valid VM option file to perform test with relative path */
195         copyFromSource(VM_OPTION_FILE_2);
196 
197         /* Copy flags file to the current working folder */
198         copyFromSource(FLAGS_FILE);
199 
200         /* Create a new empty file */
201         new File(VM_OPTION_FILE_EMPTY).createNewFile();
202     }
203 
204     /*
205      * Add parameters to the VM Parameters list
206      */
addVMParam(String... params)207     private static void addVMParam(String... params) {
208         VMParams.addAll(Arrays.asList(params));
209     }
210 
211     /*
212      * Add VM option name to the application arguments list
213      */
addVMOptionsToCheck(String... params)214     private static void addVMOptionsToCheck(String... params) {
215         for (String param : params) {
216             appParams.add("vmoption=" + param);
217         }
218     }
219 
220     /*
221      * Add property to the VM Params list and to the application arguments list
222      */
addProperty(String propertyName, String propertyValue)223     private static void addProperty(String propertyName, String propertyValue) {
224         addVMParam("-D" + propertyName + "=" + propertyValue);
225     }
226 
227     /*
228      * Add "-XX:VMOptionsfile" parameter to the VM Params list
229      */
addVMOptionsFile(String fileName)230     private static void addVMOptionsFile(String fileName) {
231         addVMParam("-XX:VMOptionsFile=" + fileName);
232     }
233 
outputShouldContain(String expectedString)234     private static void outputShouldContain(String expectedString) {
235         output.shouldContain(expectedString);
236     }
237 
outputShouldNotContain(String expectedString)238     private static void outputShouldNotContain(String expectedString) {
239         output.shouldNotContain(expectedString);
240     }
241 
createProcessBuilder()242     private static ProcessBuilder createProcessBuilder() throws Exception {
243         ProcessBuilder pb;
244         List<String> runJava = new ArrayList<>();
245 
246         runJava.addAll(VMParams);
247         runJava.add(PrintPropertyAndOptions.class.getName());
248         runJava.addAll(appParams);
249 
250         pb = ProcessTools.createJavaProcessBuilder(runJava.toArray(new String[0]));
251 
252         VMParams.clear();
253         appParams.clear();
254 
255         return pb;
256     }
257 
runJavaCheckExitValue(ProcessBuilder pb, int expectedExitValue)258     private static void runJavaCheckExitValue(ProcessBuilder pb, int expectedExitValue) throws Exception {
259         output = new OutputAnalyzer(pb.start());
260         output.shouldHaveExitValue(expectedExitValue);
261     }
262 
runJavaCheckExitValue(int expectedExitValue)263     private static void runJavaCheckExitValue(int expectedExitValue) throws Exception {
264         runJavaCheckExitValue(createProcessBuilder(), expectedExitValue);
265     }
266 
267     /*
268      * Update environment variable in passed ProcessBuilder object to the passed value
269      */
updateEnvironment(ProcessBuilder pb, String name, String value)270     private static void updateEnvironment(ProcessBuilder pb, String name, String value) {
271         pb.environment().put(name, value);
272     }
273 
274     /*
275      * Check property value by examining output
276      */
checkProperty(String property, String expectedValue)277     private static void checkProperty(String property, String expectedValue) {
278         outputShouldContain(String.format(PRINT_PROPERTY_FORMAT, property, expectedValue));
279     }
280 
281     /*
282      * Check VM Option value by examining output
283      */
checkVMOption(String vmOption, String expectedValue)284     private static void checkVMOption(String vmOption, String expectedValue) {
285         outputShouldContain(String.format(PRINT_VM_OPTION_FORMAT, vmOption, expectedValue));
286     }
287 
testVMOptions()288     private static void testVMOptions() throws Exception {
289         ProcessBuilder pb;
290 
291         /* Check that empty VM Option file is accepted without errors */
292         addVMOptionsFile(VM_OPTION_FILE_EMPTY);
293 
294         runJavaCheckExitValue(JVM_SUCCESS);
295 
296         /* Check that VM Option file with tabs and spaces is accepted without errors */
297         addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_TABS_AND_SPACES));
298 
299         runJavaCheckExitValue(JVM_SUCCESS);
300 
301         /* Check that parameters are gotten from first VM Option file. Pass absolute path to the VM Option file */
302         addVMParam("-showversion");
303         addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_1));
304         addVMOptionsToCheck("SurvivorRatio", "MinHeapFreeRatio");
305 
306         runJavaCheckExitValue(JVM_SUCCESS);
307         outputShouldContain("interpreted mode");
308         checkProperty("optfile_1", "option_file_1");
309         checkVMOption("SurvivorRatio", "16");
310         checkVMOption("MinHeapFreeRatio", "22");
311 
312         /*
313          * Check that parameters are gotten from second VM Option file which also contains flags file.
314          * Flags file and option file contains NewRatio, but since options from VM Option file
315          * are processed later NewRatio should be set to value from VM Option file
316          * Pass relative path to the VM Option file in form "vmoptionfile"
317          */
318         addVMOptionsFile(VM_OPTION_FILE_2);
319         addVMOptionsToCheck("UseGCOverheadLimit", "NewRatio", "MinHeapFreeRatio", "MaxFDLimit", "AlwaysPreTouch");
320 
321         runJavaCheckExitValue(JVM_SUCCESS);
322         checkProperty("javax.net.ssl.keyStorePassword", "someVALUE123+");
323         checkVMOption("UseGCOverheadLimit", "true");
324         checkVMOption("NewRatio", "4");
325         checkVMOption("MinHeapFreeRatio", "3");
326         checkVMOption("MaxFDLimit", "true");
327         checkVMOption("AlwaysPreTouch", "false");
328 
329         /* Check that parameters are gotten from third VM Option file which contains a mix of the options */
330         addVMParam("-showversion");
331         addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_3));
332         addVMOptionsToCheck("UseGCOverheadLimit", "NewRatio");
333 
334         runJavaCheckExitValue(JVM_SUCCESS);
335         outputShouldContain("interpreted mode");
336         checkProperty("other.secret.data", "qwerty");
337         checkProperty("property", "second");
338         checkVMOption("UseGCOverheadLimit", "false");
339         checkVMOption("NewRatio", "16");
340 
341         /* Check that quotes are processed normally in VM Option file */
342         addVMParam("-showversion");
343         addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_QUOTE));
344         addVMOptionsToCheck("ErrorFile");
345 
346         runJavaCheckExitValue(JVM_SUCCESS);
347 
348         outputShouldContain("interpreted mode");
349         checkProperty("my.quote.single", "Property in single quote. Here a double qoute\" Add some slashes \\/");
350         checkProperty("my.quote.double", "Double qoute. Include single '.");
351         checkProperty("javax.net.ssl.trustStorePassword", "data @+NEW");
352         checkVMOption("ErrorFile", "./my error file");
353 
354         /*
355          * Verify that VM Option file accepts a file with 70 properties and with two options on separate
356          * lines and properties that use quotes a lot.
357          */
358         addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_LOT_OF_OPTIONS_QUOTE));
359         addVMOptionsToCheck("MinHeapFreeRatio", "MaxHeapFreeRatio");
360 
361         runJavaCheckExitValue(JVM_SUCCESS);
362 
363         for (int i = 1; i <= NUM_OF_PROP_IN_FILE_LOT_OF_OPTIONS_QUOTE; i++) {
364             checkProperty(String.format("prop%02d", i), String.format("%02d", i));
365         }
366         checkVMOption("MinHeapFreeRatio", "7");
367         checkVMOption("MaxHeapFreeRatio", "96");
368 
369         /*
370          * Verify that VM Option file accepts a file with very long property.
371          */
372         addVMOptionsFile(VM_OPTION_FILE_WITH_LONG_PROPERTY);
373 
374         runJavaCheckExitValue(JVM_SUCCESS);
375 
376         checkProperty(LONG_PROPERTY_NAME.replaceAll("'", ""), LONG_PROPERTY_VALUE);
377 
378         /*
379          * Verify that VM Option file accepts a big VM Option file
380          */
381         addVMOptionsFile(VM_OPTION_FILE_BIG);
382         addVMOptionsToCheck("MinHeapFreeRatio");
383         addVMOptionsToCheck("MaxHeapFreeRatio");
384 
385         runJavaCheckExitValue(JVM_SUCCESS);
386 
387         outputShouldContain("VM option '+PrintVMOptions'");
388         checkProperty("my.property", "value" + REPEAT_COUNT);
389         checkVMOption("MinHeapFreeRatio", "17");
390         checkVMOption("MaxHeapFreeRatio", "85");
391 
392         /* Pass VM Option file in _JAVA_OPTIONS environment variable */
393         addVMParam("-showversion");
394         addVMOptionsToCheck("SurvivorRatio", "MinHeapFreeRatio");
395         pb = createProcessBuilder();
396 
397         updateEnvironment(pb, JAVA_OPTIONS, "-XX:VMOptionsFile=" + getAbsolutePathFromSource(VM_OPTION_FILE_1));
398 
399         runJavaCheckExitValue(pb, JVM_SUCCESS);
400         outputShouldContain("interpreted mode");
401         checkProperty("optfile_1", "option_file_1");
402         checkVMOption("SurvivorRatio", "16");
403         checkVMOption("MinHeapFreeRatio", "22");
404 
405         /* Pass VM Option file in JAVA_TOOL_OPTIONS environment variable */
406         addVMOptionsToCheck("UseGCOverheadLimit", "NewRatio", "MinHeapFreeRatio", "MaxFDLimit", "AlwaysPreTouch");
407         pb = createProcessBuilder();
408 
409         updateEnvironment(pb, JAVA_TOOL_OPTIONS, "-XX:VMOptionsFile=" + VM_OPTION_FILE_2);
410 
411         runJavaCheckExitValue(pb, JVM_SUCCESS);
412         checkProperty("javax.net.ssl.keyStorePassword", "someVALUE123+");
413         checkVMOption("UseGCOverheadLimit", "true");
414         checkVMOption("NewRatio", "4");
415         checkVMOption("MinHeapFreeRatio", "3");
416         checkVMOption("MaxFDLimit", "true");
417         checkVMOption("AlwaysPreTouch", "false");
418     }
419 
prepareTestCase(int testCase)420     private static ProcessBuilder prepareTestCase(int testCase) throws Exception {
421         ProcessBuilder pb;
422 
423         Asserts.assertTrue(0 < testCase && testCase < 6, "testCase should be from 1 to 5");
424 
425         addVMParam("-showversion");
426         addVMOptionsToCheck("MinHeapFreeRatio", "SurvivorRatio", "NewRatio");
427 
428         if (testCase < 5) {
429             addVMParam("-XX:Flags=flags_file", "-XX:-PrintVMOptions");
430             addProperty("shared.property", "command_line_before");
431             addProperty("clb", "unique_command_line_before");
432             addVMParam("-XX:MinHeapFreeRatio=7");
433         }
434 
435         if (testCase < 4) {
436             addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_1));
437         }
438 
439         if (testCase < 3) {
440             addVMParam("-XX:MinHeapFreeRatio=9", "-XX:-PrintVMOptions");
441             addProperty("shared.property", "command_line_after");
442             addProperty("cla", "unique_command_line_after");
443         }
444 
445         /* Create ProcessBuilder after all setup is done to update environment variables */
446         pb = createProcessBuilder();
447 
448         if (testCase < 2) {
449             updateEnvironment(pb, JAVA_OPTIONS, "-Dshared.property=somevalue -Djo=unique_java_options "
450                     + "-XX:MinHeapFreeRatio=18 -Dshared.property=java_options -XX:MinHeapFreeRatio=11 -XX:+PrintVMOptions");
451         }
452 
453         if (testCase < 6) {
454             updateEnvironment(pb, JAVA_TOOL_OPTIONS, "-Dshared.property=qwerty -Djto=unique_java_tool_options "
455                     + "-XX:MinHeapFreeRatio=15 -Dshared.property=java_tool_options -XX:MinHeapFreeRatio=6 -XX:+PrintVMOptions");
456         }
457 
458         return pb;
459     }
460 
testVMOptionsLastArgumentsWins()461     private static void testVMOptionsLastArgumentsWins() throws Exception {
462         ProcessBuilder pb;
463 
464         /*
465          * "shared.property" property and "MinHeapFreeRatio" XX VM Option are defined
466          * in flags file, JAVA_TOOL_OPTIONS and _JAVA_OPTIONS environment variables,
467          * on command line before VM Option file, on command line after VM Option file
468          * and also in VM Option file. Verify that last argument wins. Also check
469          * unique properties and VM Options.
470          * Here is the order of options processing and last argument wins:
471          *    1) Flags file
472          *    2) JAVA_TOOL_OPTIONS environment variables
473          *    3) Pseudo command line from launcher
474          *    4) _JAVA_OPTIONS
475          * In every category arguments processed from left to right and from up to down
476          * and the last processed arguments wins, i.e. if argument is defined several
477          * times the value of argument will be equal to the last processed argument.
478          *
479          * "shared.property" property and "MinHeapFreeRatio" should be equal to the
480          * value from _JAVA_OPTIONS environment variable
481          */
482         pb = prepareTestCase(1);
483 
484         runJavaCheckExitValue(pb, JVM_SUCCESS);
485 
486         outputShouldContain("interpreted mode");
487         outputShouldContain("VM option '+PrintVMOptions'");
488         checkProperty("shared.property", "java_options");
489         checkVMOption("MinHeapFreeRatio", "11");
490         /* Each category defines its own properties */
491         checkProperty("jto", "unique_java_tool_options");
492         checkProperty("jo", "unique_java_options");
493         checkProperty("clb", "unique_command_line_before");
494         checkProperty("optfile_1", "option_file_1");
495         checkProperty("cla", "unique_command_line_after");
496         /* SurvivorRatio defined only in VM Option file */
497         checkVMOption("SurvivorRatio", "16");
498         /* NewRatio defined only in flags file */
499         checkVMOption("NewRatio", "5");
500 
501         /*
502          * The same as previous but without _JAVA_OPTIONS environment variable.
503          * "shared.property" property and "MinHeapFreeRatio" should be equal to the
504          * value from pseudo command line after VM Option file
505          */
506         pb = prepareTestCase(2);
507 
508         runJavaCheckExitValue(pb, JVM_SUCCESS);
509 
510         outputShouldContain("interpreted mode");
511         outputShouldNotContain("VM option '+PrintVMOptions'");
512         checkProperty("shared.property", "command_line_after");
513         checkVMOption("MinHeapFreeRatio", "9");
514 
515         /*
516          * The same as previous but without arguments in pseudo command line after
517          * VM Option file.
518          * "shared.property" property and "MinHeapFreeRatio" should be equal to the
519          * value from VM Option file.
520          */
521         pb = prepareTestCase(3);
522 
523         runJavaCheckExitValue(pb, JVM_SUCCESS);
524 
525         outputShouldContain("interpreted mode");
526         outputShouldContain("VM option '+PrintVMOptions'");
527         checkProperty("shared.property", "vmoptfile");
528         checkVMOption("MinHeapFreeRatio", "22");
529 
530         /*
531          * The same as previous but without arguments in VM Option file.
532          * "shared.property" property and "MinHeapFreeRatio" should be equal to the
533          * value from pseudo command line.
534          */
535         pb = prepareTestCase(4);
536 
537         runJavaCheckExitValue(pb, JVM_SUCCESS);
538 
539         outputShouldNotContain("VM option '+PrintVMOptions'");
540         checkProperty("shared.property", "command_line_before");
541         checkVMOption("MinHeapFreeRatio", "7");
542 
543         /*
544          * The same as previous but without arguments from pseudo command line.
545          * "shared.property" property and "MinHeapFreeRatio" should be equal to the
546          * value from JAVA_TOOL_OPTIONS environment variable.
547          */
548         pb = prepareTestCase(5);
549 
550         runJavaCheckExitValue(pb, JVM_SUCCESS);
551 
552         outputShouldContain("VM option '+PrintVMOptions'");
553         checkProperty("shared.property", "java_tool_options");
554         checkVMOption("MinHeapFreeRatio", "6");
555     }
556 
testVMOptionsInvalid()557     private static void testVMOptionsInvalid() throws Exception {
558         ProcessBuilder pb;
559 
560         /* Pass directory instead of file */
561         addVMOptionsFile(CURRENT_DIR);
562 
563         runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1);
564 
565         /* Pass not existing file */
566         addVMOptionsFile(getAbsolutePathFromSource(NOT_EXISTING_FILE));
567 
568         runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1);
569         outputShouldContain("Could not open options file");
570 
571         /* Pass VM option file with bad option */
572         addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_WITH_BAD_OPTION));
573 
574         runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1);
575         outputShouldContain("Unrecognized VM option");
576 
577         /* Pass VM option file with same VM option file option in it */
578         addVMOptionsFile(VM_OPTION_FILE_WITH_SAME_VM_OPTION_FILE);
579 
580         runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1);
581         outputShouldContain("A VM options file may not refer to a VM options file. Specification of '-XX:VMOptionsFile=<file-name>' in the options file");
582 
583         /* Pass VM option file with VM option file option in it */
584         addVMOptionsFile(VM_OPTION_FILE_WITH_VM_OPTION_FILE);
585 
586         runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1);
587         outputShouldContain("A VM options file may not refer to a VM options file. Specification of '-XX:VMOptionsFile=<file-name>' in the options file");
588 
589         /* Pass VM option file which is not accessible (without read permissions) */
590         addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_WITHOUT_READ_PERMISSIONS));
591 
592         runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1);
593         outputShouldContain("Could not open options file");
594 
595         /* Pass two VM option files */
596         addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_1));
597         addVMOptionsFile(VM_OPTION_FILE_2);
598 
599         runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1);
600         outputShouldContain("is already specified in the");
601 
602         /* Pass empty option file i.e. pass "-XX:VMOptionsFile=" */
603         addVMOptionsFile("");
604 
605         runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1);
606         outputShouldContain("Could not open options file");
607 
608         /* Pass VM option file with unmatched single quote */
609         addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_UNMATCHED_QUOTE_1));
610 
611         runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1);
612         outputShouldContain("Unmatched quote in");
613 
614         /* Pass VM option file with unmatched double quote in X option */
615         addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_UNMATCHED_QUOTE_2));
616 
617         runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1);
618         outputShouldContain("Unmatched quote in");
619     }
620 
main(String[] args)621     public static void main(String[] args) throws Exception {
622         /*
623          * Preparation before actual testing - create two VM Option files
624          * which contains VM Option file in it and copy other files to the
625          * current working folder
626          */
627         createOptionFiles();
628 
629         testVMOptions(); /* Test VM Option file general functionality */
630         testVMOptionsLastArgumentsWins(); /* Verify that last argument wins */
631         testVMOptionsInvalid(); /* Test invalid VM Option file functionality */
632 
633     }
634 
635     public static class PrintPropertyAndOptions {
636 
main(String[] arguments)637         public static void main(String[] arguments) {
638             String vmOption;
639             Properties properties = System.getProperties();
640 
641             for (String propertyName : properties.stringPropertyNames()) {
642                 System.out.println(String.format(PRINT_PROPERTY_FORMAT, propertyName, System.getProperty(propertyName, "NOT DEFINED")));
643             }
644 
645             for (String arg : arguments) {
646                 if (arg.startsWith("vmoption=")) {
647                     vmOption = arg.substring(9);
648                     System.out.println(String.format(PRINT_VM_OPTION_FORMAT, vmOption, new DynamicVMOption(vmOption).getValue()));
649                 }
650             }
651         }
652     }
653 }
654