1 /*
   2  * Copyright (c) 2014, 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 8061611
  27  * @summary Test that various options have been removed, or are deprecated, or are aliased. Can be extended to test other options as needed.
  28  * @library /testlibrary
  29  */
  30 import java.util.ArrayList;
  31 import com.oracle.java.testlibrary.*;
  32 
  33 public class VMOptionsLifecycle {
  34   
  35   private static final String PRINT_FLAGS_FINAL_FORMAT = "%s\\s*:?=\\s*%s";
  36 
  37   public static final String[] REMOVED_OPTIONS = {
  38     "CMSParPromoteBlocksToClaim",
  39     "ParCMSPromoteBlocksToClaim",
  40     "ParallelGCOldGenAllocBufferSize",
  41     "ParallelGCToSpaceAllocBufferSize",
  42     "UseGCTimeLimit",
  43     "CMSPermGenSweepingEnabled",
  44     "MaxTLERatio",
  45     "ResizeTLE",
  46     "PrintTLE",
  47     "TLEFragmentationRatio",
  48     "TLESize",
  49     "TLEThreadRatio",
  50     "UseTLE"
  51   };
  52 
  53   /**
  54    * each entry is {[0]: alias name, [1]: alias target, [2]: value to set
  55    * (+/-/n)}
  56    */
  57   public static final String[][] UNDEPRECATED_ALIAS_OPTIONS = { //undeprecated aliases:
  58   // --- none ---
  59   };
  60 
  61   /**
  62    * each entry is {[0]: alias name, [1]: alias target, [2]: value to set
  63    * (+/-/n)}. n can be any valid value for the option.
  64    */
  65   public static final String[][] DEPRECATED_ALIAS_OPTIONS = {
  66     {"CMSMarkStackSizeMax", "MarkStackSizeMax", "1032"},
  67     {"CMSMarkStackSize", "MarkStackSize", "1032"},
  68     {"G1MarkStackSize", "MarkStackSize", "1032"},
  69     {"ParallelMarkingThreads", "ConcGCThreads", "77"},
  70     {"ParallelCMSThreads", "ConcGCThreads", "77"}
  71   };
  72 
  73   public static final String[][] ALIAS_OPTIONS; // = UNDEPRECATED_ALIAS_OPTIONS + DEPRECATED_ALIAS_OPTIONS
  74 
  75   /**
  76    * each entry is {[0]: option name, [1]: value to set (+/-/n)}
  77    */
  78   public static final String[][] DEPRECATED_SIMPLE_OPTIONS = { //deprecated options:
  79   // --- none ---
  80   };
  81 
  82   public static final String[][] DEPRECATED_OPTIONS; // = DEPRECATED_SIMPLE_OPTIONS + DEPRECATED_ALIAS_OPTIONS
  83 
  84   static String[][] concatOptions(String[][] a, String[][] b) {
  85     String[][] result = new String[a.length + b.length][];
  86     System.arraycopy(a, 0, result, 0, a.length);
  87     System.arraycopy(b, 0, result, a.length, b.length);
  88     return result;
  89   }
  90   
  91   static {
  92     ALIAS_OPTIONS = concatOptions(UNDEPRECATED_ALIAS_OPTIONS, DEPRECATED_ALIAS_OPTIONS);
  93     DEPRECATED_OPTIONS = concatOptions(DEPRECATED_SIMPLE_OPTIONS, DEPRECATED_ALIAS_OPTIONS);
  94   }
  95         
  96   static void testRemoved(String option, boolean normalTest) throws Throwable {
  97     ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+" + option, "-version");
  98 
  99     OutputAnalyzer output = new OutputAnalyzer(pb.start());
 100 
 101     if (!normalTest) {
 102       output.shouldNotContain("Unrecognized VM option '" + option + "'");
 103       output.shouldHaveExitValue(0);
 104     } else {
 105       output.shouldContain("Unrecognized VM option '" + option + "'");
 106       output.shouldHaveExitValue(1);
 107     }
 108 //    System.out.println("=== output ===");
 109 //    System.out.print(output.getOutput());
 110   }
 111 
 112   /**
 113    * Turn the optionInfo into a legal -XX: command line argument.
 114    * @param optionInfo
 115    * @return 
 116    */
 117   static String makeOptionArg(String[] optionInfo) {
 118     String value = optionInfo[optionInfo.length-1];
 119     if (value.equals("+")) {
 120       return "-XX:+" + optionInfo[0];
 121     } else if (value.equals("-")) {
 122       return "-XX:-" + optionInfo[0];
 123     } else {
 124       return "-XX:" + optionInfo[0] + "=" + value;
 125     }
 126   }
 127   
 128   /**
 129    * Turn the optionInfo into pattern that might match "-XX:+PrintFlagsFinal output.
 130    * @param optionInfo
 131    * @return 
 132    */
 133   static String makeOptionFinalValue(String option, String value) {
 134     if (value.equals("+")) {
 135       value = "true";
 136     } else if (value.equals("-")) {
 137       value = "false";
 138     }
 139     return String.format(PRINT_FLAGS_FINAL_FORMAT,
 140             option, value);
 141   }
 142   
 143   /**
 144    * Test all aliased options in one jvm exec.
 145    */
 146   static void testAliases(String[][] optionInfo, boolean normalTest) throws Throwable {
 147     ArrayList<String> args = new ArrayList<>();
 148     // construct args:
 149     for (String[] alias: optionInfo) {
 150       args.add(makeOptionArg(alias));
 151     }
 152     args.add("-XX:+PrintFlagsFinal");
 153     args.add("-version");
 154 
 155     // start vm:
 156     String[] args_array = new String[args.size()];
 157     ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args.toArray(args_array));
 158 
 159     OutputAnalyzer output = new OutputAnalyzer(pb.start());
 160 
 161     // check option values:
 162     output.shouldHaveExitValue(0);
 163     for (String[] alias: optionInfo) {
 164       String match = makeOptionFinalValue(alias[1], alias[2]);
 165       if (normalTest) {
 166         output.shouldMatch(match);
 167       } else {
 168         output.shouldNotMatch(match);
 169       }
 170     }
 171   }
 172   
 173   /**
 174    * Test all deprecated options in one jvm exec.
 175    */
 176   static void testDeprecated(String[][] optionInfo, boolean normalTest) throws Throwable {
 177     ArrayList<String> args = new ArrayList<>();
 178     // construct args:
 179     for (String[] deprecated: optionInfo) {
 180       args.add(makeOptionArg(deprecated));
 181     }
 182     args.add("-version");
 183 
 184     // start vm:
 185     String[] args_array = new String[args.size()];
 186     ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args.toArray(args_array));
 187 
 188     OutputAnalyzer output = new OutputAnalyzer(pb.start());
 189 
 190     // check for option deprecation messages:
 191     output.shouldHaveExitValue(0);
 192     for (String[] deprecated: optionInfo) {
 193       // Searching precisely for deprecation warnings is too hard at the moment.
 194       // There is no standard format. For now, just search for the option name in the output,
 195       // which should only be printed if there was some deprecation warning.
 196       String realOpt = (deprecated.length == 2) ? deprecated[0] : deprecated[1];
 197       String match = realOpt;
 198       if (normalTest) {
 199         output.shouldMatch(match);
 200       } else {
 201         output.shouldNotMatch(match);
 202       }
 203     }
 204   }
 205 
 206   public static void main(String[] args) throws Throwable {
 207     testRemoved("UseTLAB", false); // Test the test. UseTLAB has NOT been removed.
 208 
 209     for (String str: REMOVED_OPTIONS) {
 210       testRemoved(str, true); // Test should fail for each removed option.
 211     }
 212 
 213     String[][] testTestAliases = {{"MarkStackSizeMax", "CMSMarkStackSizeMax", "1032"}};
 214     testAliases(testTestAliases, false); // MarkStackSizeMax is NOT an alias for CMSMarkStackSizeMax.
 215     testAliases(ALIAS_OPTIONS, true);
 216 
 217     String[][] testTestDeprecated = {{"UseTLAB", "+"}};
 218     testDeprecated(testTestDeprecated, false); // Test the test. The output should NOT mention "UseTLAB" at all.
 219     testDeprecated(DEPRECATED_OPTIONS, true);  // Make sure that each deprecated option is mentioned in the output.
 220   }
 221 }