From 639030bd6d6e89ebf796e4e05853f7265cf96789 Mon Sep 17 00:00:00 2001 From: David Roazen Date: Fri, 10 May 2013 17:26:07 -0400 Subject: [PATCH] Enable convenient display of diff engine output in Bamboo, plus misc. minor test-related improvements -Diff engine output is now included in the actual exception message thrown as a result of an MD5 mismatch, which allows it to be conveniently viewed on the main page of a build in Bamboo. Minor Additional Improvements: -WalkerTestSpec now auto-detects test class name via new JVMUtils.getCallingClass() method, and the test class name is now included as a regular part of integration test output for each test. -Fix race condition in MD5DB.ensureMd5DbDirectory() -integrationtests dir is now cleaned by "ant clean" GSA-915 #resolve --- build.xml | 3 + .../sting/utils/classloader/JVMUtils.java | 58 +++++++ .../test/org/broadinstitute/sting/MD5DB.java | 151 ++++++++++-------- .../org/broadinstitute/sting/MD5Mismatch.java | 19 ++- .../org/broadinstitute/sting/WalkerTest.java | 64 +++++--- .../utils/classloader/JVMUtilsUnitTest.java | 75 +++++++++ .../sting/queue/pipeline/PipelineTest.scala | 2 +- 7 files changed, 270 insertions(+), 102 deletions(-) create mode 100644 public/java/test/org/broadinstitute/sting/utils/classloader/JVMUtilsUnitTest.java diff --git a/build.xml b/build.xml index 56bf4f0cd..2e9df4d5e 100644 --- a/build.xml +++ b/build.xml @@ -1031,6 +1031,7 @@ + @@ -1043,6 +1044,7 @@ + @@ -1078,6 +1080,7 @@ + diff --git a/public/java/src/org/broadinstitute/sting/utils/classloader/JVMUtils.java b/public/java/src/org/broadinstitute/sting/utils/classloader/JVMUtils.java index 2f5115dfa..8f4958f6c 100644 --- a/public/java/src/org/broadinstitute/sting/utils/classloader/JVMUtils.java +++ b/public/java/src/org/broadinstitute/sting/utils/classloader/JVMUtils.java @@ -248,4 +248,62 @@ public class JVMUtils { interfaces.add(interfaceClass.getSimpleName()); return Utils.join(", ", interfaces); } + + /** + * Returns the Class that invoked the specified "callee" class by examining the runtime stack. + * The calling class is defined as the first class below the callee class on the stack. + * + * For example, given callee == MyClass and the following runtime stack: + * + * JVMUtils.getCallingClass(MyClass) <-- top + * MyClass.foo() + * MyClass.bar() + * OtherClass.foo() + * OtherClass.bar() + * etc. + * + * this method would return OtherClass, since its methods invoked the methods in MyClass. + * + * Considers only the occurrence of the callee class on the stack that is closest to the top + * (even if there are multiple, non-contiguous occurrences). + * + * @param callee Class object for the class whose calling class we want to locate + * @return Class object for the class that invoked the callee class, or null if + * no calling class was found + * @throws IllegalArgumentException if the callee class is not found on the runtime stack + * @throws IllegalStateException if we get an error while trying to load the Class object for the calling + * class reported on the runtime stack + */ + public static Class getCallingClass( final Class callee ) { + final StackTraceElement[] stackTrace = new Throwable().getStackTrace(); + final String calleeClassName = callee.getName(); + + // Start examining the stack at the second-from-the-top position, to remove + // this method call (ie., the call to getCallingClass() itself) from consideration. + int stackTraceIndex = 1; + + // Find the first occurrence of the callee on the runtime stack. Need to use String comparison + // unfortunately, due to limitations of the StackTraceElement class. + while ( stackTraceIndex < stackTrace.length && ! stackTrace[stackTraceIndex].getClassName().equals(calleeClassName) ) { + stackTraceIndex++; + } + + // Make sure we actually found the callee class on the stack + if ( stackTraceIndex == stackTrace.length ) { + throw new IllegalArgumentException(String.format("Specified callee %s is not present on the call stack", callee.getSimpleName())); + } + + // Now find the caller class, which will be the class below the callee on the stack + while ( stackTraceIndex < stackTrace.length && stackTrace[stackTraceIndex].getClassName().equals(calleeClassName) ) { + stackTraceIndex++; + } + + try { + return stackTraceIndex < stackTrace.length ? Class.forName(stackTrace[stackTraceIndex].getClassName()) : null; + } + catch ( ClassNotFoundException e ) { + throw new IllegalStateException(String.format("Could not find caller class %s from the runtime stack in the classpath", + stackTrace[stackTraceIndex].getClassName())); + } + } } diff --git a/public/java/test/org/broadinstitute/sting/MD5DB.java b/public/java/test/org/broadinstitute/sting/MD5DB.java index 2b0d52a11..7bd6f7bc4 100644 --- a/public/java/test/org/broadinstitute/sting/MD5DB.java +++ b/public/java/test/org/broadinstitute/sting/MD5DB.java @@ -97,7 +97,12 @@ public class MD5DB { if ( ! dir.exists() ) { System.out.printf("##### Creating MD5 db %s%n", LOCAL_MD5_DB_DIR); if ( ! dir.mkdir() ) { - throw new ReviewedStingException("Infrastructure failure: failed to create md5 directory " + LOCAL_MD5_DB_DIR); + // Need to check AGAIN whether the dir exists, because we might be doing multi-process parallelism + // within the same working directory, and another GATK instance may have come along and created the + // directory between the calls to exists() and mkdir() above. + if ( ! dir.exists() ) { + throw new ReviewedStingException("Infrastructure failure: failed to create md5 directory " + LOCAL_MD5_DB_DIR); + } } } } @@ -203,98 +208,106 @@ public class MD5DB { } public static class MD5Match { - final String actualMD5, expectedMD5; - final String failMessage; - boolean failed; + public final String actualMD5, expectedMD5; + public final String failMessage; + public final String diffEngineOutput; + public final boolean failed; - public MD5Match(final String actualMD5, final String expectedMD5, final String failMessage, final boolean failed) { + public MD5Match(final String actualMD5, final String expectedMD5, final String failMessage, final String diffEngineOutput, final boolean failed) { this.actualMD5 = actualMD5; this.expectedMD5 = expectedMD5; this.failMessage = failMessage; + this.diffEngineOutput = diffEngineOutput; this.failed = failed; } } /** - * Tests a file MD5 against an expected value, returning the MD5. NOTE: This function WILL throw an exception if the MD5s are different. - * @param name Name of the test. + * Tests a file MD5 against an expected value, returning an MD5Match object containing a description of the + * match or mismatch. In case of a mismatch, outputs a description of the mismatch to various log files/streams. + * + * NOTE: This function WILL NOT throw an exception if the MD5s are different. + * + * @param testName Name of the test. + * @param testClassName Name of the class that contains the test. * @param resultsFile File to MD5. * @param expectedMD5 Expected MD5 value. * @param parameterize If true or if expectedMD5 is an empty string, will print out the calculated MD5 instead of error text. - * @return The calculated MD5. + * @return an MD5Match object containing a description of the match/mismatch. Will have its "failed" field set + * to true if there was a mismatch (unless we're using the "parameterize" argument) */ - public MD5Match assertMatchingMD5(final String name, final File resultsFile, final String expectedMD5, final boolean parameterize) { - final String actualMD5 = testFileMD5(name, resultsFile, expectedMD5, parameterize); - String failMessage = null; + public MD5Match testFileMD5(final String testName, final String testClassName, final File resultsFile, final String expectedMD5, final boolean parameterize) { + final String actualMD5 = calculateFileMD5(resultsFile); + String diffEngineOutput = ""; + String failMessage = ""; boolean failed = false; + // copy md5 to integrationtests + updateMD5Db(actualMD5, resultsFile); + if (parameterize || expectedMD5.equals("")) { - // Don't assert - } else if ( actualMD5.equals(expectedMD5) ) { - //BaseTest.log(String.format(" => %s PASSED (expected=%s)", name, expectedMD5)); - } else { + BaseTest.log(String.format("PARAMETERIZATION: file %s has md5 = %s", resultsFile, actualMD5)); + } else if ( ! expectedMD5.equals(actualMD5) ) { failed = true; - failMessage = String.format("%s has mismatching MD5s: expected=%s observed=%s", name, expectedMD5, actualMD5); + failMessage = String.format("%s:%s has mismatching MD5s: expected=%s observed=%s", testClassName, testName, expectedMD5, actualMD5); + diffEngineOutput = logMD5MismatchAndGetDiffEngineOutput(testName, testClassName, expectedMD5, actualMD5); } - return new MD5Match(actualMD5, expectedMD5, failMessage, failed); + return new MD5Match(actualMD5, expectedMD5, failMessage, diffEngineOutput, failed); } - /** - * Tests a file MD5 against an expected value, returning the MD5. NOTE: This function WILL NOT throw an exception if the MD5s are different. - * @param name Name of the test. - * @param resultsFile File to MD5. - * @param expectedMD5 Expected MD5 value. - * @param parameterize If true or if expectedMD5 is an empty string, will print out the calculated MD5 instead of error text. - * @return The calculated MD5. + * Calculates the MD5 for the specified file and returns it as a String + * + * @param file file whose MD5 to calculate + * @return file's MD5 in String form + * @throws RuntimeException if the file could not be read */ - public String testFileMD5(final String name, final File resultsFile, final String expectedMD5, final boolean parameterize) { + public String calculateFileMD5( final File file ) { try { - final String filemd5sum = Utils.calcMD5(getBytesFromFile(resultsFile)); - - // - // copy md5 to integrationtests - // - updateMD5Db(filemd5sum, resultsFile); - - if (parameterize || expectedMD5.equals("")) { - BaseTest.log(String.format("PARAMETERIZATION: file %s has md5 = %s", resultsFile, filemd5sum)); - } else { - //System.out.println(String.format("Checking MD5 for %s [calculated=%s, expected=%s]", resultsFile, filemd5sum, expectedMD5)); - //System.out.flush(); - - if ( ! expectedMD5.equals(filemd5sum) ) { - // we are going to fail for real in assertEquals (so we are counted by the testing framework). - // prepare ourselves for the comparison - System.out.printf("##### Test %s is going to fail #####%n", name); - String pathToExpectedMD5File = getMD5FilePath(expectedMD5, "[No DB file found]"); - String pathToFileMD5File = getMD5FilePath(filemd5sum, "[No DB file found]"); - BaseTest.log(String.format("expected %s", expectedMD5)); - BaseTest.log(String.format("calculated %s", filemd5sum)); - BaseTest.log(String.format("diff %s %s", pathToExpectedMD5File, pathToFileMD5File)); - - md5MismatchStream.printf("%s\t%s\t%s%n", expectedMD5, filemd5sum, name); - md5MismatchStream.flush(); - - // inline differences - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - final PrintStream ps = new PrintStream(baos); - DiffEngine.SummaryReportParams params = new DiffEngine.SummaryReportParams(ps, 20, 10, 0, MAX_RAW_DIFFS_TO_SUMMARIZE, false); - boolean success = DiffEngine.simpleDiffFiles(new File(pathToExpectedMD5File), new File(pathToFileMD5File), MAX_RECORDS_TO_READ, params); - if ( success ) { - final String content = baos.toString(); - BaseTest.log(content); - System.out.printf("Note that the above list is not comprehensive. At most 20 lines of output, and 10 specific differences will be listed. Please use -T DiffObjects -R public/testdata/exampleFASTA.fasta -m %s -t %s to explore the differences more freely%n", - pathToExpectedMD5File, pathToFileMD5File); - } - ps.close(); - } - } - - return filemd5sum; - } catch (Exception e) { - throw new RuntimeException("Failed to read bytes from calls file: " + resultsFile, e); + return Utils.calcMD5(getBytesFromFile(file)); + } + catch ( Exception e ) { + throw new RuntimeException("Failed to read bytes from file: " + file + " for MD5 calculation", e); } } + + /** + * Logs a description (including diff engine output) of the MD5 mismatch between the expectedMD5 + * and actualMD5 to a combination of BaseTest.log(), the md5MismatchStream, and stdout, then returns + * the diff engine output. + * + * @param testName name of the test that generated the mismatch + * @param testClassName name of the class containing the test that generated the mismatch + * @param expectedMD5 the MD5 we were expecting from this test + * @param actualMD5 the MD5 we actually calculated from the test output + * @return the diff engine output produced while logging the description of the mismatch + */ + private String logMD5MismatchAndGetDiffEngineOutput(final String testName, final String testClassName, final String expectedMD5, final String actualMD5) { + System.out.printf("##### Test %s:%s is going to fail #####%n", testClassName, testName); + String pathToExpectedMD5File = getMD5FilePath(expectedMD5, "[No DB file found]"); + String pathToFileMD5File = getMD5FilePath(actualMD5, "[No DB file found]"); + BaseTest.log(String.format("expected %s", expectedMD5)); + BaseTest.log(String.format("calculated %s", actualMD5)); + BaseTest.log(String.format("diff %s %s", pathToExpectedMD5File, pathToFileMD5File)); + + md5MismatchStream.printf("%s\t%s\t%s%n", expectedMD5, actualMD5, testName); + md5MismatchStream.flush(); + + // inline differences + String diffEngineOutput = ""; + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final PrintStream ps = new PrintStream(baos); + DiffEngine.SummaryReportParams params = new DiffEngine.SummaryReportParams(ps, 20, 10, 0, MAX_RAW_DIFFS_TO_SUMMARIZE, false); + boolean success = DiffEngine.simpleDiffFiles(new File(pathToExpectedMD5File), new File(pathToFileMD5File), MAX_RECORDS_TO_READ, params); + if ( success ) { + diffEngineOutput = baos.toString(); + BaseTest.log(diffEngineOutput); + System.out.printf("Note that the above list is not comprehensive. At most 20 lines of output, and 10 specific differences will be listed. Please use -T DiffObjects -R public/testdata/exampleFASTA.fasta -m %s -t %s to explore the differences more freely%n", + pathToExpectedMD5File, pathToFileMD5File); + } + ps.close(); + + return diffEngineOutput; + } } diff --git a/public/java/test/org/broadinstitute/sting/MD5Mismatch.java b/public/java/test/org/broadinstitute/sting/MD5Mismatch.java index e459a24ce..56acedaf0 100644 --- a/public/java/test/org/broadinstitute/sting/MD5Mismatch.java +++ b/public/java/test/org/broadinstitute/sting/MD5Mismatch.java @@ -35,29 +35,32 @@ import java.util.List; * @since Date created */ public class MD5Mismatch extends Exception { - final List actuals, expecteds; + final List actuals, expecteds, diffEngineOutputs; - public MD5Mismatch(final String actual, final String expected) { - this(Collections.singletonList(actual), Collections.singletonList(expected)); + public MD5Mismatch(final String actual, final String expected, final String diffEngineOutput) { + this(Collections.singletonList(actual), Collections.singletonList(expected), Collections.singletonList(diffEngineOutput)); } - public MD5Mismatch(final List actuals, final List expecteds) { - super(formatMessage(actuals, expecteds)); + public MD5Mismatch(final List actuals, final List expecteds, final List diffEngineOutputs) { + super(formatMessage(actuals, expecteds, diffEngineOutputs)); this.actuals = actuals; this.expecteds = expecteds; + this.diffEngineOutputs = diffEngineOutputs; } @Override public String toString() { - return formatMessage(actuals, expecteds); + return formatMessage(actuals, expecteds, diffEngineOutputs); } - private final static String formatMessage(final List actuals, final List expecteds) { + private static String formatMessage(final List actuals, final List expecteds, final List diffEngineOutputs) { final StringBuilder b = new StringBuilder("MD5 mismatch: "); for ( int i = 0; i < actuals.size(); i++ ) { - if ( i > 1 ) b.append("\t\t\n"); + if ( i >= 1 ) b.append("\t\t\n\n"); b.append("actual ").append(actuals.get(i)); b.append(" expected ").append(expecteds.get(i)); + b.append("\nDiff Engine Output:\n"); + b.append(diffEngineOutputs.get(i)); } return b.toString(); } diff --git a/public/java/test/org/broadinstitute/sting/WalkerTest.java b/public/java/test/org/broadinstitute/sting/WalkerTest.java index dd5a2b0a7..40f1f7bcd 100644 --- a/public/java/test/org/broadinstitute/sting/WalkerTest.java +++ b/public/java/test/org/broadinstitute/sting/WalkerTest.java @@ -34,6 +34,7 @@ import org.broadinstitute.sting.gatk.CommandLineGATK; import org.broadinstitute.sting.gatk.GenomeAnalysisEngine; import org.broadinstitute.sting.gatk.phonehome.GATKRunReport; import org.broadinstitute.sting.utils.Utils; +import org.broadinstitute.sting.utils.classloader.JVMUtils; import org.broadinstitute.variant.bcf2.BCF2Utils; import org.broadinstitute.sting.utils.collections.Pair; import org.broadinstitute.variant.vcf.VCFCodec; @@ -73,10 +74,6 @@ public class WalkerTest extends BaseTest { return md5DB; } - public MD5DB.MD5Match assertMatchingMD5(final String name, final File resultsFile, final String expectedMD5) { - return getMd5DB().assertMatchingMD5(name, resultsFile, expectedMD5, parameterize()); - } - public void validateOutputBCFIfPossible(final String name, final File resultFile) { final File bcfFile = BCF2Utils.shadowBCF(resultFile); if ( bcfFile != null && bcfFile.exists() ) { @@ -114,15 +111,15 @@ public class WalkerTest extends BaseTest { } } - public List assertMatchingMD5s(final String name, List resultFiles, List expectedMD5s) { + public List assertMatchingMD5s(final String testName, final String testClassName, List resultFiles, List expectedMD5s) { List md5s = new ArrayList(); List fails = new ArrayList(); for (int i = 0; i < resultFiles.size(); i++) { - MD5DB.MD5Match result = assertMatchingMD5(name, resultFiles.get(i), expectedMD5s.get(i)); - validateOutputBCFIfPossible(name, resultFiles.get(i)); + MD5DB.MD5Match result = getMd5DB().testFileMD5(testName, testClassName, resultFiles.get(i), expectedMD5s.get(i), parameterize()); + validateOutputBCFIfPossible(testName, resultFiles.get(i)); if ( ! result.failed ) { - validateOutputIndex(name, resultFiles.get(i)); + validateOutputIndex(testName, resultFiles.get(i)); md5s.add(result.expectedMD5); } else { fails.add(result); @@ -132,14 +129,17 @@ public class WalkerTest extends BaseTest { if ( ! fails.isEmpty() ) { List actuals = new ArrayList(); List expecteds = new ArrayList(); + List diffEngineOutputs = new ArrayList(); + for ( final MD5DB.MD5Match fail : fails ) { actuals.add(fail.actualMD5); expecteds.add(fail.expectedMD5); + diffEngineOutputs.add(fail.diffEngineOutput); logger.warn("Fail: " + fail.failMessage); } - final MD5Mismatch failure = new MD5Mismatch(actuals, expecteds); - Assert.fail(failure.toString(), failure); + final MD5Mismatch failure = new MD5Mismatch(actuals, expecteds, diffEngineOutputs); + Assert.fail(failure.toString()); } return md5s; @@ -170,6 +170,9 @@ public class WalkerTest extends BaseTest { boolean includeImplicitArgs = true; boolean includeShadowBCF = true; + // Name of the test class that created this test case + private Class testClass; + // the default output path for the integration test private File outputFileLocation = null; @@ -183,6 +186,7 @@ public class WalkerTest extends BaseTest { this.args = args; this.nOutputFiles = md5s.size(); this.md5s = md5s; + this.testClass = getCallingTestClass(); } public WalkerTestSpec(String args, List exts, List md5s) { @@ -194,12 +198,22 @@ public class WalkerTest extends BaseTest { this.nOutputFiles = md5s.size(); this.md5s = md5s; this.exts = exts; + this.testClass = getCallingTestClass(); } public WalkerTestSpec(String args, int nOutputFiles, Class expectedException) { this.args = args; this.nOutputFiles = nOutputFiles; this.expectedException = expectedException; + this.testClass = getCallingTestClass(); + } + + private Class getCallingTestClass() { + return JVMUtils.getCallingClass(getClass()); + } + + public String getTestClassName() { + return testClass.getSimpleName(); } public String getArgsWithImplicitArgs() { @@ -306,7 +320,7 @@ public class WalkerTest extends BaseTest { if ( spec.expectsException() ) { // this branch handles the case were we are testing that a walker will fail as expected - return executeTest(name, spec.getOutputFileLocation(), null, tmpFiles, args, spec.getExpectedException()); + return executeTest(name, spec.getTestClassName(), spec.getOutputFileLocation(), null, tmpFiles, args, spec.getExpectedException()); } else { List md5s = new LinkedList(); md5s.addAll(spec.md5s); @@ -316,7 +330,7 @@ public class WalkerTest extends BaseTest { md5s.add(md5); tmpFiles.add(spec.auxillaryFiles.get(md5)); } - return executeTest(name, spec.getOutputFileLocation(), md5s, tmpFiles, args, null); + return executeTest(name, spec.getTestClassName(), spec.getOutputFileLocation(), md5s, tmpFiles, args, null); } } @@ -337,35 +351,37 @@ public class WalkerTest extends BaseTest { /** * execute the test, given the following: - * @param name the name of the test + * @param testName the name of the test + * @param testClassName the name of the class that contains the test * @param md5s the list of md5s * @param tmpFiles the temp file corresponding to the md5 list * @param args the argument list * @param expectedException the expected exception or null * @return a pair of file and string lists */ - private Pair, List> executeTest(String name, File outputFileLocation, List md5s, List tmpFiles, String args, Class expectedException) { - if ( md5s != null ) qcMD5s(name, md5s); + private Pair, List> executeTest(String testName, String testClassName, File outputFileLocation, List md5s, List tmpFiles, String args, Class expectedException) { + if ( md5s != null ) qcMD5s(testName, md5s); if (outputFileLocation != null) args += " -o " + outputFileLocation.getAbsolutePath(); - executeTest(name, args, expectedException); + executeTest(testName, testClassName, args, expectedException); if ( expectedException != null ) { return null; } else { // we need to check MD5s - return new Pair, List>(tmpFiles, assertMatchingMD5s(name, tmpFiles, md5s)); + return new Pair, List>(tmpFiles, assertMatchingMD5s(testName, testClassName, tmpFiles, md5s)); } } /** * execute the test, given the following: - * @param name the name of the test - * @param args the argument list + * @param testName the name of the test + * @param testClassName the name of the class that contains the test + * @param args the argument list * @param expectedException the expected exception or null */ - private void executeTest(String name, String args, Class expectedException) { + private void executeTest(String testName, String testClassName, String args, Class expectedException) { CommandLineGATK instance = new CommandLineGATK(); String[] command = Utils.escapeExpressions(args); @@ -374,7 +390,7 @@ public class WalkerTest extends BaseTest { try { final String now = new SimpleDateFormat("HH:mm:ss").format(new Date()); final String cmdline = Utils.join(" ",command); - System.out.println(String.format("[%s] Executing test %s with GATK arguments: %s", now, name, cmdline)); + System.out.println(String.format("[%s] Executing test %s:%s with GATK arguments: %s", now, testClassName, testName, cmdline)); // also write the command line to the HTML log for convenient follow-up // do the replaceAll so paths become relative to the current BaseTest.log(cmdline.replaceAll(publicTestDirRoot, "").replaceAll(privateTestDirRoot, "")); @@ -388,8 +404,8 @@ public class WalkerTest extends BaseTest { // it's the type we expected //System.out.println(String.format(" => %s PASSED", name)); } else { - final String message = String.format("Test %s expected exception %s but instead got %s with error message %s", - name, expectedException, e.getClass(), e.getMessage()); + final String message = String.format("Test %s:%s expected exception %s but instead got %s with error message %s", + testClassName, testName, expectedException, e.getClass(), e.getMessage()); if ( e.getCause() != null ) { final ByteArrayOutputStream baos = new ByteArrayOutputStream(); final PrintStream ps = new PrintStream(baos); @@ -409,7 +425,7 @@ public class WalkerTest extends BaseTest { if ( expectedException != null ) { if ( ! gotAnException ) // we expected an exception but didn't see it - Assert.fail(String.format("Test %s expected exception %s but none was thrown", name, expectedException.toString())); + Assert.fail(String.format("Test %s:%s expected exception %s but none was thrown", testClassName, testName, expectedException.toString())); } else { if ( CommandLineExecutable.result != 0) { throw new RuntimeException("Error running the GATK with arguments: " + args); diff --git a/public/java/test/org/broadinstitute/sting/utils/classloader/JVMUtilsUnitTest.java b/public/java/test/org/broadinstitute/sting/utils/classloader/JVMUtilsUnitTest.java new file mode 100644 index 000000000..6ffd47f37 --- /dev/null +++ b/public/java/test/org/broadinstitute/sting/utils/classloader/JVMUtilsUnitTest.java @@ -0,0 +1,75 @@ +/* +* Copyright (c) 2012 The Broad Institute +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, +* copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following +* conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR +* THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +package org.broadinstitute.sting.utils.classloader; + +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +public class JVMUtilsUnitTest { + + // Test classes used by the tests for JVMUtils.getCallingClass(): + private static class DummyTestClass1 { + public static Class getCaller( final Class callee ) { + return DummyTestClass2.getCaller(callee); + } + } + + private static class DummyTestClass2 { + public static Class getCaller( final Class callee ) { + return DummyTestClass3.getCaller(callee); + } + } + + private static class DummyTestClass3 { + public static Class getCaller( final Class callee ) { + return JVMUtils.getCallingClass(callee); + } + } + + @DataProvider( name = "TestGetCallingClassDataProvider" ) + public Object[][] getTestCallingClassTestData() { + return new Object[][] { + { DummyTestClass1.class, JVMUtilsUnitTest.class }, + { DummyTestClass2.class, DummyTestClass1.class }, + { DummyTestClass3.class, DummyTestClass2.class } + }; + } + + @Test( dataProvider = "TestGetCallingClassDataProvider" ) + public void testGetCallingClass( final Class callee, final Class expectedCaller ) { + final Class reportedCaller = DummyTestClass1.getCaller(callee); + + Assert.assertEquals(reportedCaller, expectedCaller, + String.format("Wrong calling class returned from DummyTestClass1.getCaller(%s)", callee.getSimpleName())); + } + + @Test( expectedExceptions = IllegalArgumentException.class ) + public void testGetCallingClassCalleeNotFound() { + // Trying to get the calling class of a class not on the runtime stack should produce an exception. + JVMUtils.getCallingClass(DummyTestClass1.class); + } +} diff --git a/public/scala/test/org/broadinstitute/sting/queue/pipeline/PipelineTest.scala b/public/scala/test/org/broadinstitute/sting/queue/pipeline/PipelineTest.scala index 03b38ffe9..6741e4107 100644 --- a/public/scala/test/org/broadinstitute/sting/queue/pipeline/PipelineTest.scala +++ b/public/scala/test/org/broadinstitute/sting/queue/pipeline/PipelineTest.scala @@ -113,7 +113,7 @@ object PipelineTest extends BaseTest with Logging { private def assertMatchingMD5s(name: String, fileMD5s: Traversable[(File, String)], parameterize: Boolean) { var failed = 0 for ((file, expectedMD5) <- fileMD5s) { - val calculatedMD5 = md5DB.testFileMD5(name, file, expectedMD5, parameterize) + val calculatedMD5 = md5DB.testFileMD5(name, "", file, expectedMD5, parameterize).actualMD5 if (!parameterize && expectedMD5 != "" && expectedMD5 != calculatedMD5) failed += 1 }