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