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 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.DynamicVMOption;
  55 import jdk.test.lib.OutputAnalyzer;
  56 import jdk.test.lib.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      */
 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      */
 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 
 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 
 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      */
 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      */
 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      */
 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      */
 230     private static void addVMOptionsFile(String fileName) {
 231         addVMParam("-XX:VMOptionsFile=" + fileName);
 232     }
 233 
 234     private static void outputShouldContain(String expectedString) {
 235         output.shouldContain(expectedString);
 236     }
 237 
 238     private static void outputShouldNotContain(String expectedString) {
 239         output.shouldNotContain(expectedString);
 240     }
 241 
 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 
 258     private static void runJavaCheckExitValue(ProcessBuilder pb, int expectedExitValue) throws Exception {
 259         output = new OutputAnalyzer(pb.start());
 260         output.shouldHaveExitValue(expectedExitValue);
 261     }
 262 
 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      */
 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      */
 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      */
 284     private static void checkVMOption(String vmOption, String expectedValue) {
 285         outputShouldContain(String.format(PRINT_VM_OPTION_FORMAT, vmOption, expectedValue));
 286     }
 287 
 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 
 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 
 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 
 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 
 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 
 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 }