diff --git a/test/functional/RasapiTest/build.xml b/test/functional/RasapiTest/build.xml new file mode 100644 index 00000000000..5d861530105 --- /dev/null +++ b/test/functional/RasapiTest/build.xml @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + Ant build script to generate com.ibm.jvm.ras.tests.jar + + + + + Cleaning build directory ${build.dir} + + + + + + + + + + + + + Ant version is ${ant.version} + Compiling code to ${build.dir} and packaging ${build.jar.tests} to ${dist.dir} + + ============COMPILER SETTINGS============ + ===fork: yes + ===executable: ${compiler.javac} + ===source: ${src.level} + ===target: ${target.level} + ===debug: on + ===destdir: ${build.dir} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/functional/RasapiTest/dummy_src/com/ibm/jvm/Dump.java b/test/functional/RasapiTest/dummy_src/com/ibm/jvm/Dump.java new file mode 100644 index 00000000000..ea30b27a7ff --- /dev/null +++ b/test/functional/RasapiTest/dummy_src/com/ibm/jvm/Dump.java @@ -0,0 +1,163 @@ +/******************************************************************************* + * Copyright (c) 2006, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.jvm; + +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * This class is used to trigger and configure the options used to produce different + * types of diagnostic dumps available from the IBM JVM. + *

+ * -Xdump must be enabled on the command line or the functions that attempt to cause + * dumps to be created or set options will fail with a java.lang.RuntimeException. + *

+ * The methods on this class can be used to trigger dumps, configure dump options and + * query those options. + *

+ * The {@link #JavaDump()}, {@link #SystemDump()}, {@link #HeapDump()} and {@link #SnapDump()} + * methods trigger dumps of the given type with no options and no return value. + * Although they are not configurable they do provide an easy API to use via reflection + * if your code is likely to run on both IBM and non-IBM JVMs and you only need the most + * basic ability to create a dump. + *

+ * The {@link #javaDumpToFile()}, {@link #systemDumpToFile()}, {@link #heapDumpToFile()} and + * {@link #snapDumpToFile()} methods allow a destination file to be optionally specified and + * will return the full path of the file that is created. + *
+ * The recommended usage of the {@link #javaDumpToFile()}, {@link #systemDumpToFile()}, + * {@link #heapDumpToFile()} and {@link #snapDumpToFile()} + * methods is to call the no argument versions of these calls rather than specifying a file + * name as this will trigger a dump to the default location. Your dump file will go to the + * default location specified by any -Xdump options given to the JVM at startup time following + * the user or administrators preferences. + * The location the dump file was written to will be returned as a String so the generated + * file can be located. + *

+ * The {@link #triggerDump(String)} method offers similar functionality as the DumpToFile() methods + * but with the ability to specify any dump options that are meaningful for a dump that occurs + * immediately. The options are passed as a String that follows the same format as the option + * strings passed to -Xdump on the command line.
+ * For example: + *

+ *

+ * The {@link #setDumpOptions(String)} method allows dump options that will cause or change how + * a dump occurs for an event in the future to be specified. The options are specified in the + * format expected by the -Xdump command line. Not all options can be configured at runtime and + * this method will throw an InvalidDumpOption exception if it is passed an option that cannot be set.

+ * For example: + *

+ * For full details of dump options see the section on dump agents in the documentation for the IBM JVM. + *

+ * The {@link #queryDumpOptions()} method returns a String array containing a snapshot of the currently + * configured dump options. Each String is in the format expected by the -Xdump command line + * option and setDumpOptions. The Strings can be passed back to setDumpOptions to recreate + * the current dump agent configuration at a later time. + *

+ * The {@link #resetDumpOptions()} method resets the dump options to the settings specified when the + * JVM was started removing any additional configuration done since then.
+ * If you wish to change the dump configuration at runtime and then reset it to an earlier + * state that included additional runtime configuration done through this API or JVMTI you should + * consider saving the result of queryDumpOptions and then later use {@link #setDumpOptions(String)} + * to restore that configuration after a call to setDumpOptions("none") to clear all dump agent + * configuration. + */ +public class Dump { + + public static void JavaDump() { + } + + public static void HeapDump() { + } + + public static void SystemDump() { + } + + private Dump() { + } + + public static void SnapDump() { + } + + public static String javaDumpToFile(String fileNamePattern ) throws InvalidDumpOptionException { + return null; + } + + public static String javaDumpToFile() { + return null; + } + + public static String heapDumpToFile(String fileNamePattern ) throws InvalidDumpOptionException { + return null; + } + + public static String heapDumpToFile() { + return null; + } + + + public static String systemDumpToFile(String fileNamePattern) throws InvalidDumpOptionException { + return null; } + + public static String systemDumpToFile() { + return null; + } + public static String snapDumpToFile(String fileNamePattern) throws InvalidDumpOptionException { + return null; + } + public static String snapDumpToFile() { + return null; + } + + public static String triggerDump(String dumpOptions) throws InvalidDumpOptionException { + return null; + } + + public static void setDumpOptions(String dumpOptions) throws InvalidDumpOptionException, DumpConfigurationUnavailableException { + } + + public static String[] queryDumpOptions() { + return null; + } + + public static void resetDumpOptions() throws DumpConfigurationUnavailableException { + } + +} diff --git a/test/functional/RasapiTest/dummy_src/com/ibm/jvm/DumpConfigurationUnavailableException.java b/test/functional/RasapiTest/dummy_src/com/ibm/jvm/DumpConfigurationUnavailableException.java new file mode 100644 index 00000000000..29177a871ec --- /dev/null +++ b/test/functional/RasapiTest/dummy_src/com/ibm/jvm/DumpConfigurationUnavailableException.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2006, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.jvm; + +public class DumpConfigurationUnavailableException extends Exception { + + public DumpConfigurationUnavailableException(String message) { + } + +} diff --git a/test/functional/RasapiTest/dummy_src/com/ibm/jvm/DumpPermission.java b/test/functional/RasapiTest/dummy_src/com/ibm/jvm/DumpPermission.java new file mode 100644 index 00000000000..e775209d9e8 --- /dev/null +++ b/test/functional/RasapiTest/dummy_src/com/ibm/jvm/DumpPermission.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2006, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.jvm; + +import java.security.BasicPermission; + +public class DumpPermission extends BasicPermission { + + public DumpPermission() { + super(null); + } +} diff --git a/test/functional/RasapiTest/dummy_src/com/ibm/jvm/InvalidDumpOptionException.java b/test/functional/RasapiTest/dummy_src/com/ibm/jvm/InvalidDumpOptionException.java new file mode 100644 index 00000000000..34a02e451f4 --- /dev/null +++ b/test/functional/RasapiTest/dummy_src/com/ibm/jvm/InvalidDumpOptionException.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2006, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.jvm; + +public class InvalidDumpOptionException extends Exception { + + public InvalidDumpOptionException(String message) { + } + +} diff --git a/test/functional/RasapiTest/dummy_src/com/ibm/jvm/Log.java b/test/functional/RasapiTest/dummy_src/com/ibm/jvm/Log.java new file mode 100644 index 00000000000..fa655121e76 --- /dev/null +++ b/test/functional/RasapiTest/dummy_src/com/ibm/jvm/Log.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2006, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.jvm; + +public class Log { + + public static String QueryOptions() { + return null; + } + + public static int SetOptions(String options) { + return 0; + } + + private Log() { + } + +} diff --git a/test/functional/RasapiTest/dummy_src/com/ibm/jvm/ToolDumpPermission.java b/test/functional/RasapiTest/dummy_src/com/ibm/jvm/ToolDumpPermission.java new file mode 100644 index 00000000000..ab5f28bf88f --- /dev/null +++ b/test/functional/RasapiTest/dummy_src/com/ibm/jvm/ToolDumpPermission.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2006, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.jvm; + +import java.security.BasicPermission; + +public class ToolDumpPermission extends BasicPermission { + + public ToolDumpPermission() { + super(null); + } +} diff --git a/test/functional/RasapiTest/playlist.xml b/test/functional/RasapiTest/playlist.xml new file mode 100644 index 00000000000..cf9499a3ab5 --- /dev/null +++ b/test/functional/RasapiTest/playlist.xml @@ -0,0 +1,46 @@ + + + + + + + testRASAPI + + backlog issue 426 + .*mac.* + + + ant -f $(TEST_RESROOT)$(D)test.xml -Dtest.java.home=$(Q)$(TEST_JDK_HOME)$(D)$(Q) launch_test; \ + $(TEST_STATUS) + + extended + + + functional + + + openj9 + ibm + + + diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/OutputFile.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/OutputFile.java new file mode 100644 index 00000000000..1d481a2b83f --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/OutputFile.java @@ -0,0 +1,322 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; + +public class OutputFile { + + BufferedReader in; + String line; + String firstReference; + String secondReference; + + public OutputFile(String fileName) throws IOException { + in = new BufferedReader(new FileReader(fileName)); + firstReference = null; + } + + /** + * Yes, finalizers may not have a very good reputation but it can't do any harm + */ + protected void finalize() throws Throwable { + try { + in.close(); + } finally { + super.finalize(); + } + } + + + /** + * Read through the file looking for the given string. Keep going to the end of the file if necessary. + * If the string is found, return true, set the instance variable line, and keep that position in the file. + * If the string is not found, return false, leave the file positioned at the end. + + * @param lookFor the string to look for + * @return true or false according to whether a line with the string was found + * @throws IOException + */ + public boolean skipUnlimitedToLineContaining(String lookFor) throws IOException { + line = in.readLine(); + while (line != null) { + if (line.indexOf(lookFor) != -1) { + System.err.printf("Successfully found the following line containing \"%s\"\n", lookFor); + System.err.printf(line); + System.err.printf("\n"); + return true; + } + line = in.readLine(); + } + System.err.printf("***Reached end of file before finding a line containing \"%s\"\n", lookFor); + return false; + } + + /** + * Read through the file looking for the given string. Keep going to the end of the file if necessary. + * If the string is found AT THE END OF THE LINE, return true, set the instance variable line, and keep that position in the file. + * If the string is not found, return false, leave the file positioned at the end. + * + * This method is especially for searching for the line ending "OBJ com/ibm/dump/tests/types/packed/NestedPacked" in the + * classic heapdump. Just using skipUnlimitedToLineContaining finds the lines for NestedPacked1 and NestedPacked2 + + * @param lookFor the string to look for + * @return true or false according to whether a line with the string was found + * @throws IOException + */ + public boolean skipUnlimitedToLineEnding(String lookFor) throws IOException { + line = in.readLine(); + while (line != null) { + if (line.endsWith(lookFor)) { + System.err.printf("Successfully found the following line ending \"%s\"\n", lookFor); + System.err.printf(line); + System.err.printf("\n"); + return true; + } + line = in.readLine(); + } + System.err.printf("***Reached end of file before finding a line ending \"%s\"\n", lookFor); + return false; + } + + /** + * Read no more than maxLinesToSkip down the file looking for a line containing the given string + * Read some number of lines down the file looking for the given string. Read no more than maxLinesToSkip lines. + * If the string is found, hold the line in instance variable line and keep the position in the file. + * If the string is not found, return false and restore the position in the file to where it was on entry: + * by doing so one failing test does not damage the tests that follow. + * @param maxLinesToSkip skip no more lines than this + * @param lookFor the string to look for + * @return true or false according to whether a line with the string was found + * @throws IOException + */ + public boolean skipLimitedToLineContaining(int maxLinesToSkip, String lookFor) throws IOException { + int linesRead = 0; + in.mark(maxLinesToSkip * 200); // generous allocation to allow reset to work. Most lines are < 100 bytes long + line = in.readLine(); + while (line != null && linesRead < maxLinesToSkip) { + // System.err.printf("line read was %s\n", line); + if (line.indexOf(lookFor) != -1) { + System.err.printf("Successfully found a line containing \"%s\"\n", lookFor); + return true; + } + line = in.readLine(); + linesRead++; + } + System.err.printf("***Failed to find a line containing \"%s\"\n", lookFor); + in.reset(); + return false; + } + + + /** + * Examine the last line read and check that the word at the given position is equal to given string + * @param lookFor the string to look for + * @param whichWord the index of the word to check + * @return + */ + public boolean linePassesCheckForStringAtWord(String lookFor, int whichWord) { + if (line == null) { + // previous call to skip[Un]limitedToLineContaining has failed + // so appropriate error message has been emitted already + // just return false and allow test to contine. + return false; + } + return StringUtils.linePassesCheckForStringAtWord(line, whichWord, lookFor); + } + + /** + * Return true or false depending on whether the word at position whichWord is in the list + * of values in validValues + * + * @param validValues + * @param whichWord + * @return + */ + public boolean linePassesCheckForStringsAtWord(String[] validValues, int whichWord) { + if (line == null) { + // previous call to skip[Un]limitedToLineContaining has failed + // so appropriate error message has been emitted already + // just return false and allow test to contine. + return false; + } + return StringUtils.linePassesCheckForStringsAtWord(line, whichWord, validValues); + } + + /** + * + * @return the first reference that was found by the previous call to skipToNextLineAndCheckReferencesCount. + * This is just the first token that was on that line. + */ + public String getFirstReference() { + return firstReference; + } + + /** + * + * @return the second reference that was found by the previous call to skipToNextLineAndCheckReferencesCount. + * This is just the second token that was on that line. + */ + public String getSecondReference() { + return secondReference; + } + + /** + * Skip down to the lines containing "references:" then check the number of references on the + * succeeding line. + * @param maxLinesToSkip + * @param expectedNumberOfReferences + * @return true or false depending on whether the number of references matches the expected number. + * @throws IOException + */ + public boolean skipToLineContainingListOfReferencesAndCheckCount(int maxLinesToSkip, int expectedNumberOfReferences) throws IOException { + + if (! skipLimitedToLineContaining(maxLinesToSkip, "references:")) { + // if we cannot find the references line, don't go further + return false; + } + return skipToNextLineAndCheckReferencesCount(expectedNumberOfReferences); + + } + + /** + * Skip down the output from jdmpview's x/j command looking for the line containing "references:" + * @param maxLinesToSkip + * @return + * @throws IOException + */ + public boolean skipLimitedToReferencesLine(int maxLinesToSkip) throws IOException { + if (! skipLimitedToLineContaining(maxLinesToSkip, "references:")) { + // if we cannot find the references line, don't go further + return false; + } + return true; + } + + /** + * Read the next line, tokenise it, and check that the number of tokens equals the given parameter. + * As a side effect, set the instance variable firstReference. + * + * This method can be called either from the classic heapdump checkers, when the file will be already + * positioned on the OBJ line and the references always come on the next line, + * or called from skipToLineContainingListOfReferencesAndCheckCount() when checking the + * output from jdmpview's x/j command. In either case, the list of references is on the very next line. + * + * + * + * @param expectedNumberOfReferences + * @return true or false depending on whether the line does or does not contain the given number of tokens. + * @throws IOException + */ + public boolean skipToNextLineAndCheckReferencesCount(int expectedNumberOfReferences) throws IOException { + // assert + // if we are called by one of the classic heapdump checkers we are currently on the OBJ line and + // skipping to the next line will put us on the list of references, or + // we will have been called from skipToReferencesLineAndCheckCount if we are checking the output + // from jdmpview's x/j command during phd checking + + + String line = in.readLine(); + if (line == null) { + System.err.println("***Unable to check count of references - previous call to find the references lines has failed."); + return false; + } + + ArrayList references = StringUtils.extractTokensFromLine(line); + if (references.size() > 0) { + firstReference = references.get(0); + } else { + firstReference = null; + } + if (references.size() > 1) { + secondReference = references.get(1); + } else { + secondReference = null; + } + if (references.size() != expectedNumberOfReferences) { + System.err.println("***Failure: there should have been exactly " + expectedNumberOfReferences + " reference(s), not " + references.size()); + return false; + } else { + System.err.println("Successfully found exactly " + expectedNumberOfReferences + " reference(s)"); + return true; + } + } + + /** + * Read the next line, tokenise it, and return the the number of tokens (references). + * + * This method is called from the classic heapdump checkers, when the file will be already + * positioned on the OBJ line and the references always come on the next line + * + * @return number of references + * @throws IOException + */ + public int skipToNextLineAndCountReferences() throws IOException { + // if we are called by one of the classic heapdump checkers we are currently on the OBJ line and + // skipping to the next line will put us on the list of references + String line = in.readLine(); + if (line == null) { + System.err.println("***Unable to check count of references - previous call to find the references lines has failed."); + return 0; + } + + ArrayList references = StringUtils.extractTokensFromLine(line); + return references.size(); + } + + public static boolean checkReferenceInClassicHeapdumpIsToObject(String fileName, String reference, String className) throws IOException { + OutputFile o = new OutputFile(fileName); + boolean passed = true; + System.err.println("Checking that the reference " + reference + " is to an object of type " + className); + passed &= o.skipUnlimitedToLineBeginning(reference); + passed &= o.linePassesCheckForStringAtWord(className,4); + return passed; + } + + private boolean skipUnlimitedToLineBeginning(String lookFor) throws IOException { + line = in.readLine(); + while (line != null) { + if (line.startsWith(lookFor) ) { + System.err.printf("Successfully found a line beginning \"%s\"\n", lookFor); + System.err.printf(line); + System.err.printf("\n"); + return true; + } + line = in.readLine(); + } + System.err.printf("***Reached end of file before finding a line beginning \"%s\"\n", lookFor); + return false; + } + + public static boolean checkReferenceIsToObject(String fileName, String reference, String className) throws IOException { + OutputFile o = new OutputFile(fileName); + boolean passed = true; + System.err.println("Checking that the reference " + reference + " is to an object of type " + className); + passed &= o.skipUnlimitedToLineContaining(className + " @ " + reference); + return passed; + } + +} + diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/StringUtils.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/StringUtils.java new file mode 100644 index 00000000000..657027854ee --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/StringUtils.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests; + +import java.util.ArrayList; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; + + +public class StringUtils { + + /** + * Check that the line contains a given value at a given position. + * Whether it does or not, write a line to System.err to trace progress. + * + * @param line the line to check + * @param whichWord which word in the line to check + * @param requiredValue the number to look for + * @return true or false depending on whether the line does indeed contain the given number at the given word + */ + static boolean linePassesCheckForStringAtWord(String line, int whichWord, String requiredValue) { + StringTokenizer st = new StringTokenizer(line); + String word = ""; + try { + for (int i = 0;i < whichWord; i++) { + word = st.nextToken(); + } + } catch (NoSuchElementException e) { + System.err.printf("***Failed to find the value %s at word %d in line \"%s\", no such element\n", requiredValue, whichWord, line, word) ; + return false; + } + if (word.equals(requiredValue)) { + System.err.printf("Successfully found the value %s at word %d in line \"%s\"\n", requiredValue, whichWord, line) ; + return true; + } else { + System.err.printf("***Failed to find the value %s at word %d in line \"%s\", found %s instead\n", requiredValue, whichWord, line, word) ; + return false; + } + + } + + /** + * Check that the line contains one of a number of given values at a given position. + * Whether it does or not, write a line to System.err to trace progress. + * + * @param line the line to check + * @param whichWord which word in the line to check + * @param requiredValue the number to look for + * @return true or false depending on whether the line does indeed contain the given number at the given word + */ + static boolean linePassesCheckForStringsAtWord(String line, int whichWord, String[] requiredValues) { + StringTokenizer st = new StringTokenizer(line); + String word = ""; + try { + for (int i = 0;i < whichWord; i++) { + word = st.nextToken(); + } + } catch (NoSuchElementException e) { + System.err.printf("***Failed to find any value at word %d in line \"%s\", no such element\n", whichWord, line, word) ; + return false; + } + for (String requiredValue : requiredValues) { + if (word.equals(requiredValue)) { + System.err.printf("Successfully found the value %s at word %d in line \"%s\"\n", requiredValue, whichWord, line) ; + return true; + } + } + System.err.printf("***Failed to find any of the required values at word %d in line \"%s\", found %s instead. ", whichWord, line, word) ; + System.err.printf("The required values were:") ; + for (String requiredValue : requiredValues) { + System.err.printf(requiredValue + " "); + } + System.err.printf("\n"); + return false; + } + + + /** + * Given a line break it into an array of tokens (words) + * @param line + * @return arraylist of tokens (words) + */ + public static ArrayList extractTokensFromLine(String line) { + ArrayList tokens = new ArrayList(); + StringTokenizer st = new StringTokenizer(line); + while (st.hasMoreTokens()) { + String word = st.nextToken(); + tokens.add(word); + } + return tokens; + } + + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/CheckClassicHeapdump.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/CheckClassicHeapdump.java new file mode 100644 index 00000000000..5f764bf92cc --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/CheckClassicHeapdump.java @@ -0,0 +1,152 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.classic_heapdump_packed_objects; + + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; + +/** + * This class checks a classic heapdump containing packed objects + * + * @author matthew + * + */ +public class CheckClassicHeapdump { + + /** + * @param args + */ + public static void main(String[] args) { + + if (args.length < 1) { + System.err.println("A file containing a classic heapdump is required to check."); + System.exit(1); + } + + String fileName = args[0]; + boolean passed = true; + + System.err.println("Classic Heapdump Checker"); + System.err.println("Checking " + fileName); + + try{ + /** + * Test 1. Check PackedPrimitives + */ + System.err.println("\n**************************************************"); + System.err.println("* 1. Check PackedPrimitives"); + System.err.println("**************************************************"); + passed &= ClassicHeapdumpTest1PackedPrimitivesChecker.check(fileName); + + /** + * Test 2. Check array of PackedPrimitives + */ + System.err.println("\n**************************************************"); + System.err.println("* 2. Check array of PackedPrimitives"); + System.err.println("**************************************************"); + passed &= ClassicHeapdumpTest2ArrayOfPackedPrimitivesChecker.check(fileName); + + /** + * Test 3. Check PackedMixed + */ + System.err.println("\n**************************************************"); + System.err.println("* 3. Check PackedMixed"); + System.err.println("**************************************************"); + passed &= ClassicHeapdumpTest3PackedMixedOneRefChecker.check(fileName); + + /** + * Test 4. Check array of PackedMixed + */ + System.err.println("\n**************************************************"); + System.err.println("* 4. Check array of PackedMixed"); + System.err.println("**************************************************"); + passed &= ClassicHeapdumpTest4ArrayOfPackedMixedOneRefChecker.check(fileName); + + /** + * Test 5. Check array of PackedMixedTwoRefs + */ + System.err.println("\n**************************************************"); + System.err.println("* 5. Check PackedMixedTwoRefs"); + System.err.println("**************************************************"); + passed &= ClassicHeapdumpTest5ArrayOfPackedMixedTwoRefsChecker.check(fileName); + + /** + * Test 6. Check PackedMixedWithReferenceToSelf + */ + System.err.println("\n**************************************************"); + System.err.println("* 6. Check PackedMixedWithReferenceToSelf"); + System.err.println("**************************************************"); + passed &= ClassicHeapdumpTest6PackedMixedWithReferenceToSelfChecker.check(fileName); + + /** + * Test 7. Check NestedPacked + */ + System.err.println("\n**************************************************"); + System.err.println("* 7. Check NestedPacked"); + System.err.println("**************************************************"); + passed &= ClassicHeapdumpTest7NestedPackedChecker.check(fileName); + + /** + * Test 8. Check PackedIntsArray + */ + System.err.println("\n**************************************************"); + System.err.println("* 8. Check PackedIntsArray"); + System.err.println("**************************************************"); + passed &= ClassicHeapdumpTest8PackedIntsArrayChecker.check(fileName); + + /** + * Test 9. Check array of PackedMixedWithReferenceToSelf and the derived object + */ + System.err.println("\n**************************************************"); + System.err.println("* 9. Check PackedMixedArrayElement"); + System.err.println("**************************************************"); + passed &= ClassicHeapdumpTest9ArrayOfPackedMixedArrayElementChecker.check(fileName); + + } catch (FileNotFoundException e) { + System.err.println("FileNotFoundException occured reading " + fileName); + e.printStackTrace(System.err); + System.exit(1); + } catch (IOException e) { + System.err.println("IOException occured reading " + fileName); + e.printStackTrace(System.err); + System.exit(1); + } + + if( passed ) { + System.err.println("\n**************************************************"); + System.err.println("CheckClassicHeapdump: All tests passed."); + System.exit(0); + } else { + System.err.println("\n**************************************************"); + System.err.println("CheckClassicHeapdump: Some or all tests failed, see messages in tests 1 to 9 above."); + System.exit(1); + } + } + + + + + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest1PackedPrimitivesChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest1PackedPrimitivesChecker.java new file mode 100644 index 00000000000..4196c8f4479 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest1PackedPrimitivesChecker.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.classic_heapdump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class ClassicHeapdumpTest1PackedPrimitivesChecker { + + /** + * Check through the classic heapdump looking for the lines containing "OBJ com/ibm/dump/tests/types/packed/PackedPrimitives". + * + * Check there are no references from the objects - this will check that the curious and irritating self-reference + * that gc returns for on-heap packed objects has been suppressed correctly when the dump was written. + * + * The expected output is lines such as follows: + *

+	 *  
+    0x2EF48F80 [48] OBJ com/ibm/dump/tests/types/packed/PackedPrimitives <-------------- java packed
+        0x2EF48F80                       <-------------- one self-reference for a java packed object
+    0x2EF48FB0 [16] OBJ com/ibm/dump/tests/types/packed/PackedPrimitives <-- --------- native packed
+      [blank line]
+      	
+ * @throws IOException + */ + + public static boolean check(String fileName) throws IOException { + String[] validSizes = { + "[48]", // on heap 32 and 64cr + "[16]", // off heap 32 and 64cr + "[56]", // on heap 64 + "[24]"}; // off heap 64 + + String objectLine = "OBJ com/ibm/dump/tests/types/packed/PackedPrimitives"; + System.err.println("\nChecking the output for \"" + objectLine + "\""); + + OutputFile o = new OutputFile(fileName); + + // check for three OBJ lines, one of which will have a single reference, the others no references + boolean passed = true; + int refCount = 0; + passed &= o.skipUnlimitedToLineEnding(objectLine); + passed &= o.linePassesCheckForStringsAtWord(validSizes,2); + refCount += o.skipToNextLineAndCountReferences(); + + passed &= o.skipUnlimitedToLineEnding(objectLine); + passed &= o.linePassesCheckForStringsAtWord(validSizes,2); + refCount += o.skipToNextLineAndCountReferences(); + + passed &= o.skipUnlimitedToLineEnding(objectLine); + passed &= o.linePassesCheckForStringsAtWord(validSizes,2); + refCount += o.skipToNextLineAndCountReferences(); + + passed &= (refCount == 1); // expect one reference found in the three objects + + if (!passed) { + System.err.println("ClassicHeapdumpTest1PackedPrimitivesChecker failed"); + } + return passed; + } +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest2ArrayOfPackedPrimitivesChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest2ArrayOfPackedPrimitivesChecker.java new file mode 100644 index 00000000000..b025ae65fbc --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest2ArrayOfPackedPrimitivesChecker.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.classic_heapdump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class ClassicHeapdumpTest2ArrayOfPackedPrimitivesChecker { + + /** + * Check through the classic heapdump looking for two arrays of PackedPrimitives and check the length. + * Check there are no references from the arrays - this will check that the odd self-reference + * that on-heap packed objects have has been suppressed correctly. + * + * The expected output is similar to: + *
+    0x2EF48FE0 [336] OBJ [Lcom/ibm/dump/tests/types/packed/PackedPrimitives;
+        0x2EF48FE0
+    0x2EF49130 [16] OBJ [Lcom/ibm/dump/tests/types/packed/PackedPrimitives;
+      [blank line]	
+		
+ * @throws IOException + */ + + public static boolean check(String fileName) throws IOException { + + String[] validSizes = { + "[336]", // on heap 32 + "[16]", // off heap 32 + "[344]", // on heap 64cr + "[24]", // off heap 64cr + "[352]", // on heap 64 + "[32]"}; // off heap 64 + + String objectLine = "OBJ com/ibm/dump/tests/types/packed/PackedPrimitives$Array"; + System.err.println("\nChecking the output for \"" + objectLine + "\""); + + OutputFile o = new OutputFile(fileName); + boolean passed = true; + int refCount = 0; + passed &= o.skipUnlimitedToLineContaining(objectLine); + passed &= o.linePassesCheckForStringsAtWord(validSizes,2); + refCount += o.skipToNextLineAndCountReferences(); + + passed &= o.skipUnlimitedToLineContaining(objectLine); + passed &= o.linePassesCheckForStringsAtWord(validSizes,2); + refCount += o.skipToNextLineAndCountReferences(); + + passed &= (refCount == 1); // expect one reference found in the two objects + + if (!passed) { + System.err.println("ClassicHeapdumpTest2ArrayOfPackedPrimitivesChecker failed"); + } + return passed; + } +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest3PackedMixedOneRefChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest3PackedMixedOneRefChecker.java new file mode 100644 index 00000000000..a16dce1ce40 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest3PackedMixedOneRefChecker.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.classic_heapdump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class ClassicHeapdumpTest3PackedMixedOneRefChecker { + + /** + * Check through the classic heapdump looking for the PackedMixed object, and the one reference + * to the NotPackedPrimitives contained therein. + * + * Rely on the NotPackedPrimitives immediately after in the file, which is a weakness, but seems to + * always work. + * + * The expected output is lines such as follows: + *
+    0x2EF49180 [24] OBJ com/ibm/dump/tests/types/packed/PackedMixedOneRef
+        0x2EF49180 0x2EF49198
+    0x2EF49198 [48] OBJ com/ibm/dump/tests/types/notpacked/NotPackedPrimitives
+      [blank line]
+		
+ * @throws IOException + */ + + public static boolean check(String fileName) throws IOException { + String[] validSizes = { + "[24]", // on heap 32 and 64cr + "[40]"}; // on heap 64 + + String objectLine = "OBJ com/ibm/dump/tests/types/packed/PackedMixedOneRef"; + System.err.println("\nChecking the output for \"" + objectLine + "\""); + + OutputFile o = new OutputFile(fileName); + boolean passed = true; + + passed &= o.skipUnlimitedToLineEnding(objectLine); + passed &= o.linePassesCheckForStringsAtWord(validSizes,2); + passed &= o.skipToNextLineAndCheckReferencesCount(2); + String secondReference = o.getSecondReference(); + + passed &= OutputFile.checkReferenceInClassicHeapdumpIsToObject(fileName, secondReference, "com/ibm/dump/tests/types/notpacked/NotPackedPrimitives"); + + return passed; + } +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest4ArrayOfPackedMixedOneRefChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest4ArrayOfPackedMixedOneRefChecker.java new file mode 100644 index 00000000000..71ece44fab5 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest4ArrayOfPackedMixedOneRefChecker.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.classic_heapdump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class ClassicHeapdumpTest4ArrayOfPackedMixedOneRefChecker { + + /** + * Check through the classic heapdump looking for the array of PackedMixed and check the length. + * Each PackedMixed object contains a reference to a non-packed object within it. + * When we iterate the references in the array we expect to see 10 references. These are in fact references + * to the non-packed objects that each PackedMixed contains, not to the PackedMixed objects themselves as + * would be the case for an array of non-packed objects. + * + * The expected output is similar to: + *
+    0x2EF486E8 [96] OBJ [Lcom/ibm/dump/tests/types/packed/PackedMixedOneRef;
+        0x2EF486E8 0x2EF488F8 0x2EF488C8 0x2EF48898 0x2EF48868 0x2EF48838 0x2EF48808 0x2EF487D8 0x2EF487A8 0x2EF48778 0x2EF48748 <-------------- one self-ref then 10 references to NotPackedPrimitives objects
+    0x2EF48748 [48] OBJ com/ibm/dump/tests/types/notpacked/NotPackedPrimitives
+      [blank line]
+		
+ * @throws IOException + */ + + public static boolean check(String fileName) throws IOException { + + String[] validSizes = { + "[96]", // on heap 32 + "[104]", // on heap 64cr + "[192]"}; // on heap 64 + + String objectLine = " OBJ com/ibm/dump/tests/types/packed/PackedMixedOneRef$Array"; + System.err.println("\nChecking the output for \"" + objectLine + "\""); + + OutputFile o = new OutputFile(fileName); + boolean passed = true; + + passed &= o.skipUnlimitedToLineContaining(objectLine); + passed &= o.linePassesCheckForStringsAtWord(validSizes,2); + passed &= o.skipToNextLineAndCheckReferencesCount(11); + String secondReference = o.getSecondReference(); + + passed &= OutputFile.checkReferenceInClassicHeapdumpIsToObject(fileName, secondReference, "com/ibm/dump/tests/types/notpacked/NotPackedPrimitives"); + + return passed; + } +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest5ArrayOfPackedMixedTwoRefsChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest5ArrayOfPackedMixedTwoRefsChecker.java new file mode 100644 index 00000000000..e830953e2fb --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest5ArrayOfPackedMixedTwoRefsChecker.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.classic_heapdump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class ClassicHeapdumpTest5ArrayOfPackedMixedTwoRefsChecker { + + + + /** + * Check through the classic heapdump looking for the array of PackedMixedTwoRefs and + * check the length. Also check the references. + * + * The essential point is that in the array we will see the references, not to the PackedMixedTwoRefs objects + * as we would if this were a normal array, but the references to the objects to which the PackedMixed objects point. + * Hence we expect to see 20 references, not 10. + * + * The expected output is similar to: + *
+    0x2EF48938 [136] OBJ [Lcom/ibm/dump/tests/types/packed/PackedMixedTwoRefs;
+        0x2EF48938 0x2EF48D20 [ ... 18 references removed for brevity ... ] 0x2EF489F0 <-------------------- one self-ref then 20 references to NotPackedPrimitives objects
+    0x2EF489C0 [48] OBJ com/ibm/dump/tests/types/notpacked/NotPackedPrimitives
+      [blank line]
+		
+ * @throws IOException + */ + + public static boolean check(String fileName) throws IOException { + + String[] validSizes = { + "[136]", // on heap 32 + "[144]", // on heap 64cr + "[272]"}; // on heap 64 + + String objectLine = " OBJ com/ibm/dump/tests/types/packed/PackedMixedTwoRefs$Array"; + System.err.println("\nChecking the output for \"" + objectLine + "\""); + + OutputFile o = new OutputFile(fileName); + boolean passed = true; + + passed &= o.skipUnlimitedToLineContaining(objectLine); + passed &= o.linePassesCheckForStringsAtWord(validSizes,2); + passed &= o.skipToNextLineAndCheckReferencesCount(21); + String secondReference = o.getSecondReference(); + + passed &= OutputFile.checkReferenceInClassicHeapdumpIsToObject(fileName, secondReference, "com/ibm/dump/tests/types/notpacked/NotPackedPrimitives"); + + return passed; + + } + + + + + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest6PackedMixedWithReferenceToSelfChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest6PackedMixedWithReferenceToSelfChecker.java new file mode 100644 index 00000000000..2ba459e95ab --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest6PackedMixedWithReferenceToSelfChecker.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.classic_heapdump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class ClassicHeapdumpTest6PackedMixedWithReferenceToSelfChecker { + + /** + * Check through the classic heapdump looking for the PackedMixedWithReferenceToSelf object, and check that it has two + * references to itself. + * + * The expected output is lines such as follows: + *
+    0x2EF48D80 [24] OBJ com/ibm/dump/tests/types/packed/PackedMixedWithReferenceToSelf
+        0x2EF48D80 0x2EF48D80
+		
+ * @throws IOException + */ + + public static boolean check(String fileName) throws IOException { + + + String[] validSizes = { + "[24]", // on heap 32 and 64cr + "[40]"}; // on heap 64 + + String objectLine = " OBJ com/ibm/dump/tests/types/packed/PackedMixedWithReferenceToSelf"; + System.err.println("\nChecking the output for \"" + objectLine + "\""); + + OutputFile o = new OutputFile(fileName); + boolean passed = true; + + passed &= o.skipUnlimitedToLineContaining(objectLine); + passed &= o.linePassesCheckForStringsAtWord(validSizes,2); + + passed &= o.skipToNextLineAndCheckReferencesCount(2); + + String firstReference = o.getFirstReference(); + passed &= OutputFile.checkReferenceInClassicHeapdumpIsToObject(fileName, firstReference, "com/ibm/dump/tests/types/packed/PackedMixedWithReferenceToSelf"); + + String secondReference = o.getSecondReference(); + passed &= OutputFile.checkReferenceInClassicHeapdumpIsToObject(fileName, secondReference, "com/ibm/dump/tests/types/packed/PackedMixedWithReferenceToSelf"); + + + return passed; + } +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest7NestedPackedChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest7NestedPackedChecker.java new file mode 100644 index 00000000000..527a7e32061 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest7NestedPackedChecker.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.classic_heapdump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class ClassicHeapdumpTest7NestedPackedChecker { + + /** + * Check through the classic heapdump looking for the NestedPacked object. + * + * The expected output is as follows: + *
+    0x2EF48DB8 [24] OBJ com/ibm/dump/tests/types/packed/NestedPacked <---------------------------------------- on-heap
+        0x2EF48DB8
+    0x2EF48DD0 [16] OBJ com/ibm/dump/tests/types/packed/NestedPacked <---------------------------------------- off-heap
+      [blank line]
+        
+ * @throws IOException + */ + + public static boolean check(String fileName) throws IOException { + String[] validSizes = { + "[24]", // on heap 32 + "[16]", // off heap 32 + "[32]", // on heap 64cr + "[16]", // off heap 64cr + "[40]", // on heap 64 + "[24]"}; // off heap 64 + + String objectLine = " OBJ com/ibm/dump/tests/types/packed/NestedPacked"; + System.err.println("\nChecking the output for \"" + objectLine + "\""); + + OutputFile o = new OutputFile(fileName); + boolean passed = true; + + passed &= o.skipUnlimitedToLineEnding(objectLine); + passed &= o.linePassesCheckForStringsAtWord(validSizes,2); + // the two instances can appear in either order, so cannot check number of refs +// passed &= o.skipToNextLineAndCheckReferencesCount(1); + + passed &= o.skipUnlimitedToLineEnding(objectLine); + passed &= o.linePassesCheckForStringsAtWord(validSizes,2); +// passed &= o.skipToNextLineAndCheckReferencesCount(0); + + return passed; + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest8PackedIntsArrayChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest8PackedIntsArrayChecker.java new file mode 100644 index 00000000000..08c05b0f0cd --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest8PackedIntsArrayChecker.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.classic_heapdump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class ClassicHeapdumpTest8PackedIntsArrayChecker { + + /** + * Check through the classic heapdump looking for the on and off heap PackedIntsArray objects. + * + * The expected output is as follows: + *
+0x2EF48FD8 [40] OBJ com/ibm/dump/tests/types/packed/PackedIntsArray
+	0x2EF48FD8 
+0x2EF49000 [16] OBJ com/ibm/dump/tests/types/packed/PackedIntsArray
+[blank line]
+		
+ * @throws IOException + */ + + public static boolean check(String fileName) throws IOException { + + String[] validSizes = { + "[40]", // on heap 32 + "[16]", // off heap 32 + "[48]", // on heap 64cr + "[16]", // off heap 64cr + "[56]", // on heap 64 + "[24]", // off heap 64 + }; + + String objectLine = " OBJ com/ibm/dump/tests/types/packed/PackedIntsArray"; + System.err.println("\nChecking the output for \"" + objectLine + "\""); + + OutputFile o = new OutputFile(fileName); + boolean passed = true; + + passed &= o.skipUnlimitedToLineEnding(objectLine); + passed &= o.linePassesCheckForStringsAtWord(validSizes,2); + passed &= o.skipToNextLineAndCheckReferencesCount(1); + + passed &= o.skipUnlimitedToLineEnding(objectLine); + passed &= o.linePassesCheckForStringsAtWord(validSizes,2); + passed &= o.skipToNextLineAndCheckReferencesCount(0); + + return passed; + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest9ArrayOfPackedMixedArrayElementChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest9ArrayOfPackedMixedArrayElementChecker.java new file mode 100644 index 00000000000..479c3b5cbc3 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/classic_heapdump_packed_objects/ClassicHeapdumpTest9ArrayOfPackedMixedArrayElementChecker.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.classic_heapdump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class ClassicHeapdumpTest9ArrayOfPackedMixedArrayElementChecker { + + /** + * Check through the classic heapdump looking for the derived object representing the + * element in the array of PackedMixedWithReferenceToSelf and + * check that it points back to the array. + * + * The expected output is as follows: + *
+0x2EF49020 [24] OBJ [Lcom/ibm/dump/tests/types/packed/PackedMixedWithReferenceToSelf;
+	0x2EF49020 0x2EF49038 
+0x2EF49038 [16] OBJ com/ibm/dump/tests/types/packed/PackedMixedWithReferenceToSelf
+	0x2EF49020  			
+        
+ * @throws IOException + */ + + public static boolean check(String fileName) throws IOException { + String[] validArraySizes = { + "[24]", // on heap 32 + "[32]", // on heap 64cr + "[48]"}; // on heap 64 + + String arrayLine = " OBJ com/ibm/dump/tests/types/packed/PackedMixedArrayElement$Array"; + System.err.println("\nChecking the output for \"" + arrayLine + "\""); + + OutputFile o = new OutputFile(fileName); + boolean passed = true; + + passed &= o.skipUnlimitedToLineContaining(arrayLine); + passed &= o.linePassesCheckForStringsAtWord(validArraySizes,2); + passed &= o.skipToNextLineAndCheckReferencesCount(2); + String secondReference = o.getSecondReference(); + + // check the array points to the element + passed &= OutputFile.checkReferenceInClassicHeapdumpIsToObject(fileName, secondReference, "com/ibm/dump/tests/types/packed/PackedMixedArrayElement"); + + + String[] validElementSizes = {"[16]","[24]"}; // on-heap 32 and 64cr, on-heap 64 + + String className = "com/ibm/dump/tests/types/packed/PackedMixedArrayElement"; + System.err.println("\nLooking for object at " + secondReference + " and checking that it is a PackedMixedArrayElement"); + + passed &= o.skipUnlimitedToLineContaining(secondReference); + passed &= o.linePassesCheckForStringAtWord(className,4); + passed &= o.linePassesCheckForStringsAtWord(validElementSizes,2); + passed &= o.skipToNextLineAndCheckReferencesCount(1); + secondReference = o.getFirstReference(); + + // check the element points to the array + passed &= OutputFile.checkReferenceInClassicHeapdumpIsToObject(fileName, secondReference, "com/ibm/dump/tests/types/packed/PackedMixedArrayElement$Array"); + + return passed; + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/commands/CheckCommandOutput.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/commands/CheckCommandOutput.java new file mode 100644 index 00000000000..eeebb838381 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/commands/CheckCommandOutput.java @@ -0,0 +1,263 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.commands; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * This is the main class to validate the command output from Jdmpview. + * Usage: + * java com.ibm.dump.tests.commands.CheckCommandOutput + *

+ * The is what we defined as the -outfile option when launching jdmpview. It is the result + * of executing commands in a command input file (defined as the -cmdfile option when launching Jdmpview). + *

+ * The defines what to check in the . + * Note: + * (1) The contains a list of command checking units. + * Each command checking unit contains 1 or more lines, the first line has to be the command line, followed + * by the checker lines. A command line always starts with "command :"; a checker line always starts "checker :". + * (2) The command checking unit has to be composed in the exact order as the commands in the command input file. + * (3) You can use "#" or "//" to start a comment line. Command line will be ignored by the file parser. + * (4) Empty lines (lines with only spaces) will be ignored by the file parser. + *

+ * Each checker line has to start with the full class name (including the package name). It can follow by its arguments (if any). + * The arguments details are defined by each checker itself. + *

+ * @author Manqing Li + * + */ +public class CheckCommandOutput { + private static final String PROMPT_FORMAT_DEFAULT = "> "; + + public static void main(String[] args) { + + if (args.length < 2) { + System.err.println("The command output file and the command checking file are required to check."); + System.exit(1); + } + + CheckCommandOutput checker = new CheckCommandOutput(); + List commandOutputs = null; + try { + commandOutputs = checker.readFile(args[0]); + } catch (FileNotFoundException e) { + System.err.println("Command output file " + args[0] + " not found."); + System.exit(1); + } catch (IOException e) { + System.err.println("Failed to read command output file " + args[0]); + System.exit(1); + } + + List commandChecker = null; + + try { + commandChecker = checker.readFile(args[1]); + } catch (FileNotFoundException e) { + System.err.println("Command checking file " + args[1] + " not found."); + System.exit(1); + } catch (IOException e) { + System.err.println("Failed to read command checking file " + args[1]); + System.exit(1); + } + + boolean passed = checker.check(commandOutputs, commandChecker); + if(passed) { + System.err.println("Tests passed."); + System.exit(0); + } else { + System.err.println("Tests failed."); + System.exit(1); + } + } + + private boolean check(List commandOutputs, List commandCheckerLines) { + boolean allTestsSucceeded = true; + List commandCheckingUnits = parseCheckers(commandCheckerLines); + if(commandCheckerLines == null || commandCheckerLines.size() == 0) { + System.err.println("Warning : no checkers are found.\n"); + return true; + } + OutputContentParser parser = new OutputContentParser(commandOutputs, PROMPT_FORMAT_DEFAULT + commandCheckingUnits.get(0).targetCommand); + for(int i = 0; i < commandCheckingUnits.size(); i++) { + CommandWithCheckers aCheckingUnit = commandCheckingUnits.get(i); + String nextCommand = null; + if( i < commandCheckingUnits.size() - 1) { + nextCommand = commandCheckingUnits.get(i + 1).targetCommand; + } + List output = parser.extractOutputLinesUntilTheStartOfNextCommand(aCheckingUnit.targetCommand, nextCommand); + + if(aCheckingUnit.hasCheckers()) { + System.err.println("Checking the output from command : " + aCheckingUnit.targetCommand); + if(aCheckingUnit.checking(output) == false) { + System.err.println("Tests failed."); + allTestsSucceeded = false; + } else { + System.err.println("Tests passed."); + } + } + } + return allTestsSucceeded; + } + + private static final Pattern CHECKER_LINE = Pattern.compile("\\s*//\\s*checker\\s*:\\s*(\\S+.*)", Pattern.CASE_INSENSITIVE + Pattern.DOTALL); + private List parseCheckers(List allLines) { + List result = new ArrayList(); + String tmpCommand = null; + List tmpCheckerLineList = new ArrayList(); + for(String line : allLines) { + if(line.trim().length() == 0) { + continue; + } + if(isCommentsLine(line)) { + Matcher matcher = CHECKER_LINE.matcher(line); + if(matcher.matches()) { + tmpCheckerLineList.add(matcher.group(1)); + } + } else { + if(tmpCommand != null) { + result.add(new CommandWithCheckers(tmpCommand, tmpCheckerLineList)); + } + tmpCommand = line; + tmpCheckerLineList = new ArrayList(); + } + } + if(tmpCommand != null) { + result.add(new CommandWithCheckers(tmpCommand, tmpCheckerLineList)); + } + + return result; + } + + private List readFile(String filePath) throws FileNotFoundException, IOException { + BufferedReader in = new BufferedReader(new FileReader(filePath)); + List result = new ArrayList(); + String line = null; + while((line = in.readLine()) != null) { + result.add(line); + } + in.close(); + return result; + } + + private boolean isCommentsLine(String line) { + return line.trim().startsWith("#") || line.trim().startsWith("//"); + } + + private class CommandWithCheckers { + public CommandWithCheckers(String targetCommand, List checkers) { + this.targetCommand = targetCommand; + this.checkingLines = (checkers == null ? new ArrayList() : checkers); + } + public boolean checking(List output) { + for(String line : checkingLines) { + line = line.trim(); + int index = StringUtils.getFirstTokenEndIndex(line); + String checkerClass = line.substring(0, index + 1); + try { + ICommandOutputChecker checkerObject = (ICommandOutputChecker)Class.forName(checkerClass).newInstance(); + + if(checkerObject.check(targetCommand, line.substring(index + 1).trim(), output) == false) { + System.err.println("The outputs are : "); + for(String outputLine : output) { + System.err.println("\t" + outputLine); + } + System.err.println("The checker is : "); + System.err.println("\t" + line); + return false; + } + } catch (IllegalAccessException e) { + e.printStackTrace(System.err); + System.err.println("Failed to create the checker " + checkerClass); + return false; + } catch (InstantiationException e) { + e.printStackTrace(System.err); + System.err.println("Failed to create the checker " + checkerClass); + return false; + } catch (ClassNotFoundException e) { + e.printStackTrace(System.err); + System.err.println("Failed to create the checker " + checkerClass); + return false; + } + } + return true; + } + + public boolean hasCheckers() { + return this.checkingLines.size() > 0; + } + + private String targetCommand; + private List checkingLines; + } + + private class OutputContentParser { + public OutputContentParser(List output, String startOfFirstCommand) { + this.output = output; + this.position = 0; + while(this.position < output.size() && startOfFirstCommand.trim().equals(output.get(position).trim()) == false) { + this.position++; + } + } + + public List extractOutputLinesUntilTheStartOfNextCommand(String command, String nextCommand) { + List result = new ArrayList(); + + if(position < output.size()) { + if(output.get(position).trim().equalsIgnoreCase(PROMPT_FORMAT_DEFAULT + command) == false) { + System.err.println("Failed to found the matching output for command " + command); + System.err.println("Tests failed."); + System.exit(1); + } + } + position++; + String commandInputLine = nextCommand == null ? null : PROMPT_FORMAT_DEFAULT + nextCommand; + while(position < output.size()) { + String line = output.get(position); + if(commandInputLine == null) { + // if the startOfNextCommand is null, then position == output.size() to exit the while loop. + result.add(line); + } else { + // if the startOfNextCommand is NOT null, then the position will point to the + //nextCommand to exit the while loop or it points to the end of the list. + if(commandInputLine.trim().equals(line.trim())) { + break; + } else { + result.add(line); + } + } + position++; + } + return result; + } + + private int position; + private List output; + } +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/commands/ContainingString.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/commands/ContainingString.java new file mode 100644 index 00000000000..6ee6461ebd5 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/commands/ContainingString.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.commands; + +import java.util.List; +/** + * This class is to check if the given string is contained in any of the output lines. + * Usage: + * com.ibm.dump.tests.commands.ContainingString [N] [-i] [-negate] + * Use N to check the Nth line only (N starts from 0!). + * Note, Use -1 to check the last line, and -N to check the Nth line from the last line. + * Use -i to ignore case. + * Use -negate to fail the test when the given string is contained in any of the output lines. + *

+ * @author Manqing Li + * + */ +public class ContainingString implements ICommandOutputChecker { + + public boolean check(String command, String args, List outputLines) { + boolean ignoreCase = false; + boolean negate = false; + int n = Integer.MAX_VALUE; + + args = args.trim(); + int tokenEndIndex = StringUtils.getFirstTokenEndIndex(args); + + while((tokenEndIndex = StringUtils.getFirstTokenEndIndex(args)) >= 0) { + String token = args.substring(0, tokenEndIndex + 1).trim(); + if(token.equals(ARG_IGNORE_CASE)) { + ignoreCase = true; + args = args.substring(tokenEndIndex + 1).trim(); + } else if (token.equals(ARG_NEGATE)) { + negate = true; + args = args.substring(tokenEndIndex + 1).trim(); + } else if(n == Integer.MAX_VALUE) { + try { + n = Integer.parseInt(token); + args = args.substring(tokenEndIndex + 1).trim(); + } catch (NumberFormatException e) { + break; + } + } else { + break; + } + } + + if(n != Integer.MAX_VALUE) { + if(n < 0) { + n = outputLines.size() + n; + } + if(n >= 0 && n < outputLines.size()) { + return StringUtils.contain(outputLines.get(n), args, ignoreCase) != negate; + } + return negate == false; + } + + if(StringUtils.containInAnyLines(outputLines, args, ignoreCase)) { + return negate == false; + } else { + return negate == true; + } + } + + private static final String ARG_IGNORE_CASE = "-i"; + private static final String ARG_NEGATE = "-negate"; +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/commands/CountingChars.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/commands/CountingChars.java new file mode 100644 index 00000000000..a7347e68c08 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/commands/CountingChars.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.commands; + +import java.util.List; +import java.util.StringTokenizer; +/** + * This class is to count how many characters in the output lines. + * Note, the leading spaces and tailing spaces will be trimmed for all lines + * before it starts counting. + * Usage: + * com.ibm.dump.tests.commands.CountingChars [] [max=] [min=] + *

+ * @author Manqing Li + * + */ +public class CountingChars implements ICommandOutputChecker { + + public boolean check(String command, String args, List output) { + int counter = count(output); + StringTokenizer st = new StringTokenizer(args); + while(st.hasMoreTokens()) { + String t = st.nextToken(); + int index = t.indexOf("="); + if(index > 0) { + String key = t.substring(0, index); + String value = t.substring(index + 1); + + if(MAX.equals(key)) { + if(counter > Integer.parseInt(value)) { + return false; + } + } else if(MIN.equals(key)) { + if(counter < Integer.parseInt(value)) { + return false; + } + } + } else if( counter != Integer.parseInt(t)) { + return false; + } + } + return true; + } + + private int count (List output) { + int counter = 0; + for(String line : output) { + counter += line.trim().length(); + } + return counter; + } + + private static final String MAX = "max"; + private static final String MIN = "min"; +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/commands/CountingLines.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/commands/CountingLines.java new file mode 100644 index 00000000000..9a393525a48 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/commands/CountingLines.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.commands; + +import java.util.List; +import java.util.StringTokenizer; + +/** + * This class is to count how many lines a command outputs. + * Usage: + * com.ibm.dump.tests.commands.CountingLines [] [max=] [min=] + *

+ * @author Manqing Li + * + */ +public class CountingLines implements ICommandOutputChecker { + + public boolean check(String command, String args, List output) { + int counter = count(output); + StringTokenizer st = new StringTokenizer(args); + while(st.hasMoreTokens()) { + String t = st.nextToken(); + int index = t.indexOf("="); + if(index > 0) { + String key = t.substring(0, index); + String value = t.substring(index + 1); + + if(MAX.equals(key)) { + if(counter > Integer.parseInt(value)) { + return false; + } + } else if(MIN.equals(key)) { + if(counter < Integer.parseInt(value)) { + return false; + } + } + } else if( counter != Integer.parseInt(t)) { + return false; + } + } + return true; + } + + private int count (List output) { + return output.size(); + } + + private static final String MAX = "max"; + private static final String MIN = "min"; +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/commands/ICommandOutputChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/commands/ICommandOutputChecker.java new file mode 100644 index 00000000000..a126d260f38 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/commands/ICommandOutputChecker.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.commands; + +import java.util.List; + +/** + * This is the interface all CommandOutputChecker has to implement. + * Note, if any constructors are implemented at all, the implementation class has to + * provide the default constructor (the one with no argument). + *

+ * @author Manqing Li + * + */ +public interface ICommandOutputChecker { + + /** + * To check the output. + *

+ * @param command The command string for this checker. Normally this is the class name (with package). + * @param args The arguments to this checker. + * @param outputLines The output lines to be checked. + *

+ * @return true if the checking was successful; false otherwise. + */ + public boolean check(String command, String args, List outputLines); +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/commands/StringUtils.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/commands/StringUtils.java new file mode 100644 index 00000000000..c856cc0abb7 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/commands/StringUtils.java @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.commands; + +import java.util.List; + +public class StringUtils { + + /** + * To get the first token end index. Note tokens are separated by spaces. + *

+ * @param line The string containing all tokens. + *

+ * @return The end index of the first token. + */ + public static int getFirstTokenEndIndex(String line) { + return getNextTokenEndIndex(0, line); + } + /** + * To get the next token end index. Note tokens are separated by spaces. + *

+ * @param startIndex The start index from where the first token is to be searched. + * @param line The string containing all tokens. + *

+ * @return The end index of the next token. + */ + public static int getNextTokenEndIndex(int startIndex, String line) { + int index = startIndex; + + // move over to the first no space char. + for(; index < line.length(); index++) { + if(" \t\n\r\f".indexOf(line.charAt(index)) < 0) { + break; + } + } + + // find the first non-space char or the end of the line. + while(index < line.length()) { + if(" \t\n\r\f".indexOf(line.charAt(index)) >= 0) { + return index - 1; + } + if(index == line.length() - 1) { + return index; + } else { + index++; + } + } + return -1; + } + + /** + * To check if any line in the list contains a special string. + *

+ * @param allLines All the lines. + * @param strToSearch The string to look for. + * @param ignoreCase Indicating whether the comparison should ignore case. + *

+ * @return true if any of the line contains the string to be searched; + * false otherwise. + */ + public static boolean containInAnyLines(List allLines, String strToSearch, boolean ignoreCase) { + + for(String line : allLines) { + if(ignoreCase) { + if(line.toLowerCase().contains(strToSearch.toLowerCase())) { + return true; + } + } else { + if(line.contains(strToSearch)) { + return true; + } + } + } + return false; + } + + /** + * To check if any line in the list contains a special string. + *

+ * @param str The string to be searched on. + * @param strToSearch The string to look for. + * @param ignoreCase Indicating whether the comparison should ignore case. + *

+ * @return true if string contains the string to be searched; + * false otherwise. + */ + public static boolean contain(String str, String strToSearch, boolean ignoreCase) { + + if(ignoreCase) { + if(str.toLowerCase().contains(strToSearch.toLowerCase())) { + return true; + } + } else { + if(str.contains(strToSearch)) { + return true; + } + } + return false; + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/excessive_gc/HeapAllocation.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/excessive_gc/HeapAllocation.java new file mode 100644 index 00000000000..ce3ecfbec0f --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/excessive_gc/HeapAllocation.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.excessive_gc; + +import sun.misc.*; +import java.util.*; + +public class HeapAllocation { + + static Hashtable globalTable = new Hashtable(); + + public static void main(String args[]) { + // Takes 2 parameters - integer numbers of threads and objects + int nThreads=1,nObjects=100000; + + if (args != null && args.length == 2) { + try { + nThreads = Integer.parseInt(args[0]); + nObjects = Integer.parseInt(args[1]); + } catch (NumberFormatException nfe){ + System.out.println("Test program HeapAllocation.main() - bad parameter(s)"); + return; + } + } + + Object[] objects = new Object[nThreads]; + for (int i=0; i threadNums = new ArrayList(); + List threadNames = new ArrayList(); + while(true) { + if( line.startsWith("2LKDEADLOCKTHR") ) { + String threadName = getQuotedThreadName(line); + int threadNo = getThreadNumber(threadName); + threadNames.add(threadName); + threadNums.add(threadNo); + } + if( line.startsWith("NULL")) { + break; // Check we have a valid cycle outside this loop. + } + line = in.readLine(); + } + // The threads should all be in a cycle waiting on each other in order. + // Validate they are all the same kind of thread and the numbers are in order. + int currentThread = threadNums.get(0); + int firstThread = currentThread; + String currentName = threadNames.get(0); + String firstName = currentName; + String threadPrefix = currentName.substring( 0, currentName.indexOf("##")).trim(); + // Length of the deadlock chain is (threadNums.size() - 1) since the first thread repeats to complete the chain. + System.err.println("Checking deadlock chain for \"" + threadPrefix + "\" threads that is " + (threadNums.size() - 1) + " threads long"); + for( int i = 1; i < threadNums.size(); i++ ) { + int nextThread = threadNums.get(i); + String nextThreadName = threadNames.get(i); + if( nextThread != currentThread + 1 && nextThread != 0 ) { + System.err.println("Threads out of order: " + threadNames.get(i) + " after " + currentThread ); + passed &= false; + break; + } + if( !nextThreadName.startsWith(threadPrefix)) { + System.err.println("Wrong thread type: " + threadNames.get(i) + " does not start with " + currentThread ); + passed &= false; + break; + } + currentThread = nextThread; + currentName = nextThreadName; + } + if( firstThread == currentThread ) { + System.err.println("Complete thread cycle found, confirmed deadlock for " + threadPrefix + " threads" ); + } + System.err.println("------------"); + + } + } catch (IOException e) { + System.err.println("Error reading javacore file."); + System.exit(1); + } + if( deadlockCount == expectedDeadlocks ) { + passed &= true; + } + + return passed; + } + + /** + * Given a string, returns the contents of the first quoted string. + * (Which in java cores is generally the thread name. + * @param line + * @return + */ + public static String getQuotedThreadName(String line) { + // Pull the thread name out of a line that looks like: + // 3XMTHREADINFO "main" J9VMThread:0x00129100, j9thread_t:0x002B5A30, java/lang/Thread:0x00DDC4F8, state:R, prio=5 + // There are threads that don't have quotes, but they aren't Java threads so we aren't + // interested here. + int openQuote = -1; + int closeQuote = -1; + openQuote = line.indexOf('"'); + closeQuote = line.indexOf('"', openQuote + 1); + if( openQuote > -1 && closeQuote > -1 ) { + String threadName = line.substring(openQuote + 1, closeQuote); + return threadName; + } else { + return null; + } + } + + public static int getThreadNumber(String threadName) { + // Pull the thread number out of a name that looks like: + // Deadlock Thread ##6## + int openQuote = -1; + int closeQuote = -1; + openQuote = threadName.indexOf("##"); + closeQuote = threadName.indexOf("##", openQuote + 1); + if( openQuote > -1 && closeQuote > -1 ) { + String threadNo_string = threadName.substring(openQuote + 2, closeQuote); + int threadNo = Integer.parseInt(threadNo_string); + return threadNo; + } else { + return Integer.MIN_VALUE; + } + } +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_deadlock/CheckJdmpviewDeadlock.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_deadlock/CheckJdmpviewDeadlock.java new file mode 100644 index 00000000000..cda59c64288 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_deadlock/CheckJdmpviewDeadlock.java @@ -0,0 +1,177 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.javacore_deadlock; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * This class check a javacore for a few pre-setup deadlock cycles. + * + * @author hhellyer + * + */ +public class CheckJdmpviewDeadlock { + + /** + * @param args + */ + public static void main(String[] args) { + + if (args.length < 1) { + System.err.println("An input file is required to check."); + System.exit(1); + } + String fileName = args[0]; + + BufferedReader in = null; + try { + in = new BufferedReader(new FileReader(fileName)); + } catch (FileNotFoundException e) { + System.err.println("File: " + fileName + " not found."); + System.exit(1); + } + if (in == null) { + System.err.println("Failed to open file: " + fileName); + System.exit(1); + } + + boolean passed = true; + + passed &= checkDeadlockSection(in); + + if( passed ) { + System.err.println("Test passed."); + System.exit(0); + } else { + System.err.println("Test failed."); + System.exit(1); + } + } + + private static boolean checkDeadlockSection(BufferedReader in) { + String line; + boolean passed = true; + int deadlockCount = 0; + final int expectedDeadlocks = 3; + + // Fast forward to "deadlock loop:" + // (Fail if we don't find it.) + try { + line = readLine(in); + while( line != null ) { + while (line != null && !line.startsWith("deadlock loop:") && deadlockCount < expectedDeadlocks) { + line = readLine(in); + } + if( line == null ) { + System.err.println("Null line"); + passed = false; + break; + } + if( deadlockCount == expectedDeadlocks ) { + break; + } + deadlockCount++; + System.err.println("Found a deadlock, line: " + line); + line = readLine(in); + // Now validate the deadlock is reported correctly. + List threadNums = new ArrayList(); + List threadNames = new ArrayList(); + while(true) { + if( line.startsWith("thread: ") ) { + String threadName = line.substring(line.indexOf("thread: ") + "thread: ".length(), line.indexOf("id: ")); + int threadNo = getThreadNumber(threadName); + threadNames.add(threadName); + threadNums.add(threadNo); + } else { + break; // Check we have a valid cycle outside this loop. + } + line = readLine(in); + } + // The threads should all be in a cycle waiting on each other in order. + // Validate they are all the same kind of thread and the numbers are in order. + int currentThread = threadNums.get(0); + int firstThread = currentThread; + String currentName = threadNames.get(0); + String firstName = currentName; + String threadPrefix = currentName.substring( 0, currentName.indexOf("##")).trim(); + // Length of the deadlock chain is (threadNums.size() - 1) since the first thread repeats to complete the chain. + System.err.println("Checking deadlock chain for \"" + threadPrefix + "\" threads that is " + (threadNums.size() - 1) + " threads long"); + for( int i = 1; i < threadNums.size(); i++ ) { + int nextThread = threadNums.get(i); + String nextThreadName = threadNames.get(i); + if( nextThread != currentThread + 1 && nextThread != 0 ) { + System.err.println("Threads out of order: " + threadNames.get(i) + " after " + currentThread ); + passed &= false; + break; + } + if( !nextThreadName.startsWith(threadPrefix)) { + System.err.println("Wrong thread type: " + threadNames.get(i) + " does not start with " + currentThread ); + passed &= false; + break; + } + currentThread = nextThread; + currentName = nextThreadName; + } + if( firstThread == currentThread ) { + System.err.println("Complete thread cycle found, confirmed deadlock for " + threadPrefix + " threads" ); + } + System.err.println("------------"); + + } + } catch (IOException e) { + System.err.println("Error reading javacore file."); + System.exit(1); + } + if( deadlockCount == expectedDeadlocks ) { + passed &= true; + } + + return passed; + } + + // Wrap this up as it's worth trimming the whitespace off the start of each jdmpview line. + private static String readLine(BufferedReader in) throws IOException { + String line = in.readLine(); + return line!=null?line.trim():null; + } + + public static int getThreadNumber(String threadName) { + // Pull the thread number out of a name that looks like: + // Deadlock Thread ##6## + int openQuote = -1; + int closeQuote = -1; + openQuote = threadName.indexOf("##"); + closeQuote = threadName.indexOf("##", openQuote + 1); + if( openQuote > -1 && closeQuote > -1 ) { + String threadNo_string = threadName.substring(openQuote + 2, closeQuote); + int threadNo = Integer.parseInt(threadNo_string); + return threadNo; + } else { + return Integer.MIN_VALUE; + } + } +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_deadlock/CreateJavaCore.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_deadlock/CreateJavaCore.java new file mode 100644 index 00000000000..5cf20f05702 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_deadlock/CreateJavaCore.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.javacore_deadlock; + +import java.lang.Thread.State; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.LockSupport; +import java.util.concurrent.locks.ReentrantLock; + +public class CreateJavaCore { + + private static DeadlockCreator[] deadlockCreators = { new Deadlock(), new JUCDeadlock(), new MixedDeadlock()}; + + /** + * @param args + */ + public static void main(String[] args) { + + boolean generateSystemCore = false; + if( args.length > 0 && args[0].equals("-core") ) { + // Only generate system core if that's what we're testing to save space. + // (We might as well always generate a javacore, they aren't big and would + // be useful for debugging problems with the core tests.) + generateSystemCore = true; + } + + for( DeadlockCreator d: deadlockCreators ) { + // Even numbers only, otherwise the mixed deadlock creator won't work. + d.createDeadlockCycle(10); + } + + com.ibm.jvm.Dump.JavaDump(); + if( generateSystemCore ) { + com.ibm.jvm.Dump.SystemDump(); + } + // We've deliberately deadlocked a bunch of threads. + // Don't wait for them before quitting. + System.exit(0); + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_deadlock/Deadlock.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_deadlock/Deadlock.java new file mode 100644 index 00000000000..9c7fd5a7f1f --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_deadlock/Deadlock.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/package com.ibm.dump.tests.javacore_deadlock; + +import java.lang.Thread.State; + +public class Deadlock implements DeadlockCreator { + + /** + * Create a chain of deadlocked threads. + */ + public void createDeadlockCycle(int threadCount) { + Thread[] threads = new Thread[threadCount]; + + LockObject[] locks = new LockObject[threadCount]; + for( int i = 0; i < threadCount; i++ ) { + locks[i] = new LockObject(); + } + + for( int i = 0; i < threadCount; i++ ) { + threads[i] = new Thread(new DeadlockThread(locks[i%threadCount], locks[(i+1)%threadCount])); + threads[i].setName("Deadlock Thread ##" + i + "##"); + } + + for( int i = 0; i < threadCount; i++ ) { + threads[i].start(); + } + + boolean deadlocked = false; + while(!deadlocked) { + deadlocked = true; + for( int i = 0; i < threads.length; i++ ) { + deadlocked &= threads[i].getState() == State.BLOCKED; + } + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + } + System.err.println(this.getClass().getSimpleName() + ": Should be able to take dump now, threads should be deadlocked."); + } + + private static class LockObject { + public volatile boolean taken = false; + } + + private static class DeadlockThread implements Runnable { + + LockObject prev; + LockObject next; + + public DeadlockThread(LockObject lastLock, LockObject nextLock ) { + prev = lastLock; + next = nextLock; + } + + public void run() { + synchronized (prev) { + prev.taken = true; + System.out.println("Thread " + Thread.currentThread().getName() + " has last lock"); + while( next.taken == false ) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + System.out.println("Thread " + Thread.currentThread().getName() + " attempting to get second lock"); + synchronized (next) { + next.taken = true; + System.out.println("Thread " + Thread.currentThread().getName() + " has both locks"); + } + } + } + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_deadlock/DeadlockCreator.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_deadlock/DeadlockCreator.java new file mode 100644 index 00000000000..1b151a96593 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_deadlock/DeadlockCreator.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.javacore_deadlock; + +public interface DeadlockCreator { + + /** + * Creates a group of threads and gets them into a deadlocked state + * before returning. (When the method returns the threads should be + * started and deadlocked.) + * @param threads the number of threads to start in the cycle. + */ + public void createDeadlockCycle(int threads); + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_deadlock/JUCDeadlock.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_deadlock/JUCDeadlock.java new file mode 100644 index 00000000000..bdbc4e8f54e --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_deadlock/JUCDeadlock.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.javacore_deadlock; + +import java.lang.Thread.State; +import java.util.concurrent.locks.ReentrantLock; + +public class JUCDeadlock implements DeadlockCreator { + + final static int DEFAULT_THREADS = 10; + + /** + * Create a chain of deadlocked threads. + * @param args + */ + public void createDeadlockCycle(int threadCount) { + Thread[] threads = new Thread[threadCount]; + + ReentrantLock[] locks = new ReentrantLock[threadCount]; + for( int i = 0; i < threadCount; i++ ) { + locks[i] = new ReentrantLock(); + } + + for( int i = 0; i < threadCount; i++ ) { + threads[i] = new Thread(new DeadlockThread(locks[i%threadCount], locks[(i+1)%threadCount])); + threads[i].setName("java.util.concurrent Deadlock Thread ##" + i + "##"); + } + + for( int i = 0; i < threadCount; i++ ) { + threads[i].start(); + } + + boolean deadlocked = false; + while(!deadlocked) { + deadlocked = true; + for( int i = 0; i < locks.length; i++ ) { + deadlocked &= locks[i].isLocked(); + } + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + } + System.err.println(this.getClass().getSimpleName() + ": Should be able to take dump now, threads should be deadlocked."); + } + + private static class LockObject { + public volatile boolean taken = false; + } + + private static class DeadlockThread implements Runnable { + + ReentrantLock prev; + ReentrantLock next; + + public DeadlockThread(ReentrantLock lastLock, ReentrantLock nextLock ) { + prev = lastLock; + next = nextLock; + } + + public void run() { + prev.lock(); + try { + System.out.println("Thread " + Thread.currentThread().getName() + " has last lock"); + while( next.isLocked() == false ) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + System.out.println("Thread " + Thread.currentThread().getName() + " attempting to get second lock"); + next.lock(); + try { + System.out.println("Thread " + Thread.currentThread().getName() + " has both locks"); + } finally { + next.unlock(); + } + } finally { + prev.unlock(); + } + } + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_deadlock/MixedDeadlock.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_deadlock/MixedDeadlock.java new file mode 100644 index 00000000000..02d485158e9 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_deadlock/MixedDeadlock.java @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.javacore_deadlock; + +import java.lang.Thread.State; +import java.util.concurrent.locks.ReentrantLock; + +public class MixedDeadlock implements DeadlockCreator { + + final static int DEFAULT_THREADS = 10; + + /** + * Create a chain of deadlocked threads. + * @param args + */ + public void createDeadlockCycle(int threadCount) { + int lockCount = threadCount / 2; + Thread[] threads = new Thread[threadCount]; + + ReentrantLock[] jucLocks = new ReentrantLock[threadCount]; + for( int i = 0; i < lockCount; i++ ) { + jucLocks[i] = new ReentrantLock(); + } + LockObject[] objectLocks = new LockObject[threadCount]; + for( int i = 0; i < lockCount; i++ ) { + objectLocks[i] = new LockObject(); + } + + for( int i = 0; i < threadCount; i++ ) { + if( (i % 2) == 0 ) { + threads[i] = new Thread(new DeadlockThreadEven(jucLocks[i%lockCount], objectLocks[(i+1)%lockCount])); + } else { + threads[i] = new Thread(new DeadlockThreadOdd(objectLocks[i%lockCount], jucLocks[(i+1)%lockCount])); + } + threads[i].setName("Mixed Deadlock Thread ##" + i + "##"); + } + + for( int i = 0; i < threadCount; i++ ) { + threads[i].start(); + } + + boolean deadlocked = false; + while(!deadlocked) { + deadlocked = true; + for( int i = 0; i < threads.length; i++ ) { + if( i % 2 == 0 ) { + deadlocked &= threads[i].getState() == State.BLOCKED; + } else { + deadlocked &= jucLocks[i%lockCount].isLocked(); + } + } + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + } + System.err.println(this.getClass().getSimpleName() + ": Should be able to take dump now, threads should be deadlocked."); + } + + private static class LockObject { + public volatile boolean taken = false; + } + + private static class DeadlockThreadEven implements Runnable { + + ReentrantLock prev; + LockObject next; + + public DeadlockThreadEven(ReentrantLock lastLock, LockObject nextLock ) { + prev = lastLock; + next = nextLock; + } + + public void run() { + prev.lock(); + try { + System.out.println("Thread: " + Thread.currentThread().getName() + " has last lock"); + while( next.taken == false ) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + System.out.println("Thread: " + Thread.currentThread().getName() + " attempting to get second lock"); + synchronized (next) { + next.taken = true; + System.out.println("Thread: " + Thread.currentThread().getName() + " has both locks"); + } + } finally { + prev.unlock(); + } + } + } + + private static class DeadlockThreadOdd implements Runnable { + + LockObject prev; + ReentrantLock next; + + public DeadlockThreadOdd(LockObject lastLock, ReentrantLock nextLock ) { + prev = lastLock; + next = nextLock; + } + + public void run() { + synchronized(prev) { + prev.taken = true; + System.out.println("Thread " + Thread.currentThread().getName() + " has last lock"); + while( next.isLocked() == false ) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + System.out.println("Thread " + Thread.currentThread().getName() + " attempting to get second lock"); + next.lock(); + try { + System.out.println("Thread " + Thread.currentThread().getName() + " has both locks"); + } finally { + next.unlock(); + } + } + } + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_lock_context/CheckJavaCore.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_lock_context/CheckJavaCore.java new file mode 100644 index 00000000000..e58e5b1e3cb --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_lock_context/CheckJavaCore.java @@ -0,0 +1,198 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.javacore_lock_context; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.Map; +import java.util.Stack; + +/** + * This class check a javacore for a few pre-setup deadlock cycles. + * + * @author hhellyer + * + */ +public class CheckJavaCore { + + /** + * @param args + */ + public static void main(String[] args) { + + if (args.length < 1) { + System.err.println("An input javacore is required to check."); + System.exit(1); + } + String fileName = args[0]; + + BufferedReader in = null; + try { + in = new BufferedReader(new FileReader(fileName)); + } catch (FileNotFoundException e) { + System.err.println("File: " + fileName + " not found."); + System.exit(1); + } + if (in == null) { + System.err.println("Failed to open file: " + fileName); + System.exit(1); + } + + // We get the expected results by re-running the threads. + CreateJavaCore.setupThreads(); + + boolean passed = true; + + passed &= checkThreadSection(in); + + if( passed ) { + System.err.println("Test passed."); + System.exit(0); + } else { + System.err.println("Test failed."); + System.exit(1); + } + } + + private static boolean checkThreadSection(BufferedReader in) { + String line; + boolean passed = true; + + Map threadsToEntries = CreateJavaCore.threadsToEntries; + final int threadsToCheck = threadsToEntries.size(); + int threadsChecked = 0; + + // Fast forward to 1XMTHDINFO Thread Details + // (Fail if we don't find it.) + try { + line = in.readLine(); + while( line != null ) { + // Look for "3XMTHREADINFO " (with space) so we don't match "3XMTHREADINFO1 2 or 3" + while (line != null && !line.startsWith("3XMTHREADINFO ")) { + line = in.readLine(); + } + if( line == null ) { + System.err.println("Null line"); + passed = false; + break; + } + + String threadName = getQuotedThreadName(line); + line = in.readLine(); + StackCreator stackCreator = threadsToEntries.get(threadName); + if( stackCreator == null ) { + // Not one of our threads, skip this one. + continue; + } + System.err.println("Checking " + threadName); + Stack entryStack = new Stack(); + entryStack.addAll(stackCreator.getEntryRecords()); + EntryRecord nextEntry = entryStack.pop(); + // Walk the thread stack until we get to the end, look for "NULL" + while (line != null && !line.startsWith("NULL")) { + if( line != null && nextEntry != null && line.startsWith("4XESTACKTRACE") && line.contains(nextEntry.getMethodName() )) { + // Get the method name, see if it's the next one we are looking for. + // (Not all entries in the stack will have entry records.) + // System.err.println("Found: " + line + " looking for " + nextEntry.getMethodName()); + + // Next line should contain an entry record, read and check. + line = in.readLine(); + while( line.startsWith("5XESTACKTRACE")) { + if( !line.startsWith("5XESTACKTRACE (entered lock: " + nextEntry.getLockName())) { + System.err.println("Fail - Didn't find entry record for " + nextEntry.getMethodName()); + System.err.println("Expected: 5XESTACKTRACE (entered lock: " + nextEntry.getLockName()); + // System.err.println("Line: " + line); + } else if( !line.contains("entry count: " + nextEntry.getEntryCount() + ")")) { + System.err.println("Fail - Didn't find expected enter count " + "entry count: " + nextEntry.getEntryCount() + ")"); + // System.err.println("Line: " + line); + } else { + // System.err.println("Found expected entry."); + } + nextEntry = entryStack.isEmpty()?null:entryStack.pop(); + line = in.readLine(); + } + } else { + line = in.readLine(); + } + } + threadsChecked++; + if( !entryStack.isEmpty() ) { + System.err.println("Failed to find all lock entry records for " + threadName); + passed = false; + } else { + System.err.println("Found correct lock entry records for " + threadName); + } + System.err.println("------------"); + if( threadsChecked == threadsToCheck ) { + break; // Finished. (There will be other threads but we are only interested in ours.) + } + + } + } catch (IOException e) { + System.err.println("Error reading javacore file."); + System.exit(1); + } + + return passed; + } + + /** + * Given a string, returns the contents of the first quoted string. + * (Which in java cores is generally the thread name. + * @param line + * @return + */ + public static String getQuotedThreadName(String line) { + // Pull the thread name out of a line that looks like: + // 3XMTHREADINFO "main" J9VMThread:0x00129100, j9thread_t:0x002B5A30, java/lang/Thread:0x00DDC4F8, state:R, prio=5 + // There are threads that don't have quotes, but they aren't Java threads so we aren't + // interested here. + int openQuote = -1; + int closeQuote = -1; + openQuote = line.indexOf('"'); + closeQuote = line.indexOf('"', openQuote + 1); + if( openQuote > -1 && closeQuote > -1 ) { + String threadName = line.substring(openQuote + 1, closeQuote); + return threadName; + } else { + return null; + } + } + + public static int getThreadNumber(String threadName) { + // Pull the thread number out of a name that looks like: + // Deadlock Thread ##6## + int openQuote = -1; + int closeQuote = -1; + openQuote = threadName.indexOf("##"); + closeQuote = threadName.indexOf("##", openQuote + 1); + if( openQuote > -1 && closeQuote > -1 ) { + String threadNo_string = threadName.substring(openQuote + 2, closeQuote); + int threadNo = Integer.parseInt(threadNo_string); + return threadNo; + } else { + return Integer.MIN_VALUE; + } + } +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_lock_context/CreateJavaCore.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_lock_context/CreateJavaCore.java new file mode 100644 index 00000000000..63a038110ba --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_lock_context/CreateJavaCore.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.javacore_lock_context; + +import java.util.HashMap; +import java.util.Map; + +/** + * Lock context checks: + * + * Enter a lock. Check we enter expected lock in expected method. + * + * Enter a lock twice. Check lock count incremented twice. + * + * Enter a lock n times going down a stack. Check highest entry count matches + * entry count in monitor section. + * + * Enter n different locks in 1 frame. Check correct number of entries take + * place. + * + * Enter 3 different locks, twice, in mixed up order. Check only 1 record per + * lock. e.g sync(a), sync(b), sync(c), sync(a), sync(b), sync(c) + * + * @author hhellyer + * + */ +public class CreateJavaCore { + + private static StackCreator[] stackCreator = { new SimpleEnter(), new EnterTwice(), new EnterInStack(), new EnterInSequence() }; + + protected static Map threadsToEntries = new HashMap(); + + /** + * @param args + */ + public static void main(String[] args) { + + boolean generateSystemCore = false; + if( args.length > 0 && args[0].equals("-core") ) { + // Only generate system core if that's what we're testing to save space. + // (We might as well always generate a javacore, they aren't big and would + // be useful for debugging problems with the core tests.) + generateSystemCore = true; + } + + setupThreads(); + + com.ibm.jvm.Dump.JavaDump(); + if( generateSystemCore ) { + com.ibm.jvm.Dump.SystemDump(); + } + // We've deliberately deadlocked a bunch of threads. + // Don't wait for them before quitting. + System.exit(0); + } + + public static void setupThreads() { + for( StackCreator s: stackCreator ) { + Thread t = new Thread( s ); + t.start(); + threadsToEntries.put( s.getClass().getSimpleName() + " Thread", s); + } + boolean ready = false; + while( !ready ) { + ready = true; + for( StackCreator s: stackCreator ) { + ready &= s.isReady(); + } + } + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_lock_context/EnterInSequence.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_lock_context/EnterInSequence.java new file mode 100644 index 00000000000..f44c468eeff --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_lock_context/EnterInSequence.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.javacore_lock_context; + + +public class EnterInSequence extends StackCreator { + + private boolean ready = false; + + private class LockA {} + private class LockB {} + private class LockC {} + + private LockA lockA = new LockA(); + private LockB lockB = new LockB(); + private LockC lockC = new LockC(); + + @Override + public void run() { + Thread.currentThread().setName(this.getClass().getSimpleName() + " Thread"); + enterMethod(); + } + + private void enterMethod() { + + // A silly sequence of locking to confirm we only get one enter record (counting 2 enters) + // for each of these locks. + synchronized (lockA) { + synchronized (lockB) { + synchronized (lockC) { + synchronized (lockA) { + synchronized (lockB) { + synchronized (lockC) { + try { + entryRecords.add(new EntryRecord(lockA.getClass().getName(), 2)); + entryRecords.add(new EntryRecord(lockB.getClass().getName(), 2)); + entryRecords.add(new EntryRecord(lockC.getClass().getName(), 2)); + ready = true; // We have taken our own lock. + Thread.sleep(1000*60*60); // Sleep for an hour. (The test will exit before then.) + } catch (InterruptedException e) { + } + } + } + } + } + } + } + } + + @Override + public boolean isReady() { + return ready; + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_lock_context/EnterInStack.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_lock_context/EnterInStack.java new file mode 100644 index 00000000000..2599f453a97 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_lock_context/EnterInStack.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.javacore_lock_context; + +public class EnterInStack extends StackCreator { + + private boolean ready = false; + + private class Lock {} + + Lock lock = new Lock(); + + private static final int stackDepth = 10; + + @Override + public void run() { + Thread.currentThread().setName(this.getClass().getSimpleName() + " Thread"); + enterMethod(stackDepth); + } + + private void enterMethod(int depth) { + try { + synchronized (lock) { + entryRecords.add(new EntryRecord(lock.getClass().getName(), stackDepth - depth + 1)); + if( depth <= 1 ) { + ready = true; // We have taken our own lock. + Thread.sleep(1000*60*60); // Sleep for an hour. (The test will exit before then.) + } else { + enterMethod(depth - 1); + } + } + } catch (InterruptedException e) { + } + } + + @Override + public boolean isReady() { + return ready; + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_lock_context/EnterTwice.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_lock_context/EnterTwice.java new file mode 100644 index 00000000000..52484e9f248 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_lock_context/EnterTwice.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.javacore_lock_context; + +public class EnterTwice extends StackCreator { + + private boolean ready = false; + + private class Lock {} + + Lock lock = new Lock(); + + @Override + public void run() { + Thread.currentThread().setName(this.getClass().getSimpleName() + " Thread"); + enterMethod(); + } + + private void enterMethod() { + synchronized (lock) { + try { + synchronized (lock) { + entryRecords.add(new EntryRecord(lock.getClass().getName(), 2)); + ready = true; // We have taken our own lock. + Thread.sleep(1000*60*60); // Sleep for an hour. (The test will exit before then.) + } + } catch (InterruptedException e) { + } + } + } + + @Override + public boolean isReady() { + return ready; + } + + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_lock_context/EntryRecord.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_lock_context/EntryRecord.java new file mode 100644 index 00000000000..a387a32bb3f --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_lock_context/EntryRecord.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.javacore_lock_context; + +/** + * Class to hold the *expected* entry records we expect to find in the javacore. + * + * @author hhellyer + * + */ +public class EntryRecord { + + private int entryCount; + private StackTraceElement stackEntry; + private String lockName; + + public EntryRecord( String lockName, int entryCount ) { + this.entryCount = entryCount; + this.lockName = lockName.replace('.', '/');; + // Get the stack frame for the calling method. + // (Yes this is evil, this is just a testcase.) + this.stackEntry = (new Throwable()).getStackTrace()[1]; + } + + public String getMethodName() { + String className = stackEntry.getClassName().replace('.', '/'); + return className + "." +stackEntry.getMethodName(); + } + + public String getLockName() { + return lockName; + } + + public int getEntryCount() { + return entryCount; + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_lock_context/SimpleEnter.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_lock_context/SimpleEnter.java new file mode 100644 index 00000000000..9ffbbf1eb42 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_lock_context/SimpleEnter.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.javacore_lock_context; + +public class SimpleEnter extends StackCreator { + + private boolean ready = false; + + @Override + public void run() { + Thread.currentThread().setName(this.getClass().getSimpleName() + " Thread"); + synchronziedMethod(); + } + + private synchronized void synchronziedMethod() { + + try { + entryRecords.add(new EntryRecord(this.getClass().getName(), 1)); + ready = true; // We have taken our own lock. + Thread.sleep(1000*60*60); // Sleep for an hour. (The test will exit before then.) + } catch (InterruptedException e) { + } + } + + @Override + public boolean isReady() { + return ready; + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_lock_context/StackCreator.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_lock_context/StackCreator.java new file mode 100644 index 00000000000..2f0df8b2e5a --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_lock_context/StackCreator.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.javacore_lock_context; + +import java.util.ArrayList; +import java.util.List; + +public abstract class StackCreator implements Runnable { + + public abstract boolean isReady(); + + protected List entryRecords = new ArrayList(); + + public List getEntryRecords() { + return entryRecords; + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_meminfo/ValidateMemInfo.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_meminfo/ValidateMemInfo.java new file mode 100644 index 00000000000..cba23ac6dcf --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_meminfo/ValidateMemInfo.java @@ -0,0 +1,268 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.javacore_meminfo; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; + +/** + * Test application that reads a javacore and validates the MEMINFO section against !dumpallsegments + * debug extension output from a core file read by jdmpview. + * + * Usage: + * java com.ibm.memorycategories.ValidateMeminfo + * + * @author Richard Chamberlain + * + */ +public class ValidateMemInfo { + + /** + * main() + * + * @param args - javacore and jdmpview !dumpallsegments output + */ + public static void main(String[] args) { + + if (args.length < 2) { + System.err.println("Input javacore and jdmpview !dumpallsegments files are required."); + System.exit(1); + } + String javacoreFile = args[0]; + String jdmpviewFile = args[1]; + + BufferedReader in1 = null; + BufferedReader in2 = null; + try { + in1 = new BufferedReader(new FileReader(javacoreFile)); + in2 = new BufferedReader(new FileReader(jdmpviewFile)); + } catch (FileNotFoundException e) { + System.err.println("File not found"); + e.printStackTrace(); + System.exit(1); + } + if (in1 == null) { + System.err.println("Failed to open javacore file"); + System.exit(1); + } + if (in2 == null) { + System.err.println("Failed to open jdmpview !dumpallsegments file"); + System.exit(1); + } + + boolean rc = compareMemInfo(in1, in2); + + if (rc == true) { + System.err.println("Test passed."); + System.exit(0); + } else { + System.err.println("Test failed."); + System.exit(1); + } + } + + + /* + * compareMemInfo() + * + * @param in1 javacore + * @param in2 jdmpview !dumpallsegments output + * @return true/false for pass/fail + */ + private static boolean compareMemInfo(BufferedReader in1, BufferedReader in2) { + String line; + + // First parse and validate the code cache memory segments in the javacore + long jcCodeCacheTotal = 0; + long jcCodeCacheAlloc = 0; + long jcCodeCacheFree = 0; + + /* 2.6 VM and later: + * 1STSEGTYPE JIT Code Cache + * NULL segment start alloc end type size + * 1STSEGMENT 0x0000000002C9FCA8 0x000007FFDEE80000 0x000007FFDEE80000 0x000007FFDF080000 0x00000068 0x0000000000200000 + * 1STSEGMENT 0x0000000002CDBD58 0x000007FFDF080000 0x000007FFDF080000 0x000007FFDF280000 0x00000068 0x0000000000200000 + * 1STSEGMENT 0x0000000002CDBCA0 0x000007FFDF280000 0x000007FFDF280000 0x000007FFDF480000 0x00000068 0x0000000000200000 + * 1STSEGMENT 0x0000000002CDBBE8 0x000007FFDF480000 0x000007FFDF480000 0x000007FFDF680000 0x00000068 0x0000000000200000 + * NULL + * 1STSEGTOTAL Total memory: 8388608 (0x0000000000800000) + * 1STSEGINUSE Total memory in use: 0 (0x0000000000000000) + * 1STSEGFREE Total memory free: 8388608 (0x0000000000800000) + * + * 2.4 VM: + * 1STSEGTYPE JIT Code Cache + * NULL segment start alloc end type bytes + * 1STSEGMENT 000000000029E4C8 000007FFFF7A0000 000007FFFF80D9C0 000007FFFFFA0000 00000068 800000 + */ + try { + System.out.println("Parsing code cache memory segments in javacore:"); + line = in1.readLine(); + // Find the JIT Code Cache + while (line != null && !line.startsWith("1STSEGTYPE JIT Code Cache")) { + line = in1.readLine(); + } + + while ((line = in1.readLine()) != null ) { + if (line.startsWith("1STSEGMENT")) { + String[] values = line.split("[ ]+"); + // Get the start, alloc and end values for this segment. The .substring(2) removes the 0x prfix + long start = Long.parseLong(values[2].substring(2), 16); + long alloc = Long.parseLong(values[3].substring(2), 16); + long end = Long.parseLong(values[4].substring(2), 16); + // System.out.println("seg values " + start + " " + alloc + " " + end + "\n"); + jcCodeCacheTotal += end - start; + jcCodeCacheAlloc += alloc - start; + jcCodeCacheFree += end - alloc; + continue; // Processed this line. + } else if (line.startsWith("1STSEGTOTAL")) { + String[] values = line.split("[ ]+"); + if (jcCodeCacheTotal == Long.parseLong(values[3], 10)) { + System.out.println("\tcorrect total"); + } else { + System.out.println("\tincorrect total: " + jcCodeCacheTotal + " " + Long.parseLong(values[3], 10)); + } + continue; + } else if (line.startsWith("1STSEGINUSE")) { + String[] values = line.split("[ ]+"); + if (jcCodeCacheAlloc == Long.parseLong(values[5], 10)) { + System.out.println("\tcorrect in use total"); + } else { + System.out.println("\tincorrect in use total: " + jcCodeCacheAlloc + " " + Long.parseLong(values[5], 10)); + } + continue; + } else if (line.startsWith("1STSEGFREE")) { + String[] values = line.split("[ ]+"); + if (jcCodeCacheFree == Long.parseLong(values[4], 10)) { + System.out.println("\tcorrect free total"); + } else { + System.out.println("\tincorrect free total: " + jcCodeCacheFree + " " + Long.parseLong(values[4], 10)); + } + break; // we are done + } else if (line.startsWith("NULL")) { + // ignore + } else { + System.err.println("Unexpected javacore line"); + break; + } + } + } catch (IOException e) { + System.err.println("Error reading javacore file."); + return false; + } + + // Now parse and validate the code cache segment information in the jdmpview output + long jdCodeCacheTotal = 0; + long jdCodeCacheAlloc = 0; + long jdCodeCacheFree = 0; + /* + * jit code segments - !j9memorysegmentlist 0x293e670 + * +----------------+----------------+----------------+----------------+----------------+--------+ + * | segment | start | warmAlloc | coldAlloc | end | size | + * +----------------+----------------+----------------+----------------+----------------+--------+ + * 00000000029b9968 000007ffdee80000 000007ffdee83280 000007ffdf0602c0 000007ffdf080000 200000 + * 0000000002946f18 000007ffdf080000 000007ffdf080020 000007ffdf260318 000007ffdf280000 200000 + * 0000000002946e60 000007ffdf280000 000007ffdf280020 000007ffdf460318 000007ffdf480000 200000 + * 0000000002946da8 000007ffdf480000 000007ffdf480020 000007ffdf660318 000007ffdf680000 200000 + * +----------------+----------------+----------------+----------------+----------------+--------+ + * Total memory: 0000000008388608 (0000000000800000) + * Total memory in use: 0000000000534232 (00000000000826d8) + * Total memory free: 0000000007854376 (000000000077d928) + */ + try { + System.out.println("Parsing code cache memory segments in jdmpview output:"); + line = in2.readLine(); + // Find the JIT Code Cache + while (line != null && !line.startsWith("jit code segments")) { + line = in2.readLine(); + } + + while ((line = in2.readLine()) != null ) { + if (line.startsWith("Total memory:")) { + String[] values = line.split("[ ]+"); + if (jdCodeCacheTotal == Long.parseLong(values[2], 10)) { + System.out.println("\tcorrect total"); + } else { + System.out.println("\tincorrect total: " + jdCodeCacheTotal + " " + Long.parseLong(values[2], 10)); + } + continue; + } else if (line.startsWith("Total memory in use:")) { + String[] values = line.split("[ ]+"); + if (jdCodeCacheAlloc == Long.parseLong(values[4], 10)) { + System.out.println("\tcorrect in use total"); + } else { + System.out.println("\tincorrect in use total: " + jdCodeCacheAlloc + " " + Long.parseLong(values[4], 10)); + } + continue; + } else if (line.startsWith("Total memory free:")) { + String[] values = line.split("[ ]+"); + if (jdCodeCacheFree == Long.parseLong(values[3], 10)) { + System.out.println("\tcorrect free total"); + } else { + System.out.println("\tincorrect free total: " + jdCodeCacheFree + " " + Long.parseLong(values[3], 10)); + } + break; // we are done + } else if (line.startsWith("+")) { + // header line, ignore + } else if (line.startsWith("|")) { + // header line, ignore + } else { + // Should be a data line. Note that the data lines have a leading space, so 'start' is at index=2 + String[] values = line.split("[ ]+"); + long start = Long.parseLong(values[2], 16); + long warm = Long.parseLong(values[3], 16); + long cold = Long.parseLong(values[4], 16); + long end = Long.parseLong(values[5], 16); + System.out.println("\tsegment values " + start + " " + warm + " " + cold + " " + end); + jdCodeCacheTotal += end - start; + jdCodeCacheAlloc += (warm - start) + (end - cold); + jdCodeCacheFree += cold - warm; + continue; // Processed this line. + } + } + } catch (IOException e) { + System.err.println("Error reading jdmpview output file."); + return false; + } + + // Finally, compare the code cache segment totals from the javacore with those from the jdmpview output. + System.out.println("Code cache (javacore) total: " + jcCodeCacheTotal + " alloc: " + jcCodeCacheAlloc + " free: " + jcCodeCacheFree); + System.out.println("Code cache (coredump) total: " + jdCodeCacheTotal + " alloc: " + jdCodeCacheAlloc + " free: " + jdCodeCacheFree); + if (jcCodeCacheTotal != jdCodeCacheTotal) { + System.err.println("Test failed: code cache total memory validation failed"); + return false; + } + // The JIT may have allocated or freed memory in the time interval between the javacore and + // system dumps. So allow for a +/- 10% variation between the corresponding code cache values. + if (Math.abs(jcCodeCacheAlloc - jdCodeCacheAlloc) > jcCodeCacheTotal/10) { + System.err.println("Test failed: code cache allocated memory validation failed"); + return false; + } + if (Math.abs(jcCodeCacheFree - jdCodeCacheFree) > jcCodeCacheTotal/10) { + System.err.println("Test failed: code cache free memory validation failed"); + return false; + } + return true; + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_thread/CheckJavaCore.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_thread/CheckJavaCore.java new file mode 100644 index 00000000000..acdd84d524e --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_thread/CheckJavaCore.java @@ -0,0 +1,273 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.javacore_thread; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * This class check a javacore for a set of thread with known names and checks + * that they are correctly marked as blocked by other threads. + * + * @author hhellyer + * + */ +public class CheckJavaCore { + + private static final String THREADINFO_TAG = "3XMTHREADINFO "; + + private static final String THREADBLOCK_TAG = "3XMTHREADBLOCK"; + + /** + * @param args + */ + public static void main(String[] args) { + + if (args.length < 1) { + System.err.println("An input javacore is required to check."); + System.exit(1); + } + String fileName = args[0]; + + BufferedReader in = null; + try { + in = new BufferedReader(new FileReader(fileName)); + } catch (FileNotFoundException e) { + System.err.println("File: " + fileName + " not found."); + System.exit(1); + } + if (in == null) { + System.err.println("Failed to open file: " + fileName); + System.exit(1); + } + + boolean passed = true; + + passed &= checkThreadSection(in); + try { + in = new BufferedReader(new FileReader(fileName)); + } catch (FileNotFoundException e) { + System.err.println("File: " + fileName + " not found on second read."); + System.exit(1); + } + System.err.println(); + passed &= checkMonitorSection(in); + if( passed ) { + System.err.println("Test passed."); + System.exit(0); + } else { + System.err.println("Test failed."); + System.exit(1); + } + } + + + /* + * 2LKMONINUSE sys_mon_t:0x00007F6B903C5E98 infl_mon_t: 0x00007F6B903C5F10: + * 3LKMONOBJECT java/lang/String@0x00007F6B68CFB210: Flat locked by "BlockedOnSynchronized: lock owner" (0x00007F6B14007400), entry count 1 + * 3LKWAITERQ Waiting to enter: + * 3LKWAITER "BlockedOnSynchronized: waiting thread" (0x00007F6B1400EA00) + */ + private static boolean checkMonitorSection(BufferedReader in) { + String line; + // Increment this every time we find one of our threads. + int lockCount = 0; + boolean passed = true; + Map threadNameToCreator = new HashMap(); + + System.err.println("Checking Monitors"); + + for(CoreThreadCreator job: CoreThreadCreator.setupJobs ) { + if( job.isSynchronizedLock() ) { + threadNameToCreator.put(job.getThreadNameToCheck(), job); + } + } + final int expectedLockCount = threadNameToCreator.size(); + + try { + line = in.readLine(); + while (line != null) { + String lockOwnerLine = null; + String blockingThreadName = null; + String blockedThreadName = null; + if( !line.startsWith("2LKMONINUSE")) { + // Skip boring lines. + line = in.readLine(); + continue; + } + line = in.readLine(); + if( line.startsWith("3LKMONOBJECT")) { + getQuotedThreadName(line); + blockingThreadName = getQuotedThreadName(line); + if( blockingThreadName == null ) { + blockingThreadName = ""; + } + lockOwnerLine = line; + } + line = in.readLine(); // 3LKNOTIFYQ, 3LKWAITERQ + line = in.readLine(); // 3LKWAITNOTIFY, 3LKWAITER + if( line.startsWith("3LKWAIT")) { + blockedThreadName = getQuotedThreadName(line); + } + + CoreThreadCreator threadCreator = (CoreThreadCreator)threadNameToCreator.remove(blockedThreadName); + if( threadCreator == null ) { + line = in.readLine(); + System.err.println("Found no entry for " + blockedThreadName); + continue; + } + System.err.println("Found expected lock for - \"" + threadCreator.getThreadNameToCheck() + "\""); + if( !blockingThreadName.equals(threadCreator.getOwnerName())){ + System.err.println("Did not find expected owning thread \"" + threadCreator.getOwnerName() + "\""); + System.err.println("*** FAIL ***"); + passed = false; + } else { + System.err.println("Confirmed " + blockingThreadName + " held the lock blocking " + blockedThreadName); + System.err.println("Pass"); + } + lockCount++; + + + line = in.readLine(); + System.err.println("------------"); + } + } catch (IOException e) { + System.err.println("Error reading javacore file."); + System.exit(1); + } + System.err.println("Checked " + lockCount + " blocked threads out of " + expectedLockCount + " expected blocked threads"); + if( threadNameToCreator.size() != 0 ) { + System.err.println("*** FAIL ***"); + passed = false; + System.err.println("Failed to find all expected threads blocked: "); + for( Object key: threadNameToCreator.keySet() ) { + System.err.println("Missing thread: \"" + key + "\""); + } + } else { + System.err.println("Found and checked all expected threads."); + } + return passed; + } + + private static boolean checkThreadSection(BufferedReader in) { + String line; + // Increment this every time we find one of our threads. + int threadCount = 0; + boolean passed = true; + Map threadNameToCreator = new HashMap(); + + System.err.println("Checking Thread Blockers"); + + for(CoreThreadCreator job: CoreThreadCreator.setupJobs ) { + threadNameToCreator.put(job.getThreadNameToCheck(), job); + } + final int expectedThreadCount = threadNameToCreator.size(); + + try { + line = in.readLine(); + while (line != null) { + if( !line.startsWith(THREADINFO_TAG)) { + // Skip boring lines. + line = in.readLine(); + continue; + } + String threadName = getQuotedThreadName(line); + CoreThreadCreator threadCreator = (CoreThreadCreator)threadNameToCreator.remove(threadName); + if( threadName == null || threadCreator == null ) { + line = in.readLine(); + continue; + } + System.err.println("Found expected thread - \"" + threadCreator.getThreadNameToCheck() + "\""); + threadCount++; + while( !line.startsWith(THREADBLOCK_TAG) ) { + // If we reach NULL we know we've gone off the end of this thread and should fail. + if( line.startsWith("NULL")) { + break; + } + line = in.readLine(); + } + if( !line.startsWith(THREADBLOCK_TAG)) { + System.err.println("*** FAIL ***"); + passed = false; + System.err.println("No " + THREADBLOCK_TAG + " line for thread " + threadName); + System.err.println("Fail"); + System.err.println("------------"); + // This isn't a blocked thread so carry on. + line = in.readLine(); + continue; + } + System.err.println("Blocked line: " + line); + if( threadCreator.checkBlockingLine(line) ) { + System.err.println("Pass"); + } else { + System.err.println("*** FAIL ***"); + passed = false; + } + System.err.println("------------"); + line = in.readLine(); + } + } catch (IOException e) { + System.err.println("Error reading javacore file."); + System.exit(1); + } + System.err.println("Checked " + threadCount + " threads out of " + expectedThreadCount + " expected threads"); + if( threadNameToCreator.size() != 0 ) { + passed = false; + System.err.println("Failed to find all expected threads: "); + for( Object key: threadNameToCreator.keySet() ) { + System.err.println("Missing thread: \"" + key + "\""); + } + } else { + System.err.println("Found and checked all expected threads."); + } + return passed; + } + + /** + * Given a string, returns the contents of the first quoted string. + * (Which in java cores is generally the thread name. + * @param line + * @return + */ + public static String getQuotedThreadName(String line) { + // Pull the thread name out of a line that looks like: + // 3XMTHREADINFO "main" J9VMThread:0x00129100, j9thread_t:0x002B5A30, java/lang/Thread:0x00DDC4F8, state:R, prio=5 + // There are threads that don't have quotes, but they aren't Java threads so we aren't + // interested here. + int openQuote = -1; + int closeQuote = -1; + openQuote = line.indexOf('"'); + closeQuote = line.indexOf('"', openQuote + 1); + if( openQuote > -1 && closeQuote > -1 ) { + String threadName = line.substring(openQuote + 1, closeQuote); + return threadName; + } else { + return null; + } + } +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_thread/CheckJdmpviewInfoThread.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_thread/CheckJdmpviewInfoThread.java new file mode 100644 index 00000000000..c14debdda6f --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_thread/CheckJdmpviewInfoThread.java @@ -0,0 +1,309 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.javacore_thread; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * This class check a javacore for a set of thread with known names and checks + * that they are correctly marked as blocked by other threads. + * + * @author hhellyer + * + */ +public class CheckJdmpviewInfoThread { + + private static final String THREADINFO_TAG = " name: "; + + private static final String[] THREADBLOCK_TAGS = {" parked on: "," waiting to be notified on: "," waiting to enter: " }; + +// private static Map threadNameToCreator = new HashMap(); + + /** + * @param args + */ + public static void main(String[] args) { + + if (args.length < 1) { + System.err.println("An input file is required to check."); + System.exit(1); + } + String fileName = args[0]; + + BufferedReader in = null; + try { + in = new BufferedReader(new FileReader(fileName)); + } catch (FileNotFoundException e) { + System.err.println("File: " + fileName + " not found."); + System.exit(1); + } + if (in == null) { + System.err.println("Failed to open file: " + fileName); + System.exit(1); + } + + boolean passed = true; + + passed &= checkThreadSection(in); + try { + in = new BufferedReader(new FileReader(fileName)); + } catch (FileNotFoundException e) { + System.err.println("File: " + fileName + " not found on second read."); + System.exit(1); + } + System.err.println(); + passed &= checkMonitorSection(in); + if( passed ) { + System.err.println("Test passed."); + System.exit(0); + } else { + System.err.println("Test failed."); + System.exit(1); + } + } + + /* + * 2LKMONINUSE sys_mon_t:0x00007F6B903C5E98 infl_mon_t: 0x00007F6B903C5F10: + * 3LKMONOBJECT java/lang/String@0x00007F6B68CFB210: Flat locked by "BlockedOnSynchronized: lock owner" (0x00007F6B14007400), entry count 1 + * 3LKWAITERQ Waiting to enter: + * 3LKWAITER "BlockedOnSynchronized: waiting thread" (0x00007F6B1400EA00) + */ + private static boolean checkMonitorSection(BufferedReader in) { + String line; + // Increment this every time we find one of our threads. + int lockCount = 0; + boolean passed = true; + Map threadNameToCreator = new HashMap(); + + System.err.println("Checking Monitors"); + + for(CoreThreadCreator job: CoreThreadCreator.setupJobs ) { + // The parked thread isn't actual locked on anything, it's just parked. + if( !(job instanceof CoreThreadCreator.ParkedThread) ) { + threadNameToCreator.put(job.getThreadNameToCheck(), job); + } + } + final int expectedLockCount = threadNameToCreator.size(); + + try { + line = in.readLine(); + // Fast forward through the system monitors. + while (line != null && !line.startsWith("Object Locks in use")) { + line = in.readLine(); + } + + /* Now looking at something like: + * java/lang/String@0x7fbb7cadba80 + * owner thread id: 20107 name: WaitingOnSynchronized: lock owner + * waiting thread id: 20094 name: WaitingOnSynchronized: waiting thread + */ + String lock = null; + String blockingThreadName = ""; + String blockedThreadName = null; + while ( (line = in.readLine()) != null ) { + if( line.contains("@")) { + // New lock. + lock = line; + blockingThreadName = ""; + blockedThreadName = null; + continue; // Processed this line. + } + if( line.contains("owner thread id:")) { + blockingThreadName = line.substring( line.indexOf("name: ") + "name: ".length()); + continue; // Processed this line. + } + if( line.contains("waiting thread id:")) { + blockedThreadName = line.substring( line.indexOf("name: ") + "name: ".length()); + // Do checks here now we know the id of the blocked thread. + CoreThreadCreator threadCreator = (CoreThreadCreator)threadNameToCreator.remove(blockedThreadName); + if( threadCreator == null ) { + System.err.println("Found no entry for " + blockedThreadName); + continue; // Processed this line. + } + System.err.println("Found expected lock for - \"" + threadCreator.getThreadNameToCheck() + "\""); + if( !blockingThreadName.equals(threadCreator.getOwnerName()) ){ + System.err.println("Did not find expected owning thread \"" + threadCreator.getOwnerName() + "\""); + System.err.println("Found: \"" + blockingThreadName + "\""); + System.err.println("*** FAIL ***"); + passed = false; + System.err.println("------------"); + } else { + System.err.println("Confirmed " + blockingThreadName + " held the lock blocking " + blockedThreadName); + System.err.println("Pass"); + lockCount++; + System.err.println("------------"); + } + continue; + } + if( line.startsWith("java.util.concurrent locks in use")) { + break; // Done with monitors, juc locks next. + } + } + while ( (line = in.readLine()) != null ) { + if( line.contains("@")) { + // New lock. + lock = line; + blockingThreadName = ""; + blockedThreadName = null; + continue; // Processed this line. + } + if( line.contains("locked by java thread id:")) { + blockingThreadName = line.substring( line.indexOf("name: ") + "name: ".length()); + continue; // Processed this line. + } + if( line.contains("waiting thread id:")) { + blockedThreadName = line.substring( line.indexOf("name: ") + "name: ".length()); + // Do checks here now we know the id of the blocked thread. + CoreThreadCreator threadCreator = (CoreThreadCreator)threadNameToCreator.remove(blockedThreadName); + if( threadCreator == null ) { + System.err.println("Found no entry for " + blockedThreadName); + continue; // Processed this line. + } + System.err.println("Found expected lock for - \"" + threadCreator.getThreadNameToCheck() + "\""); + if( !blockingThreadName.equals(threadCreator.getOwnerName()) ){ + System.err.println("Did not find expected owning thread \"" + threadCreator.getOwnerName() + "\""); + System.err.println("Found: \"" + blockingThreadName + "\""); + System.err.println("*** FAIL ***"); + passed = false; + System.err.println("------------"); + } else { + System.err.println("Confirmed " + blockingThreadName + " held the lock blocking " + blockedThreadName); + System.err.println("Pass"); + lockCount++; + System.err.println("------------"); + } + continue; + } + if( line.startsWith("java.util.concurrent locks in use")) { + break; // Done with monitors, juc locks next. + } + } + } catch (IOException e) { + System.err.println("Error reading jdmpview output file."); + System.exit(1); + } + System.err.println("Checked " + lockCount + " blocked threads out of " + expectedLockCount + " expected blocked threads"); + if( threadNameToCreator.size() != 0 ) { + passed = false; + System.err.println("Failed to find all expected threads blocked: "); + for( Object key: threadNameToCreator.keySet() ) { + System.err.println("Missing thread: \"" + key + "\""); + } + } else { + System.err.println("Found and checked all expected threads."); + } + return passed; + } + + private static boolean checkThreadSection(BufferedReader in) { + String line; + // Increment this every time we find one of our threads. + int threadCount = 0; + boolean passed = true; + Map threadNameToCreator = new HashMap(); + + System.err.println("Checking Thread Blockers"); + + for(CoreThreadCreator job: CoreThreadCreator.setupJobs ) { + threadNameToCreator.put(job.getThreadNameToCheck(), job); + } + final int expectedThreadCount = threadNameToCreator.size(); + + try { + line = in.readLine(); + while (line != null) { + if( !line.startsWith(THREADINFO_TAG)) { + // Skip boring lines. + line = in.readLine(); + continue; + } + String threadName = getThreadNameFromThreadInfo(line); + CoreThreadCreator threadCreator = (CoreThreadCreator)threadNameToCreator.remove(threadName); + if( threadName == null || threadCreator == null ) { + line = in.readLine(); + continue; + } + System.err.println("Found expected thread - \"" + threadCreator.getThreadNameToCheck() + "\""); + threadCount++; + + // Skip to monitor line + while( (findMatchingStartTag(line, THREADBLOCK_TAGS) == null) && !line.startsWith(" Java stack frames:")) { + line = in.readLine(); + } + if( (findMatchingStartTag(line, THREADBLOCK_TAGS) == null)) { + passed = false; + System.err.println("No blocking information line for thread " + threadName); + System.err.println("Fail"); + System.err.println("------------"); + // This isn't a blocked thread so carry on. + line = in.readLine(); + continue; + } + System.err.println("Blocked line: " + line); + if( threadCreator.checkJdmpviewInfoThreadLine(line.substring(findMatchingStartTag(line, THREADBLOCK_TAGS).length() )) ) { + System.err.println("Pass"); + } else { + System.err.println("*** FAIL ***"); + passed = false; + } + System.err.println("------------"); + line = in.readLine(); + } + } catch (IOException e) { + System.err.println("Error reading javacore file."); + System.exit(1); + } + System.err.println("Checked " + threadCount + " threads out of " + expectedThreadCount + " expected threads"); + if( threadNameToCreator.size() != 0 ) { + passed = false; + System.err.println("Failed to find all expected threads: "); + for( Object key: threadNameToCreator.keySet() ) { + System.err.println("Missing thread: \"" + key + "\""); + } + } else { + System.err.println("Found and checked all expected threads."); + } + return passed; + } + + public static String getThreadNameFromThreadInfo(String threadInfoLine) { + // Pull the thread name out of a line that looks like: + // name: Deadlock Thread 2 + return threadInfoLine.substring(THREADINFO_TAG.length() ); + } + + private static String findMatchingStartTag(String toCheck, String[] possibilities) { + for( String s: possibilities ) { + if( toCheck.startsWith(s) ) { + return s; + } + } + return null; + } +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_thread/CoreThreadCreator.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_thread/CoreThreadCreator.java new file mode 100644 index 00000000000..62d5fe3ed93 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_thread/CoreThreadCreator.java @@ -0,0 +1,744 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.javacore_thread; + +import com.ibm.dump.tests.javacore_thread.CoreThreadCreator; + +import java.lang.Thread.State; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.LockSupport; +import java.util.concurrent.locks.ReentrantLock; + +public abstract class CoreThreadCreator implements Runnable { + + public static final CoreThreadCreator[] setupJobs = { + new CoreThreadCreator.BlockedOnSynchronized(), new CoreThreadCreator.BlockedOnJUCLock(), + new CoreThreadCreator.TimedBlockedOnJUCLock(), new CoreThreadCreator.DeadlockedOnJUCLock(), + new CoreThreadCreator.BlockedOnFIFOMutex(), new CoreThreadCreator.BlockedOnOwnableFIFOMutex(), + new CoreThreadCreator.ParkedThread(), new CoreThreadCreator.WaitingOnSynchronized(), + new CoreThreadCreator.WaitingOnUnowned() }; + + public abstract String getThreadNameToCheck(); + + public String getLockName() { + return ""; + } + + public String getOwnerName() { + return ""; + } + + // Default implementation + public boolean checkBlockingLine(String line) { + + boolean good = true; + good &= line.contains("Parked on: " + getLockName()); + // Threads are quoted, unknowns aren't. + good &= line.contains("Owned by: " + getOwnerName()) || line.contains("Owned by: \"" + getOwnerName() + "\""); + return good; + } + + public boolean checkWaitingLine(String line) { + + boolean good = true; + good &= line.contains("Parked on: " + getLockName()); + // Threads are quoted, unknowns aren't. + good &= line.contains("Owned by: " + getOwnerName()) || line.contains("Owned by: \"" + getOwnerName() + "\""); + return good; + } + + public boolean checkJdmpviewInfoThreadLine(String line) { + + boolean good = true; + good &= line.contains(getLockName() + "@0x"); + good &= line.contains("owner name: \"" + getOwnerName() + "\" owner id: "); + return good; + } + + public abstract boolean isReady(); + + public static class ParkedThread extends CoreThreadCreator { + + private Thread parkingThread = null; + + public boolean isReady() { + if (parkingThread != null + && parkingThread.getState() == State.WAITING) { + return true; + } + return false; + } + + public void run() { + parkingThread = Thread.currentThread(); + parkingThread.setName(getThreadNameToCheck()); + LockSupport.park(); + } + + @Override + public String getThreadNameToCheck() { + return "ParkedThread: parked thread"; + } + + public boolean checkJdmpviewInfoThreadLine(String line) { + + boolean good = true; + good &= line.contains(""); + return good; + } + } + + public static class BlockedOnJUCLock extends CoreThreadCreator { + + private final ReentrantLock jucLock = new ReentrantLock(true); + + private Thread parkingThread = null; + private Thread blockingThread = null; + private volatile boolean lockTaken = false; + + public boolean isReady() { + if (parkingThread != null + && parkingThread.getState() == State.WAITING) { + return true; + } + return false; + } + + public void run() { + // Take the lock, thread will terminate without releasing + // leaving the second thread blocked. + blockingThread = new Thread(new Runnable() { + public void run() { + jucLock.lock(); + lockTaken = true; + while (true) { + try { + // Hold the lock forever, but don't terminate. + Thread.sleep(1000); + } catch (InterruptedException e) { + } + } + } + }); + blockingThread.setName(getOwnerName()); + blockingThread.start(); + while (!lockTaken) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + } + parkingThread = new Thread(new Runnable() { + public void run() { + jucLock.lock(); + } + }); + parkingThread.setName(getThreadNameToCheck()); + parkingThread.start(); + } + + @Override + public String getThreadNameToCheck() { + return "BlockedOnJUCLock: waiting thread"; + } + + public String getLockName() { + return "java/util/concurrent/locks/ReentrantLock$FairSync"; + } + + public String getOwnerName() { + return "BlockedOnJUCLock: lock owner"; + } + } + + public static class TimedBlockedOnJUCLock extends CoreThreadCreator { + + private final ReentrantLock jucLock = new ReentrantLock(true); + + private Thread parkingThread = null; + private Thread blockingThread = null; + private volatile boolean lockTaken = false; + + public boolean isReady() { + if (parkingThread != null + && parkingThread.getState() == State.TIMED_WAITING) { + return true; + } + return false; + } + + public void run() { + // Take the lock, thread will terminate without releasing + // leaving the second thread blocked. + blockingThread = new Thread(new Runnable() { + public void run() { + jucLock.lock(); + lockTaken = true; + while (true) { + try { + // Hold the lock forever, but don't terminate. + Thread.sleep(1000); + } catch (InterruptedException e) { + } + } + } + }); + blockingThread.setName("TimedBlockedOnJUCLock: lock owner"); + blockingThread.start(); + while (!lockTaken) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + } + parkingThread = new Thread(new Runnable() { + public void run() { + try { + // We want a thread that will be in a timed park, + // but without any risk of it actually waking up. + jucLock.tryLock(10, TimeUnit.DAYS); + } catch (InterruptedException e) { + } + } + }); + parkingThread.setName(getThreadNameToCheck()); + parkingThread.start(); + } + + @Override + public String getThreadNameToCheck() { + return "TimedBlockedOnJUCLock: waiting thread"; + } + + public String getLockName() { + return "java/util/concurrent/locks/ReentrantLock$FairSync"; + } + + public String getOwnerName() { + return "TimedBlockedOnJUCLock: lock owner"; + } + } + + public static class DeadlockedOnJUCLock extends CoreThreadCreator { + + private final ReentrantLock jucLock = new ReentrantLock(true); + + private Thread parkingThread = null; + private Thread setupThread = null; + + public boolean isReady() { + if (setupThread != null + && setupThread.getState() == State.TERMINATED + && parkingThread != null + && parkingThread.getState() == State.WAITING) { + return true; + } + return false; + } + + public void run() { + // Take the lock, thread will terminate without releasing + // leaving the second thread blocked. + jucLock.lock(); + setupThread = Thread.currentThread(); + setupThread.setName(getOwnerName()); + parkingThread = new Thread(new Runnable() { + public void run() { + jucLock.lock(); + } + }); + parkingThread.setName(getThreadNameToCheck()); + parkingThread.start(); + } + + @Override + public String getThreadNameToCheck() { + return "DeadlockedOnJUCLock: waiting thread"; + } + + @Override + public String getLockName() { + return "java/util/concurrent/locks/ReentrantLock$FairSync"; + } + + @Override + public String getOwnerName() { + return "DeadlockedOnJUCLock: lock owner (dead)"; + } + + @Override + public boolean checkBlockingLine(String line) { + boolean good = super.checkBlockingLine(line); + // Make sure the J9VMThread for this case is null. + good &= line.contains("Owned by: \"" + getOwnerName() + + "\" (J9VMThread:, java/lang/Thread:"); + return good; + } + + @Override + public boolean checkJdmpviewInfoThreadLine(String line) { + boolean good = super.checkJdmpviewInfoThreadLine(line); + // Make sure the J9VMThread for this case is null. + good &= line.contains("owner name: \"" + getOwnerName() + "\" owner id: "); + return good; + } + } + + public static class BlockedOnFIFOMutex extends CoreThreadCreator { + + private final FIFOMutex fifoMutex = new FIFOMutex(); + + private Thread parkingThread = null; + private Thread blockingThread = null; + private volatile boolean lockTaken = false; + + public boolean isReady() { + if (parkingThread != null + && parkingThread.getState() == State.WAITING) { + return true; + } + return false; + } + + public void run() { + // Take the lock, thread will terminate without releasing + // leaving the second thread blocked. + blockingThread = new Thread(new Runnable() { + public void run() { + fifoMutex.lock(); + lockTaken = true; + // Hold the lock forever, but don't terminate. + while (true) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + } + } + }); + blockingThread.setName(getOwnerName()); + blockingThread.start(); + while (!lockTaken) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + } + parkingThread = new Thread(new Runnable() { + public void run() { + fifoMutex.lock(); + } + }); + parkingThread.setName(getThreadNameToCheck()); + parkingThread.start(); + } + + @Override + public String getThreadNameToCheck() { + return "BlockedOnFIFOMutex: waiting thread"; + } + + @Override + public String getLockName() { + return fifoMutex.getClass().getName().replace('.', '/'); + } + + } + + public static class BlockedOnOwnableFIFOMutex extends CoreThreadCreator { + + private final OwnableFIFOMutex fifoMutex = new OwnableFIFOMutex(); + + private Thread parkingThread = null; + private Thread blockingThread = null; + private volatile boolean lockTaken = false; + + public boolean isReady() { + if (parkingThread != null + && parkingThread.getState() == State.WAITING) { + return true; + } + return false; + } + + public void run() { + // Take the lock, thread will terminate without releasing + // leaving the second thread blocked. + blockingThread = new Thread(new Runnable() { + public void run() { + fifoMutex.lock(); + lockTaken = true; + while (true) { + try { + // Hold the lock forever, but don't terminate. + Thread.sleep(1000); + } catch (InterruptedException e) { + } + } + } + }); + blockingThread.setName(getOwnerName()); + blockingThread.start(); + while (!lockTaken) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + } + parkingThread = new Thread(new Runnable() { + public void run() { + fifoMutex.lock(); + } + }); + parkingThread.setName(getThreadNameToCheck()); + parkingThread.start(); + } + + @Override + public String getThreadNameToCheck() { + return "BlockedOnOwnableFIFOMutex: waiting thread"; + } + + @Override + public String getLockName() { + return fifoMutex.getClass().getName().replace('.', '/'); + } + + @Override + public String getOwnerName() { + return "BlockedOnOwnableFIFOMutex: lock owner"; + } + } + + public static class BlockedOnSynchronized extends CoreThreadCreator { + + private final String lock = "Lock for BlockedOnSynchronized"; + + private Thread parkingThread = null; + private Thread blockingThread = null; + private volatile boolean lockTaken = false; + + public boolean isReady() { + if (parkingThread != null + && parkingThread.getState() == State.BLOCKED) { + return true; + } + return false; + } + + public boolean isSynchronizedLock() { + return true; + } + + public void run() { + // Take the lock, thread will terminate without releasing + // leaving the second thread blocked. + blockingThread = new Thread(new Runnable() { + public void run() { + synchronized (lock) { + lockTaken = true; + while (true) { + try { + // Hold the lock forever, but don't terminate. + Thread.sleep(1000); + } catch (InterruptedException e) { + } + } + } + } + }); + blockingThread.setName(getOwnerName()); + blockingThread.start(); + while (!lockTaken) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + } + parkingThread = new Thread(new Runnable() { + public void run() { + synchronized (lock) { + } + } + }); + parkingThread.setName(getThreadNameToCheck()); + parkingThread.start(); + } + + @Override + public String getThreadNameToCheck() { + return "BlockedOnSynchronized: blocked thread"; + } + + @Override + public String getLockName() { + return lock.getClass().getName().replace('.', '/'); + } + + @Override + public String getOwnerName() { + return "BlockedOnSynchronized: lock owner"; + } + + public boolean checkBlockingLine(String line) { + + boolean good = true; + good &= line.contains("Blocked on: " + getLockName()); + // Threads are quoted, unknowns aren't. + good &= line.contains("Owned by: " + getOwnerName()) || line.contains("Owned by: \"" + getOwnerName() + "\""); + return good; + } + } + + public static class WaitingOnSynchronized extends CoreThreadCreator { + + private final String lock = "Lock for WaitingOnSynchronized"; + + private Thread owningThread = null; + private Thread waitingThread = null; + private volatile boolean lockTaken = false; + + public boolean isReady() { + if (waitingThread != null + && waitingThread.getState() == State.WAITING + && owningThread != null + && owningThread.getState() == State.TIMED_WAITING) { + return true; + } + return false; + } + + public boolean isSynchronizedLock() { + return true; + } + + public void run() { + // First thread will wait on the object lock + waitingThread = new Thread(new Runnable() { + public void run() { + synchronized (lock) { + lockTaken = true; + try { + lock.wait(); + } catch (InterruptedException e) { + } + } + } + }); + waitingThread.setName(getThreadNameToCheck()); + waitingThread.start(); + while (!lockTaken) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + } + // Second thread will take and own the lock forever + owningThread = new Thread(new Runnable() { + public void run() { + synchronized (lock) { + while (true) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + } + } + } + }); + owningThread.setName(getOwnerName()); + owningThread.start(); + } + + @Override + public String getThreadNameToCheck() { + return "WaitingOnSynchronized: waiting thread"; + } + + @Override + public String getLockName() { + return lock.getClass().getName().replace('.', '/'); + } + + @Override + public String getOwnerName() { + return "WaitingOnSynchronized: lock owner"; + } + + public boolean checkBlockingLine(String line) { + + boolean good = true; + good &= line.contains("Waiting on: " + getLockName()); + // Threads are quoted, unknowns aren't. + good &= line.contains("Owned by: " + getOwnerName()) || line.contains("Owned by: \"" + getOwnerName() + "\""); + return good; + } + + public boolean checkJdmpviewInfoThreadLine(String line) { + + boolean good = true; + good &= line.contains(getLockName() + "@0x"); + good &= line.contains("owner name: \"" + getOwnerName() + "\" owner id:"); + return good; + } + } + + public static class WaitingOnUnowned extends CoreThreadCreator { + + private final String lock = "Lock for WaitingOnUnowned"; + + private Thread owningThread = null; + private Thread waitingThread = null; + private volatile boolean lockTaken = false; + + public boolean isReady() { + if (waitingThread != null + && waitingThread.getState() == State.WAITING) { + return true; + } + return false; + } + + public boolean isSynchronizedLock() { + return true; + } + + public void run() { + // Take the lock, thread will terminate without releasing + // leaving the second thread blocked. + waitingThread = new Thread(new Runnable() { + public void run() { + synchronized (lock) { + lockTaken = true; + try { + lock.wait(); + } catch (InterruptedException e) { + } + } + } + }); + waitingThread.setName(getThreadNameToCheck()); + waitingThread.start(); + while (!lockTaken) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + } + } + + @Override + public String getThreadNameToCheck() { + return "WaitingOnUnowned: waiting thread"; + } + + @Override + public String getLockName() { + return lock.getClass().getName().replace('.', '/'); + } + + public String getOwnerName() { + return ""; + } + + public boolean checkBlockingLine(String line) { + + boolean good = true; + good &= line.contains("Waiting on: " + getLockName()); + // Threads are quoted, unknowns aren't. + good &= line.contains("Owned by: " + getOwnerName()) || line.contains("Owned by: \"" + getOwnerName() + "\""); + return good; + } + + public boolean checkJdmpviewInfoThreadLine(String line) { + + boolean good = true; + System.err.println("Checking: |" + line +"|"); + good &= line.contains(getLockName() + "@0x"); + good &= line.contains("owner name: " + getOwnerName()); + return good; + } + } + + public boolean isSynchronizedLock() { + return false; + } + + public boolean isAbstractOwnableSynchronizer() { + return false; + } + + +// public static class DeadlockCycleOnJUCLock extends CoreThreadCreator { +// +// private final ReentrantLock jucLockA = new ReentrantLock(true); +// private final ReentrantLock jucLockB = new ReentrantLock(true); +// +// private Thread threadA = null; +// private Thread threadB = null; +// +// public boolean isReady() { +// if (jucLockA.isLocked() && jucLockB.isLocked() && threadB != null +// && jucLockA.isLocked() +// && threadA != null +// && threadA.getState() == State.WAITING) { +// return true; +// } +// return false; +// } +// +// public void run() { +// parkingThread = new Thread(new Runnable() { +// public void run() { +// jucLockB.lock(); +// jucLockA.lock(); +// } +// }); +// parkingThread.setName(getThreadNameToCheck()); +// parkingThread.start(); +// } +// +// @Override +// public String getThreadNameToCheck() { +// return "DeadlockedOnJUCLock: waiting thread"; +// } +// +// @Override +// public String getLockName() { +// return "java/util/concurrent/locks/ReentrantLock$FairSync"; +// } +// +// @Override +// public String getOwnerName() { +// return "DeadlockedOnJUCLock: lock owner (dead)"; +// } +// +// @Override +// public boolean checkBlockingLine(String line) { +// boolean good = super.checkBlockingLine(line); +// // Make sure the J9VMThread for this case is null. +// good &= line.contains("Owned by: \"" + getOwnerName() +// + "\" (J9VMThread:, java/lang/Thread:"); +// return good; +// } +// } +} \ No newline at end of file diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_thread/CreateJavaCore.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_thread/CreateJavaCore.java new file mode 100644 index 00000000000..092f9375235 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_thread/CreateJavaCore.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.javacore_thread; + +import java.lang.Thread.State; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.LockSupport; +import java.util.concurrent.locks.ReentrantLock; + +public class CreateJavaCore { + + /** + * @param args + */ + public static void main(String[] args) { + + boolean generateSystemCore = false; + if( args.length > 0 && args[0].equals("-core") ) { + // Only generate system core if that's what we're testing to save space. + // (We might as well always generate a javacore, they aren't big and would + // be useful for debugging problems with the core tests.) + generateSystemCore = true; + } + for(CoreThreadCreator job: CoreThreadCreator.setupJobs ) { + Thread t = new Thread(job); + t.setName("Setup for" + job.getClass().getName()); + System.out.println("Running: " + t.getName()); + t.start(); + } + for(CoreThreadCreator job: CoreThreadCreator.setupJobs ) { + System.out.println("Checking: " + job + " is ready."); + while( !job.isReady() ) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + // Likely to just keep waiting. May have to + // add a timeout in case something goes wrong. + } + } + } + com.ibm.jvm.Dump.JavaDump(); + if( generateSystemCore ) { + com.ibm.jvm.Dump.SystemDump(); + } + // We've deliberately deadlocked a bunch of threads. + // Don't wait for them before quitting. + System.exit(0); + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_thread/FIFOMutex.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_thread/FIFOMutex.java new file mode 100644 index 00000000000..871cbbd4dd7 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_thread/FIFOMutex.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.javacore_thread; + +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.LockSupport; + +/** + * Example FIFOMutex from the JUC docs. + */ +class FIFOMutex { + private final AtomicBoolean locked = new AtomicBoolean(false); + private final Queue waiters + = new ConcurrentLinkedQueue(); + + + public void lock() { + long i = 0; + boolean wasInterrupted = false; + Thread current = Thread.currentThread(); + waiters.add(current); + + // Block while not first in queue or cannot acquire lock + while (waiters.peek() != current || + !locked.compareAndSet(false, true)) { + LockSupport.park(this); + i++; + if (Thread.interrupted()) {// ignore interrupts while waiting + wasInterrupted = true; + } + } + + waiters.remove(); + if (wasInterrupted) { // reassert interrupt status on exit + current.interrupt(); + } + } + + public void unlock() { + locked.set(false); + LockSupport.unpark(waiters.peek()); + } + } diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_thread/OwnableFIFOMutex.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_thread/OwnableFIFOMutex.java new file mode 100644 index 00000000000..27a7a441892 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/javacore_thread/OwnableFIFOMutex.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.javacore_thread; + +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.AbstractOwnableSynchronizer; +import java.util.concurrent.locks.LockSupport; + +/** + * Example FIFOMutex from the JUC docs. + * Altered to extend AbstractOwnableSynchronizer to + * confirm we can introspect user code that extends + * this not just default class library versions. + */ +class OwnableFIFOMutex extends AbstractOwnableSynchronizer{ + private final AtomicBoolean locked = new AtomicBoolean(false); + private final Queue waiters + = new ConcurrentLinkedQueue(); + + + public void lock() { + long i = 0; + boolean wasInterrupted = false; + Thread current = Thread.currentThread(); + waiters.add(current); + + // Block while not first in queue or cannot acquire lock + while (waiters.peek() != current || + !locked.compareAndSet(false, true)) { + LockSupport.park(this); + i++; + if (Thread.interrupted()) {// ignore interrupts while waiting + wasInterrupted = true; + } + } + + waiters.remove(); + setExclusiveOwnerThread(current); + if (wasInterrupted) { // reassert interrupt status on exit + current.interrupt(); + } + } + + public void unlock() { + setExclusiveOwnerThread(null); + locked.set(false); + LockSupport.unpark(waiters.peek()); + } + } diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/jdmpview_heapdump/CompareDumps.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/jdmpview_heapdump/CompareDumps.java new file mode 100644 index 00000000000..ce65533d356 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/jdmpview_heapdump/CompareDumps.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.jdmpview_heapdump; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; + +public class CompareDumps { + + public static void main(String[] args) throws IOException { + + int error_count = 0; + if (args.length != 2) { + System.err.println("CreateDump takes two arguments: the names of two files to compare"); + } + + System.err.println("Comparing the first 1000 lines of " + args[0] + " with the first 1000 lines of " + args[1]); + BufferedReader in1 = new BufferedReader(new FileReader(args[0])); + BufferedReader in2 = new BufferedReader(new FileReader(args[1])); + + for (int i = 0;i<1000;i++) { + String line1 = in1.readLine(); + String line2 = in2.readLine(); + if ( ! line1.equals(line2)) { + error_count++; + System.err.println("The two files differ at line " + (i + 1)); + System.err.println("The first file has:"); + System.err.println(line1); + System.err.println("The second file has:"); + System.err.println(line2); + } + } + + System.err.println("Count of differences in the first 1000 lines: " + error_count); + + System.exit(error_count); +} + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/jdmpview_heapdump/CreateDumps.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/jdmpview_heapdump/CreateDumps.java new file mode 100644 index 00000000000..239481c51b3 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/jdmpview_heapdump/CreateDumps.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.jdmpview_heapdump; + +public class CreateDumps { + + public static void main(String[] args) { + System.gc(); + System.gc(); + com.ibm.jvm.Dump.HeapDump(); + com.ibm.jvm.Dump.SystemDump(); + } +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/memorycategories/DTFJMemoryCategoryTest.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/memorycategories/DTFJMemoryCategoryTest.java new file mode 100644 index 00000000000..61791b5e94c --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/memorycategories/DTFJMemoryCategoryTest.java @@ -0,0 +1,402 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.memorycategories; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import com.ibm.dtfj.image.CorruptDataException; +import com.ibm.dtfj.image.DataUnavailable; +import com.ibm.dtfj.image.Image; +import com.ibm.dtfj.image.ImageAddressSpace; +import com.ibm.dtfj.image.ImageProcess; +import com.ibm.dtfj.java.JavaRuntime; +import com.ibm.dtfj.java.JavaRuntimeMemoryCategory; + +/** + * Test class that will check all JavaRuntimes inside an Image + * and checks the state of the JavaRuntimeMemoryCategories. + * + * Encapsulates knowledge of which memory categories are expected to be present, + * and what constitutes sanity for a + * + * @author andhall + * + */ +public final class DTFJMemoryCategoryTest +{ + /* List of memory categories we expect to have in all good dumps with default options */ + public static final List EXPECTED_MEMORY_CATEGORIES; + + static { + List localList = new ArrayList(); + + localList.add("JRE"); + localList.add("JRE/VM"); + localList.add("JRE/VM/Classes"); + localList.add("JRE/VM/Memory Manager (GC)"); + localList.add("JRE/VM/Memory Manager (GC)/Java Heap"); + localList.add("JRE/VM/Threads"); + localList.add("JRE/VM/Threads/Java Stack"); + localList.add("JRE/VM/Threads/Native Stack"); + localList.add("JRE/VM/Port Library"); + localList.add("JRE/Class Libraries"); + /* Note: this test expects to be run against dumps from JIT-On VMs */ + localList.add("JRE/JIT"); + localList.add("JRE/JIT/JIT Code Cache"); + localList.add("JRE/JIT/JIT Data Cache"); + + EXPECTED_MEMORY_CATEGORIES = Collections.unmodifiableList(localList); + } + + private final Image image; + private final List failureReasons = new LinkedList(); + + public DTFJMemoryCategoryTest(Image image) + { + this.image = image; + } + + /* Does the address space -> process -> Java runtime walk. + * We expect this test to be run on simple, good dumps. Any CorruptData is a test failure. + */ + private void walkJavaRuntimes() + { + boolean javaRuntimeFound = false; + Iterator addressSpaceIt = image.getAddressSpaces(); + + while (addressSpaceIt.hasNext()) { + Object addressSpaceObj = addressSpaceIt.next(); + + if (addressSpaceObj instanceof ImageAddressSpace) { + ImageAddressSpace addressSpace = (ImageAddressSpace) addressSpaceObj; + + Iterator processIt = addressSpace.getProcesses(); + + while( processIt.hasNext() ) { + Object processObj = processIt.next(); + + if (processObj instanceof ImageProcess) { + ImageProcess process = (ImageProcess) processObj; + + Iterator runtimeIt = process.getRuntimes(); + + while (runtimeIt.hasNext()) { + Object runtimeObj = runtimeIt.next(); + + if (runtimeObj instanceof JavaRuntime) { + JavaRuntime runtime = (JavaRuntime) runtimeObj; + + testJavaRuntime(runtime); + javaRuntimeFound = true; + } else { + recordFailure("Corrupt JavaRuntime object : " + runtimeObj + ", type " + runtimeObj.getClass()); + } + } + + } else { + recordFailure("Corrupt ImageProcess object : " + processObj + ", type " + processObj.getClass()); + } + } + } else { + recordFailure("Corrupt ImageAddressSpace object : " + addressSpaceObj + ", type " + addressSpaceObj.getClass()); + } + } + + if (! javaRuntimeFound) { + recordFailure("No JavaRuntime objects found in dump"); + } + } + + /** + * Test method run on each JavaRuntime found in the dump. + * @param runtime + */ + private void testJavaRuntime(JavaRuntime runtime) + { + boolean sane = sanityCheckMemoryCategories(runtime); + + if (sane) { + checkMemoryCategoryDetails(runtime); + } else { + recordFailure("MemoryCategory sanity check failed on runtime " + runtime + ". See other messages for details"); + } + } + + private void checkMemoryCategoryDetails(JavaRuntime runtime) + { + for (String path : EXPECTED_MEMORY_CATEGORIES) { + JavaRuntimeMemoryCategory category = findCategoryPath(runtime, path); + + if (category == null) { + recordFailure("Dump missing expected memory category " + path); + } + + /* None of the expected memory categories should have 0 counters */ + try { + if (category.getDeepAllocations() <= 0) { + recordFailure("Expected memory category " + path + " has <=0 deepAllocations: " + category.getDeepAllocations()); + } + + if (category.getDeepBytes() <= 0) { + recordFailure("Expected memory category " + path + " has <=0 deepBytes: " + category.getDeepBytes()); + } + } catch (CorruptDataException ex) { + recordFailure("CorruptDataException checking allocations/bytes from category " + path); + } + } + } + + /** + * Finds a memory category based on a path + * @param runtime Java runtime to walk categories from + * @param path Qualified path to category e.g. JRE/Memory Manager (GC)/Java Heap + * @return JavaRuntimeMemoryCategory object, or null if not found + */ + private JavaRuntimeMemoryCategory findCategoryPath(JavaRuntime runtime, String path) + { + // Strip any leading or trailing '/' + path = path.replaceAll("^/+", ""); + path = path.replaceAll("/+$", ""); + + try { + return findCategoryPath(runtime.getMemoryCategories(), path); + } catch (DataUnavailable e) { + throw new Error("Unexpected DataUnavailable - this should have been caught in the sanity check"); + } + } + + private JavaRuntimeMemoryCategory findCategoryPath(Iterator categoriesIt, String path) + { + int nextSeparatorIndex = path.indexOf('/'); + + String matchName = null; + if (nextSeparatorIndex != -1) { + matchName = path.substring(0, nextSeparatorIndex); + path = path.substring(nextSeparatorIndex + 1); + } else { + matchName = path; + path = ""; + } + + while (categoriesIt.hasNext()) { + Object categoryObj = categoriesIt.next(); + + if (categoryObj instanceof JavaRuntimeMemoryCategory) { + JavaRuntimeMemoryCategory category = (JavaRuntimeMemoryCategory) categoryObj; + + try { + if (category.getName().equals(matchName)) { + if (path.length() == 0) { + return category; + } else { + return findCategoryPath(category.getChildren(), path); + } + } + } catch (CorruptDataException e) { + recordFailure("CorruptDataException getting name from category " + category, e); + } + + } else { + /* Should have been caught in the sanity check */ + throw new Error("Unexpected bad memory category object: " + categoryObj + " type: " + categoryObj.getClass() + " - this should have been caught in the sanity check"); + } + } + return null; + } + + /** + * Verifies that we can get memory categories from the runtime, and that + * there aren't any loops or repeated nodes. + */ + private boolean sanityCheckMemoryCategories(JavaRuntime runtime) + { + try { + Iterator memoryCategoryIt = runtime.getMemoryCategories(); + boolean memoryCategoryFound = false; + Set knownSet = new HashSet(); + + while ( memoryCategoryIt.hasNext() ) { + Object memoryCategoryObj = memoryCategoryIt.next(); + + if (memoryCategoryObj instanceof JavaRuntimeMemoryCategory) { + JavaRuntimeMemoryCategory category = (JavaRuntimeMemoryCategory) memoryCategoryObj; + memoryCategoryFound = true; + + if (! sanityWalkCategory(knownSet, category) ) { + return false; + } + } else { + recordFailure("Corrupt JavaRuntimeMemoryCategory returned from runtime " + runtime + "; Object = " + memoryCategoryObj + ", type = " + memoryCategoryObj.getClass()); + } + } + + if (! memoryCategoryFound) { + recordFailure("No memory categories iterated for runtime " + runtime); + return false; + } + return true; + + } catch (DataUnavailable e) { + recordFailure("Runtime " + runtime + " has no memory categories available"); + return false; + } + } + + private boolean sanityWalkCategory(Set knownSet, JavaRuntimeMemoryCategory currentCategory) + { + String currentCategoryName; + try { + currentCategoryName = currentCategory.getName(); + } catch (CorruptDataException e1) { + recordFailure("CorruptDataException trying to read name of category " + currentCategory, e1); + currentCategoryName = ""; + } + + if (knownSet.contains(currentCategory)) { + recordFailure("Loop detected in JavaRuntimeMemoryCategory tree. Found " + currentCategory + " at least twice. Name = " + currentCategoryName); + return false; + } + + knownSet.add(currentCategory); + + Iterator childIt = null; + try { + childIt = currentCategory.getChildren(); + } catch (CorruptDataException e) { + recordFailure("CorruptDataException trying to get children of category " + currentCategoryName, e); + //Even though we can't walk children - we haven't found a loop or any really dangerous damage + //so we'll call this sane + return true; + } + + try { + long deepBytes = currentCategory.getDeepBytes(); + if (deepBytes < 0) { + recordFailure("Category " + currentCategoryName + " has negative deepBytes: " + deepBytes); + return false; + } + + long shallowBytes = currentCategory.getShallowBytes(); + if (shallowBytes < 0) { + recordFailure("Category " + currentCategoryName + " has negative shallowBytes: " + shallowBytes); + return false; + } + + long deepAllocations = currentCategory.getDeepAllocations(); + if (deepAllocations < 0) { + recordFailure("Category " + currentCategoryName + " has negative deepAllocations: " + deepAllocations); + return false; + } + + long shallowAllocations = currentCategory.getShallowAllocations(); + if (shallowAllocations < 0) { + recordFailure("Category " + currentCategoryName + " has negative shallowAllocations: " + shallowAllocations); + return false; + } + + } catch (CorruptDataException ex) { + recordFailure("CorruptDataException thrown trying to introspect category " + currentCategoryName, ex); + return false; + } + + try { + currentCategory.getMemorySections(false); + currentCategory.getMemorySections(true); + } catch (CorruptDataException e) { + recordFailure("CorruptDataException thrown trying to getMemorySections from " + currentCategoryName, e); + return false; + } catch (DataUnavailable e) { + //This is permissable + } + + while (childIt.hasNext()) { + Object childCategoryObj = childIt.next(); + + if (childCategoryObj instanceof JavaRuntimeMemoryCategory) { + JavaRuntimeMemoryCategory childCategory = (JavaRuntimeMemoryCategory) childCategoryObj; + + if (! sanityWalkCategory(knownSet, childCategory) ) { + return false; + } + } else { + recordFailure("Unrecognised child category " + childCategoryObj + " type: " + childCategoryObj.getClass() + " returned as child of category " + currentCategoryName); + return false; + } + } + + return true; + } + + public boolean runTest() { + resetFailureInfo(); + + try { + walkJavaRuntimes(); + } catch (Throwable t) { + recordFailure("Throwable caught in runTest()", t); + } + + return testPassed(); + } + + private void recordFailure(String message) + { + failureReasons.add(message); + } + + private void recordFailure(String message, Throwable t) + { + StringWriter writer = new StringWriter(); + PrintWriter pw = new PrintWriter(writer); + + pw.println(message); + t.printStackTrace(pw); + + failureReasons.add(writer.toString()); + } + + private boolean testPassed() + { + return failureReasons.size() == 0; + } + + private void resetFailureInfo() + { + failureReasons.clear(); + } + + public void printFailures() + { + for (String failure : failureReasons) { + System.err.println("* " + failure); + } + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/memorycategories/ValidateMemoryCategories.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/memorycategories/ValidateMemoryCategories.java new file mode 100644 index 00000000000..7dfab819fce --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/memorycategories/ValidateMemoryCategories.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.memorycategories; + +import java.io.File; +import java.io.IOException; + +import com.ibm.dtfj.image.Image; +import com.ibm.dtfj.image.ImageFactory; + +/** + * Test application that reads a DTFJ image and validates that the state of its + * JavaRuntimeMemoryCategories. + * + * It uses knowledge of the memory categories that should be present to check + * the memory categories are being calculated, stored and parsed correctly. + * + * Usage: + * + * java com.ibm.memorycategories.ValidateMemoryCategories + */ +public class ValidateMemoryCategories +{ + + + public static void main(String args[]) throws Exception + { + if (args.length < 2) { + System.err.println("Unexpected number of arguments. Got " + args.length); + usage(); + return; + } + + String imageFactoryClassName = args[0]; + String dumpPath = args[1]; + + System.err.println("Loading DTFJ Image"); + + Image image = loadImage(imageFactoryClassName, dumpPath); + + DTFJMemoryCategoryTest test = new DTFJMemoryCategoryTest(image); + + boolean success = false; + + try { + success = test.runTest(); + } finally { + if (success) { + System.err.println("Test PASSED"); + } else { + System.err.println("Test FAILED"); + System.err.println("Failure reasons:"); + test.printFailures(); + } + } + + } + + private static Image loadImage(String imageFactoryClassName, String dumpPath) { + Class clazz = null; + try { + clazz = Class.forName(imageFactoryClassName); + } catch (ClassNotFoundException e) { + System.err.println("Cannot load supplied ImageFactory class name: " + imageFactoryClassName); + System.exit(1); + } + + if (! ImageFactory.class.isAssignableFrom(clazz)) { + System.err.println("Supplied class: " + clazz.getName() + " does not implement the ImageFactory interface"); + } + + ImageFactory factory = null; + try { + factory = (ImageFactory) clazz.newInstance(); + } catch (Exception e) { + System.err.println("Couldn't instantiate image factory from class: " + clazz.getName()); + e.printStackTrace(); + System.exit(1); + } + + + try { + return factory.getImage(new File(dumpPath)); + } catch (IOException e) { + System.err.println("Error creating Image from ImageFactory"); + e.printStackTrace(); + System.exit(1); + } + + //Can't get here + throw new Error("Control shouldn't reach here"); + } + + private static void usage() + { + System.err.println("Usage:"); + System.err.println(); + System.err.println("java " + ValidateMemoryCategories.class.getName() + " "); + } +} \ No newline at end of file diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/oomtest/OOMTest.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/oomtest/OOMTest.java new file mode 100644 index 00000000000..a53b6a345b9 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/oomtest/OOMTest.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.oomtest; + +import java.util.Vector; + +/** + * This class uses up memory. + * + * @author rleigh + * + */ +public class OOMTest { + + /** + * @param args + */ + public static void main(String[] args) { + Vector myLongs = new Vector(); + + for (long i=0; i + info class com/ibm/dump/tests/types/packed/PackedPrimitives + name = com/ibm/dump/tests/types/packed/PackedPrimitives + + ID = 0xf020730 superID = 0xf010150 + classLoader = modifiers: No modifiers available + + This is a packed class + + number of instances: 3 + total size of instances on the heap: 80 bytes + + * @throws IOException + */ + + public static boolean checkInfoClassCommand(String fileName) throws IOException { + + String[] validTotalSizes = { + "80", // 32 and 64cr + "104" // 64 + }; + String command = "info class com/ibm/dump/tests/types/packed/PackedPrimitives"; + + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; + passed &= o.skipLimitedToLineContaining(6, "This is a packed class"); + passed &= o.skipLimitedToLineContaining(2, "number of instances"); + passed &= o.linePassesCheckForStringAtWord("3", 4); + passed &= o.skipLimitedToLineContaining(1, "total size of instances on the heap"); + passed &= o.linePassesCheckForStringsAtWord(validTotalSizes, 8); + + return passed; + } + + /** + * Check through the output looking for the output from "x/j com/ibm/dump/tests/types/packed/PackedPrimitives". + * Check that the "This class is packed" line is present. + * Check that there are three instances. + * Check that there is one on-heap packed instance and that the memory on the heap is right. + * Check that there are two off-heap packed instances and that the memory on the heap is right. + * + * The expected output is as follows: + *

+x/j com/ibm/dump/tests/types/packed/PackedPrimitives
+	 heap #1 - name: Java heap
+
+	  "com/ibm/dump/tests/types/packed/PackedPrimitives" has no static fields
+
+	  com/ibm/dump/tests/types/packed/PackedPrimitives @ 0x2ef488d0
+	   This is an on-heap packed object occupying 48 bytes on the heap
+
+	    references:
+ 	      0x2ef488d0
+
+	  com/ibm/dump/tests/types/packed/PackedPrimitives @ 0x2ef48900
+	   This is an off-heap packed object occupying 16 bytes on the heap
+
+	    references: 
+ 	     
+
+	  com/ibm/dump/tests/types/packed/PackedPrimitives @ 0x2ef48910
+	   This is an off-heap packed object occupying 16 bytes on the heap
+
+	    references: 
+
+	    references:
+		
+ * @throws IOException + */ + + public static boolean checkXJClassCommand(String fileName) throws IOException { + String[] validSizes = { + "48", // on heap 32 and 64cr + "16", // off heap 32 and 64cr + "56", // on heap 64 + "24" // off heap 64 + }; + + String command = "x/j com/ibm/dump/tests/types/packed/PackedPrimitives"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; + passed &= o.skipLimitedToLineContaining(6, "com/ibm/dump/tests/types/packed/PackedPrimitives @"); + passed &= o.skipLimitedToLineContaining(1, "This is an on-heap packed object"); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); + + passed &= o.skipLimitedToLineContaining(6, "com/ibm/dump/tests/types/packed/PackedPrimitives @"); + passed &= o.skipLimitedToLineContaining(1, "This is an off-heap packed object"); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); + + passed &= o.skipLimitedToLineContaining(6, "com/ibm/dump/tests/types/packed/PackedPrimitives @"); + passed &= o.skipLimitedToLineContaining(1, "This is an off-heap packed object"); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); + return passed; + } + + + + + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/portable_heapdump_packed_objects/PortableHeapdumpTest2ArrayOfPackedPrimitivesChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/portable_heapdump_packed_objects/PortableHeapdumpTest2ArrayOfPackedPrimitivesChecker.java new file mode 100644 index 00000000000..358943b107c --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/portable_heapdump_packed_objects/PortableHeapdumpTest2ArrayOfPackedPrimitivesChecker.java @@ -0,0 +1,146 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.portable_heapdump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class PortableHeapdumpTest2ArrayOfPackedPrimitivesChecker { + + /** + * Check through the output looking for the output from "info class [Lcom/ibm/dump/tests/types/packed/PackedPrimitives;". + * Check that the "This class is packed" line is present. + * Check that there are two instances. + * Check that the memory on the heap is right. + * + * The expected output is as follows: + *
+> info class [Lcom/ibm/dump/tests/types/packed/PackedPrimitives;
+name = [Lcom/ibm/dump/tests/types/packed/PackedPrimitives;
+
+        ID = 0xf0764f0    superID = 0xf010650
+        classLoader =     modifiers: No modifiers available
+
+        This is a packed class
+
+        number of instances:     2
+        total size of instances on the heap: 112 bytes
+		
+ * @throws IOException + */ + + public static boolean checkInfoClassCommand(String fileName) throws IOException { + String[] validTotalSizes = { + "352", // 32 + "368", // 64cr + "384"}; // 64 + + + String command = "info class com/ibm/dump/tests/types/packed/PackedPrimitives$Array"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; + passed &= o.skipLimitedToLineContaining(6, "This is a packed class"); + passed &= o.skipLimitedToLineContaining(2, "number of instances"); + passed &= o.linePassesCheckForStringAtWord("2",4); + passed &= o.skipLimitedToLineContaining(1, "total size of instances on the heap"); + passed &= o.linePassesCheckForStringsAtWord(validTotalSizes,8); + return passed; + } + + /** + * Check through the output looking for the output from "x/j [Lcom/ibm/dump/tests/types/packed/PackedPrimitives;". + * + * The expected output is as follows: + *
+x/j [Lcom/ibm/dump/tests/types/packed/PackedPrimitives;
+	 heap #1 - name: Java heap
+
+	  [Lcom/ibm/dump/tests/types/packed/PackedPrimitives; @ 0x2ef491c0
+	    This is an on-heap packed object occupying 336 bytes on the heap
+	    This is an array of size 10
+	    references:
+ 	      0x2ef491c0
+	  [Lcom/ibm/dump/tests/types/packed/PackedPrimitives; @ 0x2ef49310
+	    This is a native packed object occupying 16 bytes on the heap
+	    The native memory is allocated at 
+ This is an array of size 10 + references: + [blank line] +
+ * @throws IOException + */ + + public static boolean checkXJClassCommand(String fileName) throws IOException { + String[] validSizes = { + "336", // on heap 32 + "16", // off heap 32 + "344", // on heap 64cr + "24", // off heap 64cr + "352", // on heap 64 + "32"}; // off heap 64 + + String command = "x/j com/ibm/dump/tests/types/packed/PackedPrimitives$Array"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + // Check for two packed primitive arrays, one of which is on-heap and has one reference, the other has no references + boolean passed = true; + int refCount = 0; + + passed &= o.skipUnlimitedToLineContaining("com/ibm/dump/tests/types/packed/PackedPrimitives$Array @"); + passed &= o.skipLimitedToLineContaining(1, "packed object"); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); + passed &= o.skipLimitedToReferencesLine(3); + refCount += o.skipToNextLineAndCountReferences(); + + passed &= o.skipUnlimitedToLineContaining("com/ibm/dump/tests/types/packed/PackedPrimitives$Array @"); + passed &= o.skipLimitedToLineContaining(1, "packed object"); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); + passed &= o.skipLimitedToReferencesLine(3); + refCount += o.skipToNextLineAndCountReferences(); + + passed &= (refCount == 1); // expect one reference found in total + + if (!passed) { + System.err.println("PortableHeapdumpTest2ArrayOfPackedPrimitivesChecker failed"); + } + return passed; + } + + + + + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/portable_heapdump_packed_objects/PortableHeapdumpTest3PackedMixedChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/portable_heapdump_packed_objects/PortableHeapdumpTest3PackedMixedChecker.java new file mode 100644 index 00000000000..ce3824fbe51 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/portable_heapdump_packed_objects/PortableHeapdumpTest3PackedMixedChecker.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.portable_heapdump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class PortableHeapdumpTest3PackedMixedChecker { + + /** + * Check through the output "info class com/ibm/dump/tests/types/packed/PackedMixedOneRef". + * + * The expected output is as follows: + *
+> info class com/ibm/dump/tests/types/packed/PackedMixedOneRef
+name = com/ibm/dump/tests/types/packed/PackedMixedOneRef
+
+	ID = 0xf020708    superID = 0xf010150    
+	classLoader =     modifiers: No modifiers available
+
+	This is a packed class
+
+	number of instances:     1
+	total size of instances on the heap: 24 bytes
+		
+ + */ + + public static boolean checkInfoClassCommand(String fileName) throws IOException { + String[] validTotalSizes = { + "24", // 32 and 64cr + "40" // 64 + }; + + + String command = "info class com/ibm/dump/tests/types/packed/PackedMixedOneRef"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + boolean passed = true; + passed &= o.skipLimitedToLineContaining(6, "This is a packed class"); + passed &= o.skipLimitedToLineContaining(2, "number of instances"); + passed &= o.linePassesCheckForStringAtWord("1", 4); // number of instances 1 + passed &= o.skipLimitedToLineContaining(1, "total size of instances on the heap"); + passed &= o.linePassesCheckForStringsAtWord(validTotalSizes, 8); + return passed; + + } + + /** + * Check through the output looking for the output from "x/j com/ibm/dump/tests/types/packed/PackedMixedOneRef". + * + * The expected output is as follows: + *
+x/j com/ibm/dump/tests/types/packed/PackedMixedOneRef
+	 heap #1 - name: Java heap
+
+	  "com/ibm/dump/tests/types/packed/PackedMixedOneRef" has no static fields
+
+	  com/ibm/dump/tests/types/packed/PackedMixedOneRef @ 0x2ef49360
+	    This is an on-heap packed object occupying 24 bytes on the heap
+
+	    references:
+ 	      0x2ef49360 0x2ef49378
+		
+ * @throws IOException + */ + + public static boolean checkXJClassCommand(String fileName) throws IOException { + String[] validSizes = { + "24", // on heap 32 and 64cr + "40"}; // on heap 64 + + String command = "x/j com/ibm/dump/tests/types/packed/PackedMixedOneRef"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + boolean passed = true; + passed &= o.skipUnlimitedToLineContaining("com/ibm/dump/tests/types/packed/PackedMixedOneRef @"); + passed &= o.skipLimitedToLineContaining(1, "This is an on-heap packed object"); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); + + System.err.println("Checking the first reference from the PackedMixedOneRef is to a com/ibm/dump/tests/types/notpacked/NotPackedPrimitives"); + passed &= o.skipToLineContainingListOfReferencesAndCheckCount(2, 2); + String secondReference = o.getSecondReference(); + + passed &= OutputFile.checkReferenceIsToObject(fileName, secondReference, "com/ibm/dump/tests/types/notpacked/NotPackedPrimitives"); + return passed; + + } + + + + + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/portable_heapdump_packed_objects/PortableHeapdumpTest4ArrayOfPackedMixedOneRefChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/portable_heapdump_packed_objects/PortableHeapdumpTest4ArrayOfPackedMixedOneRefChecker.java new file mode 100644 index 00000000000..8c63c2348e0 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/portable_heapdump_packed_objects/PortableHeapdumpTest4ArrayOfPackedMixedOneRefChecker.java @@ -0,0 +1,129 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.portable_heapdump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class PortableHeapdumpTest4ArrayOfPackedMixedOneRefChecker { + + /** + * Check through the output looking for the output from "info class [Lcom/ibm/dump/tests/types/packed/PackedMixedOneRef;". + * + * The expected output is as follows: + *
+> info class [Lcom/ibm/dump/tests/types/packed/PackedMixedOneRef;
+name = [Lcom/ibm/dump/tests/types/packed/PackedMixedOneRef;
+
+        ID = 0xf0767f8    superID = 0xf010650
+        classLoader =     modifiers: No modifiers available
+
+        This is a packed class
+
+        number of instances:     1
+        total size of instances on the heap: 56 bytes
+
+		
+ * @throws IOException + */ + + public static boolean checkInfoClassCommand(String fileName) throws IOException { + String[] validTotalSizes = { + "96", // 32 + "104", // 64cr + "192"}; // 64 + + String command = "info class com/ibm/dump/tests/types/packed/PackedMixedOneRef$Array"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; + passed &= o.skipLimitedToLineContaining(6, "This is a packed class"); + passed &= o.skipLimitedToLineContaining(2, "number of instances"); + passed &= o.linePassesCheckForStringAtWord("1",4); + passed &= o.skipLimitedToLineContaining(1, "total size of instances on the heap"); + passed &= o.linePassesCheckForStringsAtWord(validTotalSizes,8); + return passed; + } + + /** + * Check through the output looking for the output from "x/j [Lcom/ibm/dump/tests/types/packed/PackedMixedOneRef;". + * + * The essential point is that in the array we will see the references, not to the PackedMixedOneRef objects as we would if this were + * a normal array, but the references to the objects to which the PackedMixedOneRef objects point. + * The expected output is as follows: + *
+x/j [Lcom/ibm/dump/tests/types/packed/PackedMixedOneRef;
+	 heap #1 - name: Java heap
+
+	  [Lcom/ibm/dump/tests/types/packed/PackedMixedOneRef; @ 0x2ef493b8
+	    This is an on-heap packed object occupying 96 bytes on the heap
+	    This is an array of size 10
+	    references:
+ 	      0x2ef49418 0x2ef49448 0x2ef49478 0x2ef494a8 0x2ef494d8 0x2ef49508 0x2ef49538 0x2ef49568 0x2ef49598 0x2ef495c8 0x2ef493b8
+ 	      
+ * @throws IOException + */ + + public static boolean checkXJClassCommand(String fileName) throws IOException { + String[] validSizes = { + "96", // on heap 32 + "104", // on heap 64cr + "192" // on heap 64 + }; + + + String command = "x/j com/ibm/dump/tests/types/packed/PackedMixedOneRef$Array"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; + passed &= o.skipUnlimitedToLineContaining("com/ibm/dump/tests/types/packed/PackedMixedOneRef$Array @"); + passed &= o.skipLimitedToLineContaining(1, "This is an on-heap packed object"); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); + + System.err.println("Checking the first reference from the array of PackedMixedOneRef is to a com/ibm/dump/tests/types/notpacked/NotPackedPrimitives"); + passed &= o.skipToLineContainingListOfReferencesAndCheckCount(12, 11); + String secondReference = o.getSecondReference(); + + passed &= OutputFile.checkReferenceIsToObject(fileName, secondReference, "com/ibm/dump/tests/types/notpacked/NotPackedPrimitives"); + + + return passed; + } + + + + + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/portable_heapdump_packed_objects/PortableHeapdumpTest5ArrayOfPackedMixedTwoRefsChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/portable_heapdump_packed_objects/PortableHeapdumpTest5ArrayOfPackedMixedTwoRefsChecker.java new file mode 100644 index 00000000000..e927f9ed5c1 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/portable_heapdump_packed_objects/PortableHeapdumpTest5ArrayOfPackedMixedTwoRefsChecker.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.portable_heapdump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class PortableHeapdumpTest5ArrayOfPackedMixedTwoRefsChecker { + + + + /** + * Check through the output looking for the output from "x/j [Lcom/ibm/dump/tests/types/packed/PackedMixedTwoRefs;". + * + * The essential point is that in the array we will see the references, not to the PackedMixedTwoRefs objects + * as we would if this were a normal array, but the references to the objects to which the PackedMixed objects point. + * Hence we expect to see 20 references, not 10. + *
+x/j [Lcom/ibm/dump/tests/types/packed/PackedMixedTwoRefs;
+	 heap #1 - name: Java heap
+
+	  [Lcom/ibm/dump/tests/types/packed/PackedMixedTwoRefs; @ 0x2ef49608
+	    This is an on-heap packed object occupying 136 bytes on the heap
+	    This is an array of size 10
+	    references:
+ 	      0x2ef496c0 0x2ef49690 0x2ef49720 0x2ef496f0 0x2ef49780 0x2ef49750 0x2ef497e0 0x2ef497b0 0x2ef49840 0x2ef49810 0x2ef498a0 0x2ef49870 0x2ef49900 0x2ef498d0 0x2ef49960 0x2ef49930 0x2ef499c0 0x2ef49990 0x2ef49a20 0x2ef499f0 0x2ef49608
+		
+ * @throws IOException + */ + + public static boolean checkXJClassCommand(String fileName) throws IOException { + String[] validSizes = { + "136", // on heap 32 + "144", // 64cr + "272" // 64 + }; + + + String command = "x/j com/ibm/dump/tests/types/packed/PackedMixedTwoRefs$Array"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; + passed &= o.skipUnlimitedToLineContaining("com/ibm/dump/tests/types/packed/PackedMixedTwoRefs$Array @"); + passed &= o.skipLimitedToLineContaining(1, "This is an on-heap packed object"); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); + + System.err.println("Checking that the first reference from the array of PackedMixedTwoRefs is to an instance of com/ibm/dump/tests/types/notpacked/NotPackedPrimitives"); + passed &= o.skipToLineContainingListOfReferencesAndCheckCount(2, 21); + String secondReference = o.getSecondReference(); + + passed &= OutputFile.checkReferenceIsToObject(fileName, secondReference, "com/ibm/dump/tests/types/notpacked/NotPackedPrimitives"); + + + return passed; + } + + + + + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/portable_heapdump_packed_objects/PortableHeapdumpTest6PackedMixedWithReferenceToSelfChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/portable_heapdump_packed_objects/PortableHeapdumpTest6PackedMixedWithReferenceToSelfChecker.java new file mode 100644 index 00000000000..8c99a3e5afb --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/portable_heapdump_packed_objects/PortableHeapdumpTest6PackedMixedWithReferenceToSelfChecker.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.portable_heapdump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class PortableHeapdumpTest6PackedMixedWithReferenceToSelfChecker { + + /** + * Check through the output looking for the output from "x/j com/ibm/dump/tests/types/packed/PackedMixedWithReferenceToSelf". + * + * The expected output is as follows: + *
+x/j com/ibm/dump/tests/types/packed/PackedMixedWithReferenceToSelf
+	 heap #1 - name: Java heap
+
+	  "com/ibm/dump/tests/types/packed/PackedMixedWithReferenceToSelf" has no static fields
+
+	  com/ibm/dump/tests/types/packed/PackedMixedWithReferenceToSelf @ 0x2ef49a50
+	    This is an on-heap packed object occupying 24 bytes on the heap
+
+	    references:
+ 	      0x2ef49a50 0x2ef49a50
+
+		
+ * @throws IOException + */ + + public static boolean checkXJClassCommand(String fileName) throws IOException { + String[] validSizes = { + "24", // 32 and 64cr + "40"}; // 64 + + String command = "x/j com/ibm/dump/tests/types/packed/PackedMixedWithReferenceToSelf"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; + passed &= o.skipUnlimitedToLineContaining("com/ibm/dump/tests/types/packed/PackedMixedWithReferenceToSelf @"); + passed &= o.skipLimitedToLineContaining(1, "This is an on-heap packed object"); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); + + + System.err.println("Checking that the first (and only) reference from the PackedMixedWithReferenceToSelf is indeed to itself"); + passed &= o.skipToLineContainingListOfReferencesAndCheckCount(8, 2); + String secondReference = o.getSecondReference(); + + passed &= OutputFile.checkReferenceIsToObject(fileName, secondReference, "com/ibm/dump/tests/types/packed/PackedMixedWithReferenceToSelf"); + + + return passed; + } + + + + + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/portable_heapdump_packed_objects/PortableHeapdumpTest7NestedPackedChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/portable_heapdump_packed_objects/PortableHeapdumpTest7NestedPackedChecker.java new file mode 100644 index 00000000000..0333805661f --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/portable_heapdump_packed_objects/PortableHeapdumpTest7NestedPackedChecker.java @@ -0,0 +1,136 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.portable_heapdump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class PortableHeapdumpTest7NestedPackedChecker { + + /** + * Check through the output looking for the output from "info class com/ibm/dump/tests/types/packed/NestedPacked". + * + * The expected output is as follows: + *
+> info class com/ibm/dump/tests/types/packed/NestedPacked
+name = com/ibm/dump/tests/types/packed/NestedPacked
+
+        ID = 0xf077a80    superID = 0xf010650
+        classLoader =     modifiers: No modifiers available
+
+        This is a packed class
+
+        number of instances:     2
+        total size of instances on the heap: 40 bytes		
+        
+ * @throws IOException + */ + + public static boolean checkInfoClassCommand(String fileName) throws IOException { + String[] validTotalSizes = { + "40", // 32 + "48", // 64cr + "64"}; // 64 + + + boolean passed = true; + + String command = "info class com/ibm/dump/tests/types/packed/NestedPacked"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + passed &= o.skipLimitedToLineContaining(6, "This is a packed class"); + passed &= o.skipLimitedToLineContaining(2, "number of instances"); + passed &= o.linePassesCheckForStringAtWord("2",4); + passed &= o.skipLimitedToLineContaining(1, "total size of instances on the heap"); + passed &= o.linePassesCheckForStringsAtWord(validTotalSizes,8); + + return passed; + } + + /** + * Check through the output looking for the output from "x/j com/ibm/dump/tests/types/packed/NestedPacked". + * + * The expected output is as follows: + *
+x/j com/ibm/dump/tests/types/packed/NestedPacked
+	 heap #1 - name: Java heap
+
+	  "com/ibm/dump/tests/types/packed/NestedPacked" has no static fields
+
+	  com/ibm/dump/tests/types/packed/NestedPacked @ 0x2ef49a88
+	    This is an on-heap packed object occupying 24 bytes on the heap
+
+	    references:
+ 	      0x2ef49a88
+	  com/ibm/dump/tests/types/packed/NestedPacked @ 0x2ef49aa0
+	    This is a native packed object occupying 16 bytes on the heap
+	    The native memory is allocated at 
+ + references: + +
+ * @throws IOException + */ + + public static boolean checkXJClassCommand(String fileName) throws IOException { + String[] validSizes = { + "24", // on heap 32 + "16", // off heap 32 + "32", // on heap 64cr + "16", // off heap 64cr + "40", // on heap 64 + "24" // off heap 64 + }; + + String command = "x/j com/ibm/dump/tests/types/packed/NestedPacked"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; + passed &= o.skipLimitedToLineContaining(6, "This is an on-heap packed object"); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); + passed &= o.skipToLineContainingListOfReferencesAndCheckCount(2, 1); + + passed &= o.skipLimitedToLineContaining(6, "com/ibm/dump/tests/types/packed/NestedPacked @"); + passed &= o.skipLimitedToLineContaining(1, "This is an off-heap packed object"); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); + passed &= o.skipToLineContainingListOfReferencesAndCheckCount(2, 0); + + return passed; + } + + + + + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/portable_heapdump_packed_objects/PortableHeapdumpTest8PackedIntsArrayChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/portable_heapdump_packed_objects/PortableHeapdumpTest8PackedIntsArrayChecker.java new file mode 100644 index 00000000000..2e93bfe1269 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/portable_heapdump_packed_objects/PortableHeapdumpTest8PackedIntsArrayChecker.java @@ -0,0 +1,136 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.portable_heapdump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class PortableHeapdumpTest8PackedIntsArrayChecker { + + /** + * Check through the output looking for the output from "info class com/ibm/dump/tests/types/packed/PackedIntsArray". + * + * The expected output is as follows: + *
+> info class com/ibm/dump/tests/types/packed/PackedIntsArray
+name = com/ibm/dump/tests/types/packed/PackedIntsArray
+
+        ID = 0xf076cf0    superID = 0xf010650
+        classLoader =     modifiers: No modifiers available
+
+        This is a packed class
+
+        number of instances:     2
+        total size of instances on the heap: 56 bytes
+
+		
+ * @throws IOException + */ + + public static boolean checkInfoClassCommand(String fileName) throws IOException { + String[] validTotalSizes = { + "56", // 32 + "64", // 64cr + "80"}; // 64 + + + String command = "info class com/ibm/dump/tests/types/packed/PackedIntsArray"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; + passed &= o.skipLimitedToLineContaining(6, "This is a packed class"); + passed &= o.skipLimitedToLineContaining(2, "number of instances"); + passed &= o.linePassesCheckForStringAtWord("2", 4); + passed &= o.skipLimitedToLineContaining(1, "total size of instances on the heap"); + passed &= o.linePassesCheckForStringsAtWord(validTotalSizes, 8); + + return passed; + } + + /** + * Check through the output looking for the output from "x/j com/ibm/dump/tests/types/packed/PackedIntsArray". + * + * The expected output is as follows: + *
+x/j com/ibm/dump/tests/types/packed/PackedIntsArray
+	 heap #1 - name: Java heap
+
+	  "com/ibm/dump/tests/types/packed/PackedIntsArray" has no static fields
+
+	  com/ibm/dump/tests/types/packed/PackedIntsArray @ 0x2ef49ca8
+	    This is an on-heap packed object occupying 40 bytes on the heap
+
+	    references:
+ 	      0x2ef49ca8
+	  com/ibm/dump/tests/types/packed/PackedIntsArray @ 0x2ef49cd0
+	    This is a native packed object occupying 16 bytes on the heap
+	    The native memory is allocated at 
+ + references: +
+ * @throws IOException + */ + + public static boolean checkXJClassCommand(String fileName) throws IOException { + String[] validSizes = { + "40", // on heap 32 + "16", // off heap 32 + "48", // on heap 64cr + "16", // off heap 64cr + "56", // on heap 64 + "24" // off heap 64 + }; + + + String command = "x/j com/ibm/dump/tests/types/packed/PackedIntsArray"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; + passed &= o.skipLimitedToLineContaining(6, "com/ibm/dump/tests/types/packed/PackedIntsArray @"); + passed &= o.skipLimitedToLineContaining(1, "This is an on-heap packed object"); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); + + passed &= o.skipLimitedToLineContaining(6, "com/ibm/dump/tests/types/packed/PackedIntsArray @"); + passed &= o.skipLimitedToLineContaining(1, "This is an off-heap packed object"); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); + + return passed; + } + + + + + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/portable_heapdump_packed_objects/PortableHeapdumpTest9ArrayOfPackedMixedArrayElementChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/portable_heapdump_packed_objects/PortableHeapdumpTest9ArrayOfPackedMixedArrayElementChecker.java new file mode 100644 index 00000000000..3b676bc02af --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/portable_heapdump_packed_objects/PortableHeapdumpTest9ArrayOfPackedMixedArrayElementChecker.java @@ -0,0 +1,109 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.portable_heapdump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class PortableHeapdumpTest9ArrayOfPackedMixedArrayElementChecker { + + /** + * Check through the output looking for the output from "x/j com/ibm/dump/tests/types/packed/PackedMixedArrayElement". + * + * The essential point of this test is to check that the array has a reference to the packed object + * and that the derived object has a reference to the array + * + * The expected output is as follows: + *
+x/j [Lcom/ibm/dump/tests/types/packed/PackedMixedArrayElement;
+	 heap #1 - name: Java heap
+
+	  [Lcom/ibm/dump/tests/types/packed/PackedMixedArrayElement; @ 0x2ef49cf0
+	    This is an on-heap packed object occupying 24 bytes on the heap
+	    This is an array of size 1
+	    references:
+ 	      0x2ef49d08 0x2ef49cf0
+x/j com/ibm/dump/tests/types/packed/PackedMixedArrayElement
+	 heap #1 - name: Java heap
+
+	  "com/ibm/dump/tests/types/packed/PackedMixedArrayElement" has no static fields
+
+	  com/ibm/dump/tests/types/packed/PackedMixedArrayElement @ 0x2ef49a50
+	    This is an on-heap packed object occupying 24 bytes on the heap
+
+	    references:
+ 	      0x2ef49a50 0x2ef49a50
+	  com/ibm/dump/tests/types/packed/PackedMixedArrayElement @ 0x2ef49d08
+	    This is an on-heap packed object occupying 16 bytes on the heap
+
+	    references:
+ 	      0x2ef49cf0       
+		
+ * @throws IOException + */ + + public static boolean checkXJClassCommand(String fileName) throws IOException { + String[] validArraySizes = { + "24", // 32 + "32", // 64cr + "40", // 64 nocr Z + "48"}; // 64 + + String command = "x/j com/ibm/dump/tests/types/packed/PackedMixedArrayElement$Array"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; + passed &= o.skipUnlimitedToLineContaining("com/ibm/dump/tests/types/packed/PackedMixedArrayElement$Array @"); + passed &= o.skipLimitedToLineContaining(1, "This is an on-heap packed object"); + passed &= o.linePassesCheckForStringsAtWord(validArraySizes,8); + + System.err.println("Checking that the second reference from the array of PackedMixedArrayElement is to the element"); + passed &= o.skipToLineContainingListOfReferencesAndCheckCount(2, 2); + String secondReference = o.getSecondReference(); + + // check the array points to the element + passed &= OutputFile.checkReferenceIsToObject(fileName, secondReference, "com/ibm/dump/tests/types/packed/PackedMixedArrayElement"); + + passed &= o.skipUnlimitedToLineContaining("com/ibm/dump/tests/types/packed/PackedMixedArrayElement @ " + secondReference); + + System.err.println("Checking that the first (and only) reference from the first element of the array of PackedMixedArrayElement is back to the array"); + passed &= o.skipToLineContainingListOfReferencesAndCheckCount(5, 1); + String firstReference = o.getFirstReference(); + + // check the element points to the array + passed &= OutputFile.checkReferenceIsToObject(fileName, firstReference, "com/ibm/dump/tests/types/packed/PackedMixedArrayElement$Array"); + + return passed; + } + + + + + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/CheckSystemDump.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/CheckSystemDump.java new file mode 100644 index 00000000000..d3eab0e0855 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/CheckSystemDump.java @@ -0,0 +1,176 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.system_dump_packed_objects; + + +import java.io.FileNotFoundException; +import java.io.IOException; + +/** + * This class checks the output from jdmpview run against a PHD containing packed objects + * + * @author matthew + * + */ +public class CheckSystemDump { + + /** + * @param args + */ + public static void main(String[] args) { + + if (args.length < 1) { + System.err.println("A file containing jdmpview output is required to check."); + System.exit(1); + } + String fileName = args[0]; + + System.err.println("Portable Heapdump Checker"); + System.err.println("Checking " + fileName); + + boolean passed = true; + + try { + /** + * Test 1. Check PackedPrimitives + */ + System.err.println("\n**************************************************\n"); + System.err.println("* 1. Check PackedPrimitives\n"); + System.err.println("**************************************************"); + passed &= SystemDumpTest1PackedPrimitivesChecker.checkInfoClassCommand(fileName); + passed &= SystemDumpTest1PackedPrimitivesChecker.checkXJClassCommand(fileName); + + /** + * Test 2. Check array of PackedPrimitives + */ + System.err.println("\n**************************************************\n"); + System.err.println("* 2. Check array of PackedPrimitives\n"); + System.err.println("**************************************************"); + passed &= SystemDumpTest2ArrayOfPackedPrimitivesChecker.checkInfoClassCommand(fileName); + passed &= SystemDumpTest2ArrayOfPackedPrimitivesChecker.checkXJClassCommand(fileName); + + /** + * Test 3. Check PackedMixed + */ + System.err.println("\n**************************************************\n"); + System.err.println("* 3. Check PackedMixedOneRef\n"); + System.err.println("**************************************************"); + passed &= SystemDumpTest3PackedMixedOneRefChecker.checkInfoClassCommand(fileName); + passed &= SystemDumpTest3PackedMixedOneRefChecker.checkXJClassCommand(fileName); + + + /** + * Test 4. Check array of PackedMixed + */ + System.err.println("\n**************************************************\n"); + System.err.println("* 4. Check array of PackedMixed\n"); + System.err.println("**************************************************"); + passed &= SystemDumpTest4ArrayOfPackedMixedOneRefChecker.checkInfoClassCommand(fileName); + passed &= SystemDumpTest4ArrayOfPackedMixedOneRefChecker.checkXJClassCommand(fileName); + + /** + * Test 5. Check array of PackedMixedTwoRefs + */ + System.err.println("\n**************************************************\n"); + System.err.println("* 5. Check PackedMixedTwoRefs\n"); + System.err.println("**************************************************"); + passed &= SystemDumpTest5ArrayOfPackedMixedTwoRefsChecker.checkXJClassCommand(fileName); + + /** + * Test 6. Check PackedMixedWithReferenceToSelf + */ + System.err.println("\n**************************************************\n"); + System.err.println("* 6. Check PackedMixedWithReferenceToSelf\n"); + System.err.println("**************************************************"); + passed &= SystemDumpTest6PackedMixedWithReferenceToSelfChecker.checkXJClassCommand(fileName); + + /** + * Test 7. Check NestedPacked + */ + System.err.println("\n**************************************************\n"); + System.err.println("* 7. Check NestedPacked and NestedPacked1\n"); + System.err.println("**************************************************"); + passed &= SystemDumpTest7NestedPackedChecker.checkInfoClassCommand(fileName); + passed &= SystemDumpTest7NestedPackedChecker.checkXJClassCommand(fileName); + passed &= SystemDumpTest71NestedPacked1Checker.checkXJClassCommand(fileName); + + /** + * Test 8. Check NestedPackedMixed + */ + System.err.println("\n**************************************************\n"); + System.err.println("* 8. Check NestedPackedMixed\n"); + System.err.println("**************************************************"); + passed &= SystemDumpTest8NestedPackedMixedChecker.checkInfoClassCommand(fileName); + passed &= SystemDumpTest8NestedPackedMixedChecker.checkXJClassCommand(fileName); + + /** + * Test 9. Check PackedIntsArray + */ + System.err.println("\n**************************************************\n"); + System.err.println("* 9. Check PackedIntsArray\n"); + System.err.println("**************************************************"); + passed &= SystemDumpTest9PackedIntsArrayChecker.checkInfoClassCommand(fileName); + passed &= SystemDumpTest9PackedIntsArrayChecker.checkXJClassCommand(fileName); + + /** + * Test 10. Check PackedIntsArrayArray and derived object + */ + System.err.println("\n**************************************************\n"); + System.err.println("* 10. Check PackedIntsArrayArray and derived object\n"); + System.err.println("**************************************************"); + passed &= SystemDumpTest10PackedIntsArrayArrayChecker.checkInfoClassCommand(fileName); + passed &= SystemDumpTest10PackedIntsArrayArrayChecker.checkXJClassCommand(fileName); + passed &= SystemDumpTest101DerivedPackedIntsArrayArrayChecker.checkXJClassCommand(fileName); + + /** + * Test 11. Check array of PackedMixedWithReferenceToSelf + */ + System.err.println("\n**************************************************\n"); + System.err.println("* 11. Check array of PackedMixedWithReferenceToSelf\n"); + System.err.println("**************************************************"); + passed &= SystemDumpTest11ArrayOfPackedMixedArrayElementChecker.checkXJClassCommand(fileName); + + } catch (FileNotFoundException e) { + System.err.println("FileNotFoundException occured reading " + fileName); + e.printStackTrace(System.err); + System.exit(1); + } catch (IOException e) { + System.err.println("IOException occured reading " + fileName); + e.printStackTrace(System.err); + System.exit(1); + } + + + if( passed ) { + System.err.println("Test passed."); + System.exit(0); + } else { + System.err.println("Test failed."); + System.exit(1); + } + } + + + + + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest101DerivedPackedIntsArrayArrayChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest101DerivedPackedIntsArrayArrayChecker.java new file mode 100644 index 00000000000..092214fc63c --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest101DerivedPackedIntsArrayArrayChecker.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.system_dump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class SystemDumpTest101DerivedPackedIntsArrayArrayChecker { + + /** + * Check through the output looking for the output from "x/j [Lcom/ibm/dump/tests/types/packed/PackedIntsArray;". + * + * The expected output is as follows: + *
+> x/j [Lcom/ibm/dump/tests/types/packed/PackedIntsArray;
+	 heap #1 - name: Generational@2d22b0
+
+	  [Lcom/ibm/dump/tests/types/packed/PackedIntsArray; @ 0x2ef48e58
+	   This is an on-heap packed object occupying 16 bytes on the heap
+	   This is a derived packed object:
+	    target object: com/ibm/dump/tests/types/packed/PackedIntsArrayArray @ 0x2ef48df8
+	    target offset: 0xc
+	  showing fields for  [Lcom/ibm/dump/tests/types/packed/PackedIntsArray; packed @ 0x2ef48e04
+	   0:	 com/ibm/dump/tests/types/packed/PackedIntsArray packed @ 0x2ef48e04
+	   1:	 com/ibm/dump/tests/types/packed/PackedIntsArray packed @ 0x2ef48e20
+	   2:	 com/ibm/dump/tests/types/packed/PackedIntsArray packed @ 0x2ef48e3c
+
+	    references:
+ 	      0x2ef48df8
+		
+ * @throws IOException + */ + + public static boolean checkXJClassCommand(String fileName) throws IOException { + String[] validSizes = {"16","24", "32"}; // object header on 32 , 64, 64 nocr + + + String command = "x/j com/ibm/dump/tests/types/packed/PackedIntsArray$Array"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; + passed &= o.skipLimitedToLineContaining(7, "This is an on-heap packed object"); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); + passed &= o.skipLimitedToLineContaining(1, "This is a derived packed object"); + passed &= o.skipLimitedToLineContaining(1, "target object: com/ibm/dump/tests/types/packed/PackedIntsArrayArray @ 0x"); + passed &= o.skipLimitedToLineContaining(1, "target offset: 0x"); + passed &= o.skipLimitedToLineContaining(1, "showing fields for com/ibm/dump/tests/types/packed/PackedIntsArray$Array packed @ 0x"); + passed &= o.skipToLineContainingListOfReferencesAndCheckCount(6, 1); + return passed; + } + + + + + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest10PackedIntsArrayArrayChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest10PackedIntsArrayArrayChecker.java new file mode 100644 index 00000000000..b3dbe5dabd2 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest10PackedIntsArrayArrayChecker.java @@ -0,0 +1,126 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.system_dump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class SystemDumpTest10PackedIntsArrayArrayChecker { + + /** + * Check through the output looking for the output from "info class com/ibm/dump/tests/types/packed/PackedIntsArray". + * + * The expected output is as follows: + *
+info class com/ibm/dump/tests/types/packed/PackedIntsArrayArray
+name = com/ibm/dump/tests/types/packed/PackedIntsArrayArray
+
+	ID = 0x3f96c00    superID = 0x3cc2700    
+	classLoader = 0x2ef39e78    modifiers: public final 
+
+	This is a packed class
+
+	number of instances:     1
+	total size of instances on the heap: 96 bytes
+
+Inheritance chain....
+
+	com/ibm/jvm/packed/PackedObject
+	   com/ibm/dump/tests/types/packed/PackedIntsArrayArray
+
+		
+ * @throws IOException + */ + + public static boolean checkInfoClassCommand(String fileName) throws IOException { + String[] validTotalSizes = {"96","192", "104", "112", "136"}; // 96 is 32bit, 136 is 64nocr, not sure about the others and can't run packed and compressed refs anyway + + + String command = "info class com/ibm/dump/tests/types/packed/PackedIntsArrayArray"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; + passed &= o.skipLimitedToLineContaining(6, "This is a packed class"); + passed &= o.skipLimitedToLineContaining(2, "number of instances"); + passed &= o.linePassesCheckForStringAtWord("2", 4); + passed &= o.skipLimitedToLineContaining(1, "total size of instances on the heap"); + passed &= o.linePassesCheckForStringsAtWord(validTotalSizes, 8); + + return passed; + } + + /** + * Check through the output looking for the output from "x/j com/ibm/dump/tests/types/packed/PackedIntsArray". + * + * The expected output is as follows: + *
+x/j com/ibm/dump/tests/types/packed/PackedIntsArrayArray
+	 heap #1 - name: Generational@83d0f8
+
+	  "com/ibm/dump/tests/types/packed/PackedIntsArrayArray" has no static fields
+
+	  com/ibm/dump/tests/types/packed/PackedIntsArrayArray @ 0x2ef49758
+	   This is an on-heap packed object occupying 96 bytes on the heap
+	   fields inherited from "com/ibm/jvm/packed/PackedObject":
+	   declared fields:
+	    @Length(3) public com.ibm.dump.tests.types.packed.PackedIntsArray[] piArrayArray1 =  com/ibm/dump/tests/types/packed/PackedIntsArray[3] packed @ 0x2ef49764
+
+	    references:
+ 	      0x2ef49758
+		
+ * @throws IOException + */ + + public static boolean checkXJClassCommand(String fileName) throws IOException { + String[] validSizes = {"96","192", "104", "112", "32"}; // 32 , 64, nocr + + + String command = "x/j com/ibm/dump/tests/types/packed/PackedIntsArrayArray"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; + passed &= o.skipLimitedToLineContaining(6, "com/ibm/dump/tests/types/packed/PackedIntsArrayArray @"); + passed &= o.skipLimitedToLineContaining(1, "This is an on-heap packed object"); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); + passed &= o.skipLimitedToLineContaining(3, "@Length(3) public com.ibm.dump.tests.types.packed.PackedIntsArray$Array piArrayArray1 = com/ibm/dump/tests/types/packed/PackedIntsArray$Array[3] packed @ 0x"); + + return passed; + } + + + + + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest11ArrayOfPackedMixedArrayElementChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest11ArrayOfPackedMixedArrayElementChecker.java new file mode 100644 index 00000000000..05cc836047c --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest11ArrayOfPackedMixedArrayElementChecker.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.system_dump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class SystemDumpTest11ArrayOfPackedMixedArrayElementChecker { + + /** + * Check through the output looking for the output from "x/j com/ibm/dump/tests/types/packed/PackedMixedArrayElement". + * + * The essential point of this test is to check that there is one reference and one only. This will be a + * reference to the one element in the array. The odd extra self-reference that + * all on-heap packed objects have will have been suppressed + * + * The expected output is as follows: + *
+x/j [Lcom/ibm/dump/tests/types/packed/PackedMixedArrayElement;
+	 heap #1 - name: Generational@3960f0
+
+	  [Lcom/ibm/dump/tests/types/packed/PackedMixedArrayElement; @ 0x2ef48b98
+	   This is an on-heap packed object occupying 24 bytes on the heap
+	   0:	 com/ibm/dump/tests/types/packed/PackedMixedArrayElement packed @ 0x2ef48ba8
+
+	    references:
+ 	      0x2ef48b98 0x2ef48bb0
+        
+		
+ * @throws IOException + */ + + public static boolean checkXJClassCommand(String fileName) throws IOException { + String[] validArraySizes = {"24", "32", "40", "48"}; // on-heap 32, on-heap 64, 64 nocr Z, nocr + + String command = "x/j com/ibm/dump/tests/types/packed/PackedMixedArrayElement$Array"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; + passed &= o.skipUnlimitedToLineContaining("com/ibm/dump/tests/types/packed/PackedMixedArrayElement$Array @"); + passed &= o.skipLimitedToLineContaining(1, "This is an on-heap packed object"); + passed &= o.linePassesCheckForStringsAtWord(validArraySizes,8); + passed &= o.skipLimitedToLineContaining(1, "0: com/ibm/dump/tests/types/packed/PackedMixedArrayElement packed @ 0x"); + + System.err.println("Checking that the second reference from the array of PackedMixedArrayElement is to the element"); + passed &= o.skipToLineContainingListOfReferencesAndCheckCount(2, 2); + String secondReference = o.getSecondReference(); + + // check the second reference is to the element + passed &= OutputFile.checkReferenceIsToObject(fileName, secondReference, "com/ibm/dump/tests/types/packed/PackedMixedArrayElement"); + + return passed; + } + + + + + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest1PackedPrimitivesChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest1PackedPrimitivesChecker.java new file mode 100644 index 00000000000..dcd4bd28f00 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest1PackedPrimitivesChecker.java @@ -0,0 +1,178 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.system_dump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class SystemDumpTest1PackedPrimitivesChecker { + + /** + * Check through the output looking for the output from "info class com/ibm/dump/tests/types/packed/PackedPrimitives". + * Check that the "This class is packed" line is present. + * Check that there are three instances. + * Check that there is one packed instance and that the memory on the heap is right. + * Check that there are two off-heap packed instances and that the memory on the heap is right. + * + * The expected output is as follows: + *
+	info class com/ibm/dump/tests/types/packed/PackedPrimitives
+	name = com/ibm/dump/tests/types/packed/PackedPrimitives
+
+		ID = 0xf020730    superID = 0xf010150    
+		classLoader =     modifiers: No modifiers available
+
+		This is a packed class
+
+		number of instances:     3
+		total size of instances on the heap: 80 bytes
+		
+ * @throws IOException + */ + + public static boolean checkInfoClassCommand(String fileName) throws IOException { + + String[] validTotalSizes = {"80","120", "104"}; // 32 , 64, nocr + String command = "info class com/ibm/dump/tests/types/packed/PackedPrimitives"; + + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; + passed &= o.skipLimitedToLineContaining(6, "This is a packed class"); + passed &= o.skipLimitedToLineContaining(2, "number of instances"); + passed &= o.linePassesCheckForStringAtWord("3", 4); + passed &= o.skipLimitedToLineContaining(1, "total size of instances on the heap"); + passed &= o.linePassesCheckForStringsAtWord(validTotalSizes, 8); + + return passed; + } + + /** + * Check through the output looking for the output from "x/j com/ibm/dump/tests/types/packed/PackedPrimitives". + * Check that the "This class is packed" line is present. + * Check that there are three instances. + * Check that there is one packed instance and that the memory on the heap is right. + * Check that there are two off-heap packed instances and that the memory on the heap is right. + * + * The expected output is as follows: + *
+x/j com/ibm/dump/tests/types/packed/PackedPrimitives
+	 heap #1 - name: Generational@689b98
+
+	  static fields for "com/ibm/dump/tests/types/packed/PackedPrimitives"
+	    public static int staticIntField = 99 (0x63)
+	    public static long staticLongField = 101 (0x65)
+
+	  com/ibm/dump/tests/types/packed/PackedPrimitives @ 0x2ef49f38
+	   This is an on-heap packed object occupying 48 bytes on the heap
+	   fields inherited from "com/ibm/jvm/packed/PackedObject":
+	   declared fields:
+	    public byte byteField = 97 (0x61)
+	    public boolean booleanField = true
+	    public char charField = '\377' (0xff)
+	    public int intField = 99 (0x63)
+	    public float floatField = 123.4 (0x42f6cccd)
+	    public double doubleField = 123.4 (0x405ed9999999999a)
+	    public long longField = 101 (0x65)
+	    public int int2Field = 98 (0x62)
+
+	    references:
+ 	      0x2ef49f38
+
+	  com/ibm/dump/tests/types/packed/PackedPrimitives @ 0x2ef49f68
+	   This is an off-heap packed object occupying 16 bytes on the heap
+	    The native memory is allocated at 0x68a118
+	    The packed data is 32 bytes long
+	   fields inherited from "com/ibm/jvm/packed/PackedObject":
+	   declared fields:
+	    public byte byteField = 97 (0x61)
+	    public boolean booleanField = true
+	    public char charField = '\377' (0xff)
+	    public int intField = 99 (0x63)
+	    public float floatField = 123.4 (0x42f6cccd)
+	    public double doubleField = 123.4 (0x405ed9999999999a)
+	    public long longField = 101 (0x65)
+	    public int int2Field = 98 (0x62)
+
+	    references: 
+ 	     
+
+	  com/ibm/dump/tests/types/packed/PackedPrimitives @ 0x2ef49f78
+	   This is an off-heap packed object occupying 16 bytes on the heap
+	    The native memory is allocated at 0x1000
+	    The packed data is 32 bytes long
+	   fields inherited from "com/ibm/jvm/packed/PackedObject":
+	   declared fields:
+	    public byte byteField = 
+	    public boolean booleanField = 
+	    public char charField = 
+	    public int intField = 
+	    public float floatField = 
+	    public double doubleField = 
+	    public long longField = 
+	    public int int2Field = 
+
+	    references: 
+ 	     
+		
+ * @throws IOException + */ + + public static boolean checkXJClassCommand(String fileName) throws IOException { + String[] validSizes = {"48","16","56","24"}; // on-heap 32, off-heap 32, on-heap 64, off-heap 64 + + String command = "x/j com/ibm/dump/tests/types/packed/PackedPrimitives"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; + passed &= o.skipUnlimitedToLineContaining("com/ibm/dump/tests/types/packed/PackedPrimitives @"); + passed &= o.skipLimitedToLineContaining(1, "packed object"); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); + passed &= o.skipLimitedToLineContaining(8, "public int intField"); + + + passed &= o.skipUnlimitedToLineContaining("com/ibm/dump/tests/types/packed/PackedPrimitives @"); + passed &= o.skipLimitedToLineContaining(1, "packed object"); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); + passed &= o.skipLimitedToLineContaining(8, "public int intField"); + + passed &= o.skipUnlimitedToLineContaining("com/ibm/dump/tests/types/packed/PackedPrimitives @"); + passed &= o.skipLimitedToLineContaining(1, "packed object"); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); + passed &= o.skipLimitedToLineContaining(8, "public int intField"); + + return passed; + } +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest2ArrayOfPackedPrimitivesChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest2ArrayOfPackedPrimitivesChecker.java new file mode 100644 index 00000000000..a8215c3c81c --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest2ArrayOfPackedPrimitivesChecker.java @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.system_dump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class SystemDumpTest2ArrayOfPackedPrimitivesChecker { + + /** + * Check through the output looking for the output from "info class com/ibm/dump/tests/types/packed/PackedPrimitives;". + * Check that the "This class is packed" line is present. + * Check that there are two instances. + * Check that the memory on the heap is right. + * + * The expected output is as follows: + *
+> info class com/ibm/dump/tests/types/packed/PackedPrimitives;
+name = com/ibm/dump/tests/types/packed/PackedPrimitives;
+
+        ID = 0xf0764f0    superID = 0xf010650
+        classLoader =     modifiers: No modifiers available
+
+        This is a packed class
+
+        number of instances:     2
+        total size of instances on the heap: 112 bytes
+		
+ * @throws IOException + */ + + public static boolean checkInfoClassCommand(String fileName) throws IOException { + String[] validTotalSizes = {"352","384", "368"}; // 32, 64 + + + String command = "info class com/ibm/dump/tests/types/packed/PackedPrimitives$Array"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; + passed &= o.skipLimitedToLineContaining(6, "This is a packed class"); + passed &= o.skipLimitedToLineContaining(2, "number of instances"); + passed &= o.linePassesCheckForStringAtWord("2",4); + passed &= o.skipLimitedToLineContaining(1, "total size of instances on the heap"); + passed &= o.linePassesCheckForStringsAtWord(validTotalSizes,8); + return passed; + } + + /** + * Check through the output looking for the output from "x/j com/ibm/dump/tests/types/packed/PackedPrimitives;". + * + * The expected output is as follows: + *
+> x/j com/ibm/dump/tests/types/packed/PackedPrimitives;
+	 heap #1 - name: Generational@538c90
+
+	  com/ibm/dump/tests/types/packed/PackedPrimitives; @ 0x2ef47d18
+	    This is an on-heap packed object occupying 336 bytes on the heap
+	   0:	 com/ibm/dump/tests/types/packed/PackedPrimitives packed @ 0x2ef47d28
+	   1:	 com/ibm/dump/tests/types/packed/PackedPrimitives packed @ 0x2ef47d48
+	   2:	 com/ibm/dump/tests/types/packed/PackedPrimitives packed @ 0x2ef47d68
+	   3:	 com/ibm/dump/tests/types/packed/PackedPrimitives packed @ 0x2ef47d88
+	   4:	 com/ibm/dump/tests/types/packed/PackedPrimitives packed @ 0x2ef47da8
+	   5:	 com/ibm/dump/tests/types/packed/PackedPrimitives packed @ 0x2ef47dc8
+	   6:	 com/ibm/dump/tests/types/packed/PackedPrimitives packed @ 0x2ef47de8
+	   7:	 com/ibm/dump/tests/types/packed/PackedPrimitives packed @ 0x2ef47e08
+	   8:	 com/ibm/dump/tests/types/packed/PackedPrimitives packed @ 0x2ef47e28
+	   9:	 com/ibm/dump/tests/types/packed/PackedPrimitives packed @ 0x2ef47e48
+
+	    references:
+ 	      0x2ef47d18
+	  com/ibm/dump/tests/types/packed/PackedPrimitives; @ 0x2ef47e68
+	    This is an off-heap packed object occupying 16 bytes on the heap
+	    The native memory is allocated at 0x3afa760
+	   0:	 com/ibm/dump/tests/types/packed/PackedPrimitives packed @ 0x3afa760
+	   1:	 com/ibm/dump/tests/types/packed/PackedPrimitives packed @ 0x3afa780
+	   2:	 com/ibm/dump/tests/types/packed/PackedPrimitives packed @ 0x3afa7a0
+	   3:	 com/ibm/dump/tests/types/packed/PackedPrimitives packed @ 0x3afa7c0
+	   4:	 com/ibm/dump/tests/types/packed/PackedPrimitives packed @ 0x3afa7e0
+	   5:	 com/ibm/dump/tests/types/packed/PackedPrimitives packed @ 0x3afa800
+	   6:	 com/ibm/dump/tests/types/packed/PackedPrimitives packed @ 0x3afa820
+	   7:	 com/ibm/dump/tests/types/packed/PackedPrimitives packed @ 0x3afa840
+	   8:	 com/ibm/dump/tests/types/packed/PackedPrimitives packed @ 0x3afa860
+	   9:	 com/ibm/dump/tests/types/packed/PackedPrimitives packed @ 0x3afa880
+
+	    references:
+              [blank line]
+		
+ * @throws IOException + */ + + public static boolean checkXJClassCommand(String fileName) throws IOException { + String[] validSizes = {"336","16","352","32", "344", "24"}; // on-heap 32, off-heap 32, on-heap 64, off-heap 64 + + String command = "x/j com/ibm/dump/tests/types/packed/PackedPrimitives$Array"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + // Check for two packed primitive arrays, one of which is on-heap and has one reference, the other has no references + boolean passed = true; + int refCount = 0; + + passed &= o.skipUnlimitedToLineContaining("com/ibm/dump/tests/types/packed/PackedPrimitives$Array @"); + passed &= o.skipLimitedToLineContaining(1, "packed object"); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); + passed &= o.skipLimitedToReferencesLine(14); + refCount += o.skipToNextLineAndCountReferences(); + + passed &= o.skipUnlimitedToLineContaining("com/ibm/dump/tests/types/packed/PackedPrimitives$Array @"); + passed &= o.skipLimitedToLineContaining(1, "packed object"); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); + passed &= o.skipLimitedToReferencesLine(14); + refCount += o.skipToNextLineAndCountReferences(); + + passed &= (refCount == 1); // expect one reference found in total + + if (!passed) { + System.err.println("SystemDumpTest2ArrayOfPackedPrimitivesChecker failed"); + } + + return passed; + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest3PackedMixedOneRefChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest3PackedMixedOneRefChecker.java new file mode 100644 index 00000000000..b3e11c08af5 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest3PackedMixedOneRefChecker.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.system_dump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class SystemDumpTest3PackedMixedOneRefChecker { + + /** + * Check through the output "info class com/ibm/dump/tests/types/packed/PackedMixedOneRef". + * + * The expected output is as follows: + *
+> info class com/ibm/dump/tests/types/packed/PackedMixedOneRef
+name = com/ibm/dump/tests/types/packed/PackedMixedOneRef
+
+	ID = 0xf020708    superID = 0xf010150    
+	classLoader =     modifiers: No modifiers available
+
+	This is a packed class
+
+	number of instances:     1
+	total size of instances on the heap: 24 bytes
+		
+ + */ + + public static boolean checkInfoClassCommand(String fileName) throws IOException { + String[] validTotalSizes = {"24","40"}; // 32 , 64 + + + String command = "info class com/ibm/dump/tests/types/packed/PackedMixedOneRef"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + boolean passed = true; + passed &= o.skipLimitedToLineContaining(6, "This is a packed class"); + passed &= o.skipLimitedToLineContaining(2, "number of instances"); + passed &= o.linePassesCheckForStringAtWord("1", 4); // number of instances 1 + passed &= o.skipLimitedToLineContaining(1, "total size of instances on the heap"); + passed &= o.linePassesCheckForStringsAtWord(validTotalSizes, 8); + return passed; + + } + + /** + * Check through the output looking for the output from "x/j com/ibm/dump/tests/types/packed/PackedMixedOneRef". + * + * The expected output is as follows: + *
+x/j com/ibm/dump/tests/types/packed/PackedMixedOneRef
+	 heap #1 - name: Generational@298c90
+
+	  "com/ibm/dump/tests/types/packed/PackedMixedOneRef" has no static fields
+
+	  com/ibm/dump/tests/types/packed/PackedMixedOneRef @ 0x2ef47f30
+	    This is an on-heap packed object occupying 24 bytes on the heap
+	   fields inherited from "com/ibm/jvm/packed/PackedObject":
+	   declared fields:
+	    public int intField = 99 (0x63)
+	    public com.ibm.dump.tests.types.notpacked.NotPackedPrimitives npp =  @ 0x2ef47f48
+
+	    references:
+ 	      0x2ef47f30 0x2ef47f48
+		
+	 * @throws IOException 
+	 */
+	
+	public static boolean checkXJClassCommand(String fileName) throws IOException {
+		String[] validSizes = {"24","40"}; // 32 , 64
+		
+		String command = "x/j com/ibm/dump/tests/types/packed/PackedMixedOneRef";
+		System.err.println("\nChecking the output from the command \"" + command + "\"");
+		
+		OutputFile o = new OutputFile(fileName);
+		if (! o.skipUnlimitedToLineContaining(command) ) {
+			// if we cannot find this line, don't bother going any further
+			return false;
+		}
+		boolean passed = true;
+		passed &= o.skipUnlimitedToLineContaining("com/ibm/dump/tests/types/packed/PackedMixedOneRef @");
+		passed &= o.skipLimitedToLineContaining(1, "This is an on-heap packed object");
+		passed &= o.linePassesCheckForStringsAtWord(validSizes,8);
+
+		System.err.println("Checking the second reference from the PackedMixedOneRef is to a com/ibm/dump/tests/types/notpacked/NotPackedPrimitives");
+		passed &= o.skipToLineContainingListOfReferencesAndCheckCount(6, 2);
+		String secondReference = o.getSecondReference();		
+
+		passed &= OutputFile.checkReferenceIsToObject(fileName, secondReference, "com/ibm/dump/tests/types/notpacked/NotPackedPrimitives");
+		return passed;
+		
+	}
+
+
+
+
+
+}
diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest4ArrayOfPackedMixedOneRefChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest4ArrayOfPackedMixedOneRefChecker.java
new file mode 100644
index 00000000000..da0c6ab4285
--- /dev/null
+++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest4ArrayOfPackedMixedOneRefChecker.java
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * Copyright (c) 2016, 2021 IBM Corp. and others
+ *
+ * This program and the accompanying materials are made available under
+ * the terms of the Eclipse Public License 2.0 which accompanies this
+ * distribution and is available at https://www.eclipse.org/legal/epl-2.0/
+ * or the Apache License, Version 2.0 which accompanies this distribution and
+ * is available at https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * This Source Code may also be made available under the following
+ * Secondary Licenses when the conditions for such availability set
+ * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
+ * General Public License, version 2 with the GNU Classpath
+ * Exception [1] and GNU General Public License, version 2 with the
+ * OpenJDK Assembly Exception [2].
+ *
+ * [1] https://www.gnu.org/software/classpath/license.html
+ * [2] http://openjdk.java.net/legal/assembly-exception.html
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
+ *******************************************************************************/
+package com.ibm.dump.tests.system_dump_packed_objects;
+
+import java.io.IOException;
+
+import com.ibm.dump.tests.OutputFile;
+
+public class SystemDumpTest4ArrayOfPackedMixedOneRefChecker {
+	
+	/**
+	 * Check through the output looking for the output from "info class com/ibm/dump/tests/types/packed/PackedMixedOneRef;".
+	 * 
+	 *  The expected output is as follows:
+	 *  
+> info class com/ibm/dump/tests/types/packed/PackedMixed;
+name = com/ibm/dump/tests/types/packed/PackedMixed;
+
+        ID = 0xf0767f8    superID = 0xf010650
+        classLoader =     modifiers: No modifiers available
+
+        This is a packed class
+
+        number of instances:     1
+        total size of instances on the heap: 56 bytes
+
+		
+ * @throws IOException + */ + + public static boolean checkInfoClassCommand(String fileName) throws IOException { + String[] validTotalSizes = {"96","192", "104"}; // 32 , 64 + + String command = "info class com/ibm/dump/tests/types/packed/PackedMixedOneRef$Array"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; + passed &= o.skipLimitedToLineContaining(6, "This is a packed class"); + passed &= o.skipLimitedToLineContaining(2, "number of instances"); + passed &= o.linePassesCheckForStringAtWord("1",4); + passed &= o.skipLimitedToLineContaining(1, "total size of instances on the heap"); + passed &= o.linePassesCheckForStringsAtWord(validTotalSizes,8); + return passed; + } + + /** + * Check through the output looking for the output from "x/j com/ibm/dump/tests/types/packed/PackedMixed;". + * + * The expected output is as follows: + *
+x/j com/ibm/dump/tests/types/packed/PackedMixedOneRef;
+	 heap #1 - name: Generational@5860f0
+
+	  com/ibm/dump/tests/types/packed/PackedMixedOneRef; @ 0x2ef48350
+	   This is an on-heap packed object occupying 96 bytes on the heap
+	   0:	 com/ibm/dump/tests/types/packed/PackedMixedOneRef packed @ 0x2ef48360
+	   1:	 com/ibm/dump/tests/types/packed/PackedMixedOneRef packed @ 0x2ef48368
+	   2:	 com/ibm/dump/tests/types/packed/PackedMixedOneRef packed @ 0x2ef48370
+	   3:	 com/ibm/dump/tests/types/packed/PackedMixedOneRef packed @ 0x2ef48378
+	   4:	 com/ibm/dump/tests/types/packed/PackedMixedOneRef packed @ 0x2ef48380
+	   5:	 com/ibm/dump/tests/types/packed/PackedMixedOneRef packed @ 0x2ef48388
+	   6:	 com/ibm/dump/tests/types/packed/PackedMixedOneRef packed @ 0x2ef48390
+	   7:	 com/ibm/dump/tests/types/packed/PackedMixedOneRef packed @ 0x2ef48398
+	   8:	 com/ibm/dump/tests/types/packed/PackedMixedOneRef packed @ 0x2ef483a0
+	   9:	 com/ibm/dump/tests/types/packed/PackedMixedOneRef packed @ 0x2ef483a8
+
+	    references:
+ 	      0x2ef48350 0x2ef48560 0x2ef48530 0x2ef48500 0x2ef484d0 0x2ef484a0 0x2ef48470 0x2ef48440 0x2ef48410 0x2ef483e0 0x2ef483b0
+		
+ * @throws IOException + */ + + public static boolean checkXJClassCommand(String fileName) throws IOException { + String[] validSizes = {"96","192", "104"}; // 32 , 64 + + + String command = "x/j com/ibm/dump/tests/types/packed/PackedMixedOneRef$Array"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; + passed &= o.skipUnlimitedToLineContaining("com/ibm/dump/tests/types/packed/PackedMixedOneRef$Array @"); + passed &= o.skipLimitedToLineContaining(1, "This is an on-heap packed object"); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); + + System.err.println("Checking the array contents show packed objects"); + passed &= o.skipLimitedToLineContaining(1, "0: com/ibm/dump/tests/types/packed/PackedMixedOneRef packed @ "); + passed &= o.skipToLineContainingListOfReferencesAndCheckCount(12, 11); + String firstReference = o.getFirstReference(); + + passed &= OutputFile.checkReferenceIsToObject(fileName, firstReference, "com/ibm/dump/tests/types/packed/PackedMixedOneRef$Array"); + + + return passed; + } + + + + + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest5ArrayOfPackedMixedTwoRefsChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest5ArrayOfPackedMixedTwoRefsChecker.java new file mode 100644 index 00000000000..f3cce41ddab --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest5ArrayOfPackedMixedTwoRefsChecker.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.system_dump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class SystemDumpTest5ArrayOfPackedMixedTwoRefsChecker { + + + + /** + * Check through the output looking for the output from "x/j com/ibm/dump/tests/types/packed/PackedMixedTwoRefs;". + * + *
+x/j com/ibm/dump/tests/types/packed/PackedMixedTwoRefs;
+	 heap #1 - name: Generational@5860f0
+
+	  com/ibm/dump/tests/types/packed/PackedMixedTwoRefs; @ 0x2ef485a0
+	   This is an on-heap packed object occupying 136 bytes on the heap
+	   0:	 com/ibm/dump/tests/types/packed/PackedMixedTwoRefs packed @ 0x2ef485b0
+	   1:	 com/ibm/dump/tests/types/packed/PackedMixedTwoRefs packed @ 0x2ef485bc
+	   2:	 com/ibm/dump/tests/types/packed/PackedMixedTwoRefs packed @ 0x2ef485c8
+	   3:	 com/ibm/dump/tests/types/packed/PackedMixedTwoRefs packed @ 0x2ef485d4
+	   4:	 com/ibm/dump/tests/types/packed/PackedMixedTwoRefs packed @ 0x2ef485e0
+	   5:	 com/ibm/dump/tests/types/packed/PackedMixedTwoRefs packed @ 0x2ef485ec
+	   6:	 com/ibm/dump/tests/types/packed/PackedMixedTwoRefs packed @ 0x2ef485f8
+	   7:	 com/ibm/dump/tests/types/packed/PackedMixedTwoRefs packed @ 0x2ef48604
+	   8:	 com/ibm/dump/tests/types/packed/PackedMixedTwoRefs packed @ 0x2ef48610
+	   9:	 com/ibm/dump/tests/types/packed/PackedMixedTwoRefs packed @ 0x2ef4861c
+
+	    references:
+ 	      0x2ef485a0 0x2ef48988 0x2ef489b8 0x2ef48928 0x2ef48958 0x2ef488c8 0x2ef488f8 0x2ef48868 0x2ef48898 0x2ef48808 0x2ef48838 0x2ef487a8 0x2ef487d8 0x2ef48748 0x2ef48778 0x2ef486e8 0x2ef48718 0x2ef48688 0x2ef486b8 0x2ef48628 0x2ef48658
+
+ 	   
+ * @throws IOException + */ + + public static boolean checkXJClassCommand(String fileName) throws IOException { + String[] validSizes = {"136","272", "144"}; // 32 , 64 + + + String command = "x/j com/ibm/dump/tests/types/packed/PackedMixedTwoRefs$Array"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; + passed &= o.skipUnlimitedToLineContaining("com/ibm/dump/tests/types/packed/PackedMixedTwoRefs$Array @"); + passed &= o.skipLimitedToLineContaining(1, "This is an on-heap packed object"); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); + + System.err.println("Checking the array contents show packed objects"); + passed &= o.skipLimitedToLineContaining(1, "0: com/ibm/dump/tests/types/packed/PackedMixedTwoRefs packed @ "); + passed &= o.skipToLineContainingListOfReferencesAndCheckCount(12, 21); + String firstReference = o.getFirstReference(); + + passed &= OutputFile.checkReferenceIsToObject(fileName, firstReference, "com/ibm/dump/tests/types/packed/PackedMixedTwoRefs$Array"); + + + return passed; + } + + + + + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest6PackedMixedWithReferenceToSelfChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest6PackedMixedWithReferenceToSelfChecker.java new file mode 100644 index 00000000000..ec8bced42ed --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest6PackedMixedWithReferenceToSelfChecker.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.system_dump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class SystemDumpTest6PackedMixedWithReferenceToSelfChecker { + + /** + * Check through the output looking for the output from "x/j com/ibm/dump/tests/types/packed/PackedMixedWithReferenceToSelf". + * + * + * The expected output is as follows: + *
+x/j com/ibm/dump/tests/types/packed/PackedMixedWithReferenceToSelf
+	 heap #1 - name: Generational@308c90
+
+	  static fields for "com/ibm/dump/tests/types/packed/PackedMixedWithReferenceToSelf"
+	    public static int staticIntField = 99 (0x63)
+
+	  com/ibm/dump/tests/types/packed/PackedMixedWithReferenceToSelf @ 0x2ef485d0
+	    This is an on-heap packed object occupying 24 bytes on the heap
+	   fields inherited from "com/ibm/jvm/packed/PackedObject":
+	   declared fields:
+	    public int intField = 99 (0x63)
+	    public com.ibm.jvm.packed.PackedObject obj =  @ 0x2ef485d0
+
+	    references:
+ 	      0x2ef485d0 0x2ef485d0
+
+	  com/ibm/dump/tests/types/packed/PackedMixedWithReferenceToSelf @ 0x2ef48808
+	    This is a derived packed object occupying 16 bytes on the heap
+	   fields inherited from "com/ibm/jvm/packed/PackedObject":
+	   declared fields:
+	    public int intField = 99 (0x63)
+	    public com.ibm.jvm.packed.PackedObject obj =  @ 0x2ef48808
+
+	    references:
+ 	      0x2ef487f0 0x2ef48808
+
+		
+	 * @throws IOException 
+	 */
+	
+	public static boolean checkXJClassCommand(String fileName) throws IOException {
+		String[] validSizes = {"24","40"}; // on-heap 32, on-heap 64
+		
+		String command = "x/j com/ibm/dump/tests/types/packed/PackedMixedWithReferenceToSelf";
+		System.err.println("\nChecking the output from the command \"" + command + "\"");
+		
+		OutputFile o = new OutputFile(fileName);
+		if (! o.skipUnlimitedToLineContaining(command) ) {
+			// if we cannot find this line, don't bother going any further
+			return false;
+		}
+
+		boolean passed = true;
+		passed &= o.skipUnlimitedToLineContaining("com/ibm/dump/tests/types/packed/PackedMixedWithReferenceToSelf @");
+		passed &= o.skipLimitedToLineContaining(1, "This is an on-heap packed object");
+		passed &= o.linePassesCheckForStringsAtWord(validSizes,8);
+
+		
+		System.err.println("Checking that the both references from the PackedMixedWithReferenceToSelf is indeed to itself");
+		passed &= o.skipToLineContainingListOfReferencesAndCheckCount(8, 2);
+		String firstReference = o.getFirstReference();	
+		
+		passed &= OutputFile.checkReferenceIsToObject(fileName, firstReference, "com/ibm/dump/tests/types/packed/PackedMixedWithReferenceToSelf");
+
+		String secondReference = o.getFirstReference();	
+		
+		passed &= OutputFile.checkReferenceIsToObject(fileName, secondReference, "com/ibm/dump/tests/types/packed/PackedMixedWithReferenceToSelf");
+		
+		
+		return passed;
+	}
+
+
+
+
+
+}
diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest71NestedPacked1Checker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest71NestedPacked1Checker.java
new file mode 100644
index 00000000000..17fa44a07fb
--- /dev/null
+++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest71NestedPacked1Checker.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2016, 2021 IBM Corp. and others
+ *
+ * This program and the accompanying materials are made available under
+ * the terms of the Eclipse Public License 2.0 which accompanies this
+ * distribution and is available at https://www.eclipse.org/legal/epl-2.0/
+ * or the Apache License, Version 2.0 which accompanies this distribution and
+ * is available at https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * This Source Code may also be made available under the following
+ * Secondary Licenses when the conditions for such availability set
+ * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
+ * General Public License, version 2 with the GNU Classpath
+ * Exception [1] and GNU General Public License, version 2 with the
+ * OpenJDK Assembly Exception [2].
+ *
+ * [1] https://www.gnu.org/software/classpath/license.html
+ * [2] http://openjdk.java.net/legal/assembly-exception.html
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
+ *******************************************************************************/
+package com.ibm.dump.tests.system_dump_packed_objects;
+
+import java.io.IOException;
+
+import com.ibm.dump.tests.OutputFile;
+
+public class SystemDumpTest71NestedPacked1Checker {
+	
+	/**
+	 * Check through the output looking for the output from "x/j com/ibm/dump/tests/types/packed/NestedPacked1".
+	 * 
+	 * We specifically want to find the derived object
+	 *  The expected output is as follows:
+	 *  
+	 *  BUT  can appear in either order :-(
+	 *  
+	 *  
+x/j com/ibm/dump/tests/types/packed/NestedPacked1
+	 heap #1 - name: Generational@709b98
+
+	  static fields for "com/ibm/dump/tests/types/packed/NestedPacked1"
+	    public static int staticIntField = 98 (0x62)
+
+	  com/ibm/dump/tests/types/packed/NestedPacked1 @ 0x2ef4a7e0
+	   This is an on-heap packed object occupying 16 bytes on the heap
+	   This is a derived packed object:
+	    target object: com/ibm/dump/tests/types/packed/NestedPacked @ 0x2ef4a7c8
+	    target offset: 0x10
+	  showing fields for  com/ibm/dump/tests/types/packed/NestedPacked1 packed @ 0x2ef4a7d8
+	   fields inherited from "com/ibm/jvm/packed/PackedObject":
+	   declared fields:
+	    public int intField = 98 (0x62)
+	    public com.ibm.dump.tests.types.packed.NestedPacked2 nestedPacked2Field =  com/ibm/dump/tests/types/packed/NestedPacked2 packed @ 0x2ef4a7dc
+
+	    references:
+ 	      0x2ef4a7c8
+
+	  com/ibm/dump/tests/types/packed/NestedPacked1 @ 0x2ef4a810
+	   This is an off-heap packed object occupying 16 bytes on the heap
+	    The native memory is allocated at 0x35de1cc
+	    The packed data is 8 bytes long
+	   fields inherited from "com/ibm/jvm/packed/PackedObject":
+	   declared fields:
+	    public int intField = 98 (0x62)
+	    public com.ibm.dump.tests.types.packed.NestedPacked2 nestedPacked2Field =  com/ibm/dump/tests/types/packed/NestedPacked2 packed @ 0x35de1d0
+
+	    references: 
+		
+ * @throws IOException + */ + + public static boolean checkXJClassCommand(String fileName) throws IOException { + String[] validSizes = {"16","24"}; // object header size on 32, 64 + + String command = "x/j com/ibm/dump/tests/types/packed/NestedPacked1"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; +// passed &= o.skipLimitedToLineContaining(7, "This is an on-heap packed object"); + passed &= o.skipLimitedToLineContaining(7, "This is an "); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); +// passed &= o.skipLimitedToLineContaining(1, "This is a derived packed object"); +// passed &= o.skipLimitedToLineContaining(1, "target object: com/ibm/dump/tests/types/packed/NestedPacked @ 0x"); +// passed &= o.skipLimitedToLineContaining(1, "target offset: 0x"); +// passed &= o.skipLimitedToLineContaining(1, "showing fields for com/ibm/dump/tests/types/packed/NestedPacked1 packed @ 0x"); +// passed &= o.skipToLineContainingListOfReferencesAndCheckCount(6, 1); + +// passed &= o.skipLimitedToLineContaining(6, "com/ibm/dump/tests/types/packed/NestedPacked1 @"); + passed &= o.skipLimitedToLineContaining(14, "com/ibm/dump/tests/types/packed/NestedPacked1 @"); +// passed &= o.skipLimitedToLineContaining(1, "This is an off-heap packed object"); + passed &= o.skipLimitedToLineContaining(1, "This is an "); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); +// passed &= o.skipLimitedToLineContaining(1, "The native memory is allocated at 0x"); +// passed &= o.skipLimitedToLineContaining(1, "The packed data is "); +// passed &= o.skipToLineContainingListOfReferencesAndCheckCount(6, 0); + + return passed; + } + + + + + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest7NestedPackedChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest7NestedPackedChecker.java new file mode 100644 index 00000000000..0a628a172e9 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest7NestedPackedChecker.java @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/package com.ibm.dump.tests.system_dump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class SystemDumpTest7NestedPackedChecker { + + /** + * Check through the output looking for the output from "info class com/ibm/dump/tests/types/packed/NestedPacked". + * + * The expected output is as follows: + *
+info class com/ibm/dump/tests/types/packed/NestedPacked
+name = com/ibm/dump/tests/types/packed/NestedPacked
+
+	ID = 0x3d8fb00    superID = 0x3bd3f00    
+	classLoader = 0x2ef39d70    modifiers: public final 
+
+	This is a packed class
+
+	number of instances:     2
+	total size of instances on the heap: 40 bytes
+
+Inheritance chain....
+
+	com/ibm/jvm/packed/PackedObject
+	   com/ibm/dump/tests/types/packed/NestedPacked
+
+Fields......
+
+	  static fields for "com/ibm/dump/tests/types/packed/NestedPacked"
+	    public static int staticIntField = 99 (0x63)
+
+	  non-static fields for "com/ibm/dump/tests/types/packed/NestedPacked"
+	    public int intField
+	    public com.ibm.dump.tests.types.packed.NestedPacked1 nestedPacked1Field
+
+ * @throws IOException + */ + + public static boolean checkInfoClassCommand(String fileName) throws IOException { + String[] validTotalSizes = {"40","64", "48"}; // on- + off-heap 32, on- + off-heap 64 + + + boolean passed = true; + + String command = "info class com/ibm/dump/tests/types/packed/NestedPacked"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + passed &= o.skipLimitedToLineContaining(6, "This is a packed class"); + passed &= o.skipLimitedToLineContaining(2, "number of instances"); + passed &= o.linePassesCheckForStringAtWord("2",4); + passed &= o.skipLimitedToLineContaining(1, "total size of instances on the heap"); + passed &= o.linePassesCheckForStringsAtWord(validTotalSizes,8); + + return passed; + } + + /** + * Check through the output looking for the output from "x/j com/ibm/dump/tests/types/packed/NestedPacked". + * + * The expected output is as follows: + * + * BUT can appear in either order :-( + *
+x/j com/ibm/dump/tests/types/packed/NestedPacked
+	 heap #1 - name: Generational@689b98
+
+	  static fields for "com/ibm/dump/tests/types/packed/NestedPacked"
+	    public static int staticIntField = 99 (0x63)
+
+	  com/ibm/dump/tests/types/packed/NestedPacked @ 0x2ef4a840
+	   This is an on-heap packed object occupying 24 bytes on the heap
+	   fields inherited from "com/ibm/jvm/packed/PackedObject":
+	   declared fields:
+	    public int intField = 99 (0x63)
+	    public com.ibm.dump.tests.types.packed.NestedPacked1 nestedPacked1Field =  com/ibm/dump/tests/types/packed/NestedPacked1 packed @ 0x2ef4a850
+
+	    references:
+ 	      0x2ef4a840
+
+	  com/ibm/dump/tests/types/packed/NestedPacked @ 0x2ef4a878
+	   This is an off-heap packed object occupying 16 bytes on the heap
+	    The native memory is allocated at 0x359e1c8
+	    The packed data is 12 bytes long
+	   fields inherited from "com/ibm/jvm/packed/PackedObject":
+	   declared fields:
+	    public int intField = 99 (0x63)
+	    public com.ibm.dump.tests.types.packed.NestedPacked1 nestedPacked1Field =  com/ibm/dump/tests/types/packed/NestedPacked1 packed @ 0x359e1cc
+
+	    references: 
+
+		
+ * @throws IOException + */ + + public static boolean checkXJClassCommand(String fileName) throws IOException { + String[] validSizes = {"24","16","40","24", "32"}; // on-heap 32, off-heap 32, on-heap 64, off-heap 64 + + String command = "x/j com/ibm/dump/tests/types/packed/NestedPacked"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; + passed &= o.skipLimitedToLineContaining(7, "This is an "); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); +// passed &= o.skipToLineContainingListOfReferencesAndCheckCount(6, 1); + + passed &= o.skipLimitedToLineContaining(12, "com/ibm/dump/tests/types/packed/NestedPacked @"); + passed &= o.skipLimitedToLineContaining(1, "This is an "); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); +// passed &= o.skipLimitedToLineContaining(1, "The native memory is allocated at 0x"); +// passed &= o.skipLimitedToLineContaining(1, "The packed data is "); +// passed &= o.skipToLineContainingListOfReferencesAndCheckCount(6, 0); + + return passed; + } + + + + + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest8NestedPackedMixedChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest8NestedPackedMixedChecker.java new file mode 100644 index 00000000000..a96e9a767a7 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest8NestedPackedMixedChecker.java @@ -0,0 +1,135 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.system_dump_packed_objects; + +import java.io.IOException; + +import com.ibm.dump.tests.OutputFile; + +public class SystemDumpTest8NestedPackedMixedChecker { + + /** + * Check through the output looking for the output from "info class com/ibm/dump/tests/types/packed/NestedPackedMixed". + * + * The expected output is as follows: + *
+info class com/ibm/dump/tests/types/packed/NestedPackedMixed
+name = com/ibm/dump/tests/types/packed/NestedPackedMixed
+
+	ID = 0x3a40200    superID = 0x3883f00    
+	classLoader = 0x2ef39e28    modifiers: public final 
+
+	This is a packed class
+
+	number of instances:     1
+	total size of instances on the heap: 40 bytes
+
+Inheritance chain....
+
+	com/ibm/jvm/packed/PackedObject
+	   com/ibm/dump/tests/types/packed/NestedPackedMixed
+
+Fields......
+
+	  "com/ibm/dump/tests/types/packed/NestedPackedMixed" has no static fields
+
+	  non-static fields for "com/ibm/dump/tests/types/packed/NestedPackedMixed"
+	    public int intField
+	    public com.ibm.dump.tests.types.notpacked.NotPackedPrimitives npp
+	    public com.ibm.dump.tests.types.packed.NestedPackedMixed1 nestedPacked1Field
+
+ * @throws IOException + */ + + public static boolean checkInfoClassCommand(String fileName) throws IOException { + String[] validTotalSizes = {"24","16","40","24", "72"}; // on-heap 32, off-heap 32, on-heap 64, off-heap 64, nocr + + + boolean passed = true; + + String command = "info class com/ibm/dump/tests/types/packed/NestedPackedMixed"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + passed &= o.skipLimitedToLineContaining(6, "This is a packed class"); + passed &= o.skipLimitedToLineContaining(2, "number of instances"); + passed &= o.linePassesCheckForStringAtWord("1",4); + passed &= o.skipLimitedToLineContaining(1, "total size of instances on the heap"); + passed &= o.linePassesCheckForStringsAtWord(validTotalSizes,8); + + return passed; + } + + /** + * Check through the output looking for the output from "x/j com/ibm/dump/tests/types/packed/NestedPackedMixed". + * + * The expected output is as follows: + *
+x/j com/ibm/dump/tests/types/packed/NestedPackedMixed
+	 heap #1 - name: Generational@5860f0
+
+	  "com/ibm/dump/tests/types/packed/NestedPackedMixed" has no static fields
+
+	  com/ibm/dump/tests/types/packed/NestedPackedMixed @ 0x2ef48a88
+	   This is an on-heap packed object occupying 40 bytes on the heap
+	   fields inherited from "com/ibm/jvm/packed/PackedObject":
+	   declared fields:
+	    public int intField = 99 (0x63)
+	    public com.ibm.dump.tests.types.notpacked.NotPackedPrimitives npp =  @ 0x2ef48ab0
+	    public com.ibm.dump.tests.types.packed.NestedPackedMixed1 nestedPacked1Field =  com/ibm/dump/tests/types/packed/NestedPackedMixed1 packed @ 0x2ef48a9c
+
+	    references:
+ 	      0x2ef48a88 0x2ef48ab0 0x2ef48ae0
+
+		
+	 * @throws IOException 
+	 */
+	
+	public static boolean checkXJClassCommand(String fileName) throws IOException {
+		String[] validSizes = {"24","16","40","24", "72"}; // on-heap 32, off-heap 32, on-heap 64, off-heap 64, no cr
+
+		String command = "x/j com/ibm/dump/tests/types/packed/NestedPackedMixed";
+		System.err.println("\nChecking the output from the command \"" + command + "\"");
+		
+		OutputFile o = new OutputFile(fileName);
+		if (! o.skipUnlimitedToLineContaining(command) ) {
+			// if we cannot find this line, don't bother going any further
+			return false;
+		}
+
+		boolean passed = true;
+		passed &= o.skipLimitedToLineContaining(6, "This is an on-heap packed object");
+		passed &= o.linePassesCheckForStringsAtWord(validSizes,8);		
+		passed &= o.skipToLineContainingListOfReferencesAndCheckCount(8, 3);
+
+		return passed;
+	}
+
+
+
+
+
+}
diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest9PackedIntsArrayChecker.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest9PackedIntsArrayChecker.java
new file mode 100644
index 00000000000..aa12f2a060d
--- /dev/null
+++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/system_dump_packed_objects/SystemDumpTest9PackedIntsArrayChecker.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2016, 2021 IBM Corp. and others
+ *
+ * This program and the accompanying materials are made available under
+ * the terms of the Eclipse Public License 2.0 which accompanies this
+ * distribution and is available at https://www.eclipse.org/legal/epl-2.0/
+ * or the Apache License, Version 2.0 which accompanies this distribution and
+ * is available at https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * This Source Code may also be made available under the following
+ * Secondary Licenses when the conditions for such availability set
+ * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
+ * General Public License, version 2 with the GNU Classpath
+ * Exception [1] and GNU General Public License, version 2 with the
+ * OpenJDK Assembly Exception [2].
+ *
+ * [1] https://www.gnu.org/software/classpath/license.html
+ * [2] http://openjdk.java.net/legal/assembly-exception.html
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
+ *******************************************************************************/
+package com.ibm.dump.tests.system_dump_packed_objects;
+
+import java.io.IOException;
+
+import com.ibm.dump.tests.OutputFile;
+
+public class SystemDumpTest9PackedIntsArrayChecker {
+	
+	/**
+	 * Check through the output looking for the output from "info class com/ibm/dump/tests/types/packed/PackedIntsArray".
+	 * 
+	 *  The expected output is as follows:
+	 *  
+> info class com/ibm/dump/tests/types/packed/PackedIntsArray
+name = com/ibm/dump/tests/types/packed/PackedIntsArray
+
+        ID = 0xf076cf0    superID = 0xf010650
+        classLoader =     modifiers: No modifiers available
+
+        This is a packed class
+
+        number of instances:     2
+        total size of instances on the heap: 56 bytes
+
+		
+ * @throws IOException + */ + + public static boolean checkInfoClassCommand(String fileName) throws IOException { + String[] validTotalSizes = {"56","80", "64"}; // 32 , 64 + + + String command = "info class com/ibm/dump/tests/types/packed/PackedIntsArray"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; + passed &= o.skipLimitedToLineContaining(6, "This is a packed class"); + passed &= o.skipLimitedToLineContaining(2, "number of instances"); + passed &= o.linePassesCheckForStringAtWord("2", 4); + passed &= o.skipLimitedToLineContaining(1, "total size of instances on the heap"); + passed &= o.linePassesCheckForStringsAtWord(validTotalSizes, 8); + + return passed; + } + + /** + * Check through the output looking for the output from "x/j com/ibm/dump/tests/types/packed/PackedIntsArray". + * + * The expected output is as follows: + *
+x/j com/ibm/dump/tests/types/packed/PackedIntsArray
+	 heap #1 - name: Generational@689b98
+
+	  "com/ibm/dump/tests/types/packed/PackedIntsArray" has no static fields
+
+	  com/ibm/dump/tests/types/packed/PackedIntsArray @ 0x2ef4a9c0
+	   This is an on-heap packed object occupying 40 bytes on the heap
+	   fields inherited from "com/ibm/jvm/packed/PackedObject":
+	   declared fields:
+	    @Length(2) public com.ibm.jvm.packed.types.PackedInt[] piArray1 =  com/ibm/jvm/packed/types/PackedInt[2] packed @ 0x2ef4a9cc
+	    @Length(5) public com.ibm.jvm.packed.types.PackedInt[] piArray2 =  com/ibm/jvm/packed/types/PackedInt[5] packed @ 0x2ef4a9d4
+
+	    references:
+ 	      0x2ef4a9c0
+
+	  com/ibm/dump/tests/types/packed/PackedIntsArray @ 0x2ef4a9e8
+	   This is an off-heap packed object occupying 16 bytes on the heap
+	    The native memory is allocated at 0x68a170
+	    The packed data is 28 bytes long
+	   fields inherited from "com/ibm/jvm/packed/PackedObject":
+	   declared fields:
+	    @Length(2) public com.ibm.jvm.packed.types.PackedInt[] piArray1 =  com/ibm/jvm/packed/types/PackedInt[2] packed @ 0x68a170
+	    @Length(5) public com.ibm.jvm.packed.types.PackedInt[] piArray2 =  com/ibm/jvm/packed/types/PackedInt[5] packed @ 0x68a178
+
+	    references: 
+		
+ * @throws IOException + */ + + public static boolean checkXJClassCommand(String fileName) throws IOException { + String[] validSizes = {"40","16", "48", "56", "24"}; // on-heap 32, on-heap 64, nocr + + + String command = "x/j com/ibm/dump/tests/types/packed/PackedIntsArray"; + System.err.println("\nChecking the output from the command \"" + command + "\""); + + OutputFile o = new OutputFile(fileName); + if (! o.skipUnlimitedToLineContaining(command) ) { + // if we cannot find this line, don't bother going any further + return false; + } + + boolean passed = true; + passed &= o.skipLimitedToLineContaining(6, "com/ibm/dump/tests/types/packed/PackedIntsArray @"); + passed &= o.skipLimitedToLineContaining(1, "This is an on-heap packed object"); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); + passed &= o.skipLimitedToLineContaining(3, "@Length(2) public com.ibm.jvm.packed.types.PackedInt$Array piArray1 = com/ibm/jvm/packed/types/PackedInt$Array[2] packed @ 0x"); + passed &= o.skipLimitedToLineContaining(1, "@Length(5) public com.ibm.jvm.packed.types.PackedInt$Array piArray2 = com/ibm/jvm/packed/types/PackedInt$Array[5] packed @ 0x"); + + passed &= o.skipLimitedToLineContaining(6, "com/ibm/dump/tests/types/packed/PackedIntsArray @"); + passed &= o.skipLimitedToLineContaining(1, "This is an off-heap packed object"); + passed &= o.linePassesCheckForStringsAtWord(validSizes,8); + passed &= o.skipLimitedToLineContaining(1, "The native memory is allocated at 0x"); + passed &= o.skipLimitedToLineContaining(1, "The packed data is "); + passed &= o.skipLimitedToLineContaining(3, "@Length(2) public com.ibm.jvm.packed.types.PackedInt$Array piArray1 = com/ibm/jvm/packed/types/PackedInt$Array[2] packed @ 0x"); + passed &= o.skipLimitedToLineContaining(1, "@Length(5) public com.ibm.jvm.packed.types.PackedInt$Array piArray2 = com/ibm/jvm/packed/types/PackedInt$Array[5] packed @ 0x"); + + return passed; + } + + + + + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/timestamp/CreateDump.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/timestamp/CreateDump.java new file mode 100644 index 00000000000..06b5b09fc17 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/timestamp/CreateDump.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.timestamp; + + +public class CreateDump { + + public static void main(String[] args) { + + try { + java.lang.Thread.sleep(1000); + } catch (InterruptedException e) { + } + + System.out.println("com.ibm.dump.tests.timestamp.CreateJavaCore: nanotime before dump ###" + java.lang.System.nanoTime() + "###"); + + try { + java.lang.Thread.sleep(1000); + } catch (InterruptedException e) { + } + + try { + throw new com.ibm.dump.tests.timestamp.TestException(); + } catch (Exception e) { + } + + try { + java.lang.Thread.sleep(1000); + } catch (InterruptedException e) { + } + + System.out.println("com.ibm.dump.tests.timestamp.CreateJavaCore: nanotime after dump ###" + java.lang.System.nanoTime() + "###"); + } +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/timestamp/TestException.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/timestamp/TestException.java new file mode 100644 index 00000000000..37bec679c60 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/timestamp/TestException.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.timestamp; + +public class TestException extends Exception { + +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/types/notpacked/NotPackedMixedTwoRefs.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/types/notpacked/NotPackedMixedTwoRefs.java new file mode 100644 index 00000000000..0618bf6d41a --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/types/notpacked/NotPackedMixedTwoRefs.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package com.ibm.dump.tests.types.notpacked; + +import com.ibm.dump.tests.types.notpacked.NotPackedPrimitives; + +public class NotPackedMixedTwoRefs { + public int intField; + public NotPackedPrimitives npp1; + public NotPackedPrimitives npp2; +} + diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/types/notpacked/NotPackedPrimitives.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/types/notpacked/NotPackedPrimitives.java new file mode 100644 index 00000000000..173b3053ff5 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/types/notpacked/NotPackedPrimitives.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.types.notpacked; + +public final class NotPackedPrimitives { + public byte byteField = 'a'; + public boolean booleanField = true; + public char charField = 0xff; + public int intField = 99; + public float floatField = (float) 123.4; + public double doubleField = 123.4; + public long longField = 101L; + public int int2Field = 99; +} diff --git a/test/functional/RasapiTest/src/com/ibm/dump/tests/version_info/CheckVersionString.java b/test/functional/RasapiTest/src/com/ibm/dump/tests/version_info/CheckVersionString.java new file mode 100644 index 00000000000..d85fc48c1a9 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/dump/tests/version_info/CheckVersionString.java @@ -0,0 +1,398 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.dump.tests.version_info; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel.MapMode; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import com.ibm.dtfj.image.Image; +import com.ibm.dtfj.image.ImageAddressSpace; +import com.ibm.dtfj.image.ImageFactory; +import com.ibm.dtfj.image.ImageProcess; +import com.ibm.dtfj.java.JavaRuntime; +import com.ibm.jvm.trace.format.api.TraceContext; + +/** + * This class checks the various RAS artifacts contain the correct version + * string. It is in java rather than perl so we can use DTFJ to read system and + * heap dumps and the trace formatter to read the binary trace files directly. + * + * It expects to be run by the JVM that generated the artifacts in the first + * place. + * + * @author hhellyer + * + */ +public class CheckVersionString { + + /** + * Arguments passed via system properties rather than command line arguments + * so we don't have to write parsing code. + */ + private static final String JAVACORE_FILE_PROPERTY = "java.file"; + private static final String SYSTEMDUMP_FILE_PROPERTY = "system.file"; + private static final String HEAPDUMP_FILE_PROPERTY = "heap.file"; + private static final String HEAPDUMP_CLASSIC_FILE_PROPERTY = "classic.heap.file"; + private static final String SNAPDUMP_FILE_PROPERTY = "snap.file"; + + private static final String SDK_VERSION = "sdk.version"; + + private static final DumpType[] allDumps = { new JavaDumpType(), + /*new SystemDumpType(), - Disabled until DDR is stable. */ + new HeapDumpType(), + new ClassicHeapDumpType(), new SnapDumpType() }; + + private static Properties sysProps = System.getProperties(); + + /** + * @param args + */ + public static void main(String[] args) { + + // Check the version.properties file exists. If it + // doesn't the dumps cannot get the right version + // String anyway. + String versionFilePath = sysProps.getProperty("java.home") + + File.separator + "lib" + File.separator + + "version.properties"; + File versionFile = new File(versionFilePath); + if (!versionFile.exists()) { + System.err + .println("Package build does not contain " + versionFilePath); + System.err + .println("This should be present to indicate the build level of the fully packaged build of JVM and class libraries."); + System.exit(1); + } + Properties versionProperties = new Properties(); + try { + versionProperties.load(new FileInputStream(versionFile)); + } catch (FileNotFoundException e) { + // We don't expect this to happen as we've already checked the file + // exists. + System.err + .println("Package build does not contain " + versionFilePath); + System.err + .println("This should be present to indicate the build level of the fully packaged build of JVM and class libraries."); + e.printStackTrace(); + System.exit(1); + } catch (IOException e) { + System.err.println("Unable to read " + versionFilePath); + e.printStackTrace(); + System.exit(1); + } + + final String sdkVersion = versionProperties.getProperty(SDK_VERSION); + if (sdkVersion == null) { + System.err.println(SDK_VERSION + " property in " + versionFilePath + + " was missing."); + System.err + .println("This should be present to indicate the build level of the fully packaged build of JVM and class libraries."); + System.exit(1); + } + + Set failures = new HashSet(); + // Check each artifact exists and contains the right data. + for (int i = 0; i < allDumps.length; i++) { + String error = checkDumpProperty(allDumps[i].getPropertyName(), + sysProps); + if (error != null) { + failures.add(error); + } + } + if (!failures.isEmpty()) { + Iterator fails = failures.iterator(); + while (fails.hasNext()) { + System.err.println(fails.next()); + } + System.exit(1); + } + + Map versions = new HashMap(); + + // Keyed list for printing on error messages. + StringBuffer keyedVersions = new StringBuffer(); + + for (int i = 0; i < allDumps.length; i++) { + String versionString = allDumps[i].getVersionString(); + keyedVersions.append(allDumps[i].getPropertyName()); + keyedVersions.append(" : '"); + keyedVersions.append(versionString); + keyedVersions.append("'\n"); + System.err.println(allDumps[i].getPropertyName() + " : " + + versionString); + versions.put(allDumps[i].getPropertyName(), versionString); + } + // Check all versions are the same (after extraction) and that they all + // contain + // the contents of version.properties. + Iterator results = versions.values().iterator(); + String version = results.next(); + while (results.hasNext()) { + String nextVersion = results.next(); + if (!version.equals(nextVersion)) { + System.err + .println("Version strings from all artifacts did not match. The strings were:\n" + + keyedVersions); + System.exit(1); + break; + } + version = nextVersion; + } + + // Finally the version string must contain the contends of the sdk.version property + // from version.properties. + if (!version.contains(sdkVersion)) { + System.err + .println("The version strings did not contain the value of the sdk.version property in " + + versionFilePath + + "\n" + + "The value of sdk.version was " + + sdkVersion + + "\n" + + "The version strings all matched and were: " + + version); + System.exit(1); + } + System.out.println("Version string checks passed."); + System.exit(0); + } + + private static String checkDumpProperty(String property, Properties sysProps) { + if (sysProps.getProperty(property) == null) { + return "Required -D parameter: " + property + " not set."; + } + File file = new File(sysProps.getProperty(property)); + if (!file.exists()) { + return "Filed specified by " + property + " does not exist."; + } + return null; + } + + private static abstract class DumpType { + + private final String propertyName; + + protected DumpType(String propName) { + propertyName = propName; + } + + public abstract String getVersionString(); + + public String getPropertyName() { + return propertyName; + } + } + + private static class SnapDumpType extends DumpType { + + protected SnapDumpType() { + super(SNAPDUMP_FILE_PROPERTY); + } + + @Override + public String getVersionString() { + String fileName = sysProps.getProperty(getPropertyName()); + File file = new File(fileName); + FileInputStream f; + try { + f = new FileInputStream(file); + ByteBuffer data = f.getChannel().map(MapMode.READ_ONLY, 0, + file.length()); + String j9TraceFormat_dat = sysProps.getProperty("java.home") + + "/lib/J9TraceFormat.dat"; + TraceContext context = TraceContext.getContext(data, + new FileInputStream(new File(j9TraceFormat_dat))); + return context.getVmVersionString(); + } catch (FileNotFoundException e) { + System.err.println(e.getMessage()); + e.printStackTrace(); + } catch (IOException e) { + System.err.println(e.getMessage()); + e.printStackTrace(); + } + return null; + } + } + + private static class SystemDumpType extends DTFJDumpType { + + protected SystemDumpType() { + super(SYSTEMDUMP_FILE_PROPERTY, + "com.ibm.dtfj.image.j9.ImageFactory"); + } + + public String getVersionString() { + String version = super.getVersionString(); + if (version == null) { + return version; + } + /* + * The version string looks like: + * Java(TM) SE Runtime Environment(build JRE 1.6.0 IBM J9 2.6 Windows XP x86-32 build 20100901_064112 (pwi3260sr9-20100818_03(SR9))) + * IBM J9 VM(JRE 1.6.0 IBM J9 2.6 Windows XP x86-32 20100901_064112 (JIT enabled, AOT enabled) + * J9VM - VM JIT - dev_20100825_16819 GC - + * R26_head_20100831_1631_B64043) but we only want this bit: JRE 1.6.0 IBM J9 2.6 Windows XP x86-32 build 20100901_064112 (pwi3260sr9-20100818_03(SR9)) + */ + String prefix = "Java(TM) SE Runtime Environment(build "; + int start = version.indexOf(prefix) + prefix.length(); + int end = version.indexOf(")))") + 2; + if( start > -1 && end > -1 && end > start) { + version = version.substring(start, end); + } + return version; + } + } + + private static class HeapDumpType extends DTFJDumpType { + + protected HeapDumpType() { + super(HEAPDUMP_FILE_PROPERTY, "com.ibm.dtfj.phd.PHDImageFactory"); + } + } + + private abstract static class DTFJDumpType extends DumpType { + + private final String factoryName; + + protected DTFJDumpType(String propertyName, String factoryName) { + super(propertyName); + this.factoryName = factoryName; + } + + @Override + public String getVersionString() { + String fileName = sysProps.getProperty(getPropertyName()); + File file = new File(fileName); + String version = null; + try { + Class factoryClass = (Class)Class.forName(factoryName); + ImageFactory factory = factoryClass + .newInstance(); + Image image = factory.getImage(file); + Iterator asItr = image.getAddressSpaces(); + while (asItr.hasNext() && version == null) { + Object nextAS = asItr.next(); + if (!(nextAS instanceof ImageAddressSpace)) { + continue; + } + ImageAddressSpace as = (ImageAddressSpace) nextAS; + Iterator psItr = as.getProcesses(); + while (psItr.hasNext() && version == null) { + Object nextPS = psItr.next(); + if (!(nextPS instanceof ImageProcess)) { + continue; + } + ImageProcess ps = (ImageProcess) nextPS; + Iterator rtItr = ps.getRuntimes(); + while (rtItr.hasNext() && version == null) { + Object nextRT = rtItr.next(); + if (!(nextRT instanceof JavaRuntime)) { + continue; + } + JavaRuntime rt = (JavaRuntime) nextRT; + version = rt.getVersion(); + } + } + } + } catch (Exception e) { + System.err + .println("Exception getting version information from system dump: " + + e.getMessage()); + e.printStackTrace(); + } + if (version == null) { + return null; + } + return version; + } + } + + private static class JavaDumpType extends TextDumpType { + + private static final String EYECATCHER = "1CIJAVAVERSION "; + + protected JavaDumpType() { + super(JAVACORE_FILE_PROPERTY, EYECATCHER); + } + } + + private static class ClassicHeapDumpType extends TextDumpType { + + private static final String EYECATCHER = "// Version: "; + + protected ClassicHeapDumpType() { + super(HEAPDUMP_CLASSIC_FILE_PROPERTY, EYECATCHER); + } + + } + + private abstract static class TextDumpType extends DumpType { + + private final String eyeCatcher; + + protected TextDumpType(String propertyName, String eyeCatcher) { + super(propertyName); + this.eyeCatcher = eyeCatcher; + } + + @Override + public String getVersionString() { + // Find the string that starts 1CIJAVAVERSION + // and return the contents of that line. + String fileName = sysProps.getProperty(getPropertyName()); + File file = new File(fileName); + FileReader f; + String version = null; + try { + f = new FileReader(file); + BufferedReader in = new BufferedReader(f); + String line = in.readLine(); + while (line != null) { + if (line.startsWith(eyeCatcher)) { + version = line.substring(eyeCatcher.length()); + break; + } + line = in.readLine(); + } + } catch (FileNotFoundException e) { + System.err.println(e.getMessage()); + e.printStackTrace(); + } catch (IOException e) { + System.err.println(e.getMessage()); + e.printStackTrace(); + } + return version; + } + } +} diff --git a/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/DumpAPIBasicTests.java b/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/DumpAPIBasicTests.java new file mode 100644 index 00000000000..93f091ec1a3 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/DumpAPIBasicTests.java @@ -0,0 +1,1051 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.jvm.ras.tests; + +import static com.ibm.jvm.ras.tests.DumpAPISuite.deleteFile; +import static com.ibm.jvm.ras.tests.DumpAPISuite.getContentType; +import static com.ibm.jvm.ras.tests.DumpAPISuite.getFilesByPattern; +import static com.ibm.jvm.ras.tests.DumpAPISuite.isZOS; + +import java.io.File; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import junit.framework.TestCase; + +import com.ibm.jvm.InvalidDumpOptionException; +import com.ibm.jvm.ras.tests.DumpAPISuite.DumpType; + +public class DumpAPIBasicTests extends TestCase { + + private long uid = System.currentTimeMillis(); + + // Record the files created by each testcase here so we can delete them + // later. Otherwise we will fill the disk up pretty quickly. While we check + // that the right kind of dump was created for each call we do any further + // validity checking on the dumps themselves. This test is just checking the + // API does what it should not that the dumps themselves are correct. + private Set fileNames; + + @Override + protected void setUp() throws Exception { + super.setUp(); + fileNames = new HashSet(); + // This isn't to free space, it's to trigger GC tracepoints so we don't get empty snap dumps! + System.gc(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + for( String fileName: fileNames) { + deleteFile(fileName, this.getName()); + } + } + + /** + * Test a java dump is generated from the standard com.ibm.jvm.Dump.JavaDump() + * call. + */ + public void testJavaDumpNoArgs() { + String userDir = System.getProperty("user.dir"); + String javaCorePattern = "javacore\\..*\\.txt"; + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, javaCorePattern); + int beforeCount = beforeFileNames.length; + + com.ibm.jvm.Dump.JavaDump(); + + String[] afterFileNames = getFilesByPattern(userDir, javaCorePattern); + + addNewFilesToDelete(beforeFileNames, afterFileNames); + + int afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount + 1, afterCount); + } + + private void addNewFilesToDelete(String[] beforeFileNames, + String[] afterFileNames) { + for( String after : afterFileNames ) { + boolean newFile = true; + for( String before : beforeFileNames ) { + if( before.equals(after) ) { + newFile = false; + break; + } + } + if( newFile ) { + fileNames.add(after); + } + } + } + + public void testJavaDumpWithFile() { + String userDir = System.getProperty("user.dir"); + + String expectedName = userDir + File.separator + "javacore."+ getName() + "." + uid + ".txt"; + + // Check the file doesn't exist, otherwise the dump code moves it. + File expectedFile = new File(expectedName); + assertFalse("The javacore file " + expectedName + " already exists", expectedFile.exists()); + + // Check we got the correct name. + String javacoreName = null; + try { + javacoreName = com.ibm.jvm.Dump.javaDumpToFile(expectedName); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + + assertNotNull("Expected javacore filename to be returned, not null", javacoreName); + fileNames.add(javacoreName); + assertEquals("Expected javacore to be written to file: " + expectedName + " but was written to " + javacoreName, expectedName, javacoreName); + + // Check it really exists. + File javacoreFile = new File(javacoreName); + assertTrue("Failed to find files " + javacoreName + " after requesting " + javacoreName, javacoreFile.exists()); + DumpType type = getContentType(javacoreFile); + assertEquals("Expected file " + javacoreName + " to contain a java core but content type was: " + type, DumpType.JAVA_TYPE, type); + } + + /** Test what happens when a filename includes options e.g "heap.phd,opts=CLASSIC" + */ + public void testJavaDumpWithOptions() { + String[] options = { + ",exec=gdb", + ",file=foo.dmp", + ",filter=java/lang/OutOfMemoryError", + ",opts=CLASSIC", + ",priority=500", + ",range=1..6", + ",request=exclusive", + ",suspendwith=2", + }; + + String userDir = System.getProperty("user.dir"); + + String expectedName = userDir + File.separator + "javacore."+ getName() + "." + uid + ".txt"; + + // Check the file doesn't exist, otherwise the dump code moves it. + File expectedFile = new File(expectedName); + assertFalse("The java core file " + expectedName + " already exists", expectedFile.exists()); + + // Check none of these options works in a file name. + for( String option : options ) { + String javaDumpName = null; + try { + javaDumpName = com.ibm.jvm.Dump.javaDumpToFile(expectedName + option); + fail("Expected InvalidDumpOption exception to be thrown instead " + javaDumpName + " was written when specifying: " + option); + } catch (InvalidDumpOptionException e ) { + } + } + } + + + /** + * Test a java dump is generated from the standard com.ibm.jvm.Dump.JavaDump() + * call. + */ + public void testJavaDumpNullFile() { + String userDir = System.getProperty("user.dir"); + String javaCorePattern = "javacore\\..*\\.txt"; + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, javaCorePattern); + int beforeCount = beforeFileNames.length; + + String javacoreName = null; + try { + javacoreName = com.ibm.jvm.Dump.javaDumpToFile(null); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + + assertNotNull("Expected javacore filename to be returned, not null", javacoreName); + fileNames.add(javacoreName); + + // Check the generated file really exists. + File javacoreFile = new File(javacoreName); + assertTrue("Failed to find files " + javacoreName + " after requesting " + javacoreName, javacoreFile.exists()); + + // Check the number of files has increased. (We weren't returned a filename that already existed.) + String[] afterFileNames = getFilesByPattern(userDir, javaCorePattern); + int afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount + 1, afterCount); + + // Check content + DumpType type = getContentType(javacoreFile); + assertEquals("Expected file " + javacoreName + " to contain a java core but content type was: " + type, DumpType.JAVA_TYPE, type); + } + + /** + * Test a java dump is generated from the standard com.ibm.jvm.Dump.JavaDump() + * call. + */ + public void testJavaDumpEmptyFile() { + String userDir = System.getProperty("user.dir"); + String javaCorePattern = "javacore\\..*\\.txt"; + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, javaCorePattern); + int beforeCount = beforeFileNames.length; + + String javacoreName = null; + try { + javacoreName = com.ibm.jvm.Dump.javaDumpToFile(""); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + + assertNotNull("Expected javacore filename to be returned, not null", javacoreName); + fileNames.add(javacoreName); + + // Check the generated file really exists. + File javacoreFile = new File(javacoreName); + assertTrue("Failed to find files " + javacoreName + " after requesting " + javacoreName, javacoreFile.exists()); + + // Check the number of files has increased. (We weren't returned a filename that already existed.) + String[] afterFileNames = getFilesByPattern(userDir, javaCorePattern); + int afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount + 1, afterCount); + + // Check content + DumpType type = getContentType(javacoreFile); + assertEquals("Expected file " + javacoreName + " to contain a java core but content type was: " + type, DumpType.JAVA_TYPE, type); + + } + + /** + * Test a java dump isn't generated when the path is "-" + */ + public void testJavaDumpToDashFile() { + String userDir = System.getProperty("user.dir"); + String javaCorePattern = "javacore\\..*\\.txt"; + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, javaCorePattern); + int beforeCount = beforeFileNames.length; + + String javacoreName = null; + try { + javacoreName = com.ibm.jvm.Dump.javaDumpToFile("-"); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + + // Check the number of files has stayed the same + String[] afterFileNames = getFilesByPattern(userDir, javaCorePattern); + int afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount, afterCount); + + } + + /* Test we relocate files if they clash with an existing file, but only once! */ + public void testJavaDumpWithSameFile() { + String userDir = System.getProperty("user.dir"); + + String expectedName = userDir + File.separator + "javacore."+ getName() + "." + uid + ".txt"; + + // Check the file doesn't exist, otherwise the dump code moves it. + File expectedFile = new File(expectedName); + assertFalse("The javacore file " + expectedName + " already exists", expectedFile.exists()); + + // Check we got the correct name. + String javacoreName = null; + try { + javacoreName = com.ibm.jvm.Dump.javaDumpToFile(expectedName); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + + assertNotNull("Expected javacore filename to be returned, not null", javacoreName); + fileNames.add(javacoreName); + assertEquals("Expected javacore to be written to file: " + expectedName + " but was written to " + javacoreName, expectedName, javacoreName); + + // Check it really exists. + File javacoreFile = new File(javacoreName); + assertTrue("Failed to find files " + javacoreName + " after requesting " + javacoreName, javacoreFile.exists()); + + // Check we get a different name the second time. + + String javacoreName2 = null; + try { + javacoreName2 = com.ibm.jvm.Dump.javaDumpToFile(expectedName); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + + assertNotNull("Expected javacore filename to be returned, not null", javacoreName2); + fileNames.add(javacoreName2); + assertFalse( + "Expected second dump file to be written to a different location. Original dump: " + + javacoreName + " second dump: " + javacoreName2, javacoreName.equals(javacoreName2)); + // Check it really exists. + File javacoreFile2 = new File(javacoreName2); + assertTrue("Failed to find files " + javacoreName2 + + " after requesting " + javacoreName + " a second time.", + javacoreFile2.exists()); + + // Now check this file is replaced if we end up writing to it again + // the same way. + long timestamp2 = javacoreFile2.lastModified(); + + // Some timestamps are only down to the second on some platforms. + // Dumps can happen quicker than that. + try { + Thread.sleep(1000); + } catch (InterruptedException e){ + // Ignore. + } + + // Check we get a different name the second time. + String javacoreName3 = null; + try { + javacoreName3 = com.ibm.jvm.Dump.javaDumpToFile(expectedName); + fail("Expected to fail when we tried overwriting the file we failed over to."); + } catch (InvalidDumpOptionException e ) { + System.out.println(e); + System.out.println("reach here"); + } + + } + + /* + * Test a heap dump is generated from the standard com.ibm.jvm.Dump.HeapDump() + * call. + */ + public void testHeapDumpNoArgs() { + String userDir = System.getProperty("user.dir"); + String javaCorePattern = "heapdump\\..*\\.phd"; + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, javaCorePattern); + int beforeCount = beforeFileNames.length; + + com.ibm.jvm.Dump.HeapDump(); + + String[] afterFileNames = getFilesByPattern(userDir, javaCorePattern); + + addNewFilesToDelete(beforeFileNames, afterFileNames); + + int afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount + 1, afterCount); + } + + public void testHeapDumpWithFile() { + String userDir = System.getProperty("user.dir"); + + String expectedName = userDir + File.separator + "heapdump."+ getName() + "." + uid + ".phd"; + + // Check the file doesn't exist, otherwise the dump code moves it. + File expectedFile = new File(expectedName); + assertFalse("The javacore file " + expectedName + " already exists", expectedFile.exists()); + + // Check we got the correct name. + String heapDumpName = null; + try { + heapDumpName = com.ibm.jvm.Dump.heapDumpToFile(expectedName); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + + assertNotNull("Expected javacore filename to be returned, not null", heapDumpName); + fileNames.add(heapDumpName); + assertEquals("Expected javacore to be written to file: " + expectedName + " but was written to " + heapDumpName, expectedName, heapDumpName); + + // Check it really exists. + File heapDumpFile = new File(heapDumpName); + assertTrue("Failed to find files " + heapDumpName + " after requesting " + heapDumpName, heapDumpFile.exists()); + + // Check content + DumpType type = getContentType(heapDumpFile); + assertEquals("Expected file " + heapDumpName + " to contain a heap dump but content type was: " + type, DumpType.PHD_HEAP_TYPE, type); + + } + + /** + * Test what happens when a filename includes options e.g "heap.phd,opts=CLASSIC" + */ + public void testHeapDumpWithOptions() { + String[] options = { + ",exec=gdb", + ",file=foo.dmp", + ",filter=java/lang/OutOfMemoryError", + ",opts=CLASSIC", + ",priority=500", + ",range=1..6", + ",request=exclusive", + ",suspendwith=2", + }; + + String userDir = System.getProperty("user.dir"); + + String expectedName = userDir + File.separator + "heapdump."+ getName() + "." + uid + ".phd"; + + // Check the file doesn't exist, otherwise the dump code moves it. + File expectedFile = new File(expectedName); + assertFalse("The heap dump file " + expectedName + " already exists", expectedFile.exists()); + + // Check none of these options works in a file name. + for( String option : options ) { + String heapDumpName = null; + try { + heapDumpName = com.ibm.jvm.Dump.heapDumpToFile(expectedName + option); + fail("Expected InvalidDumpOption exception to be thrown instead " + heapDumpName + " was written when specifying: " + option); + } catch (InvalidDumpOptionException e ) { + } + } + } + + /** + * Test a java dump is generated from the standard com.ibm.jvm.Dump.JavaDump() + * call. + */ + public void testHeapDumpNullFile() { + String userDir = System.getProperty("user.dir"); + String heapDumpPattern = "heapdump\\..*\\.phd"; + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, heapDumpPattern); + int beforeCount = beforeFileNames.length; + + String heapDumpName = null; + try { + heapDumpName = com.ibm.jvm.Dump.heapDumpToFile(null); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + + assertNotNull("Expected heapdump filename to be returned, not null", heapDumpName); + fileNames.add(heapDumpName); + + // Check the generated file really exists. + File heapDumpFile = new File(heapDumpName); + assertTrue("Failed to find files " + heapDumpName + " after requesting " + heapDumpName, heapDumpFile.exists()); + + // Check the number of files has increased. (We weren't returned a filename that already existed.) + String[] afterFileNames = getFilesByPattern(userDir, heapDumpPattern); + int afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount + 1, afterCount); + + // Check content + DumpType type = getContentType(heapDumpFile); + assertEquals("Expected file " + heapDumpName + " to contain a heap dump but content type was: " + type, DumpType.PHD_HEAP_TYPE, type); + } + + /** + * Test a heap dump isn't generated when the path is "-" + */ + public void testHeapDumpToDashFile() { + String userDir = System.getProperty("user.dir"); + String javaCorePattern = "heap\\..*\\.phd"; + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, javaCorePattern); + int beforeCount = beforeFileNames.length; + + String heapName = null; + try { + heapName = com.ibm.jvm.Dump.heapDumpToFile("-"); + fail("Expected InvalidDumpOption exception to be thrown filename " + heapName + " was returned"); + } catch (InvalidDumpOptionException e ) { + // Pass + } + } + + /* Test we relocate files if they clash with an existing file, but only once! */ + public void testHeapDumpWithSameFile() { + String userDir = System.getProperty("user.dir"); + + String expectedName = userDir + File.separator + "heapdump."+ getName() + "." + uid + ".phd"; + + // Check the file doesn't exist, otherwise the dump code moves it. + File expectedFile = new File(expectedName); + assertFalse("The heapdump file " + expectedName + " already exists", expectedFile.exists()); + + // Check we got the correct name. + String heapDumpName = null; + try { + heapDumpName = com.ibm.jvm.Dump.heapDumpToFile(expectedName); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + + assertNotNull("Expected heapdump filename to be returned, not null", heapDumpName); + fileNames.add(heapDumpName); + assertEquals("Expected heapdump to be written to file: " + expectedName + " but was written to " + heapDumpName, expectedName, heapDumpName); + + // Check it really exists. + File heapdumpFile = new File(heapDumpName); + assertTrue("Failed to find files " + heapDumpName + " after requesting " + heapDumpName, heapdumpFile.exists()); + + // Check we get a different name the second time. + String heapdumpName2 = null; + try { + heapdumpName2 = com.ibm.jvm.Dump.heapDumpToFile(expectedName); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + + assertNotNull("Expected heapdump filename to be returned, not null", heapdumpName2); + fileNames.add(heapdumpName2); + assertFalse( + "Expected second dump file to be written to a different location. Original dump: " + + heapDumpName + " second dump: " + heapdumpName2, heapDumpName.equals(heapdumpName2)); + // Check it really exists. + File heapdumpFile2 = new File(heapdumpName2); + assertTrue("Failed to find files " + heapdumpName2 + + " after requesting " + heapDumpName + " a second time.", + heapdumpFile2.exists()); + + // Now check this file is replaced if we end up writing to it again + // the same way. + long timestamp2 = heapdumpFile2.lastModified(); + + // Some timestamps are only down to the second on some platforms. + // Dumps can happen quicker than that. + try { + Thread.sleep(1000); + } catch (InterruptedException e){ + // Ignore. + } + + // Check we get a different name the second time. + String heapdumpName3 = null; + try { + heapdumpName3 = com.ibm.jvm.Dump.heapDumpToFile(expectedName); + fail("Expected to fail when we tried overwriting the file we failed over to."); + } catch (InvalidDumpOptionException e ) { + } + + } + + + /** + * Test a snap dump is generated from the standard com.ibm.jvm.Dump.SnapDump() + * call. + */ + public void testSnapDumpNoArgs() { + String userDir = System.getProperty("user.dir"); + String javaCorePattern = "Snap\\..*\\.trc"; + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, javaCorePattern); + int beforeCount = beforeFileNames.length; + + com.ibm.jvm.Dump.SnapDump(); + + String[] afterFileNames = getFilesByPattern(userDir, javaCorePattern); + + addNewFilesToDelete(beforeFileNames, afterFileNames); + + int afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount + 1, afterCount); + } + + public void testSnapDumpWithFile() { + String userDir = System.getProperty("user.dir"); + + String expectedName = userDir + File.separator + "snap."+ getName() + "." + uid + ".trc"; + + // Check the file doesn't exist, otherwise the dump code moves it. + File expectedFile = new File(expectedName); + assertFalse("The snap file " + expectedName + " already exists", expectedFile.exists()); + + // Check we got the correct name. + String snapName = null; + try { + snapName = com.ibm.jvm.Dump.snapDumpToFile(expectedName); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + + assertNotNull("Expected snap filename to be returned, not null", snapName); + fileNames.add(snapName); + assertEquals("Expected snap to be written to file: " + expectedName + " but was written to " + snapName, expectedName, snapName); + + // Check it really exists. + File snapFile = new File(snapName); + assertTrue("Failed to find files " + snapName + " after requesting " + snapName, snapFile.exists()); + + // Check content + DumpType type = getContentType(snapFile); + assertEquals("Expected file " + snapName + " to contain a snap trace but content type was: " + type, DumpType.SNAP_TYPE, type); + + } + + /** + * Test what happens when a filename includes options e.g "heap.phd,opts=CLASSIC" + */ + public void testSnapDumpWithOptions() { + String[] options = { + ",exec=gdb", + ",file=foo.dmp", + ",filter=java/lang/OutOfMemoryError", + ",opts=CLASSIC", + ",priority=500", + ",range=1..6", + ",request=exclusive", + ",suspendwith=2", + }; + + String userDir = System.getProperty("user.dir"); + + String expectedName = userDir + File.separator + "Snap."+ getName() + "." + uid + ".trc"; + + // Check the file doesn't exist, otherwise the dump code moves it. + File expectedFile = new File(expectedName); + assertFalse("The snap dump file " + expectedName + " already exists", expectedFile.exists()); + + // Check none of these options works in a file name. + for( String option : options ) { + String snapDumpName = null; + try { + snapDumpName = com.ibm.jvm.Dump.snapDumpToFile(expectedName + option); + fail("Expected InvalidDumpOption exception to be thrown instead " + snapDumpName + " was written when specifying: " + option); + } catch (InvalidDumpOptionException e ) { + } + } + } + + /** + * Test a java dump is generated from the standard com.ibm.jvm.Dump.JavaDump() + * call. + */ + public void testSnapDumpNullFile() { + String userDir = System.getProperty("user.dir"); + String snapPattern = "Snap\\..*\\.trc"; + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, snapPattern); + int beforeCount = beforeFileNames.length; + + String snapName = null; + try { + snapName = com.ibm.jvm.Dump.snapDumpToFile(null); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + + assertNotNull("Expected snap filename to be returned, not null", snapName); + fileNames.add(snapName); + + // Check the generated file really exists. + File snapFile = new File(snapName); + assertTrue("Failed to find files " + snapName + " after requesting " + snapName, snapFile.exists()); + + // Check the number of files has increased. (We weren't returned a filename that already existed.) + String[] afterFileNames = getFilesByPattern(userDir, snapPattern); + int afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount + 1, afterCount); + + // Check content + DumpType type = getContentType(snapFile); + assertEquals("Expected file " + snapName + " to contain a snap trace but content type was: " + type, DumpType.SNAP_TYPE, type); + + } + + /** + * Test a snap dump isn't generated when the path is "-" + */ + public void testSnapDumpToDashFile() { + String userDir = System.getProperty("user.dir"); + String javaCorePattern = "snap\\..*\\.trc"; + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, javaCorePattern); + int beforeCount = beforeFileNames.length; + + String snapName = null; + try { + snapName = com.ibm.jvm.Dump.snapDumpToFile("-"); + fail("Expected InvalidDumpOption exception to be thrown filename " + snapName + " was returned"); + } catch (InvalidDumpOptionException e ) { + // Pass + } + } + + /* Test we relocate files if they clash with an existing file, but only once! */ + public void testSnapDumpWithSameFile() { + String userDir = System.getProperty("user.dir"); + + String expectedName = userDir + File.separator + "Snap."+ getName() + "." + uid + ".trc"; + + // Check the file doesn't exist, otherwise the dump code moves it. + File expectedFile = new File(expectedName); + assertFalse("The Snap file " + expectedName + " already exists", expectedFile.exists()); + + // Check we got the correct name. + String snapName = null; + try { + snapName = com.ibm.jvm.Dump.snapDumpToFile(expectedName); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + assertNotNull("Expected Snap filename to be returned, not null", snapName); + fileNames.add(snapName); + assertEquals("Expected Snap to be written to file: " + expectedName + " but was written to " + snapName, expectedName, snapName); + + // Check it really exists. + File snapFile = new File(snapName); + assertTrue("Failed to find files " + snapName + " after requesting " + snapName, snapFile.exists()); + + // Check we get a different name the second time. + String snapName2 = null; + try { + snapName2 = com.ibm.jvm.Dump.snapDumpToFile(expectedName); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + + assertNotNull("Expected Snap filename to be returned, not null", snapName2); + fileNames.add(snapName2); + assertFalse( + "Expected second dump file to be written to a different location. Original dump: " + + snapName + " second dump: " + snapName2, snapName.equals(snapName2)); + // Check it really exists. + File snapFile2 = new File(snapName2); + assertTrue("Failed to find files " + snapName2 + + " after requesting " + snapName + " a second time.", + snapFile2.exists()); + + // Now check this file is replaced if we end up writing to it again + // the same way. + long timestamp2 = snapFile2.lastModified(); + + // Some timestamps are only down to the second on some platforms. + // Dumps can happen quicker than that. + try { + Thread.sleep(1000); + } catch (InterruptedException e){ + // Ignore. + } + + // Check we get a different name the second time. + String snapName3 = null; + try { + snapName3 = com.ibm.jvm.Dump.snapDumpToFile(expectedName); + fail("Expected to fail when we tried overwriting the file we failed over to."); + } catch (InvalidDumpOptionException e ) { + } + +// assertNotNull("Expected Snap filename to be returned, not null", snapName); +// assertFalse( +// "Expected third dump file to be written to a different location. Original dump: " +// + snapName + " second dump: " + snapName3, snapName.equals(snapName3)); +// assertEquals( +// "Expected third dump file to be written to the same location as the second location. Original dump: " +// + snapName + " second dump: " + snapName2 + " third dump " + snapName3, snapName2, snapName3); +// // Check it really exists. +// File snapFile3 = new File(snapName3); +// assertTrue("Failed to find files " + snapName3 +// + " after requesting " + snapName + " a second time.", +// snapFile3.exists()); +// +// // Now check this file is replaced if we end up writing to it again +// // the same way. +// long timestamp3 = snapFile3.lastModified(); +// System.err.println("Timestamp 3: " + timestamp3 + " > " + timestamp2); +// assertTrue("Expected " + snapName3 + " to be updated by second dump to " + expectedName, timestamp3 > timestamp2); + + } + + + /** + * Test a system dump is generated from the standard com.ibm.jvm.Dump.SystemDump() + * call. + */ + public void testSystemDumpNoArgs() { + if( isZOS() ) { + System.err.printf("Skipping %s, z/OS system dumps currently inaccessable in Java 8, see CMVC 193090\n", this.getName()); + return; + } + + String userDir = System.getProperty("user.dir"); + String javaCorePattern = "core\\..*\\.dmp"; + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, javaCorePattern); + int beforeCount = beforeFileNames.length; + + com.ibm.jvm.Dump.SystemDump(); + + String[] afterFileNames = getFilesByPattern(userDir, javaCorePattern); + + addNewFilesToDelete(beforeFileNames, afterFileNames); + + int afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount + 1, afterCount); + } + + public void testSystemDumpWithFile() { + if( isZOS() ) { + System.err.printf("Skipping %s, z/OS system dumps currently inaccessable in Java 8, see CMVC 193090\n", this.getName()); + return; + } + + String userDir = System.getProperty("user.dir"); + + String expectedName = userDir + File.separator + "core."+ getName() + "." + uid + ".dmp"; + + // Check the file doesn't exist, otherwise the dump code moves it. + File expectedFile = new File(expectedName); + assertFalse("The core file " + expectedName + " already exists", expectedFile.exists()); + + // Check we got the correct name. + String coreName = null; + try { + coreName = com.ibm.jvm.Dump.systemDumpToFile(expectedName); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + assertNotNull("Expected core filename to be returned, not null", coreName); + fileNames.add(coreName); + assertEquals("Expected core to be written to file: " + expectedName + " but was written to " + coreName, expectedName, coreName); + + // Check it really exists. + File coreFile = new File(coreName); + assertTrue("Failed to find files " + coreName + " after requesting " + coreName, coreFile.exists()); + + // Check content + DumpType type = getContentType(coreFile); + assertEquals("Expected file " + coreName + " to contain a system core but content type was: " + type, DumpType.SYSTEM_TYPE, type); + + } + + /** + * Test what happens when a filename includes options e.g "heap.phd,opts=CLASSIC" + */ + public void testSystemDumpWithOptions() { + if( isZOS() ) { + System.err.printf("Skipping %s, z/OS system dumps currently inaccessable in Java 8, see CMVC 193090\n", this.getName()); + return; + } + + String[] options = { + ",exec=gdb", + ",file=foo.dmp", + ",filter=java/lang/OutOfMemoryError", + ",opts=CLASSIC", + ",priority=500", + ",range=1..6", + ",request=exclusive", + ",suspendwith=2", + }; + + String userDir = System.getProperty("user.dir"); + + String expectedName = userDir + File.separator + "core."+ getName() + "." + uid + ".dmp"; + + // Check the file doesn't exist, otherwise the dump code moves it. + File expectedFile = new File(expectedName); + assertFalse("The core dump file " + expectedName + " already exists", expectedFile.exists()); + + // Check none of these options works in a file name. + for( String option : options ) { + String coreDumpName = null; + try { + coreDumpName = com.ibm.jvm.Dump.systemDumpToFile(expectedName + option); + fail("Expected InvalidDumpOption exception to be thrown instead " + coreDumpName + " was written when specifying: " + option); + } catch (InvalidDumpOptionException e ) { + } + } + } + + /** + * Test a java dump is generated from the standard com.ibm.jvm.Dump.JavaDump() + * call. + */ + public void testSystemDumpNullFile() { + if( isZOS() ) { + System.err.printf("Skipping %s, z/OS system dumps currently inaccessable in Java 8, see CMVC 193090\n", this.getName()); + return; + } + + String userDir = System.getProperty("user.dir"); + String corePattern = "core\\..*\\.dmp"; + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, corePattern); + int beforeCount = beforeFileNames.length; + + String coreName = null; + try { + coreName = com.ibm.jvm.Dump.systemDumpToFile(null); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + + assertNotNull("Expected core filename to be returned, not null", coreName); + fileNames.add(coreName); + + // Check the generated file really exists. + File coreFile = new File(coreName); + assertTrue("Failed to find files " + coreName + " after requesting " + coreName, coreFile.exists()); + + // Check the number of files has increased. (We weren't returned a filename that already existed.) + String[] afterFileNames = getFilesByPattern(userDir, corePattern); + int afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount + 1, afterCount); + + // Check content + DumpType type = getContentType(coreFile); + assertEquals("Expected file " + coreName + " to contain a system core but content type was: " + type, DumpType.SYSTEM_TYPE, type); + + } + + /** + * Test a core dump isn't generated when the path is "-" + */ + public void testSystemDumpToDashFile() { + if( isZOS() ) { + System.err.printf("Skipping %s, z/OS system dumps currently inaccessable in Java 8, see CMVC 193090\n", this.getName()); + return; + } + + String userDir = System.getProperty("user.dir"); + String corePattern = "core\\..*\\.dmp"; + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, corePattern); + int beforeCount = beforeFileNames.length; + + String coreName = null; + try { + coreName = com.ibm.jvm.Dump.systemDumpToFile("-"); + fail("Expected InvalidDumpOption exception to be thrown filename " + coreName + " was returned"); + } catch (InvalidDumpOptionException e ) { + // Pass + } + } + + /* Test we relocate files if they clash with an existing file, but only once! */ + public void testSystemDumpWithSameFile() { + if( isZOS() ) { + System.err.printf("Skipping %s, z/OS system dumps currently inaccessable in Java 8, see CMVC 193090\n", this.getName()); + return; + } + + String userDir = System.getProperty("user.dir"); + + String expectedName = userDir + File.separator + "core."+ getName() + "." + uid + ".dmp"; + + // Check the file doesn't exist, otherwise the dump code moves it. + File expectedFile = new File(expectedName); + assertFalse("The core file " + expectedName + " already exists", expectedFile.exists()); + + // Check we got the correct name. + String coreName = null; + try { + coreName = com.ibm.jvm.Dump.systemDumpToFile(expectedName); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + assertNotNull("Expected core filename to be returned, not null", coreName); + fileNames.add(coreName); + assertEquals("Expected core to be written to file: " + expectedName + " but was written to " + coreName, expectedName, coreName); + + // Check it really exists. + File coreFile = new File(coreName); + assertTrue("Failed to find files " + coreName + " after requesting " + coreName, coreFile.exists()); + + // Check we get a different name the second time. + String coreName2 = null; + try { + coreName2 = com.ibm.jvm.Dump.systemDumpToFile(expectedName); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + + assertNotNull("Expected core filename to be returned, not null", coreName2); + fileNames.add(coreName2); + assertFalse( + "Expected second dump file to be written to a different location. Original dump: " + + coreName + " second dump: " + coreName2, coreName.equals(coreName2)); + // Check it really exists. + File coreFile2 = new File(coreName2); + assertTrue("Failed to find files " + coreName2 + + " after requesting " + coreName + " a second time.", + coreFile2.exists()); + + // Now check this file is replaced if we end up writing to it again + // the same way. + long timestamp2 = coreFile2.lastModified(); + + // Some timestamps are only down to the second on some platforms. + // Dumps can happen quicker than that. + try { + Thread.sleep(1000); + } catch (InterruptedException e){ + // Ignore. + } + + // Check we get a different name the second time. + String coreName3 = null; + try { + coreName3 = com.ibm.jvm.Dump.systemDumpToFile(expectedName); + fail("Expected to fail when we tried overwriting the file we failed over to."); + } catch (InvalidDumpOptionException e ) { + } + +// assertNotNull("Expected core filename to be returned, not null", coreName); +// assertFalse( +// "Expected third dump file to be written to a different location. Original dump: " +// + coreName + " second dump: " + coreName3, coreName.equals(coreName3)); +// assertEquals( +// "Expected third dump file to be written to the same location as the second location. Original dump: " +// + coreName + " second dump: " + coreName2 + " third dump " + coreName3, coreName2, coreName3); +// // Check it really exists. +// File coreFile3 = new File(coreName3); +// assertTrue("Failed to find files " + coreName3 +// + " after requesting " + coreName + " a second time.", +// coreFile3.exists()); +// +// // Now check this file is replaced if we end up writing to it again +// // the same way. +// long timestamp3 = coreFile3.lastModified(); +// System.err.println("Timestamp 3: " + timestamp3 + " > " + timestamp2); +// assertTrue("Expected " + coreName3 + " to be updated by second dump to " + expectedName, timestamp3 > timestamp2); + + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/DumpAPIQuerySetReset.java b/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/DumpAPIQuerySetReset.java new file mode 100644 index 00000000000..c09f267c84c --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/DumpAPIQuerySetReset.java @@ -0,0 +1,652 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.jvm.ras.tests; + +import java.util.Arrays; + +import junit.framework.TestCase; + +import com.ibm.jvm.DumpConfigurationUnavailableException; +import com.ibm.jvm.InvalidDumpOptionException; + +@SuppressWarnings("nls") +public class DumpAPIQuerySetReset extends TestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + private static void clearDumpOptions() { + String initialDumpOptions[] = com.ibm.jvm.Dump.queryDumpOptions(); + + try { + com.ibm.jvm.Dump.setDumpOptions("none"); + } catch (InvalidDumpOptionException idoe) { + idoe.printStackTrace(); + } catch (NullPointerException e) { + e.printStackTrace(); + } catch (DumpConfigurationUnavailableException e) { + e.printStackTrace(); + } + + String afterNoneOptions[] = com.ibm.jvm.Dump.queryDumpOptions(); + + if (0 != afterNoneOptions.length) { + fail("Expected an empty array of dump options but got: " + Arrays.toString(afterNoneOptions)); + } + } + + public void testSetNone() { + String initialDumpOptions[] = com.ibm.jvm.Dump.queryDumpOptions(); + + try { + com.ibm.jvm.Dump.setDumpOptions("none"); + } catch (InvalidDumpOptionException idoe) { + + } catch (DumpConfigurationUnavailableException e) { + e.printStackTrace(); + } + + String afterNoneOptions[] = com.ibm.jvm.Dump.queryDumpOptions(); + + if (0 != afterNoneOptions.length) { + fail("Expected an empty array of dump options but got: " + Arrays.toString(afterNoneOptions)); + } + } + + public void testSetWhat() { + // clearDumpOptions(); + try { + com.ibm.jvm.Dump.resetDumpOptions(); + try { + com.ibm.jvm.Dump.setDumpOptions("what"); + } catch (InvalidDumpOptionException idoe) { + fail("-Xdump:what was expected to be permitted"); + } + } catch (DumpConfigurationUnavailableException e) { + e.printStackTrace(); + } + // -Xdump:what doesn't do anything but it would just be irritating if people couldn't + // use it to quickly print all available options. + } + + // testQuery - set loads of options to get a huge buffer, query, check we get all the options back as expected + public void testQuery() { + clearDumpOptions(); + String[] dumpTypes = { "java", "system", "heap", "tool", "console", "stack", "silent", "jit" }; + String[] dumpEvents = { "systhrow", "uncaught", "gpf", "traceassert", "user", "abort", "vmstop" }; + // The following events are omitted from the list above as they can affect the behaviour of the VM under test, + // e.g. "thrstart" will cause a dump to be triggered if another thread starts, and hence lock the dump configuration + // at an arbitrary point in time: "vmstart", "throw", "systhrow", "catch", "uncaught", "thrstart", "thrstop" + String[] dumpFilters = { "java/lang/OutOfMemoryError", "java/lang/NullPointerException", "made/up/Exception1", + "made/up/Exception2", "made/up/Exception3", "made/up/Exception4", "made/up/Exception5", + "made/up/Exception6", "made/up/Exception7" }; + + int count = populateDumpAgents(dumpTypes, dumpEvents, dumpFilters); + + String dumpAgents[] = com.ibm.jvm.Dump.queryDumpOptions(); + + assertNotNull("Expected array of dump agents returned, not null", dumpAgents); + assertEquals("Expected " + count + " dump agents configured.", count, dumpAgents.length); + + // Can probably have one function to validate two list of options match and re-use in lots of places. + + int foundCount = checkDumpAgents(dumpTypes, dumpEvents, dumpFilters, dumpAgents); + assertEquals("Expected to find all the expected agents.", dumpAgents.length, foundCount); + clearDumpOptions(); + } + + /** + * Use the settings we are passed to generate all those combinations of dump + * agents. + * The arrays must be the same size as the arrays passed to populateDumpAgents, + * use null for any items which have been removed. + * @param dumpTypes + * @param dumpEvents + * @param dumpFilters + * @param dumpAgents + * @return + */ + private static int checkDumpAgents(String[] dumpTypes, String[] dumpEvents, String[] dumpFilters, String[] dumpAgents) { + int checkCount = 0; + int foundCount = 0; + // System.err.println("Running checkDumpAgents..."); + for (String type : dumpTypes) { + for (String event : dumpEvents) { + String eventPattern = "events=" + event; + for (String filter : dumpFilters) { + // Find a dump type agent for each line we added. Can't do an exact match as + // the agents add paths and re-order arguments. + String filterPattern = "filter=" + filter; + // 'label' is still accepted in options, but no longer used in reports + String labelPattern = ".*\\b(dsn|exec|file)=.*" + type + checkCount + ".*"; + checkCount++; + if (type == null || event == null || filter == null) { + // This permutation should have been removed, still + // need to increment checkCount to kep the labels matching. + continue; + } + // System.err.println("Checking: " + type); + // System.err.println("Checking: " + eventPattern); + // System.err.println("Checking: " + filterPattern); + // System.err.println("Checking: " + labelPattern); + for (String agentString : dumpAgents) { + // System.err.println("Agent checked is: " + agentString); + if (!agentString.startsWith(type)) { + continue; + } + if (!agentString.contains(eventPattern)) { + continue; + } + if (!agentString.contains(filterPattern)) { + continue; + } + if (!agentString.matches(labelPattern)) { + continue; + } + foundCount++; + // System.err.println("found: " + agentString); + } + } + } + } + // System.err.println("Checked: " + checkCount); + return foundCount; + } + + /** + * Use the settings we are passed to generate all combinations of dump agents. + */ + private static int populateDumpAgents(String[] dumpTypes, String[] dumpEvents, String[] dumpFilters) { + int count = 0; + + for (String type : dumpTypes) { + for (String event : dumpEvents) { + for (String filter : dumpFilters) { + // Create agents the dump system can't merge. + String options = type + ":events=" + event + ",filter=" + filter + ",label=" + type + count++; + try { + com.ibm.jvm.Dump.setDumpOptions(options); + } catch (InvalidDumpOptionException e) { + e.printStackTrace(); + fail("Expected my dump options to work but got an InvalidDumpOptionException: " + e.getMessage()); + } catch (DumpConfigurationUnavailableException e) { + e.printStackTrace(); + fail("Expected my dump options to work but got an DumpConfigurationUnavailableException: " + e.getMessage()); + } + } + } + } + + return count; + } + + // testSetNone - test all dumps of particular types can be removed. + public void testSetNoneByType() { + clearDumpOptions(); + + String[] dumpTypes = { "java", "system", "heap", "tool", "console", "stack", "silent", "jit" }; + String[] dumpEvents = { "systhrow", "uncaught" }; // { "throw", "systhrow", "catch", "uncaught" }; + String[] dumpFilters = { "java/lang/OutOfMemoryError", "java/lang/NullPointerException", "made/up/Exception1", + "made/up/Exception2", "made/up/Exception3", "made/up/Exception4", "made/up/Exception5", + "made/up/Exception6", "made/up/Exception7" }; + + int count = populateDumpAgents(dumpTypes, dumpEvents, dumpFilters); + + String dumpAgents[] = com.ibm.jvm.Dump.queryDumpOptions(); + + assertNotNull("Expected array of dump agents returned, not null", dumpAgents); + assertEquals("Expected " + count + " dump agents configured.", count, dumpAgents.length); + + String removalType = "heap"; + try { + com.ibm.jvm.Dump.setDumpOptions(removalType + ":none"); + } catch (InvalidDumpOptionException e) { + fail("Expected to be able to remove all dump agents of type: " + removalType); + } catch (DumpConfigurationUnavailableException e) { + fail("Expected to be able to remove all dump agents of type: " + removalType); + } + + String[] afterAgents = com.ibm.jvm.Dump.queryDumpOptions(); + // System.out.println("Found " + afterAgents.length + " agents"); + // for (String agent : afterAgents) { + // System.out.println("After: " + agent); + // } + + // Validate the list of agents. + int foundCount = checkDumpAgents( + new String[] { "java", "system", null, "tool", "console", "stack", "silent", "jit" }, + dumpEvents, dumpFilters, afterAgents); + assertEquals("Expected to find all the expected agents.", afterAgents.length, foundCount); + } + + // testSetNone - test all dumps with certain options can be disabled + public void testSetNoneByOptions() { + clearDumpOptions(); + String[] dumpTypes = { "java", "system", "heap", "console", "stack", "silent", "jit" }; + String[] dumpEvents = { "systhrow", "uncaught" }; // { "throw", "systhrow", "catch", "uncaught" }; + String[] dumpFilters = { "java/lang/OutOfMemoryError", "java/lang/NullPointerException", "made/up/Exception1", + "made/up/Exception2", "made/up/Exception3", "made/up/Exception4", "made/up/Exception5", + "made/up/Exception6", "made/up/Exception7" }; + + int count = populateDumpAgents(dumpTypes, dumpEvents, dumpFilters); + + String dumpAgents[] = com.ibm.jvm.Dump.queryDumpOptions(); + + assertNotNull("Expected array of dump agents returned, not null", dumpAgents); + assertTrue("Expected " + count + " dump agents configured.", dumpAgents.length == count); + + try { + com.ibm.jvm.Dump.setDumpOptions("java+system+heap+console+stack+silent+jit:none:events=uncaught"); + com.ibm.jvm.Dump.setDumpOptions("java+system+heap+console+stack+silent+jit:none:filter=made/up/Exception3"); + com.ibm.jvm.Dump.setDumpOptions("java+system+heap+console+stack+silent+jit:none:filter=made/up/Exception5"); + } catch (InvalidDumpOptionException e) { + fail("Expected to be able to remove all dump agents by filter"); + } catch (DumpConfigurationUnavailableException e) { + fail("Expected to be able to remove all dump agents by filter. Dump configuration was unavailable."); + } + + String[] afterAgents = com.ibm.jvm.Dump.queryDumpOptions(); + // System.out.println("Found " + afterAgents.length + " agents"); + // for (String agent : afterAgents) { + // System.out.println("After: " + agent); + // } + + // Validate the list of agents. + int foundCount = checkDumpAgents(dumpTypes, + new String[] { "systhrow", null }, + new String[] { + "java/lang/OutOfMemoryError", + "java/lang/NullPointerException", "made/up/Exception1", + "made/up/Exception2", null, "made/up/Exception4", null, + "made/up/Exception6", "made/up/Exception7" }, + afterAgents); + assertEquals("Expected to find all the expected agents.", afterAgents.length, foundCount); + } + + // testSetNone - test all dumps of particular types with certain options can be disabled. + // public void testSetNoneByTypeAndOptions() { + // clearDumpOptions(); + // String[] dumpTypes = {"java", "system", "heap", "console", "stack", "silent", "jit"}; + // String[] dumpEvents = {"systhrow", "uncaught"};//{"throw", "systhrow", "catch", "uncaught"}; + // String[] dumpFilters = {"java/lang/OutOfMemoryError", "java/lang/NullPointerException", "made/up/Exception1", "made/up/Exception2", + // "made/up/Exception3", "made/up/Exception4", "made/up/Exception5", "made/up/Exception6", "made/up/Exception7"}; + // + // int count = populateDumpAgents(dumpTypes, dumpEvents, dumpFilters ); + // + // String dumpAgents[] = com.ibm.jvm.Dump.queryDumpOptions(); + // assertNotNull("Expected array of dump agents returned, not null", dumpAgents); + // assertTrue("Expected " + count + " dump agents configured.", dumpAgents.length == count); + // + // try { + // com.ibm.jvm.Dump.setDumpOptions("console:none:events=systhrow"); + // com.ibm.jvm.Dump.setDumpOptions("console:none:filter=made/up/Exception2"); + // com.ibm.jvm.Dump.setDumpOptions("console:none:filter=made/up/Exception7"); + // } catch (InvalidDumpOptionException e) { + // fail("Expected to be able to remove all dump agents by filter"); + // } + // + // String[] afterAgents = com.ibm.jvm.Dump.queryDumpOptions(); + // System.out.println("Found " + afterAgents.length + " agents"); + // for( String agent: afterAgents ) { + // System.out.println("After: " + agent); + // } + // + // // Validate the list of agents. + // int foundCount = checkDumpAgents(new String[] {"java", "system", "heap", null, "stack", "silent", "jit"}, + // new String[] { null, "uncaught" }, new String[] { + // "java/lang/OutOfMemoryError", + // "java/lang/NullPointerException", "made/up/Exception1", + // null, "made/up/Exception3", "made/up/Exception4", "made/up/Exception5", + // "made/up/Exception6", null }, + // afterAgents); + // assertEquals("Expected to find all the expected agents.", afterAgents.length, foundCount ); + // } + + // testReset - reset, query, clear with -Xdump:none (check cleared), reset again and query to see if we have the original settings + public void testReset() { + // Set the options back to the defaults. + clearDumpOptions(); + + try { + com.ibm.jvm.Dump.resetDumpOptions(); + } catch (DumpConfigurationUnavailableException e) { + fail("Dump configuration was unavailable."); + } + + String originalOptions[] = com.ibm.jvm.Dump.queryDumpOptions(); + + // Check there were some default dump options, we don't really need to + // know what they were just that there were some. + assertTrue("Expected some dump options after reset.", originalOptions.length > 0); + + clearDumpOptions(); // This asserts that the options are empty. + + try { + com.ibm.jvm.Dump.resetDumpOptions(); + } catch (DumpConfigurationUnavailableException e) { + fail("Dump configuration was unavailable."); + } + + String afterResetOptions[] = com.ibm.jvm.Dump.queryDumpOptions(); + + assertEquals("Expected the same number of options setup before and after reset.", + originalOptions.length, afterResetOptions.length); + assertTrue("Expected contents of options to be equal before and after reset.", + Arrays.equals(originalOptions, afterResetOptions)); + } + + // testRoundTrip - reset options, query them, clear with -Xdump:none, pass back original strings to set, query and check we get back what we started with, reset and check again. + public void testRoundTrip() { + // Set the options back to the defaults. + clearDumpOptions(); + + try { + com.ibm.jvm.Dump.resetDumpOptions(); + } catch (DumpConfigurationUnavailableException e) { + fail("Dump configuration was unavailable."); + } + + String originalOptions[] = com.ibm.jvm.Dump.queryDumpOptions(); + + // Check there were some default dump options, we don't really need to + // know what they were just that there were some. + assertTrue("Expected some dump options after reset.", originalOptions.length > 0); + + clearDumpOptions(); // This asserts that the options are empty. + + // Reset the options by resubmitting the result of queryDumpOptions + for (String agent : originalOptions) { + try { + com.ibm.jvm.Dump.setDumpOptions(agent); + } catch (InvalidDumpOptionException e) { + fail("Expected to be able to set dump options to the strings returned by query dump options."); + } catch (DumpConfigurationUnavailableException e) { + fail("Dump configuration was unavailable."); + } + } + + String afterResetOptions[] = com.ibm.jvm.Dump.queryDumpOptions(); + + assertEquals("Expected the same number of options setup before and after reset.", + originalOptions.length, afterResetOptions.length); + assertTrue("Expected contents of options to be equal before and after reset.", + Arrays.equals(originalOptions, afterResetOptions)); + } + + // testSet - set up a dump to trigger on some event, cause the event and check we have a dump + // testSetToolDump - confirm tool dumps are blocked, in several ways. + // public void testSetToolDump() { + // clearDumpOptions(); + // + // String toolAgents[] = {"tool", "tool:events=gpf", "java+tool", "tool+java", "java+tool+heap", + // "tool+java:events=gpf", "java+tool:events=systhrow", "java+tool+heap:events=traceassert", + // " tool", "\ntool", "TOOL"}; + // + // for( String agent: toolAgents ) { + // try { + // com.ibm.jvm.Dump.setDumpOptions(agent); + // fail("Did not expect to be able to set a tool dump agent, found: " + Arrays.toString(com.ibm.jvm.Dump.queryDumpOptions())); + // } catch (InvalidDumpOptionException e) { + // // Pass. + // // Check exception message. + // } + // // Check we didn't set things anyway. + // String newOptions[] = com.ibm.jvm.Dump.queryDumpOptions(); + // assertTrue("Expected no options to be set.", newOptions.length == 0); + // } + // } + + // testSetBadOptions - pass in garbage options. + public void testSetBadOptions() { + clearDumpOptions(); + + String badAgents[] = { + // "", // Empty String + "hippo", // Bad dump type + "java+hippo", // Bad second dump type + "java:hippo=gpf", // Bad dump option + "java:events=gpf,request=hippo", // Bad sub option + "java:events=gpf\nheap:events=systhrow", // Bad specification of two dumps + "java:events=hippo", // Bad event + "java:request=hippo", // Bad request + "java:priority=hippo", // Bad priority, should be a number + "defaults", // Setting defaults, not valid? + // "java:defaults:priority=500", // Setting defaults, not valid? + "help", // Not valid at runtime + "events", // Not valid at runtime + "request", // Not valid at runtime + "tokens", // Not valid at runtime + "nofailover", // Not valid at runtime - possibly should be! + +// Not valid, but not parsed yet. "java:events=vmstop,filter=hippo", // Bad filter (vmstop takes a number) +// Not valid, not handled right. + "java:events=throw,filter=not/a/real/Exception", // Bad option, uses event that needs -Xdump:dynamic on the command line + "java:events=vmstart+throw,filter=not/a/real/Exception" // Bad option, uses event that needs -Xdump:dynamic on the command line + +// Valid "java:events=gpf,options=CLASSIC+PHD", // Options belonging to another dump type. +// Valid "heap+java:events=gpf,opts=CLASSIC+PHD", // Options belonging to only one dump type. + }; + + try { + // System.err.println("Trying: null"); + com.ibm.jvm.Dump.setDumpOptions(null); + fail("Did not expect to be able to set a bad dump agent, found: " + + Arrays.toString(com.ibm.jvm.Dump.queryDumpOptions())); + } catch (NullPointerException e) { + // Pass. + // Check exception message. + } catch (InvalidDumpOptionException e) { + fail("Expected a null pointer exception"); + } catch (DumpConfigurationUnavailableException e) { + fail("Dump configuration was unavailable."); + } + + for (String agent : badAgents) { + try { + // System.err.println("Trying: " + agent); + com.ibm.jvm.Dump.setDumpOptions(agent); + com.ibm.jvm.Dump.setDumpOptions("what"); // We should not reach this so the output will be useful for debugging if we do. + fail("Did not expect to be able to set a bad dump option: " + agent + ", queryDumpOptions() found: " + + Arrays.toString(com.ibm.jvm.Dump.queryDumpOptions())); + } catch (InvalidDumpOptionException e) { + // Pass. + // Check exception message. + } catch (DumpConfigurationUnavailableException e) { + fail("Dump configuration was unavailable."); + } + // Check we didn't set things anyway. + String newOptions[] = com.ibm.jvm.Dump.queryDumpOptions(); + if (newOptions.length > 0) { + // System.err.println(Arrays.toString(newOptions)); + try { + com.ibm.jvm.Dump.setDumpOptions("what"); + } catch (InvalidDumpOptionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (DumpConfigurationUnavailableException e) { + fail("Dump configuration was unavailable."); + } + } + assertEquals("Expected no options to be set for agent string - " + agent, 0, newOptions.length); + } + } + + // testSetDynamic - I don't think this should work at runtime. + public void testSetDynamic() { + try { + com.ibm.jvm.Dump.setDumpOptions("dynamic"); + fail("Did not expect to be able to set -Xdump:dynamic at runtime."); + } catch (InvalidDumpOptionException e) { + // Pass. + // Check exception message. + } catch (DumpConfigurationUnavailableException e) { + fail("Dump configuration was unavailable."); + } + } + + // testSetNullOptions - I don't think this should work at runtime. + public void testSetNullOptions() { + try { + com.ibm.jvm.Dump.setDumpOptions(null); + fail("Did not expect to be able to do setDumpOptions(null)"); + } catch (NullPointerException e) { + // Pass. + } catch (InvalidDumpOptionException e) { + fail("Expected NPE to be thrown not InvalidDumpOptionException"); + } catch (DumpConfigurationUnavailableException e) { + fail("Dump configuration was unavailable."); + } + } + + // testSetDynamicOnly - This shouldn't work at runtime unless -Xdynamic was specified at startup. + public void testSetDynamicOnlyOptions() { + clearDumpOptions(); + + String[] dumpTypes = { "java", "system", "heap", "console", "stack", "silent", "jit" }; + String[] dumpEvents = { "catch", "throw", "vmstart" }; // vmstart is not fixed with -Xdump:dynamic but it can't be set at runtime. + String[] dumpFilters = { "java/lang/OutOfMemoryError", "java/lang/NullPointerException", "made/up/Exception1", + "made/up/Exception2", "made/up/Exception3", "made/up/Exception4", "made/up/Exception5", + "made/up/Exception6", "made/up/Exception7" }; + + // None of these should work since uncaught and throw cannot be set at runtime unless -Xdump:dynamic was on the + // command line. + int count = 0; + for (String type : dumpTypes) { + for (String event : dumpEvents) { + for (String filter : dumpFilters) { + // Create agents the dump system can't merge. + String options = type + ":events=" + event + ",filter=" + filter + ",label=" + type + count++; + try { + com.ibm.jvm.Dump.setDumpOptions(options); + fail("Expected not to be ablel to set these dump options: " + options); + } catch (InvalidDumpOptionException e) { + // TODO Auto-generated catch block + } catch (DumpConfigurationUnavailableException e) { + fail("Dump configuration was unavailable."); + } + } + } + } + + String dumpAgents[] = com.ibm.jvm.Dump.queryDumpOptions(); + + assertNotNull("Expected array of dump agents returned, not null", dumpAgents); + assertEquals("Expected 0 dump agents configured found " + dumpAgents.length, 0, dumpAgents.length); + + // Can probably have one function to validate two list of options match and re-use in lots of places. + + int foundCount = checkDumpAgents(dumpTypes, dumpEvents, dumpFilters, dumpAgents); + + assertEquals("Expected to find all the expected agents.", dumpAgents.length, foundCount); + + clearDumpOptions(); + } + + /** + * Set the default options. + */ + public void testSetDefaults() { + // Set the options back to the defaults. + clearDumpOptions(); // This asserts that the options are empty. + + try { + com.ibm.jvm.Dump.setDumpOptions("java:defaults:opts=HIPPO"); + com.ibm.jvm.Dump.setDumpOptions("java"); + } catch (DumpConfigurationUnavailableException e) { + fail("Dump configuration was unavailable."); + } catch (InvalidDumpOptionException e) { + fail("Expected setting the defaults to be a valid option."); + } + + String afterDefaultsSetOptions[] = com.ibm.jvm.Dump.queryDumpOptions(); + + assertEquals("Expected only one option to be setup.", 1, afterDefaultsSetOptions.length); + + String option = afterDefaultsSetOptions[0]; + + assertTrue("Expected the option string to contain opts=HIPPO and java:", + option.startsWith("java:") && option.contains("opts=HIPPO")); + } + + /** + * Set the default options and check that setting them hasn't affected + * the options we return to after reset. + */ + public void testSetDefaultsAndReset() { + // Set the options back to the defaults. + clearDumpOptions(); + + try { + com.ibm.jvm.Dump.resetDumpOptions(); + } catch (DumpConfigurationUnavailableException e) { + fail("Dump configuration was unavailable."); + } + + String originalOptions[] = com.ibm.jvm.Dump.queryDumpOptions(); + + // Check there were some default dump options, we don't really need to + // know what they were just that there were some. + assertTrue("Expected some dump options after reset.", originalOptions.length > 0); + + clearDumpOptions(); // This asserts that the options are empty. + + try { + com.ibm.jvm.Dump.setDumpOptions("java:defaults:opts=HIPPO"); + com.ibm.jvm.Dump.setDumpOptions("java"); + } catch (DumpConfigurationUnavailableException e) { + fail("Dump configuration was unavailable."); + } catch (InvalidDumpOptionException e) { + fail("Expected setting the defaults to be a valid option."); + } + + String afterDefaultsSetOptions[] = com.ibm.jvm.Dump.queryDumpOptions(); + + assertEquals("Expected only one option to be setup.", 1, afterDefaultsSetOptions.length); + + String option = afterDefaultsSetOptions[0]; + + assertTrue("Expected the option string to contain opts=HIPPO and java:", + option.startsWith("java:") && option.contains("opts=HIPPO")); + + /* Now check reseting takes us back where it should do. */ + try { + com.ibm.jvm.Dump.resetDumpOptions(); + } catch (DumpConfigurationUnavailableException e) { + fail("Dump configuration was unavailable."); + } + + String afterResetOptions[] = com.ibm.jvm.Dump.queryDumpOptions(); + + assertEquals("Expected the same number of options setup before and after reset.", + originalOptions.length, afterResetOptions.length); + assertTrue("Expected contents of options to be equal before and after reset.", + Arrays.equals(originalOptions, afterResetOptions)); + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/DumpAPISecurityTests.java b/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/DumpAPISecurityTests.java new file mode 100644 index 00000000000..c12bf1669a2 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/DumpAPISecurityTests.java @@ -0,0 +1,627 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.jvm.ras.tests; + +import static com.ibm.jvm.ras.tests.DumpAPISuite.deleteFile; +import static com.ibm.jvm.ras.tests.DumpAPISuite.getFilesByPattern; +import static com.ibm.jvm.ras.tests.DumpAPISuite.isZOS; + +import static java.lang.Boolean.TRUE; +import static java.lang.Boolean.FALSE; + +import java.io.File; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import junit.framework.TestCase; + +import com.ibm.jvm.InvalidDumpOptionException; + + +/** + * Tests of the dump API performed with a security manager set + * to block creation of files. + * + * No security manager is the default mode and covered by + * DumpAPIBasicTests + * + * *** Security is enabled by the ant script that normally runs these tests *** + * + * @author hhellyer + * + */ +public class DumpAPISecurityTests extends TestCase { + + private long uid = System.currentTimeMillis(); + + // Record the files created by each testcase here so we can delete them + // later. Otherwise we will fill the disk up pretty quickly. While we check + // that the right kind of dump was created for each call we do any further + // validity checking on the dumps themselves. This test is just checking the + // API does what it should not that the dumps themselves are correct. + private Set fileNames; + + @Override + protected void setUp() throws Exception { + + uid = System.currentTimeMillis(); + + super.setUp(); + + fileNames = new HashSet(); + + // This isn't to free space, it's to trigger GC tracepoints so we don't get empty snap dumps! + System.gc(); + + // Make sure this is off for the start of every test. + System.clearProperty("com.ibm.jvm.enableLegacyDumpSecurity"); + // And for the Trace.snap() tests. + System.clearProperty("com.ibm.jvm.enableLegacyTraceSecurity"); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + for( String fileName: fileNames) { + deleteFile(fileName, this.getName()); + } + } + + private void addNewFilesToDelete(String[] beforeFileNames, String[] afterFileNames) { + for( String after : afterFileNames ) { + boolean newFile = true; + for( String before : beforeFileNames ) { + if( before.equals(after) ) { + newFile = false; + break; + } + } + if( newFile ) { + fileNames.add(after); + } + } + } + + /** + * Test a java dump is generated from the standard com.ibm.jvm.Dump.JavaDump() + * call. + */ + public void testJavaDumpNoArgs() { + String userDir = System.getProperty("user.dir"); + String javaCorePattern = "javacore\\..*\\.txt"; + + System.setProperty("com.ibm.jvm.enableLegacyDumpSecurity", FALSE.toString()); + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, javaCorePattern); + int beforeCount = beforeFileNames.length; + + com.ibm.jvm.Dump.JavaDump(); + + String[] afterFileNames = getFilesByPattern(userDir, javaCorePattern); + + addNewFilesToDelete(beforeFileNames, afterFileNames); + + int afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount + 1, afterCount); + } + + /** + * Test a java dump is generated from the standard com.ibm.jvm.Dump.JavaDump() + * but not if the security permission should be listened to. + */ + public void testJavaDumpNoArgsBlocked() { + String userDir = System.getProperty("user.dir"); + String javaCorePattern = "javacore\\..*\\.txt"; + + System.clearProperty("com.ibm.jvm.enableLegacyDumpSecurity"); + + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, javaCorePattern); + int beforeCount = beforeFileNames.length; + + try { + com.ibm.jvm.Dump.JavaDump(); + fail("Expected security exception to be thrown."); + } catch (SecurityException e) { + //Pass + } + + String[] afterFileNames = getFilesByPattern(userDir, javaCorePattern); + + addNewFilesToDelete(beforeFileNames, afterFileNames); + + int afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount, afterCount); + + System.setProperty("com.ibm.jvm.enableLegacyDumpSecurity", FALSE.toString()); + + com.ibm.jvm.Dump.JavaDump(); + + afterFileNames = getFilesByPattern(userDir, javaCorePattern); + + addNewFilesToDelete(beforeFileNames, afterFileNames); + + afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount + 1, afterCount); + + } + + public void testJavaDumpWithFile() { + String userDir = System.getProperty("user.dir"); + + String expectedName = userDir + File.separator + "javacore."+ getName() + "." + uid + ".txt"; + + // Check the file doesn't exist, otherwise the dump code moves it. + File expectedFile = new File(expectedName); + assertFalse("The javacore file " + expectedName + " already exists", expectedFile.exists()); + + // Check we got the correct name. + try { + String javacoreName = com.ibm.jvm.Dump.javaDumpToFile(expectedName); + fail("Expected security exception to be thrown."); + } catch (SecurityException e ) { + // This is the success path! + } catch (InvalidDumpOptionException e) { + fail("Expected security exception to be thrown not InvalidDumpOptionException."); + } + } + + /** + * Test a java dump is generated from the standard com.ibm.jvm.Dump.JavaDump() + * call. + */ + public void testJavaDumpNullFile() { + String userDir = System.getProperty("user.dir"); + String javaCorePattern = "javacore\\..*\\.txt"; + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, javaCorePattern); + int beforeCount = beforeFileNames.length; + + String javacoreName = null; + try { + javacoreName = com.ibm.jvm.Dump.javaDumpToFile(null); + fail("Expected security exception to be thrown."); + } catch (SecurityException e ) { + // This is the success path! + } catch (InvalidDumpOptionException e) { + fail("Expected security exception to be thrown not InvalidDumpOptionException."); + } + } + + /** + * Test a heap dump is generated from the standard com.ibm.jvm.Dump.HeapDump() + * call. + */ + public void testHeapDumpNoArgs() { + String userDir = System.getProperty("user.dir"); + String heapdumpPattern = "heapdump\\..*\\.phd"; + + System.setProperty("com.ibm.jvm.enableLegacyDumpSecurity", FALSE.toString()); + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, heapdumpPattern); + int beforeCount = beforeFileNames.length; + + com.ibm.jvm.Dump.HeapDump(); + + String[] afterFileNames = getFilesByPattern(userDir, heapdumpPattern); + + addNewFilesToDelete(beforeFileNames, afterFileNames); + + int afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount + 1, afterCount); + } + + public void testHeapDumpNoArgsBlocked() { + String userDir = System.getProperty("user.dir"); + String heapdumpPattern = "heapdump\\..*\\.phd"; + + System.clearProperty("com.ibm.jvm.enableLegacyDumpSecurity"); + + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, heapdumpPattern); + int beforeCount = beforeFileNames.length; + + try { + com.ibm.jvm.Dump.HeapDump(); + fail("Expected security exception to be thrown."); + } catch (SecurityException e) { + //Pass + } + + String[] afterFileNames = getFilesByPattern(userDir, heapdumpPattern); + + addNewFilesToDelete(beforeFileNames, afterFileNames); + + int afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount, afterCount); + + System.setProperty("com.ibm.jvm.enableLegacyDumpSecurity", FALSE.toString()); + + com.ibm.jvm.Dump.HeapDump(); + + afterFileNames = getFilesByPattern(userDir, heapdumpPattern); + + addNewFilesToDelete(beforeFileNames, afterFileNames); + + afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount + 1, afterCount); + + } + + public void testHeapDumpWithFile() { + String userDir = System.getProperty("user.dir"); + + String expectedName = userDir + File.separator + "heapdump."+ getName() + "." + uid + ".txt"; + + // Check the file doesn't exist, otherwise the dump code moves it. + File expectedFile = new File(expectedName); + assertFalse("The heapdump file " + expectedName + " already exists", expectedFile.exists()); + + // Check we got the correct name. + try { + String heapdumpName = com.ibm.jvm.Dump.heapDumpToFile(expectedName); + fail("Expected security exception to be thrown."); + } catch (SecurityException e ) { + // This is the success path! + } catch (InvalidDumpOptionException e) { + fail("Expected security exception to be thrown not InvalidDumpOptionException."); + } + } + + /** + * Test a java dump is generated from the standard com.ibm.jvm.Dump.JavaDump() + * call. + */ + public void testHeapDumpNullFile() { + String userDir = System.getProperty("user.dir"); + String heapdumpPattern = "heapdump\\..*\\.phd"; + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, heapdumpPattern); + int beforeCount = beforeFileNames.length; + + String heapdumpName = null; + try { + heapdumpName = com.ibm.jvm.Dump.heapDumpToFile(null); + fail("Expected security exception to be thrown."); + } catch (SecurityException e ) { + // This is the success path! + } catch (InvalidDumpOptionException e) { + fail("Expected security exception to be thrown not InvalidDumpOptionException."); + } + } + + /** + * Test a heap dump is generated from the standard com.ibm.jvm.Dump.HeapDump() + * call. + */ + public void testSnapDumpNoArgs() { + String userDir = System.getProperty("user.dir"); + String snapPattern = "Snap\\..*\\.trc"; + + System.setProperty("com.ibm.jvm.enableLegacyDumpSecurity", FALSE.toString()); + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, snapPattern); + int beforeCount = beforeFileNames.length; + + com.ibm.jvm.Dump.SnapDump(); + + String[] afterFileNames = getFilesByPattern(userDir, snapPattern); + + addNewFilesToDelete(beforeFileNames, afterFileNames); + + int afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount + 1, afterCount); + } + + public void testSnapDumpNoArgsBlocked() { + String userDir = System.getProperty("user.dir"); + String snapPattern = "Snap\\..*\\.trc"; + + System.clearProperty("com.ibm.jvm.enableLegacyDumpSecurity"); + + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, snapPattern); + int beforeCount = beforeFileNames.length; + + try { + com.ibm.jvm.Dump.SnapDump(); + fail("Expected security exception to be thrown."); + } catch (SecurityException e) { + //Pass + } + + String[] afterFileNames = getFilesByPattern(userDir, snapPattern); + + addNewFilesToDelete(beforeFileNames, afterFileNames); + + int afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount, afterCount); + + System.setProperty("com.ibm.jvm.enableLegacyDumpSecurity", FALSE.toString()); + + com.ibm.jvm.Dump.SnapDump(); + + afterFileNames = getFilesByPattern(userDir, snapPattern); + + addNewFilesToDelete(beforeFileNames, afterFileNames); + + afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount + 1, afterCount); + + } + + /** + * Test a snap dump is generated from the standard com.ibm.jvm.Trace.snap() + * call. + * Done here rather than in the trace tests as this code knows how to delete + * a snap dump. + */ + public void testTraceAPISnapDumpNoArgs() { + String userDir = System.getProperty("user.dir"); + String snapPattern = "Snap\\..*\\.trc"; + + System.setProperty("com.ibm.jvm.enableLegacyTraceSecurity", FALSE.toString()); + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, snapPattern); + int beforeCount = beforeFileNames.length; + + com.ibm.jvm.Trace.snap(); + + String[] afterFileNames = getFilesByPattern(userDir, snapPattern); + + addNewFilesToDelete(beforeFileNames, afterFileNames); + + int afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount + 1, afterCount); + } + + /** + * Test a snap dump is blocked from the standard com.ibm.jvm.Trace.snap() + * call. + * Done here rather than in the trace tests as this code knows how to delete + * a snap dump. + */ + public void testTraceAPISnapDumpNoArgsBlocked() { + String userDir = System.getProperty("user.dir"); + String snapPattern = "Snap\\..*\\.trc"; + + System.clearProperty("com.ibm.jvm.enableLegacyTraceSecurity"); + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, snapPattern); + int beforeCount = beforeFileNames.length; + + try { + com.ibm.jvm.Trace.snap(); + fail("Expected security exception to be thrown."); + } catch (SecurityException e) { + //Pass + } + + String[] afterFileNames = getFilesByPattern(userDir, snapPattern); + + addNewFilesToDelete(beforeFileNames, afterFileNames); + + int afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount, afterCount); + + System.setProperty("com.ibm.jvm.enableLegacyDumpSecurity", FALSE.toString()); + + com.ibm.jvm.Dump.SnapDump(); + + afterFileNames = getFilesByPattern(userDir, snapPattern); + + addNewFilesToDelete(beforeFileNames, afterFileNames); + + afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount + 1, afterCount); + + } + + public void testSnapDumpWithFile() { + String userDir = System.getProperty("user.dir"); + + String expectedName = userDir + File.separator + "snap."+ getName() + "." + uid + ".trc"; + + // Check the file doesn't exist, otherwise the dump code moves it. + File expectedFile = new File(expectedName); + assertFalse("The snap file " + expectedName + " already exists", expectedFile.exists()); + + // Check we got the correct name. + try { + String snapName = com.ibm.jvm.Dump.snapDumpToFile(expectedName); + fail("Expected security exception to be thrown."); + } catch (SecurityException e ) { + // This is the success path! + } catch (InvalidDumpOptionException e) { + fail("Expected security exception to be thrown not InvalidDumpOptionException."); + } + } + + /** + * Test a java dump is generated from the standard com.ibm.jvm.Dump.JavaDump() + * call. + */ + public void testSnapDumpNullFile() { + String userDir = System.getProperty("user.dir"); + String snapPattern = "Snap\\..*\\.trc"; + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, snapPattern); + int beforeCount = beforeFileNames.length; + + String snapName = null; + try { + snapName = com.ibm.jvm.Dump.snapDumpToFile(null); + fail("Expected security exception to be thrown."); + } catch (SecurityException e ) { + // This is the success path! + } catch (InvalidDumpOptionException e) { + fail("Expected security exception to be thrown not InvalidDumpOptionException."); + } + } + + /** + * Test a system dump is generated from the standard com.ibm.jvm.Dump.SystemDump() + * call. + */ + public void testSystemDumpNoArgs() { + if( isZOS() ) { + System.err.printf("Skipping %s, z/OS system dumps currently inaccessable in Java 8, see CMVC 193090\n", this.getName()); + return; + } + System.setProperty("com.ibm.jvm.enableLegacyDumpSecurity", FALSE.toString()); + + String userDir = System.getProperty("user.dir"); + String corePattern = "core\\..*\\.dmp"; + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, corePattern); + int beforeCount = beforeFileNames.length; + + com.ibm.jvm.Dump.SystemDump(); + + String[] afterFileNames = getFilesByPattern(userDir, corePattern); + + addNewFilesToDelete(beforeFileNames, afterFileNames); + + int afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount + 1, afterCount); + } + + public void testSystemDumpNoArgsBlocked() { + if( isZOS() ) { + System.err.printf("Skipping %s, z/OS system dumps currently inaccessable in Java 8, see CMVC 193090\n", this.getName()); + return; + } + + String userDir = System.getProperty("user.dir"); + String corePattern = "core\\..*\\.dmp"; + + System.clearProperty("com.ibm.jvm.enableLegacyDumpSecurity"); + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, corePattern); + int beforeCount = beforeFileNames.length; + + try { + com.ibm.jvm.Dump.SystemDump(); + fail("Expected security exception to be thrown."); + } catch (SecurityException e) { + //Pass + } + + String[] afterFileNames = getFilesByPattern(userDir, corePattern); + + addNewFilesToDelete(beforeFileNames, afterFileNames); + + int afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount, afterCount); + + System.setProperty("com.ibm.jvm.enableLegacyDumpSecurity", FALSE.toString()); + + com.ibm.jvm.Dump.SystemDump(); + + afterFileNames = getFilesByPattern(userDir, corePattern); + + addNewFilesToDelete(beforeFileNames, afterFileNames); + + afterCount = afterFileNames.length; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount + 1, afterCount); + + } + + public void testSystemDumpWithFile() { + if( isZOS() ) { + System.err.printf("Skipping %s, z/OS system dumps currently inaccessable in Java 8, see CMVC 193090\n", this.getName()); + return; + } + + String userDir = System.getProperty("user.dir"); + + String expectedName = userDir + File.separator + "core."+ getName() + "." + uid + ".dmp"; + + // Check the file doesn't exist, otherwise the dump code moves it. + File expectedFile = new File(expectedName); + assertFalse("The core file " + expectedName + " already exists", expectedFile.exists()); + + // Check we got the correct name. + try { + String coreName = com.ibm.jvm.Dump.systemDumpToFile(expectedName); + fail("Expected security exception to be thrown."); + } catch (SecurityException e ) { + // This is the success path! + } catch (InvalidDumpOptionException e) { + fail("Expected security exception to be thrown not InvalidDumpOptionException."); + } + } + + /** + * Test a java dump is generated from the standard com.ibm.jvm.Dump.JavaDump() + * call. + */ + public void testSystemDumpNullFile() { + if( isZOS() ) { + System.err.printf("Skipping %s, z/OS system dumps currently inaccessable in Java 8, see CMVC 193090\n", this.getName()); + return; + } + + String userDir = System.getProperty("user.dir"); + String corePattern = "core\\..*\\.dmp"; + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, corePattern); + int beforeCount = beforeFileNames.length; + + String coreName = null; + try { + coreName = com.ibm.jvm.Dump.systemDumpToFile(null); + fail("Expected security exception to be thrown."); + } catch (SecurityException e ) { + // This is the success path! + } catch (InvalidDumpOptionException e) { + fail("Expected security exception to be thrown not InvalidDumpOptionException."); + } + } + + public void testTriggerToolDump() { + try { + // The default options for tool dump may be invalid but we don't expect the dump + // to actually run. + com.ibm.jvm.Dump.triggerDump("tool"); + fail("Expected security exception to be thrown."); + } catch (SecurityException e ) { + // This is the success path! + } catch (InvalidDumpOptionException e) { + fail("Expected security exception to be thrown not InvalidDumpOptionException."); + } + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/DumpAPISetTestXdumpdynamic.java b/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/DumpAPISetTestXdumpdynamic.java new file mode 100644 index 00000000000..d9a5d6ba365 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/DumpAPISetTestXdumpdynamic.java @@ -0,0 +1,137 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.jvm.ras.tests; + +import java.util.Arrays; +import java.io.*; + +import junit.framework.TestCase; + +import com.ibm.jvm.DumpConfigurationUnavailableException; +import com.ibm.jvm.InvalidDumpOptionException; +import static com.ibm.jvm.ras.tests.DumpAPISuite.getFilesByPattern; +import static com.ibm.jvm.ras.tests.DumpAPISuite.deleteFile; + +public class DumpAPISetTestXdumpdynamic extends TestCase { + + private short MSG_FILTER_DUMP_COUNT = 2; + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + // TODO Auto-generated method stub + super.tearDown(); + } + + private void clearDumpOptions() { + String initialDumpOptions[] = com.ibm.jvm.Dump.queryDumpOptions(); + try { + com.ibm.jvm.Dump.setDumpOptions("none"); + } catch (InvalidDumpOptionException idoe ) { + idoe.printStackTrace(); + } catch (NullPointerException e) { + e.printStackTrace(); + } catch (DumpConfigurationUnavailableException e) { + e.printStackTrace(); + } + String afterNoneOptions[] = com.ibm.jvm.Dump.queryDumpOptions(); + + assertTrue("Expected an empty array of dump options but got: " + Arrays.toString(afterNoneOptions), afterNoneOptions.length == 0); + + } + + // This shouldn't work at runtime unless -Xdynamic was specified at startup. + public void testSetDynamicOnlyOptions() { + clearDumpOptions(); + String[] dumpTypes = {"java"}; + String[] dumpEvents = {"catch", "throw", "uncaught", "systhrow"}; + String[] dumpFilters = {"java/lang/OutOfMemoryError", "java/net/SocketException", "java/io/FileNotFoundException"}; + String[] dumpMsgFilters = {"*JavaFVTTest*", "*JTC*"}; + + int count = 0; + for(String type: dumpTypes) { + for(String event: dumpEvents ) { + for(String filter: dumpFilters ) { + for(String msgFilter: dumpMsgFilters ) { + String options = type + ":events=" + event +",filter=" + filter + ",msg_filter=" + msgFilter+ ",label=" + type + count++; + try { + com.ibm.jvm.Dump.setDumpOptions(options); + } catch (InvalidDumpOptionException e) { + fail("Expected to be able to set these dump options: " + options); + } catch (DumpConfigurationUnavailableException e) { + fail("Dump configuration was unavailable."); + } + } + } + } + } + + String dumpAgents[] = com.ibm.jvm.Dump.queryDumpOptions(); + assertNotNull("Expected array of dump agents returned, not null", dumpAgents); + int noOfAgentsInstalled = dumpTypes.length * dumpEvents.length * dumpFilters.length * dumpMsgFilters.length; + assertEquals("Expected " + noOfAgentsInstalled + " dump agents configured found " + dumpAgents.length, noOfAgentsInstalled , dumpAgents.length); + + /* Throws FileNotFoundException & Expects dumps from installed agents*/ + String userDir = System.getProperty("user.dir"); + String dumpFilePattern = "java[0-9]+"; + /* Count the number of files before and after. Should increase by 2. */ + String[] beforeFileNames = getFilesByPattern(userDir, dumpFilePattern); + int beforeCount = beforeFileNames.length; + try { + FileInputStream fin = new FileInputStream("HelloJavaFVTTest.java"); + fail("Expected FileNotFoundException"); + } catch (FileNotFoundException fe) { + String[] afterFileNames = getFilesByPattern(userDir, dumpFilePattern); + int afterCount = afterFileNames.length; + int i = 0; + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount + MSG_FILTER_DUMP_COUNT, afterCount); + + /* delete the dump files */ + if (afterCount > MSG_FILTER_DUMP_COUNT) { + int j = 0; + for (i = 0; i < afterCount; i++) { + for (String bfnames: beforeFileNames) { + if (bfnames.equals(afterFileNames[i])) { + afterFileNames[i] = null; + break; + } + } + if(afterFileNames[i] != null) { + afterFileNames[j++] = afterFileNames[i]; + } + if(j == 2) { + break; + } + } + } + if (afterCount > 0) { + deleteFile(afterFileNames[0], this.getName()); + deleteFile(afterFileNames[1], this.getName()); + } + } + clearDumpOptions(); + } + +} \ No newline at end of file diff --git a/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/DumpAPISuite.java b/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/DumpAPISuite.java new file mode 100644 index 00000000000..ead331a3d73 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/DumpAPISuite.java @@ -0,0 +1,227 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.jvm.ras.tests; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.UnsupportedEncodingException; + +import com.ibm.dtfj.image.Image; +import com.ibm.dtfj.image.ImageFactory; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class DumpAPISuite { + + public static enum DumpType { + SNAP_TYPE("snap"), + CONSOLE_TYPE("console"), + JAVA_TYPE("java"), + STACK_TYPE("stack"), + PHD_HEAP_TYPE("phd"), + CLASSIC_HEAP_TYPE("classic"), + SYSTEM_TYPE("system"), + FILE_NOT_FOUND(""), + READ_ERROR(""), + UNKNOWN(""); + + public final String name; + + private DumpType(String name) { + this.name = name; + } + + } + + /* Common constants */ + public static final String DUMP_TOOL_TYPE_ERR = "Tool dumps cannot be triggered via com.ibm.jvm.Dump API"; + public static final String DUMP_ERROR_PARSING = "Error in dump options."; + public static final String DUMP_UNKNOWN_TYPE = "Error parsing dump options. Unknown dump type specified."; + public static final String DUMP_COULD_NOT_CREATE_FILE = DUMP_ERROR_PARSING; + public static final String DUMP_INVALID_OPTION = "Invalid dump option specified."; + + /** + * This runs all the tests as a single suite. + * @return + */ + public static Test suite() { + TestSuite suite = new TestSuite(DumpAPISuite.class.getName()); + //$JUnit-BEGIN$ + suite.addTestSuite(DumpAPIBasicTests.class); + suite.addTestSuite(DumpAPITriggerTests.class); + suite.addTestSuite(DumpAPIQuerySetReset.class); + suite.addTestSuite(DumpAPITokensTests.class); + suite.addTestSuite(DumpAPISetTestXdumpdynamic.class); + //$JUnit-END$ + return suite; + } + + // Deletes the named file, or prints an error message if it + // can't find it. On z/OS will check that a file doesn't exist + // in a dataset as well as on HFS. (Will check both for all files + // in case it has been copied onto HFS and exists in both locations.) + public static void deleteFile(String fileName, String testName) { + File toDelete = new File(fileName); + if( toDelete.exists() ) { + if(!toDelete.delete()) { + System.err.printf("Unable to delete file %s for test case %s will try to delete on exit.\n", fileName, testName); + toDelete.deleteOnExit(); + } else { + //System.err.printf("Deleted file %s for test case %s\n", fileName, this.getName()); + } + + } else { + System.err.printf("Unable to find file %s to delete for test case %s\n", fileName, testName); + } + } + + /* Some common functions for the whole suite. */ + public static String[] getFilesByPattern(String dirName, final String pattern) { + File dir = new File(dirName); + + FilenameFilter filter = new FilenameFilter() { + public boolean accept(File dir, String name) { + if( name.matches(pattern) ) { + return true; + } + return false; + } + }; + String[] fileNames = dir.list(filter); + return fileNames; + } + + public static boolean isZOS() { + return "z/OS".equals(System.getProperty("os.name") ); + } + + /** + * Return the dump file type for the given file parameter. + * @param dumpFile + * @return a constant string representing the dump type. + */ + public static DumpType getContentType(File dumpFile) { + // Hopefully we can usually do this by reading the first + // few bytes. + FileInputStream fileIn = null; + final byte[] portable_heap_dump; + try { + portable_heap_dump = "portable heap dump".getBytes("US-ASCII"); + } catch (UnsupportedEncodingException e1) { + // US-ASCII really should be supported. + return DumpType.UNKNOWN; + } + + try { + // Grab the first few bytes. + fileIn = new FileInputStream(dumpFile); + byte firstBytes[] = new byte[64]; + int length = fileIn.read(firstBytes); + + // Try various things we know will identify the different file types. + String initialString = new String(firstBytes); + if( (new String(firstBytes, "US-ASCII")).startsWith("UTTH") ) { + // Trace file header, trace file is binary UTTH will be in ASCII. + return DumpType.SNAP_TYPE; + } else if( initialString.startsWith("Thread=") ) { + // This is a console or stack dump, it depends how many threads! + StringBuffer contents = new StringBuffer((int)dumpFile.length()); + contents.append(initialString); + byte[] buffer = new byte[1024]; + int read = fileIn.read(buffer); + while( read > -1 ) { + contents.append(new String(buffer,0, read)); + read = fileIn.read(buffer); + } + String[] threads = contents.toString().split("Thread="); + + // We get an initial emptry array so we will have two + // elements for STACK and more for CONSOLE. + // (It is safe to assume the VM is running more than one thread.) + if( threads.length == 2) { + return DumpType.STACK_TYPE; + } else if (threads.length > 2) { + return DumpType.CONSOLE_TYPE; + } + } else if( initialString.startsWith("0SECTION TITLE")) { + return DumpType.JAVA_TYPE; + } else if( initialString.startsWith("// Version: ")) { + return DumpType.CLASSIC_HEAP_TYPE; + } + // Do the phd check by reading the first few bytes. + boolean phd = false; + for( int i = 2; i < length && i-2 < portable_heap_dump.length; i++ ) { + if( firstBytes[i] != portable_heap_dump[i-2] ) { + phd = false; + break; + } else { + phd = true; + } + } + if( phd ) { + return DumpType.PHD_HEAP_TYPE; + } + + // Check for core dump. This needs to be last as the core readers can also + // open java dumps and heap dumps. + Image image = null; + try { + Class factoryClass = Class.forName("com.ibm.dtfj.image.j9.ImageFactory"); + ImageFactory factory = (ImageFactory) factoryClass.newInstance(); + image = factory.getImage(dumpFile); + if( image != null ) { + image.close(); + return DumpType.SYSTEM_TYPE; + } + } catch (ClassNotFoundException e) { + } catch (IllegalAccessException e) { + } catch (InstantiationException e) { + } finally { + if( image != null ) { + image.close(); + } + } + + + } catch (FileNotFoundException e) { + // FILE_NOT_FOUND is expected for some tests. + return DumpType.FILE_NOT_FOUND; + } catch (IOException e) { + return DumpType.READ_ERROR; + } finally { + if( fileIn != null ) { + try { + fileIn.close(); + } catch (IOException e) { + // Not able to fix this! + } + } + } + + return DumpType.UNKNOWN; + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/DumpAPITokensTests.java b/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/DumpAPITokensTests.java new file mode 100644 index 00000000000..88ff9c43531 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/DumpAPITokensTests.java @@ -0,0 +1,396 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.jvm.ras.tests; + +import static com.ibm.jvm.ras.tests.DumpAPISuite.deleteFile; +import static com.ibm.jvm.ras.tests.DumpAPISuite.getFilesByPattern; + +import java.io.File; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.HashSet; +import java.util.Set; + +import junit.framework.TestCase; + +import com.ibm.jvm.InvalidDumpOptionException; + +/** + * This testcase checks that the dump tokens are correctly formatted into filenames. + * It only creates javacores rather than testing this for every dump type. + * + * The tokens are: + * %Y year 1900..???? + * %y century 00..99 + * %m month 01..12 + * %d day 01..31 + * %H hour 00..23 + * %M minute 00..59 + * %S second 00..59 + * + * %pid process id + * %uid user name + * %seq dump counter + * %tick msec counter + * %home java home + * %last last dump + * %event dump event + * + * The date and time tokens are tested together. + * %home and %last are not tested as they contain paths + * and are only really intended for use with tool dumps. + * + * @author hhellyer + * + */ +public class DumpAPITokensTests extends TestCase { + +// private static String originalUserDir = System.getProperty("user.dir"); + + private long uid = System.currentTimeMillis(); + + // Record the files created by each testcase here so we can delete them + // later. Otherwise we will fill the disk up pretty quickly. While we check + // that the right kind of dump was created for each call we do any further + // validity checking on the dumps themselves. This test is just checking the + // API does what it should not that the dumps themselves are correct. + private Set fileNames; + + @Override + protected void setUp() throws Exception { + super.setUp(); + fileNames = new HashSet(); + } + + @Override + protected void tearDown() throws Exception { + // TODO Auto-generated method stub + super.tearDown(); + for( String fileName: fileNames) { + deleteFile(fileName, this.getName()); + } + } + + + public void testJavaDumpWithDateAndTimeTokens() { + String userDir = System.getProperty("user.dir"); + + // %Y year 1900..???? + // %y century 00..99 + // %m month 01..12 + // %d day 01..31 + // %H hour 00..23 + // %M minute 00..59 + // %S second 00..59 + // These two patterns should correspond. + String dateFormatDump = "%Y%m%d%H%M%S"; + + String dateFormatJava = "yyyyMMddHHmmss"; + SimpleDateFormat dateFormat = new SimpleDateFormat(dateFormatJava); + + + String dumpName = userDir + File.separator + "javacore."+ getName() + "." + dateFormatDump + "." + uid + ".txt"; + String dumpFilePattern = ".*javacore\\."+ getName() + "\\.[0-9]+\\." + uid + "\\.txt"; + + // Check the file doesn't exist, otherwise the dump code moves it. + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, dumpFilePattern); + assertTrue("Found a file matching our output pattern before taking the dump.", beforeFileNames.length == 0); + + // Check we got the correct name. + long beforeTime = System.currentTimeMillis(); + // The dump timestamp will round down to the nearest millsecond once + // parsed. Dumping may take less than a second so we need to make sure + // the timestamp will advance. + // (We aren't worried about millisecond precision in file timestamps just + // that it's actually filled out correctly.!) + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // Do nothing. + } + String javacoreName = null; + try { + javacoreName = com.ibm.jvm.Dump.javaDumpToFile(dumpName); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + long afterTime = System.currentTimeMillis(); + assertNotNull("Expected javacore filename to be returned, not null", javacoreName); + fileNames.add(javacoreName); + + /* Count the number of files before and after. Should increase by one. */ + String[] afterFileNames = getFilesByPattern(userDir, dumpFilePattern); + assertTrue("Found a file matching our output pattern before taking the dump.", afterFileNames.length == 1); + + // Check it really exists. + File javacoreFile = new File(javacoreName); + assertTrue("Failed to find files " + javacoreName + " after requesting " + javacoreName, javacoreFile.exists()); + + + // Check the filename returned matches the file we found searching the directory. + assertEquals("Expected created file to match returned filename", javacoreName, userDir + File.separator + afterFileNames[0]); + + // Check the date formatted correctly and had the correct timestamp. + String javacoreDate = javacoreFile.getName().split("\\.")[2]; + long javacoreTime = 0; + try { + // Parse it in the UTC timezone. + //System.err.println("Javacore date: " + javacoreDate); + javacoreTime = dateFormat.parse(javacoreDate).getTime(); + } catch (ParseException e) { + fail("The timestamp in the filename was not in the expected format, timestamp was: " + javacoreDate + " format was: " + dateFormatJava); + } + //System.err.println("beforeTime = " + (new Date(beforeTime)) + " javacoreTime = " + (new Date(javacoreTime)) + " afterTime = " + (new Date(afterTime))); + //System.err.println("beforeTime = " + beforeTime + " javacoreTime = " + javacoreTime + " afterTime = " + afterTime); + assertTrue("The timestamp from the javacore was not between the timestamps taken before and after we took the dump.", javacoreTime >= beforeTime && afterTime >= javacoreTime ); + + } + + public void testJavaDumpWithTickToken() { + String userDir = System.getProperty("user.dir"); + + // This will use the j9time_hires_clock() value. + // We can't assume it is in a particular unit or that it will be the same unit on different platforms. + String timeFormatDump = "%tick"; + + String dumpName = userDir + File.separator + "javacore."+ getName() + "." + timeFormatDump + "." + uid + ".txt"; + String dumpFilePattern = ".*javacore\\."+ getName() + "\\.[0-9]+\\." + uid + "\\.txt"; + + // Check the file doesn't exist, otherwise the dump code moves it. + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, dumpFilePattern); + assertTrue("Found a file matching our output pattern before taking the dump.", beforeFileNames.length == 0); + + String javacoreName = null; + try { + javacoreName = com.ibm.jvm.Dump.javaDumpToFile(dumpName); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + + + assertNotNull("Expected javacore filename to be returned, not null", javacoreName); + fileNames.add(javacoreName); + + /* Count the number of files before and after. Should increase by one. */ + String[] afterFileNames = getFilesByPattern(userDir, dumpFilePattern); + assertTrue("Found a file matching our output pattern before taking the dump.", afterFileNames.length == 1); + + // Check it really exists. + File javacoreFile = new File(javacoreName); + assertTrue("Failed to find files " + javacoreName + " after requesting " + javacoreName, javacoreFile.exists()); + + + // Check the filename returned matches the file we found searching the directory. + assertEquals("Expected created file to match returned filename", javacoreName, userDir + File.separator + afterFileNames[0]); + + // We've checked we got a file named correctly, and that the file really was created. + // Cannot check the absolute value of the time stamp as its just the hires time counter. + } + + public void testJavaDumpWithPidToken() { + String userDir = System.getProperty("user.dir"); + + String dumpToken = "%pid"; + + String dumpName = userDir + File.separator + "javacore."+ getName() + "." + dumpToken + "." + uid + ".txt"; + String dumpFilePattern = ".*javacore\\."+ getName() + "\\.[0-9]+\\." + uid + "\\.txt"; + + // Check the file doesn't exist, otherwise the dump code moves it. + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, dumpFilePattern); + assertTrue("Found a file matching our output pattern before taking the dump.", beforeFileNames.length == 0); + + String javacoreName = null; + try { + javacoreName = com.ibm.jvm.Dump.javaDumpToFile(dumpName); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + + assertNotNull("Expected javacore filename to be returned, not null", javacoreName); + fileNames.add(javacoreName); + + /* Count the number of files before and after. Should increase by one. */ + String[] afterFileNames = getFilesByPattern(userDir, dumpFilePattern); + assertTrue("Found a file matching our output pattern before taking the dump.", afterFileNames.length == 1); + + // Check it really exists. + File javacoreFile = new File(javacoreName); + assertTrue("Failed to find files " + javacoreName + " after requesting " + javacoreName, javacoreFile.exists()); + + + // Check the filename returned matches the file we found searching the directory. + assertEquals("Expected created file to match returned filename", javacoreName, userDir + File.separator + afterFileNames[0]); + + } + + /* This test fails as there isn't a mapping to a friendly name for + * J9RAS_DUMP_ON_USER_REQUEST. We could fix that, until then this + * test will fail. + */ + public void testJavaDumpWithEventToken() { + String userDir = System.getProperty("user.dir"); + + String dumpToken = "%event"; + + String dumpName = userDir + File.separator + "javacore."+ getName() + "." + dumpToken + "." + uid + ".txt"; + String dumpFilePattern = ".*javacore\\."+ getName() + "\\.api." + uid + "\\.txt"; + + // Check the file doesn't exist, otherwise the dump code moves it. + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, dumpFilePattern); + assertTrue("Found a file matching our output pattern before taking the dump.", beforeFileNames.length == 0); + + String javacoreName = null; + try { + javacoreName = com.ibm.jvm.Dump.javaDumpToFile(dumpName); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + + assertNotNull("Expected javacore filename to be returned, not null", javacoreName); + fileNames.add(javacoreName); + + // Check it really exists. + File javacoreFile = new File(javacoreName); + assertTrue("Failed to find files " + javacoreName + " after requesting " + javacoreName, javacoreFile.exists()); + + /* Count the number of files before and after. Should increase by one. */ + String[] afterFileNames = getFilesByPattern(userDir, dumpFilePattern); + assertEquals("Found a file matching our output pattern before taking the dump.", 1, afterFileNames.length); + + + + // Check the filename returned matches the file we found searching the directory. + assertEquals("Expected created file to match returned filename", javacoreName, userDir + File.separator + afterFileNames[0]); + + } + + public void testJavaDumpWithUidToken() { + String userDir = System.getProperty("user.dir"); + + // This will use the j9time_hires_clock() value. + // We can't assume it is in a particular unit or that it will be the same unit on different platforms. + String dumpToken = "%uid"; + String javaUserid = System.getProperty("user.name"); + + String dumpName = userDir + File.separator + "javacore."+ getName() + "." + dumpToken + "." + uid + ".txt"; + String dumpFilePattern = ".*javacore\\."+ getName() + "\\." + javaUserid + "\\." + uid + "\\.txt"; + + // Check the file doesn't exist, otherwise the dump code moves it. + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, dumpFilePattern); + assertTrue("Found a file matching our output pattern before taking the dump.", beforeFileNames.length == 0); + + String javacoreName = null; + try { + javacoreName = com.ibm.jvm.Dump.javaDumpToFile(dumpName); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + + assertNotNull("Expected javacore filename to be returned, not null", javacoreName); + fileNames.add(javacoreName); + + /* Count the number of files before and after. Should increase by one. */ + String[] afterFileNames = getFilesByPattern(userDir, dumpFilePattern); + assertTrue("Found a file matching our output pattern before taking the dump.", afterFileNames.length == 1); + + // Check it really exists. + File javacoreFile = new File(javacoreName); + assertTrue("Failed to find files " + javacoreName + " after requesting " + javacoreName, javacoreFile.exists()); + + + // Check the filename returned matches the file we found searching the directory. + assertEquals("Expected created file to match returned filename", javacoreName, userDir + File.separator + afterFileNames[0]); + + } + + public void testJavaDumpWithSequenceToken() { + String userDir = System.getProperty("user.dir"); + + String dumpToken = "%seq"; + + String dumpName = userDir + File.separator + "javacore."+ getName() + "." + dumpToken + "." + uid + ".txt"; + String dumpFilePattern = ".*javacore\\."+ getName() + "\\.[0-9]+\\." + uid + "\\.txt"; + + // Check the file doesn't exist, otherwise the dump code moves it. + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, dumpFilePattern); + assertTrue("Found a file matching our output pattern before taking the dump.", beforeFileNames.length == 0); + + String javacoreName1 = null; + try { + javacoreName1 = com.ibm.jvm.Dump.javaDumpToFile(dumpName); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + assertNotNull("Expected javacore filename to be returned, not null", javacoreName1); + fileNames.add(javacoreName1); + + /* Count the number of files before and after. Should increase by one. */ + String[] afterFileNames = getFilesByPattern(userDir, dumpFilePattern); + assertTrue("Found a file matching our output pattern before taking the dump.", afterFileNames.length == 1); + + // Check it really exists. + File javacoreFile1 = new File(javacoreName1); + assertTrue("Failed to find files " + javacoreName1 + " after requesting " + javacoreName1, javacoreFile1.exists()); + + + // Check the filename returned matches the file we found searching the directory. + assertEquals("Expected created file to match returned filename", javacoreName1, userDir + File.separator + afterFileNames[0]); + + // Check the date formatted correctly and had the correct timestamp. + String seq1Str = javacoreFile1.getName().split("\\.")[2]; + + // Create a second javacore, to see if %seq has incremented. + String javacoreName2 = null; + try { + javacoreName2 = com.ibm.jvm.Dump.javaDumpToFile(dumpName); + } catch (InvalidDumpOptionException e ) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + assertNotNull("Expected javacore filename to be returned, not null", javacoreName2); + fileNames.add(javacoreName2); + + // Check it really exists. + File javacoreFile2 = new File(javacoreName2); + assertTrue("Failed to find files " + javacoreName2 + " after requesting " + javacoreName1, javacoreFile2.exists()); + + String seq2Str = javacoreFile2.getName().split("\\.")[2]; + + int seq1 = Integer.valueOf(seq1Str); + int seq2 = Integer.valueOf(seq2Str); + + assertTrue("Expected sequence number to increment by one, but seq1 = " + seq1 + " seq2 = " + seq2, seq1 + 1 == seq2); + + } +} diff --git a/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/DumpAPIToolSecuritySuite.java b/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/DumpAPIToolSecuritySuite.java new file mode 100644 index 00000000000..555e98f357b --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/DumpAPIToolSecuritySuite.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.jvm.ras.tests; + +import junit.framework.Test; +import junit.framework.TestSuite; + + +/** + * A simple test suite to let us re-test that tool dumps are blocked + * when DumpPermission is granted but ToolDumpPermission is not. + * Also checks that a normal dump works. + * + * @author hhellyer + * + */ +public class DumpAPIToolSecuritySuite { + /** + * This runs all the tests as a single suite. + * @return + */ + public static Test suite() { + TestSuite suite = new TestSuite(DumpAPIToolSecuritySuite.class.getName()); + //$JUnit-BEGIN$ + suite.addTest(TestSuite.createTest(DumpAPISecurityTests.class, "testTriggerToolDump")); + suite.addTest(TestSuite.createTest(DumpAPIBasicTests.class, "testJavaDumpWithFile")); + //$JUnit-END$ + return suite; + } +} diff --git a/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/DumpAPITriggerTests.java b/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/DumpAPITriggerTests.java new file mode 100644 index 00000000000..3127e929989 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/DumpAPITriggerTests.java @@ -0,0 +1,375 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.jvm.ras.tests; + +import static com.ibm.jvm.ras.tests.DumpAPISuite.DUMP_COULD_NOT_CREATE_FILE; +import static com.ibm.jvm.ras.tests.DumpAPISuite.DUMP_ERROR_PARSING; +import static com.ibm.jvm.ras.tests.DumpAPISuite.deleteFile; +import static com.ibm.jvm.ras.tests.DumpAPISuite.getContentType; +import static com.ibm.jvm.ras.tests.DumpAPISuite.getFilesByPattern; +import static com.ibm.jvm.ras.tests.DumpAPISuite.isZOS; + +import java.io.File; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import junit.framework.TestCase; + +import com.ibm.jvm.InvalidDumpOptionException; +import com.ibm.jvm.ras.tests.DumpAPISuite.DumpType; + +public class DumpAPITriggerTests extends TestCase { + + private long uid = System.currentTimeMillis(); + + // Record the files created by each testcase here so we can delete them + // later. Otherwise we will fill the disk up pretty quickly. While we check + // that the right kind of dump was created for each call we do any further + // validity checking on the dumps themselves. This test is just checking the + // API does what it should not that the dumps themselves are correct. + private Set fileNames; + + @Override + protected void setUp() throws Exception { + super.setUp(); + fileNames = new HashSet(); + + // This isn't to free space, it's to trigger GC tracepoints so we don't get empty snap dumps! + System.gc(); + } + + @Override + protected void tearDown() throws Exception { + // TODO Auto-generated method stub + super.tearDown(); + for( String fileName: fileNames) { + deleteFile(fileName, this.getName()); + } + } + + public void testTriggerDumpNullOpts() { + try { + doTestTriggerBadDumpX(null); + fail("Expected NPE to be thrown."); + } catch( NullPointerException npe ) { + // pass + } + } + + public void testTriggerDumpEmptyOpts() { + doTestTriggerBadDumpX(""); + } + + public void testTriggerDumpJavaNoOpts() { + doTestTriggerDumpNoOpts("java", DumpType.JAVA_TYPE); + } + + public void testTriggerDumpSystemNoOpts() { + if( isZOS() ) { + System.err.printf("Skipping %s, z/OS system dumps currently inaccessable in Java 8, see CMVC 193090\n", this.getName()); + return; + } + doTestTriggerDumpNoOpts("system", DumpType.SYSTEM_TYPE); + } + + public void testTriggerDumpHeapNoOpts() { + doTestTriggerDumpNoOpts("heap", DumpType.PHD_HEAP_TYPE); + } + + public void testTriggerDumpSnapNoOpts() { + doTestTriggerDumpNoOpts("snap", DumpType.SNAP_TYPE); + } + +// Don't test this, the default dump agent runs the debugger and connects back to this process. +// It's a great way to hang the test cases. +// public void testTriggerDumpToolNoOpts() { +// doTestTriggerDumpNoOpts("snap", DumpType.TOOL_TYPE); +// } + + public void testTriggerDumpConsoleNoOpts() { + // Default console dump goes to stderr therefore no file will be found. + doTestTriggerDumpNoOpts("console", DumpType.FILE_NOT_FOUND); + } + + public void testTriggerDumpStackNoOpts() { + // Default stack dump goes to stderr therefore no file will be found. + doTestTriggerDumpNoOpts("stack", DumpType.FILE_NOT_FOUND); + } + + public void testTriggerDumpSilentNoOpts() { + doTestTriggerDumpNoOpts("silent", DumpType.FILE_NOT_FOUND); + } + + public void testTriggerDumpBadAgentNoOpts() { + // The chances of us adding a new dump type called walrus in the future are small. + InvalidDumpOptionException e = doTestTriggerBadDumpX("walrus"); + assertEquals("Incorrect message triggering tool dump.", DUMP_ERROR_PARSING, e.getMessage()); + } + + public void testTriggerDumpJavaToFile() { + doTestTriggerDumpWithFile("java", "javacore." + getName() + "." + uid + ".txt", DumpType.JAVA_TYPE); + } + + public void testTriggerDumpSystemToFile() { + if( isZOS() ) { + System.err.printf("Skipping %s, z/OS system dumps currently inaccessable in Java 8, see CMVC 193090\n", this.getName()); + return; + } + doTestTriggerDumpWithFile("system", "system." + getName() + "." + uid + ".dmp", DumpType.SYSTEM_TYPE); + } + + public void testTriggerDumpHeapToFile() { + doTestTriggerDumpWithFile("heap", "heap." + getName() + "." + uid + ".phd", DumpType.PHD_HEAP_TYPE); + } + + public void testTriggerDumpClassicHeapToFile() { + String fileName = "heap." + getName() + "." + uid + ".txt"; + String type = "heap"; + File dumpFile = new File(fileName); + assertFalse("Found file " + fileName + " before requesting " + fileName, dumpFile.exists()); + doTestTriggerDumpX(type +":file=" + fileName + ",opts=CLASSIC", DumpType.CLASSIC_HEAP_TYPE); + assertTrue("Failed to find file " + fileName + " after requesting " + fileName, dumpFile.exists()); + } + + + public void testTriggerDumpSnapToFile() { + doTestTriggerDumpWithFile("snap", "snap." + getName() + "." + uid + ".trc", DumpType.SNAP_TYPE); + } + + public void testTriggerDumpTool() { + // This will be slightly broken as no file will be created but as we don't get the return code + // from the command we just want to check the string is accepted and we attempt to run something. + doTestTriggerDumpX("tool:exec=tool." + getName() + "." + uid + ".txt", DumpType.FILE_NOT_FOUND); + } + + public void testTriggerDumpConsoleToFile() { + doTestTriggerDumpWithFile("console", "console." + getName() + "." + uid + ".txt", DumpType.CONSOLE_TYPE); + } + + public void testTriggerDumpStackToFile() { + doTestTriggerDumpWithFile("stack", "stack." + getName() + "." + uid + ".txt", DumpType.STACK_TYPE); + } + + public void testTriggerDumpSilentToFile() { + doTestTriggerDumpWithFile("silent", "silent." + getName() + "." + uid + ".txt", DumpType.FILE_NOT_FOUND); + } + + public void testTriggerDumpBadAgentToFile() { + InvalidDumpOptionException e = doTestTriggerBadDumpX("walrus:label=walrus." + getName() + "." + uid + ".txt"); + assertEquals("Incorrect message triggering tool dump.", DUMP_ERROR_PARSING, e.getMessage()); + } + + public void testTriggerDumpJavaNoFile() { + InvalidDumpOptionException e = doTestTriggerBadDumpX("java:file="); + assertEquals("Incorrect message triggering java dump with missing file.", DUMP_COULD_NOT_CREATE_FILE, e.getMessage()); + } + + public void testTriggerDumpSystemNoFile() { + if( isZOS() ) { + System.err.printf("Skipping %s, z/OS system dumps currently inaccessable in Java 8, see CMVC 193090\n", this.getName()); + return; + } + InvalidDumpOptionException e = doTestTriggerBadDumpX("system:label="); + assertEquals("Incorrect message triggering system dump with missing file.", DUMP_COULD_NOT_CREATE_FILE, e.getMessage()); + } + + public void testTriggerDumpHeapNoFile() { + InvalidDumpOptionException e = doTestTriggerBadDumpX("heap:file="); + assertEquals("Incorrect message triggering heap dump with missing file.", DUMP_COULD_NOT_CREATE_FILE, e.getMessage()); + } + + public void testTriggerDumpSnapNoFile() { + InvalidDumpOptionException e = doTestTriggerBadDumpX("snap:file="); + assertEquals("Incorrect message triggering snap dump with missing file.", DUMP_COULD_NOT_CREATE_FILE, e.getMessage()); + } + + public void testTriggerDumpConsoleNoFile() { + InvalidDumpOptionException e = doTestTriggerBadDumpX("console:file="); + assertEquals("Incorrect message triggering console dump with missing file.", DUMP_COULD_NOT_CREATE_FILE, e.getMessage()); + } + + public void testTriggerDumpStackNoFile() { + InvalidDumpOptionException e = doTestTriggerBadDumpX("stack:file="); + assertEquals("Incorrect message triggering java dump with missing file.", DUMP_COULD_NOT_CREATE_FILE, e.getMessage()); + } + + public void testTriggerDumpJavaBadFile() { + InvalidDumpOptionException e = doTestTriggerBadDumpX("java:file=.."); + assertEquals("Incorrect message triggering java dump with missing file.", DUMP_COULD_NOT_CREATE_FILE, e.getMessage()); + } + + public void testTriggerDumpJavaToDirectory() { + InvalidDumpOptionException e = doTestTriggerBadDumpX("java:file=javaDump" + File.separator); + assertEquals("Incorrect message triggering java dump with missing file.", DUMP_COULD_NOT_CREATE_FILE, e.getMessage()); + } + + public void testTriggerDumpConsoleDashFile() { + doTestTriggerDumpWithFile("console", "-", DumpType.FILE_NOT_FOUND); + } + + public void testTriggerDumpStackDashFile() { + doTestTriggerDumpWithFile("stack", "-", DumpType.FILE_NOT_FOUND); + } + + public void testTriggerDumpJavaDashFile() { + doSTDOUTTestTriggerDumpX("java:file=-"); + } + + public void testTriggerMultipleDumpsNoOpts() { + InvalidDumpOptionException e = doTestTriggerBadDumpX("java+heap"); + assertEquals("Incorrect message triggering java dump with missing file.", DUMP_ERROR_PARSING, e.getMessage()); + } + + /* JIT dumps currently do nothing. */ + /*public void testTriggerDumpJit() { + doTestTriggerDump("jit"); + }*/ + + public void doTestTriggerDumpNoOpts(String type, DumpType expectedType) { + doTestTriggerDumpX(type, expectedType); + } + + + /** + * Triggers a dump to a specific file name and checks it exists. + * Assumes that the filename does not contain wild cards. + * @param type + * @param fileName + */ + public void doTestTriggerDumpWithFile(String type, String fileName, DumpType expectedType) { + File dumpFile = new File(fileName); + assertFalse("Found file " + fileName + " before requesting " + fileName, dumpFile.exists()); + doTestTriggerDumpX(type +":label=" + fileName, expectedType); + } + + /** + * Triggers a dump with the given options and does basic checking + * for files created and created with the right name. + * @param options + */ + public void doTestTriggerDumpX(String options, DumpType expectedType) { + String userDir = System.getProperty("user.dir"); + String dumpFilePattern = ".*\\.*"; + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, dumpFilePattern); + int beforeCount = beforeFileNames.length; + + String fileName = null; + try { + fileName = com.ibm.jvm.Dump.triggerDump(options); + } catch (SecurityException e) { + e.printStackTrace(); + fail("Exception thrown by triggerDump(" + options +")"); + } catch (InvalidDumpOptionException e) { + e.printStackTrace(); + fail("Exception thrown by triggerDump(" + options +")"); + } + //System.err.println("Dump file name is: " + fileName); + assertNotNull("Expected triggerDump to return file name, not null", fileName); + + // Check the generated file really exists, unless we wrote to stderr or don't expect to find a file! + File dumpFile = new File(fileName); + if( !"-".equals(fileName) && expectedType != DumpType.FILE_NOT_FOUND ) { + assertTrue("Failed to find files " + fileName + " after requesting " + fileName, dumpFile.exists()); + fileNames.add(fileName); + } + // Check content + DumpType type = getContentType(dumpFile); + assertEquals("Expected file " + dumpFile + " to contain a dump of type " + expectedType.name + " but content type was: " + type.name, expectedType, type); + + // Check the number of files has increased. (We weren't returned a filename that already existed.) + String[] afterFileNames = getFilesByPattern(userDir, dumpFilePattern); + int afterCount = afterFileNames.length; + if( "-".equals(fileName) || expectedType == DumpType.FILE_NOT_FOUND ) { + // Wrote to stderr, or no file expected so no more files. + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount, afterCount); + } else { + // Wrote to filename, one more file. + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount + 1, afterCount); + } + + } + + public void doSTDOUTTestTriggerDumpX(String options) { + String userDir = System.getProperty("user.dir"); + String dumpFilePattern = ".*\\.*"; + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, dumpFilePattern); + int beforeCount = beforeFileNames.length; + + String fileName = null; + + try { + fileName = com.ibm.jvm.Dump.triggerDump(options); + assertEquals("Expected fileName /STDOUT/, but fileName was " + fileName, "/STDOUT/", fileName); + } catch (InvalidDumpOptionException e) { + e.printStackTrace(); + fail("Unexpected InvalidDumpOption exception thrown."); + } + + // Check the number of files has not increased. (We weren't returned a filename that already existed.) + String[] afterFileNames = getFilesByPattern(userDir, dumpFilePattern); + int afterCount = afterFileNames.length; + // Should have failed to create a dump, so no more files should be created. + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount, afterCount); + } + + /** + * Triggers a dump with the given options, which are incorrect, + * and checks no files are created. + * @param options + * @return the exception that was thrown so the caller can verify it was the correct one. + */ + public InvalidDumpOptionException doTestTriggerBadDumpX(String options) { + String userDir = System.getProperty("user.dir"); + String dumpFilePattern = ".*\\.*"; + + /* Count the number of files before and after. Should increase by one. */ + String[] beforeFileNames = getFilesByPattern(userDir, dumpFilePattern); + int beforeCount = beforeFileNames.length; + + String fileName = null; + InvalidDumpOptionException exception = null; + + /* We are checking these options cause an error, so the InvalidDumpOptionException path is the good case. */ + try { + fileName = com.ibm.jvm.Dump.triggerDump(options); + fail("Exception not thrown by triggerDump(" + options +"), fileName returned was: " + fileName); + } catch (SecurityException e) { + fail("Security exception thrown by triggerDump(" + options +")"); + } catch (InvalidDumpOptionException e) { + exception = e; + } + assertNull("Expected triggerDump not to return null file name", fileName); + + // Check the number of files has increased. (We weren't returned a filename that already existed.) + String[] afterFileNames = getFilesByPattern(userDir, dumpFilePattern); + int afterCount = afterFileNames.length; + // Should have failed to create a dump, so no more files should be created. + assertEquals("Failed to find expected number of files in " + userDir + " , found:" + Arrays.toString(afterFileNames), beforeCount, afterCount); + return exception; + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/LogAPISecurityTests.java b/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/LogAPISecurityTests.java new file mode 100644 index 00000000000..53c524f829e --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/LogAPISecurityTests.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.jvm.ras.tests; + +import static java.lang.Boolean.TRUE; +import static java.lang.Boolean.FALSE; +import junit.framework.TestCase; + +public class LogAPISecurityTests extends TestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + + // Make sure this is off for the start of every test. + System.clearProperty("com.ibm.jvm.enableLegacyLogSecurity"); + } + + public void testQueryLogOptions() { + System.setProperty("com.ibm.jvm.enableLegacyLogSecurity", FALSE.toString()); + com.ibm.jvm.Log.QueryOptions(); + + } + + public void testQueryLogOptionsBlocked() { + System.clearProperty("com.ibm.jvm.enableLegacyLogSecurity"); + try { + com.ibm.jvm.Log.QueryOptions(); + fail("Expected security exception to be thrown."); + } catch (SecurityException e) { + //Pass + } + + + + } + + public void testSetLogOptions() { + System.setProperty("com.ibm.jvm.enableLegacyLogSecurity", FALSE.toString()); + /* Set to the default options so we don't really change things for other tests. */ + com.ibm.jvm.Log.SetOptions("error,vital"); + + } + + public void testSetLogOptionsBlocked() { + System.clearProperty("com.ibm.jvm.enableLegacyLogSecurity"); + try { + /* Set to the default options so we don't really change things for other tests. */ + com.ibm.jvm.Log.SetOptions("error,vital"); + fail("Expected security exception to be thrown."); + } catch (SecurityException e) { + // Pass + } + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/TraceAPISecurityTests.java b/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/TraceAPISecurityTests.java new file mode 100644 index 00000000000..4903fe29f42 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/jvm/ras/tests/TraceAPISecurityTests.java @@ -0,0 +1,742 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.jvm.ras.tests; + +import static java.lang.Boolean.TRUE; +import static java.lang.Boolean.FALSE; +import junit.framework.TestCase; +import com.ibm.jvm.Trace; + +public class TraceAPISecurityTests extends TestCase { + + static final String[] TEMPLATES = new String[54]; + static { + TEMPLATES[0] = Trace.EVENT; + TEMPLATES[1] = Trace.EVENT + "Tracepoint #1 "; + TEMPLATES[2] = Trace.EVENT + "Tracepoint #2 insert1=%s"; + TEMPLATES[3] = Trace.EVENT + "Tracepoint #3 insert1=%s insert2=%s"; + TEMPLATES[4] = Trace.EVENT + "Tracepoint #4 insert1=%s insert2=%s insert3=%s"; + TEMPLATES[5] = Trace.EVENT + "Tracepoint #5 insert1=%s insert2=%p"; + TEMPLATES[6] = Trace.EVENT + "Tracepoint #6 insert1=%p insert2=%s"; + TEMPLATES[7] = Trace.EVENT + "Tracepoint #7 insert1=%s insert2=%d"; + TEMPLATES[8] = Trace.EVENT + "Tracepoint #8 insert1=%d insert2=%s"; + TEMPLATES[9] = Trace.EVENT + "Tracepoint #9 insert1=%s insert2=%lld"; + TEMPLATES[10] = Trace.EVENT + "Tracepoint #10 insert1=%lld insert2=%s"; // mkomine@77003 + TEMPLATES[11] = Trace.EVENT + "Tracepoint #11 insert1=%s insert2=%d"; + TEMPLATES[12] = Trace.EVENT + "Tracepoint #12 insert1=%d insert2=%s"; + TEMPLATES[13] = Trace.EVENT + "Tracepoint #13 insert1=%s insert2=%c"; + TEMPLATES[14] = Trace.EVENT + "Tracepoint #14 insert1=%c insert2=%s"; + TEMPLATES[15] = Trace.EVENT + "Tracepoint #15 insert1=%s insert2=%f"; + TEMPLATES[16] = Trace.EVENT + "Tracepoint #16 insert1=%e insert2=%s"; + TEMPLATES[17] = Trace.EVENT + "Tracepoint #17 insert1=%s insert2=%e"; + TEMPLATES[18] = Trace.EVENT + "Tracepoint #18 insert1=%e insert2=%s"; + TEMPLATES[19] = Trace.EVENT + "Tracepoint #19 insert1=%p"; + TEMPLATES[20] = Trace.EVENT + "Tracepoint #20 insert1=%p insert2=%p"; + TEMPLATES[21] = Trace.EVENT + "Tracepoint #21 insert1=%d"; + TEMPLATES[22] = Trace.EVENT + "Tracepoint #22 insert1=%d insert2=%d"; + TEMPLATES[23] = Trace.EVENT + "Tracepoint #23 insert1=%d insert2=%d insert3=%d"; + TEMPLATES[24] = Trace.EVENT + "Tracepoint #24 insert1=%lld"; + TEMPLATES[25] = Trace.EVENT + "Tracepoint #25 insert1=%lld insert2=%lld"; + TEMPLATES[26] = Trace.EVENT + "Tracepoint #26 insert1=%lld insert2=%lld insert3=%lld"; + TEMPLATES[27] = Trace.EVENT + "Tracepoint #27 insert1=%d"; + TEMPLATES[28] = Trace.EVENT + "Tracepoint #28 insert1=%d insert2=%d"; + TEMPLATES[29] = Trace.EVENT + "Tracepoint #29 insert1=%d insert2=%d insert3=%d"; + TEMPLATES[30] = Trace.EVENT + "Tracepoint #30 insert1=%c"; + TEMPLATES[31] = Trace.EVENT + "Tracepoint #31 insert1=%c insert2=%c"; + TEMPLATES[32] = Trace.EVENT + "Tracepoint #32 insert1=%c insert2=%c insert3=%c"; + TEMPLATES[33] = Trace.EVENT + "Tracepoint #33 insert1=%f"; + TEMPLATES[34] = Trace.EVENT + "Tracepoint #34 insert1=%e insert2=%e"; + TEMPLATES[35] = Trace.EVENT + "Tracepoint #35 insert1=%f insert2=%f insert3=%f"; + TEMPLATES[36] = Trace.EVENT + "Tracepoint #36 insert1=%d"; + TEMPLATES[37] = Trace.EVENT + "Tracepoint #37 insert1=%d insert2=%d"; + TEMPLATES[38] = Trace.EVENT + "Tracepoint #38 insert1=%f insert2=%f insert3=%f"; + TEMPLATES[39] = Trace.EVENT + "Tracepoint #39 insert1=%s insert2=%p insert3=%s"; + TEMPLATES[40] = Trace.EVENT + "Tracepoint #40 insert1=%p insert2=%s insert3=%p"; + TEMPLATES[41] = Trace.EVENT + "Tracepoint #41 insert1=%s insert2=%d insert3=%s"; + TEMPLATES[42] = Trace.EVENT + "Tracepoint #42 insert1=%d insert2=%s insert3=%d"; + TEMPLATES[43] = Trace.EVENT + "Tracepoint #43 insert1=%s insert2=%lld insert3=%s"; + TEMPLATES[44] = Trace.EVENT + "Tracepoint #44 insert1=%lld insert2=%s insert3=%lld"; + TEMPLATES[45] = Trace.EVENT + "Tracepoint #45 insert1=%s insert2=%d insert3=%s"; + TEMPLATES[46] = Trace.EVENT + "Tracepoint #46 insert1=%d insert2=%s insert3=%d"; + TEMPLATES[47] = Trace.EVENT + "Tracepoint #47 insert1=%s insert2=%c insert3=%s"; + TEMPLATES[48] = Trace.EVENT + "Tracepoint #48 insert1=%c insert2=%s insert3=%c"; + TEMPLATES[49] = Trace.EVENT + "Tracepoint #49 insert1=%s insert2=%f insert3=%s"; + TEMPLATES[50] = Trace.EVENT + "Tracepoint #50 insert1=%f insert2=%s insert3=%f"; + TEMPLATES[51] = Trace.EVENT + "Tracepoint #51 insert1=%s insert2=%d insert3=%s"; + TEMPLATES[52] = Trace.EVENT + "Tracepoint #52 insert1=%d insert2=%s insert3=%d"; + TEMPLATES[53] = Trace.EVENT + "Tracepoint #53 TEST PASSED"; + } + + + @Override + protected void setUp() throws Exception { + super.setUp(); + + // Make sure this is off for the start of every test. + System.clearProperty("com.ibm.jvm.enableLegacyTraceSecurity"); + } + + public void testGetMicros() { + + System.setProperty("com.ibm.jvm.enableLegacyTraceSecurity", FALSE.toString()); + com.ibm.jvm.Trace.getMicros(); + + } + + public void testQueryGetMicrosNotBlocked() { + System.setProperty("com.ibm.jvm.enableLegacyLogSecurity", FALSE.toString()); + + try { + com.ibm.jvm.Log.QueryOptions(); + } catch (SecurityException e) { + // Fail, this method shouldn't have security enabled. + fail("Expected security exception to be thrown."); + } + } + + public void testSuspendResumeNotBlocked() { + System.setProperty("com.ibm.jvm.enableLegacyTraceSecurity", FALSE.toString()); + com.ibm.jvm.Trace.suspend(); + com.ibm.jvm.Trace.resume(); + } + + public void testSuspendResumeBlocked() { + + System.clearProperty("com.ibm.jvm.enableLegacyTraceSecurity"); + + try { + /* Disable global trace */ + com.ibm.jvm.Trace.suspend(); + fail("Expected security exception to be thrown."); + } catch (SecurityException e) { + // Pass + } + try { + /* Enable global trace */ + com.ibm.jvm.Trace.resume(); + fail("Expected security exception to be thrown."); + } catch (SecurityException e) { + // Pass + } + } + + public void testSuspendThisResumeThisNotBlocked() { + System.setProperty("com.ibm.jvm.enableLegacyTraceSecurity", FALSE.toString()); + com.ibm.jvm.Trace.suspendThis(); + com.ibm.jvm.Trace.resumeThis(); + + } + + public void testSuspendThisResumeThisBlocked() { + + System.clearProperty("com.ibm.jvm.enableLegacyTraceSecurity"); + + try { + /* Set to the default options so we don't really change things for other tests. */ + com.ibm.jvm.Trace.suspendThis(); + fail("Expected security exception to be thrown."); + } catch (SecurityException e) { + // Pass + } + try { + /* Set to the default options so we don't really change things for other tests. */ + com.ibm.jvm.Trace.resumeThis(); + fail("Expected security exception to be thrown."); + } catch (SecurityException e) { + // Pass + } + } + + public void testSetNotBlocked() { + System.setProperty("com.ibm.jvm.enableLegacyTraceSecurity", FALSE.toString()); + int result = com.ibm.jvm.Trace.set("maximal=j9trc.0"); + assertEquals("Expected to be able to set tracepoint", 0, result); + } + + public void testSetBlocked() { + + System.clearProperty("com.ibm.jvm.enableLegacyTraceSecurity"); + + try { + /* Set the trace init tracepoint, will already be set and won't ever fire after + * the trace library comes up anyway. + */ + com.ibm.jvm.Trace.set("maximal=j9trc.0"); + fail("Expected security exception to be thrown."); + } catch (SecurityException e) { + // Pass + } + } + + /** + * Re-run the trace point taking tests from TestTraceArguments to confirm + * that they aren't blocked by default when security is enabled. + */ + public void testApplicationTraceNotBlocked() { + Object anyOldObject = new java.lang.Thread(); + Object anotherOldObject = new java.lang.Thread(); + System.setProperty("com.ibm.jvm.enableLegacyTraceSecurity", FALSE.toString()); + + int componentId = Trace.registerApplication("TestTraceArguments",TEMPLATES); + + Trace.set("maximal=TestTraceArguments"); + + // Tests for all the different Trace.trace() methods + + // public static void trace(int, int) + Trace.trace(componentId,0); + // public static void trace(int, int) + Trace.trace(componentId,1); + // public static void trace(int, int, java.lang.String) + Trace.trace(componentId,2,"hello"); + // public static void trace(int, int, java.lang.String, java.lang.String) + Trace.trace(componentId,3,"hello1","hello2"); + // public static void trace(int, int, java.lang.String, java.lang.String, java.lang.String) + Trace.trace(componentId,4,"hello1","hello2","hello3"); + // public static void trace(int, int, java.lang.String, java.lang.Object) + Trace.trace(componentId,5,"hello",anyOldObject); + // public static void trace(int, int, java.lang.Object, java.lang.String) + Trace.trace(componentId,6,anyOldObject,"hello"); + // public static void trace(int, int, java.lang.String, int) + Trace.trace(componentId,7,"hello",9); + // public static void trace(int, int, int, java.lang.String) + Trace.trace(componentId,8,9,"hello"); + // public static void trace(int, int, java.lang.String, long) + Trace.trace(componentId,9,"hello",9L); + // public static void trace(int, int, long, java.lang.String) + Trace.trace(componentId,10,Long.MAX_VALUE,"hello"); + // public static void trace(int, int, java.lang.String, byte) + Trace.trace(componentId,11,"hello",Byte.MAX_VALUE); + // public static void trace(int, int, byte, java.lang.String) + Trace.trace(componentId,12,Byte.MAX_VALUE,"hello"); + // public static void trace(int, int, java.lang.String, char) + Trace.trace(componentId,13,"hello",'X'); + // public static void trace(int, int, char, java.lang.String) + Trace.trace(componentId,14,'X',"hello"); + // public static void trace(int, int, java.lang.String, float) + Trace.trace(componentId,15,"hello",1.0f); + // public static void trace(int, int, float, java.lang.String) + Trace.trace(componentId,16,Double.MAX_VALUE,"hello"); + // public static void trace(int, int, java.lang.String, double) + Trace.trace(componentId,17,"hello",Double.MAX_VALUE); + // public static void trace(int, int, double, java.lang.String) + Trace.trace(componentId,18,Double.MAX_VALUE,"hello"); + // public static void trace(int, int, java.lang.Object) + Trace.trace(componentId,19,anyOldObject); + // public static void trace(int, int, java.lang.Object, java.lang.Object) + Trace.trace(componentId,20,anyOldObject,anotherOldObject); + // public static void trace(int, int, int) + Trace.trace(componentId,21,9); + // public static void trace(int, int, int, int) + Trace.trace(componentId,22,-1,9); + // public static void trace(int, int, int, int, int) + Trace.trace(componentId,23,999999,0,9); + // public static void trace(int, int, long) + Trace.trace(componentId,24,9L); + // public static void trace(int, int, long, long) + Trace.trace(componentId,25,0L,9L); + // public static void trace(int, int, long, long, long) + Trace.trace(componentId,26,Long.MAX_VALUE,Long.MIN_VALUE,9L); + // public static void trace(int, int, byte) + Trace.trace(componentId,27,9); + // public static void trace(int, int, byte, byte) + Trace.trace(componentId,28,-1,0); + // public static void trace(int, int, byte, byte, byte) + Trace.trace(componentId,29,Byte.MAX_VALUE,Byte.MIN_VALUE,0); + // public static void trace(int, int, char) + Trace.trace(componentId,30,'A'); + // public static void trace(int, int, char, char) + Trace.trace(componentId,31,'A','B'); + // public static void trace(int, int, char, char, char) + Trace.trace(componentId,32,'A','B','C'); + // public static void trace(int, int, float) + Trace.trace(componentId,33,1.0f); + // public static void trace(int, int, float, float) + Trace.trace(componentId,34,Float.MAX_VALUE,Float.MIN_VALUE); + // public static void trace(int, int, float, float, float) + Trace.trace(componentId,35,Float.POSITIVE_INFINITY,Float.NEGATIVE_INFINITY,Float.NaN); + // public static void trace(int, int, double) + Trace.trace(componentId,36,999999); + // public static void trace(int, int, double, double) + Trace.trace(componentId,37,0,-1); + // public static void trace(int, int, double, double, double) + Trace.trace(componentId,38,Double.MAX_VALUE,Double.MIN_VALUE,0); + // public static void trace(int, int, java.lang.String, java.lang.Object, java.lang.String) + Trace.trace(componentId,39,"hello1",anyOldObject,"hello2"); + // public static void trace(int, int, java.lang.Object, java.lang.String, java.lang.Object) + Trace.trace(componentId,40,anyOldObject,"hello",anotherOldObject); + // public static void trace(int, int, java.lang.String, int, java.lang.String) + Trace.trace(componentId,41,"hello1",9,"hello2"); + // public static void trace(int, int, int, java.lang.String, int) + Trace.trace(componentId,42,9,"hello1",9); + // public static void trace(int, int, java.lang.String, long, java.lang.String) + Trace.trace(componentId,43,"hello1",9L,"hello2"); + // public static void trace(int, int, long, java.lang.String, long) + Trace.trace(componentId,44,9L,"hello",9L); + // public static void trace(int, int, java.lang.String, byte, java.lang.String) + Trace.trace(componentId,45,"hello1",0,"hello2"); + // public static void trace(int, int, byte, java.lang.String, byte) + Trace.trace(componentId,46,1,"hello",1); + // public static void trace(int, int, java.lang.String, char, java.lang.String) + Trace.trace(componentId,47,"hello1",'A',"hello2"); + // public static void trace(int, int, char, java.lang.String, char) + Trace.trace(componentId,48,'A',"hello",'B'); + // public static void trace(int, int, java.lang.String, float, java.lang.String) + Trace.trace(componentId,49,"hello1",1.0f,"hello2"); + // public static void trace(int, int, float, java.lang.String, float) + Trace.trace(componentId,50,-1.0f,"hello",1.0f); + // public static void trace(int, int, java.lang.String, double, java.lang.String) + Trace.trace(componentId,51,"hello1",1,"hello2"); + // public static void trace(int, int, double, java.lang.String, double) + Trace.trace(componentId,52,-1,"hello",1); + + Trace.trace(componentId,53); // test passed message, validation in script + } + + /** + * Re-run the trace point taking tests from TestTraceArguments to confirm + * that they are blocked when security is enabled. A bit long winded but it's + * the only way to make sure I didn't miss adding security to one of the + * Trace.trace() methods. + */ + public void testApplicationTraceBlocked() { + + System.clearProperty("com.ibm.jvm.enableLegacyTraceSecurity"); + + Object anyOldObject = new java.lang.Thread(); + Object anotherOldObject = new java.lang.Thread(); + + int componentId = 100; + + try { + componentId = Trace.registerApplication("TestTraceArguments", + TEMPLATES); + } catch (SecurityException e) { + /* Pass */ + } + + try { + Trace.set("maximal=TestTraceArguments"); + } catch (SecurityException e) { + /* Pass */ + } + + // Tests for all the different Trace.trace() methods + + // public static void trace(int, int) + try { + Trace.trace(componentId, 0); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int) + try { + Trace.trace(componentId, 1); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, java.lang.String) + try { + Trace.trace(componentId, 2, "hello"); + // java.lang.String) + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, java.lang.String, + try { + Trace.trace(componentId, 3, "hello1", "hello2"); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, java.lang.String, + // java.lang.String, java.lang.String) + try { + Trace.trace(componentId, 4, "hello1", "hello2", "hello3"); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, java.lang.String, + // java.lang.Object) + try { + Trace.trace(componentId, 5, "hello", anyOldObject); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, java.lang.Object, + // java.lang.String) + try { + Trace.trace(componentId, 6, anyOldObject, "hello"); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, java.lang.String, int) + try { + Trace.trace(componentId, 7, "hello", 9); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, int, java.lang.String) + try { + Trace.trace(componentId, 8, 9, "hello"); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, java.lang.String, long) + try { + Trace.trace(componentId, 9, "hello", 9L); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, long, java.lang.String) + try { + Trace.trace(componentId, 10, Long.MAX_VALUE, "hello"); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, java.lang.String, byte) + try { + Trace.trace(componentId, 11, "hello", Byte.MAX_VALUE); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, byte, java.lang.String) + try { + Trace.trace(componentId, 12, Byte.MAX_VALUE, "hello"); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, java.lang.String, char) + try { + Trace.trace(componentId, 13, "hello", 'X'); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, char, java.lang.String) + try { + Trace.trace(componentId, 14, 'X', "hello"); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, java.lang.String, float) + try { + Trace.trace(componentId, 15, "hello", 1.0f); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, float, java.lang.String) + try { + Trace.trace(componentId, 16, Double.MAX_VALUE, "hello"); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, java.lang.String, double) + try { + Trace.trace(componentId, 17, "hello", Double.MAX_VALUE); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, double, java.lang.String) + try { + Trace.trace(componentId, 18, Double.MAX_VALUE, "hello"); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, java.lang.Object) + try { + Trace.trace(componentId, 19, anyOldObject); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, java.lang.Object, + // java.lang.Object) + try { + Trace.trace(componentId, 20, anyOldObject, anotherOldObject); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, int) + try { + Trace.trace(componentId, 21, 9); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, int, int) + try { + Trace.trace(componentId, 22, -1, 9); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, int, int, int) + try { + Trace.trace(componentId, 23, 999999, 0, 9); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, long) + try { + Trace.trace(componentId, 24, 9L); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, long, long) + try { + Trace.trace(componentId, 25, 0L, 9L); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, long, long, long) + try { + Trace.trace(componentId, 26, Long.MAX_VALUE, Long.MIN_VALUE, 9L); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, byte) + try { + Trace.trace(componentId, 27, 9); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, byte, byte) + try { + Trace.trace(componentId, 28, -1, 0); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, byte, byte, byte) + try { + Trace.trace(componentId, 29, Byte.MAX_VALUE, Byte.MIN_VALUE, 0); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, char) + try { + Trace.trace(componentId, 30, 'A'); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, char, char) + try { + Trace.trace(componentId, 31, 'A', 'B'); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, char, char, char) + try { + Trace.trace(componentId, 32, 'A', 'B', 'C'); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, float) + try { + Trace.trace(componentId, 33, 1.0f); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, float, float) + try { + Trace.trace(componentId, 34, Float.MAX_VALUE, Float.MIN_VALUE); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, float, float, float) + try { + Trace.trace(componentId, 35, Float.POSITIVE_INFINITY, + Float.NEGATIVE_INFINITY, Float.NaN); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, double) + try { + Trace.trace(componentId, 36, 999999); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, double, double) + try { + Trace.trace(componentId, 37, 0, -1); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, double, double, double) + try { + Trace.trace(componentId, 38, Double.MAX_VALUE, Double.MIN_VALUE, 0); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, java.lang.String, + // java.lang.Object, java.lang.String) + try { + Trace.trace(componentId, 39, "hello1", anyOldObject, "hello2"); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, java.lang.Object, + // java.lang.String, java.lang.Object) + try { + Trace.trace(componentId, 40, anyOldObject, "hello", + anotherOldObject); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, java.lang.String, int, + // java.lang.String) + try { + Trace.trace(componentId, 41, "hello1", 9, "hello2"); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, int, java.lang.String, int) + try { + Trace.trace(componentId, 42, 9, "hello1", 9); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, java.lang.String, long, + // java.lang.String) + try { + Trace.trace(componentId, 43, "hello1", 9L, "hello2"); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, long, java.lang.String, long) + try { + Trace.trace(componentId, 44, 9L, "hello", 9L); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, java.lang.String, byte, + // java.lang.String) + try { + Trace.trace(componentId, 45, "hello1", 0, "hello2"); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, byte, java.lang.String, byte) + try { + Trace.trace(componentId, 46, 1, "hello", 1); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, java.lang.String, char, + // java.lang.String) + try { + Trace.trace(componentId, 47, "hello1", 'A', "hello2"); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, char, java.lang.String, char) + try { + Trace.trace(componentId, 48, 'A', "hello", 'B'); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, java.lang.String, float, + // java.lang.String) + try { + Trace.trace(componentId, 49, "hello1", 1.0f, "hello2"); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, float, java.lang.String, + // float) + try { + Trace.trace(componentId, 50, -1.0f, "hello", 1.0f); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, java.lang.String, double, + // java.lang.String) + try { + Trace.trace(componentId, 51, "hello1", 1, "hello2"); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + // public static void trace(int, int, double, java.lang.String, + // double) + try { + Trace.trace(componentId, 52, -1, "hello", 1); + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + try { + Trace.trace(componentId, 53); // test passed message + fail("Expected SecurityException to be thrown"); + } catch (SecurityException e) { + /* Pass */ + } + } + + +} diff --git a/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/GenerateJavaCoreAndSnap.java b/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/GenerateJavaCoreAndSnap.java new file mode 100644 index 00000000000..be8287af91e --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/GenerateJavaCoreAndSnap.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.trace.tests.apptrace; +/* +* Generate a javacore and snap dump via the dump and trace APIs for +* use with TestJavaCoreAndSnap +*/ + +public class GenerateJavaCoreAndSnap { + + public static void main(String[] args) { + + System.out.println("GenerateJavaCoreAndSnap: started"); + + // Take a javacore + com.ibm.jvm.Dump.JavaDump(); + + // Take a snap dump + com.ibm.jvm.Trace.snap(); + + System.out.println("GenerateJavaCoreAndSnap: finished"); + + } + +} + diff --git a/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/TestGetMicros.java b/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/TestGetMicros.java new file mode 100644 index 00000000000..3526275525a --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/TestGetMicros.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.trace.tests.apptrace; + +import com.ibm.jvm.Trace; + +public class TestGetMicros { + + public static void main(String[] args) { + + System.out.println("TestGetMicros: started"); + + long startMicroTime = Trace.getMicros(); + long stopMicroTime = 0; + + /* Wait 10 seconds. */ + try { + Thread.sleep(10000); + } catch (InterruptedException e ) { + // Do nothing. + } + stopMicroTime = Trace.getMicros(); + + long microDuration = stopMicroTime - startMicroTime; + + // Is the duration > 0 and less than a minute? + if( microDuration > 0 && microDuration < 60*(1000000) ) { + System.out.println("TestGetMicros: TEST PASSED"); + System.exit(0); + } else { + System.out.println("TestGetMicros: TEST FAILED"); + System.out.printf("Start time was %d, end time was %d, duration was %d\n", startMicroTime, stopMicroTime, microDuration); + System.exit(1); + } + } +} + diff --git a/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/TestJavaCoreAndSnap.java b/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/TestJavaCoreAndSnap.java new file mode 100644 index 00000000000..0330a3ca43f --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/TestJavaCoreAndSnap.java @@ -0,0 +1,219 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.trace.tests.apptrace; + +/* + * Compare the current thread trace from a javacore and a snap trace file + * (formatted to only contain that thread) to make sure the data is the same. + * + * The javacore and snap dump should have been taken as close together as possible. + */ +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.LinkedList; +import java.util.List; + +public class TestJavaCoreAndSnap { + + private static final String XEHSTTYPE = "3XEHSTTYPE "; + + public static void main(String[] args) { + + System.out.println("TestJavaCoreAndSnap: started"); + + if( args.length != 2 ) { + System.err.println("Expected two arguments, javacore and formatted snap trace."); + exit(1); + } + + String javacoreFileName = args[0]; + String traceFileName = args[1]; + + System.out.printf("Comparing current thread trace in %s and %s\n", javacoreFileName, traceFileName); + + String[] jcTrace = extractJCTrace(javacoreFileName); + + String lastTPid = getTracePointId(jcTrace[0]); + + //System.err.println("Last tpid is: " + lastTPid); + + String[] snapTrace = extractFormattedTrace(traceFileName); + + int jcTraceIndex = 0; + int snapTraceIndex = 0; + boolean found = false; + + /* The test expects the snap trace to have been taken after the javacore. + * To enable us to match the trace points up skip the first few tracepoints in the + * snap file until we get to the one that mentions the javacore (and which should be + * the last trace point in the javacore). + */ + for( ; snapTraceIndex < snapTrace.length; snapTraceIndex++) { + //System.err.println("Checking id: " + getTracePointId(snapTrace[snapTraceIndex]) + " from " + snapTrace[snapTraceIndex]); + if( "j9dmp.9".equals(getTracePointId(snapTrace[snapTraceIndex])) && + snapTrace[snapTraceIndex].contains(javacoreFileName) ) { + found = true; + //System.err.println("snapTraceIndex is: " + snapTraceIndex); + break; + } + } + + if( found == false ) { + System.err.println("Couldn't match start of trace in java core to start of trace in snap."); + exit(2); + } + + for( ; snapTraceIndex < snapTrace.length && jcTraceIndex < jcTrace.length; snapTraceIndex++, jcTraceIndex++) { + String snapTraceLine = snapTrace[snapTraceIndex]; + String jcTraceLine = jcTrace[jcTraceIndex]; + String snapTraceID = getTracePointId(snapTraceLine); + String jcTraceID = getTracePointId(jcTraceLine); + if( !snapTraceID.equals(jcTraceID) ) { + System.err.println("Trace point lines did not match:" + jcTraceID + " vs " + snapTraceID ); + System.err.println("Javacore: " + jcTraceLine); + System.err.println("Snap trace: " + snapTraceLine); + + exit(3); + } else { +// System.err.println("Trace point lines matched:" + jcTraceID + " vs " + snapTraceID ); + } + // Checking the content would be good *but* things like number formatting (with or without leading + // 0's) make it impractical even if we ignore the case. +/* String snapTraceDetail = getTracePointDetail(snapTraceLine); + String jcTraceDetail = getTracePointDetail(jcTraceLine); + if( !snapTraceDetail.equalsIgnoreCase(jcTraceDetail) ) { + System.err.println("Trace point lines did not match:" + jcTraceID + " vs " + snapTraceID ); + System.err.println("Javacore: '" + jcTraceDetail + "'"); + System.err.println("Snap trace: '" + snapTraceDetail + "'"); + + exit(3); + } else { + System.err.println("Trace point lines matched:" + jcTraceDetail + " vs " + snapTraceDetail ); + }*/ + } + + exit(0); + + } + + private static void exit(int code) { + if( code == 0 ) { + System.out.println("TestJavaCoreAndSnap: passed"); + } else { + System.out.println("TestJavaCoreAndSnap: failed"); + } + System.out.println("TestJavaCoreAndSnap: finished"); + System.exit(code); + } + + private static String[] extractJCTrace(String javacoreFileName) { + + BufferedReader in = null; + List traceLines = new LinkedList(); + + try { + try { + in = new BufferedReader(new FileReader(javacoreFileName)); + } catch (FileNotFoundException e) { + System.err.println("File: " + javacoreFileName + " not found."); + return null; + } + + String str; + try { + while( (str = in.readLine()) != null ) { + if( str.startsWith(XEHSTTYPE) ) { + traceLines.add(str.substring(XEHSTTYPE.length())); + } + } + } catch (IOException e) { + System.err.println("Failed to read from file: " + javacoreFileName); + return null; + } + } finally { + try { + in.close(); + } catch (IOException e) { + // Not much we can do about this. + } + } + + return traceLines.toArray(new String[0]); + + } + + private static String[] extractFormattedTrace(String traceFileName) { + + BufferedReader in = null; + List traceLines = new LinkedList(); + + try { + try { + in = new BufferedReader(new FileReader(traceFileName)); + } catch (FileNotFoundException e) { + System.err.println("File: " + traceFileName + " not found."); + return null; + } + + String str; + try { + while( (str = in.readLine()) != null ) { + if( str.startsWith("Time") ) { + // The next line is the start of the actual trace, + // we're past the header information. + break; + } + } + while( (str = in.readLine()) != null ) { + // Add these to the start of the list to reverse them into the same order as + // the ones from javacore. + traceLines.add(0, str); + } + } catch (IOException e) { + System.err.println("Failed to read from file: " + traceFileName); + return null; + } + } finally { + try { + in.close(); + } catch (IOException e) { + // Not much we can do about this. + } + } + + return traceLines.toArray(new String[0]); + + } + + // This works for both javacore trace and snap trace because javacore has the timezone in + // position 1 and formatted snap trace has the thread id in the same column. + private static String getTracePointId(String traceLine) { + return traceLine.split("\\s+")[2]; + } + + private static String getTracePointDetail(String traceLine) { + return traceLine.split("\\s+",5)[4].trim(); + } +} + diff --git a/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/TestMultipleApplications.java b/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/TestMultipleApplications.java new file mode 100644 index 00000000000..e090e591593 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/TestMultipleApplications.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.trace.tests.apptrace; + +import com.ibm.jvm.Trace; + +public class TestMultipleApplications { + + public static void main(String[] args) { + + String[] templates = new String[4]; + + System.out.println("TestMultipleApplications: started"); + templates[0] = Trace.EVENT; + templates[1] = Trace.EVENT + "Tracepoint #01 %s"; + templates[2] = Trace.EVENT + "Tracepoint #02 %s"; + templates[3] = Trace.EVENT + "Tracepoint #03 %s"; + + int componentId1 = Trace.registerApplication("App1",templates); + int componentId2 = Trace.registerApplication("App2",templates); + + Trace.set("print={App1,App2}"); + + // Trace from both components. + Trace.trace(componentId1, 1, "from application 1"); + Trace.trace(componentId2, 1, "from application 2"); + Trace.trace(componentId1, 2, "from application 1"); + Trace.trace(componentId2, 2, "from application 2"); + Trace.trace(componentId1, 3, "from application 1"); + Trace.trace(componentId2, 3, "from application 2"); + + System.out.println("TestMultipleApplications: finished"); + + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/TestSnap.java b/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/TestSnap.java new file mode 100644 index 00000000000..dae5dc0825c --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/TestSnap.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.trace.tests.apptrace; + +import com.ibm.jvm.Trace; + +public class TestSnap { + + public static void main(String[] args) { + + System.out.println("TestSnap: started"); + + // Test the Trace.snap() method + Trace.snap(); + + System.out.println("TestSnap: finished"); + + } + +} + diff --git a/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/TestSuspendResume.java b/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/TestSuspendResume.java new file mode 100644 index 00000000000..eb55b245125 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/TestSuspendResume.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.trace.tests.apptrace; + +import com.ibm.jvm.Trace; + +public class TestSuspendResume { + + public static void main(String[] args) { + + String[] templates = new String[4]; + + System.out.println("TestSuspendResume: started"); + templates[0] = Trace.EVENT; + templates[1] = Trace.EVENT + "Tracepoint #01"; + templates[2] = Trace.EVENT + "Tracepoint #02 Error: TEST FAILED"; + templates[3] = Trace.EVENT + "Tracepoint #03"; + + + final int componentId = Trace.registerApplication("TestSuspendResume",templates); + Trace.set("print=TestSuspendResume"); + Trace.trace(componentId,1); + + // Test the Trace.suspend() method + Trace.suspend(); + Trace.trace(componentId,2); // trace suspended, so this tracepoint should not appear + + /* Check that trace *is not* produced on another thread. */ + Thread t = new Thread() { + + public void run() { + Trace.trace(componentId, 1); + Trace.trace(componentId, 2); + Trace.trace(componentId, 3); + } + + }; + t.start(); + try { + t.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + // Test the Trace.resume() method + Trace.resume(); + Trace.trace(componentId,3); + + System.out.println("TestSuspendResume: finished"); + + } + +} + diff --git a/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/TestSuspendResumeThis.java b/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/TestSuspendResumeThis.java new file mode 100644 index 00000000000..fff09d4e506 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/TestSuspendResumeThis.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.trace.tests.apptrace; + +import com.ibm.jvm.Trace; + +public class TestSuspendResumeThis { + + + public static void main(String[] args) { + + String[] templates = new String[4]; + + System.out.println("TestSuspendResumeThis: started"); + templates[0] = Trace.EVENT; + templates[1] = Trace.EVENT + "Tracepoint #01 Thread: %s"; + templates[2] = Trace.EVENT + "Tracepoint #02 Thread: %s"; + templates[3] = Trace.EVENT + "Tracepoint #03 Thread: %s"; + + + final int componentId = Trace.registerApplication("TestSuspendResumeThis",templates); + Trace.set("print=TestSuspendResumeThis"); + Trace.trace(componentId, 1, Thread.currentThread().getName()); + + // Test the Trace.suspendThis() method + Trace.suspendThis(); + Trace.trace(componentId, 2, Thread.currentThread().getName()); // trace suspended, so this tracepoint should not appear + + /* Check that trace *is* still produced on another thread. */ + Thread t = new Thread() { + + public void run() { + Trace.trace(componentId, 1, Thread.currentThread().getName()); + Trace.trace(componentId, 2, Thread.currentThread().getName()); + Trace.trace(componentId, 3, Thread.currentThread().getName()); + } + + }; + t.start(); + try { + t.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + // Test the Trace.resumeThis() method + Trace.resumeThis(); + Trace.trace(componentId, 3, Thread.currentThread().getName()); + + System.out.println("TestSuspendResumeThis: finished"); + + } + +} + diff --git a/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/TestTraceArguments.java b/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/TestTraceArguments.java new file mode 100644 index 00000000000..dee4541a6da --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/TestTraceArguments.java @@ -0,0 +1,209 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.trace.tests.apptrace; + +import com.ibm.jvm.Trace; + +public class TestTraceArguments { + + public static void main(String[] args) { + + String[] templates = new String[54]; + Object anyOldObject = new java.lang.Thread(); + Object anotherOldObject = new java.lang.Thread(); + + System.out.println("TestTraceArguments: started"); + + templates[0] = Trace.EVENT; + templates[1] = Trace.EVENT + "Tracepoint #1 "; + templates[2] = Trace.EVENT + "Tracepoint #2 insert1=%s"; + templates[3] = Trace.EVENT + "Tracepoint #3 insert1=%s insert2=%s"; + templates[4] = Trace.EVENT + "Tracepoint #4 insert1=%s insert2=%s insert3=%s"; + templates[5] = Trace.EVENT + "Tracepoint #5 insert1=%s insert2=%p"; + templates[6] = Trace.EVENT + "Tracepoint #6 insert1=%p insert2=%s"; + templates[7] = Trace.EVENT + "Tracepoint #7 insert1=%s insert2=%d"; + templates[8] = Trace.EVENT + "Tracepoint #8 insert1=%d insert2=%s"; + templates[9] = Trace.EVENT + "Tracepoint #9 insert1=%s insert2=%lld"; + templates[10] = Trace.EVENT + "Tracepoint #10 insert1=%lld insert2=%s"; // mkomine@77003 + templates[11] = Trace.EVENT + "Tracepoint #11 insert1=%s insert2=%d"; + templates[12] = Trace.EVENT + "Tracepoint #12 insert1=%d insert2=%s"; + templates[13] = Trace.EVENT + "Tracepoint #13 insert1=%s insert2=%c"; + templates[14] = Trace.EVENT + "Tracepoint #14 insert1=%c insert2=%s"; + templates[15] = Trace.EVENT + "Tracepoint #15 insert1=%s insert2=%f"; + templates[16] = Trace.EVENT + "Tracepoint #16 insert1=%e insert2=%s"; + templates[17] = Trace.EVENT + "Tracepoint #17 insert1=%s insert2=%e"; + templates[18] = Trace.EVENT + "Tracepoint #18 insert1=%e insert2=%s"; + templates[19] = Trace.EVENT + "Tracepoint #19 insert1=%p"; + templates[20] = Trace.EVENT + "Tracepoint #20 insert1=%p insert2=%p"; + templates[21] = Trace.EVENT + "Tracepoint #21 insert1=%d"; + templates[22] = Trace.EVENT + "Tracepoint #22 insert1=%d insert2=%d"; + templates[23] = Trace.EVENT + "Tracepoint #23 insert1=%d insert2=%d insert3=%d"; + templates[24] = Trace.EVENT + "Tracepoint #24 insert1=%lld"; + templates[25] = Trace.EVENT + "Tracepoint #25 insert1=%lld insert2=%lld"; + templates[26] = Trace.EVENT + "Tracepoint #26 insert1=%lld insert2=%lld insert3=%lld"; + templates[27] = Trace.EVENT + "Tracepoint #27 insert1=%d"; + templates[28] = Trace.EVENT + "Tracepoint #28 insert1=%d insert2=%d"; + templates[29] = Trace.EVENT + "Tracepoint #29 insert1=%d insert2=%d insert3=%d"; + templates[30] = Trace.EVENT + "Tracepoint #30 insert1=%c"; + templates[31] = Trace.EVENT + "Tracepoint #31 insert1=%c insert2=%c"; + templates[32] = Trace.EVENT + "Tracepoint #32 insert1=%c insert2=%c insert3=%c"; + templates[33] = Trace.EVENT + "Tracepoint #33 insert1=%f"; + templates[34] = Trace.EVENT + "Tracepoint #34 insert1=%e insert2=%e"; + templates[35] = Trace.EVENT + "Tracepoint #35 insert1=%f insert2=%f insert3=%f"; + templates[36] = Trace.EVENT + "Tracepoint #36 insert1=%d"; + templates[37] = Trace.EVENT + "Tracepoint #37 insert1=%d insert2=%d"; + templates[38] = Trace.EVENT + "Tracepoint #38 insert1=%f insert2=%f insert3=%f"; + templates[39] = Trace.EVENT + "Tracepoint #39 insert1=%s insert2=%p insert3=%s"; + templates[40] = Trace.EVENT + "Tracepoint #40 insert1=%p insert2=%s insert3=%p"; + templates[41] = Trace.EVENT + "Tracepoint #41 insert1=%s insert2=%d insert3=%s"; + templates[42] = Trace.EVENT + "Tracepoint #42 insert1=%d insert2=%s insert3=%d"; + templates[43] = Trace.EVENT + "Tracepoint #43 insert1=%s insert2=%lld insert3=%s"; + templates[44] = Trace.EVENT + "Tracepoint #44 insert1=%lld insert2=%s insert3=%lld"; + templates[45] = Trace.EVENT + "Tracepoint #45 insert1=%s insert2=%d insert3=%s"; + templates[46] = Trace.EVENT + "Tracepoint #46 insert1=%d insert2=%s insert3=%d"; + templates[47] = Trace.EVENT + "Tracepoint #47 insert1=%s insert2=%c insert3=%s"; + templates[48] = Trace.EVENT + "Tracepoint #48 insert1=%c insert2=%s insert3=%c"; + templates[49] = Trace.EVENT + "Tracepoint #49 insert1=%s insert2=%f insert3=%s"; + templates[50] = Trace.EVENT + "Tracepoint #50 insert1=%f insert2=%s insert3=%f"; + templates[51] = Trace.EVENT + "Tracepoint #51 insert1=%s insert2=%d insert3=%s"; + templates[52] = Trace.EVENT + "Tracepoint #52 insert1=%d insert2=%s insert3=%d"; + templates[53] = Trace.EVENT + "Tracepoint #53 TEST PASSED"; + + int componentId = Trace.registerApplication("TestTraceArguments",templates); + + Trace.set("print=TestTraceArguments"); + + // Tests for all the different Trace.trace() methods + + // public static void trace(int, int) + Trace.trace(componentId,0); + // public static void trace(int, int) + Trace.trace(componentId,1); + // public static void trace(int, int, java.lang.String) + Trace.trace(componentId,2,"hello"); + // public static void trace(int, int, java.lang.String, java.lang.String) + Trace.trace(componentId,3,"hello1","hello2"); + // public static void trace(int, int, java.lang.String, java.lang.String, java.lang.String) + Trace.trace(componentId,4,"hello1","hello2","hello3"); + // public static void trace(int, int, java.lang.String, java.lang.Object) + Trace.trace(componentId,5,"hello",anyOldObject); + // public static void trace(int, int, java.lang.Object, java.lang.String) + Trace.trace(componentId,6,anyOldObject,"hello"); + // public static void trace(int, int, java.lang.String, int) + Trace.trace(componentId,7,"hello",9); + // public static void trace(int, int, int, java.lang.String) + Trace.trace(componentId,8,9,"hello"); + // public static void trace(int, int, java.lang.String, long) + Trace.trace(componentId,9,"hello",9L); + // public static void trace(int, int, long, java.lang.String) + Trace.trace(componentId,10,Long.MAX_VALUE,"hello"); + // public static void trace(int, int, java.lang.String, byte) + Trace.trace(componentId,11,"hello",Byte.MAX_VALUE); + // public static void trace(int, int, byte, java.lang.String) + Trace.trace(componentId,12,Byte.MAX_VALUE,"hello"); + // public static void trace(int, int, java.lang.String, char) + Trace.trace(componentId,13,"hello",'X'); + // public static void trace(int, int, char, java.lang.String) + Trace.trace(componentId,14,'X',"hello"); + // public static void trace(int, int, java.lang.String, float) + Trace.trace(componentId,15,"hello",1.0f); + // public static void trace(int, int, float, java.lang.String) + Trace.trace(componentId,16,Double.MAX_VALUE,"hello"); + // public static void trace(int, int, java.lang.String, double) + Trace.trace(componentId,17,"hello",Double.MAX_VALUE); + // public static void trace(int, int, double, java.lang.String) + Trace.trace(componentId,18,Double.MAX_VALUE,"hello"); + // public static void trace(int, int, java.lang.Object) + Trace.trace(componentId,19,anyOldObject); + // public static void trace(int, int, java.lang.Object, java.lang.Object) + Trace.trace(componentId,20,anyOldObject,anotherOldObject); + // public static void trace(int, int, int) + Trace.trace(componentId,21,9); + // public static void trace(int, int, int, int) + Trace.trace(componentId,22,-1,9); + // public static void trace(int, int, int, int, int) + Trace.trace(componentId,23,999999,0,9); + // public static void trace(int, int, long) + Trace.trace(componentId,24,9L); + // public static void trace(int, int, long, long) + Trace.trace(componentId,25,0L,9L); + // public static void trace(int, int, long, long, long) + Trace.trace(componentId,26,Long.MAX_VALUE,Long.MIN_VALUE,9L); + // public static void trace(int, int, byte) + Trace.trace(componentId,27,9); + // public static void trace(int, int, byte, byte) + Trace.trace(componentId,28,-1,0); + // public static void trace(int, int, byte, byte, byte) + Trace.trace(componentId,29,Byte.MAX_VALUE,Byte.MIN_VALUE,0); + // public static void trace(int, int, char) + Trace.trace(componentId,30,'A'); + // public static void trace(int, int, char, char) + Trace.trace(componentId,31,'A','B'); + // public static void trace(int, int, char, char, char) + Trace.trace(componentId,32,'A','B','C'); + // public static void trace(int, int, float) + Trace.trace(componentId,33,1.0f); + // public static void trace(int, int, float, float) + Trace.trace(componentId,34,Float.MAX_VALUE,Float.MIN_VALUE); + // public static void trace(int, int, float, float, float) + Trace.trace(componentId,35,Float.POSITIVE_INFINITY,Float.NEGATIVE_INFINITY,Float.NaN); + // public static void trace(int, int, double) + Trace.trace(componentId,36,999999); + // public static void trace(int, int, double, double) + Trace.trace(componentId,37,0,-1); + // public static void trace(int, int, double, double, double) + Trace.trace(componentId,38,Double.MAX_VALUE,Double.MIN_VALUE,0); + // public static void trace(int, int, java.lang.String, java.lang.Object, java.lang.String) + Trace.trace(componentId,39,"hello1",anyOldObject,"hello2"); + // public static void trace(int, int, java.lang.Object, java.lang.String, java.lang.Object) + Trace.trace(componentId,40,anyOldObject,"hello",anotherOldObject); + // public static void trace(int, int, java.lang.String, int, java.lang.String) + Trace.trace(componentId,41,"hello1",9,"hello2"); + // public static void trace(int, int, int, java.lang.String, int) + Trace.trace(componentId,42,9,"hello1",9); + // public static void trace(int, int, java.lang.String, long, java.lang.String) + Trace.trace(componentId,43,"hello1",9L,"hello2"); + // public static void trace(int, int, long, java.lang.String, long) + Trace.trace(componentId,44,9L,"hello",9L); + // public static void trace(int, int, java.lang.String, byte, java.lang.String) + Trace.trace(componentId,45,"hello1",0,"hello2"); + // public static void trace(int, int, byte, java.lang.String, byte) + Trace.trace(componentId,46,1,"hello",1); + // public static void trace(int, int, java.lang.String, char, java.lang.String) + Trace.trace(componentId,47,"hello1",'A',"hello2"); + // public static void trace(int, int, char, java.lang.String, char) + Trace.trace(componentId,48,'A',"hello",'B'); + // public static void trace(int, int, java.lang.String, float, java.lang.String) + Trace.trace(componentId,49,"hello1",1.0f,"hello2"); + // public static void trace(int, int, float, java.lang.String, float) + Trace.trace(componentId,50,-1.0f,"hello",1.0f); + // public static void trace(int, int, java.lang.String, double, java.lang.String) + Trace.trace(componentId,51,"hello1",1,"hello2"); + // public static void trace(int, int, double, java.lang.String, double) + Trace.trace(componentId,52,-1,"hello",1); + + Trace.trace(componentId,53); // test passed message, validation in script + System.out.println("TestTraceArguments: finished"); + + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/TestTraceTypes.java b/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/TestTraceTypes.java new file mode 100644 index 00000000000..ea9b45aaa53 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/trace/tests/apptrace/TestTraceTypes.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.trace.tests.apptrace; + +import com.ibm.jvm.Trace; + +public class TestTraceTypes { + + public static void main(String[] args) { + + String[] templates = new String[5]; + + System.out.println("TestMultipleApplications: started"); + templates[0] = Trace.EVENT; + templates[1] = Trace.EVENT + "Tracepoint #01 - Event Type"; + templates[2] = Trace.ENTRY+ "Tracepoint #02 - Entry Type"; + templates[3] = Trace.EXIT + "Tracepoint #03 - Exit Type"; + templates[4] = Trace.EXCEPTION_EXIT + "Tracepoint #04 - Exception Exit Type"; + + int componentId = Trace.registerApplication("TestTraceTypes",templates); + + Trace.set("print=TestTraceTypes"); + + // Trace from both components. + Trace.trace(componentId, 1); + Trace.trace(componentId, 2); + Trace.trace(componentId, 3); + Trace.trace(componentId, 4); + + System.out.println("TestTraceTypes: finished"); + + } + +} diff --git a/test/functional/RasapiTest/src/com/ibm/trace/tests/jstacktrace/HelloWorld.java b/test/functional/RasapiTest/src/com/ibm/trace/tests/jstacktrace/HelloWorld.java new file mode 100644 index 00000000000..187565d0540 --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/trace/tests/jstacktrace/HelloWorld.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.trace.tests.jstacktrace; + +public class HelloWorld +{ + + public static void main(String args[]) { + System.err.println("Hello, world"); + } + +} \ No newline at end of file diff --git a/test/functional/RasapiTest/src/com/ibm/trace/tests/jstacktrace/TriggerDumpTracePoint.java b/test/functional/RasapiTest/src/com/ibm/trace/tests/jstacktrace/TriggerDumpTracePoint.java new file mode 100644 index 00000000000..32b422ade1d --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/trace/tests/jstacktrace/TriggerDumpTracePoint.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.trace.tests.jstacktrace; + +/* + * Licensed Materials - Property of IBM + * (C) Copyright IBM Corp. 2009. All Rights Reserved. + * US Government Users Restricted Rights - Use, duplication or + * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. + */ + +/** + * This class is used to trigger a tracepoint in the dump system by calling + * the com.ibm.jvm.Dump API. + * + * Andrew Hall + * andhall@uk.ibm.com + */ +public class TriggerDumpTracePoint +{ + + public static void main(String args[]) { + com.ibm.jvm.Dump.JavaDump(); + } + +} \ No newline at end of file diff --git a/test/functional/RasapiTest/src/com/ibm/trace/tests/trace_subscriber/TraceQueue.java b/test/functional/RasapiTest/src/com/ibm/trace/tests/trace_subscriber/TraceQueue.java new file mode 100644 index 00000000000..e5b5e7831fe --- /dev/null +++ b/test/functional/RasapiTest/src/com/ibm/trace/tests/trace_subscriber/TraceQueue.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2016, 2021 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ +package com.ibm.trace.tests.trace_subscriber; + +public class TraceQueue { + public static void main(String[] args) { + int result = 0; + int publishers = 0; + int subscribers = 0; + + /* invoked with com.ibm.ras.tests.TraceQueue publishers subscribers */ + if (args.length == 2) { + try { + publishers = Integer.parseInt(args[0]); + } catch (NumberFormatException e) { + System.err.println("Invalid value specified for publishers, requires an integer greater than 0"); + result = -1; + } + + try { + subscribers = Integer.parseInt(args[1]); + } catch (NumberFormatException e) { + System.err.println("Invalid value specified for subscribers, requires an integer greater than 0"); + result = -1; + } + } + + /* print usage if there's been a problem */ + if (args.length != 2 || result != 0) { + System.err.println("Usage: com.ibm.ras.tests.TraceQueue publishers subscribers"); + System.exit(-1); + } + + /* try running the test */ + if (!runQueueTests(subscribers, publishers)) { + System.err.println("FAILED"); + result = -2; + } else { + System.out.println("PASSED"); + result = 0; + } + + System.exit(result); + } + + public static native boolean runQueueTests(int subscribers, int publishers); +} \ No newline at end of file diff --git a/test/functional/RasapiTest/test.xml b/test/functional/RasapiTest/test.xml new file mode 100644 index 00000000000..31fd330a4d3 --- /dev/null +++ b/test/functional/RasapiTest/test.xml @@ -0,0 +1,155 @@ + + + + + + + Ant script to run the tests for the com.ibm.jvm.Dump API. + First it runs the suite of tests defined in DumpAPISuite + Then it runs the Security tests with security on and the permission not granted. + This should show the correct methods are blocked. + Then it adds com.ibm.jvm.DumpPermssion to the security file and reruns the Basic and + QuerySetReset tests to confirm they work when security is on. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file