2010-04-20 07:00:08 +08:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2010 The Broad Institute
|
2010-04-20 23:26:32 +08:00
|
|
|
*
|
2010-04-20 07:00:08 +08:00
|
|
|
* Permission is hereby granted, free of charge, to any person
|
|
|
|
|
* obtaining a copy of this software and associated documentation
|
2010-04-20 23:26:32 +08:00
|
|
|
* files (the "Software"), to deal in the Software without
|
2010-04-20 07:00:08 +08:00
|
|
|
* 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:
|
2010-04-20 23:26:32 +08:00
|
|
|
*
|
2010-04-20 07:00:08 +08:00
|
|
|
* The above copyright notice and this permission notice shall be
|
|
|
|
|
* included in all copies or substantial portions of the Software.
|
|
|
|
|
*
|
2010-04-20 23:26:32 +08:00
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
2010-04-20 07:00:08 +08:00
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
|
2009-09-05 03:13:37 +08:00
|
|
|
package org.broadinstitute.sting;
|
|
|
|
|
|
2009-09-09 09:02:04 +08:00
|
|
|
import junit.framework.Assert;
|
|
|
|
|
import org.broadinstitute.sting.gatk.CommandLineExecutable;
|
|
|
|
|
import org.broadinstitute.sting.gatk.CommandLineGATK;
|
2010-04-20 07:00:08 +08:00
|
|
|
import org.broadinstitute.sting.utils.collections.Pair;
|
2010-03-05 04:20:58 +08:00
|
|
|
import org.broadinstitute.sting.utils.StingException;
|
2009-09-09 09:02:04 +08:00
|
|
|
import org.broadinstitute.sting.utils.Utils;
|
2009-09-05 03:13:37 +08:00
|
|
|
import org.junit.Test;
|
2010-06-01 00:06:16 +08:00
|
|
|
import org.apache.commons.io.FileUtils;
|
2009-09-05 03:13:37 +08:00
|
|
|
|
2009-09-09 09:02:04 +08:00
|
|
|
import java.io.File;
|
|
|
|
|
import java.io.FileInputStream;
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.io.InputStream;
|
2009-09-05 03:13:37 +08:00
|
|
|
import java.math.BigInteger;
|
2009-09-09 09:02:04 +08:00
|
|
|
import java.security.MessageDigest;
|
2010-03-05 00:02:21 +08:00
|
|
|
import java.util.*;
|
2009-09-05 03:13:37 +08:00
|
|
|
|
|
|
|
|
public class WalkerTest extends BaseTest {
|
2010-03-05 04:20:58 +08:00
|
|
|
// the default output path for the integration test
|
|
|
|
|
private File outputFileLocation = null;
|
|
|
|
|
|
2010-06-01 00:06:16 +08:00
|
|
|
/**
|
|
|
|
|
* Subdirectory under the ant build directory where we store integration test md5 results
|
|
|
|
|
*/
|
|
|
|
|
public static final String MD5_FILE_DB_SUBDIR = "integrationtests";
|
|
|
|
|
|
2010-03-05 04:20:58 +08:00
|
|
|
public void setOutputFileLocation(File outputFileLocation) {
|
|
|
|
|
this.outputFileLocation = outputFileLocation;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-01 00:06:16 +08:00
|
|
|
private static void ensureMd5DbDirectory() {
|
|
|
|
|
// todo -- make path
|
|
|
|
|
File dir = new File(MD5_FILE_DB_SUBDIR);
|
|
|
|
|
if ( ! dir.exists() ) {
|
|
|
|
|
System.out.printf("##### Creating MD5 db %s%n", MD5_FILE_DB_SUBDIR);
|
|
|
|
|
if ( ! dir.mkdir() ) {
|
|
|
|
|
throw new StingException("Infrastructure failure: failed to create md5 directory " + MD5_FILE_DB_SUBDIR);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static File getFileForMD5(final String md5) {
|
|
|
|
|
final String basename = String.format("%s.integrationtest", md5);
|
|
|
|
|
return new File(MD5_FILE_DB_SUBDIR + "/" + basename);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void updateMD5Db(final String md5, final File resultsFile) {
|
|
|
|
|
// todo -- copy results file to DB dir if needed under filename for md5
|
|
|
|
|
final File dbFile = getFileForMD5(md5);
|
|
|
|
|
if ( ! dbFile.exists() ) {
|
|
|
|
|
// the file isn't already in the db, copy it over
|
|
|
|
|
System.out.printf("##### Updating MD5 file: %s%n", dbFile.getPath());
|
|
|
|
|
try {
|
|
|
|
|
FileUtils.copyFile(resultsFile, dbFile);
|
|
|
|
|
} catch ( IOException e ) {
|
|
|
|
|
throw new StingException(e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
System.out.printf("##### MD5 file is up to date: %s%n", dbFile.getPath());
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static String getMD5Path(final String md5, final String valueIfNotFound) {
|
|
|
|
|
// todo -- look up the result in the directory and return the path if it exists
|
|
|
|
|
final File dbFile = getFileForMD5(md5);
|
|
|
|
|
return dbFile.exists() ? dbFile.getPath() : valueIfNotFound;
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-05 04:20:58 +08:00
|
|
|
public String assertMatchingMD5(final String name, final File resultsFile, final String expectedMD5) {
|
2009-09-05 03:13:37 +08:00
|
|
|
try {
|
|
|
|
|
byte[] bytesOfMessage = getBytesFromFile(resultsFile);
|
|
|
|
|
byte[] thedigest = MessageDigest.getInstance("MD5").digest(bytesOfMessage);
|
|
|
|
|
BigInteger bigInt = new BigInteger(1, thedigest);
|
|
|
|
|
String filemd5sum = bigInt.toString(16);
|
2009-09-09 09:02:04 +08:00
|
|
|
while (filemd5sum.length() < 32) filemd5sum = "0" + filemd5sum; // pad to length 32
|
2010-06-01 00:06:16 +08:00
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// copy md5 to integrationtests
|
|
|
|
|
//
|
|
|
|
|
updateMD5Db(filemd5sum, resultsFile);
|
|
|
|
|
|
2010-03-05 04:20:58 +08:00
|
|
|
if (parameterize() || expectedMD5.equals("")) {
|
2009-10-21 07:31:13 +08:00
|
|
|
System.out.println(String.format("PARAMETERIZATION[%s]: file %s has md5 = %s, stated expectation is %s, equal? = %b",
|
2010-03-05 04:20:58 +08:00
|
|
|
name, resultsFile, filemd5sum, expectedMD5, filemd5sum.equals(expectedMD5)));
|
2009-09-05 03:13:37 +08:00
|
|
|
} else {
|
2009-10-21 07:31:13 +08:00
|
|
|
System.out.println(String.format("Checking MD5 for %s [calculated=%s, expected=%s]", resultsFile, filemd5sum, expectedMD5));
|
|
|
|
|
System.out.flush();
|
2010-06-01 00:06:16 +08:00
|
|
|
|
|
|
|
|
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 fail #####%n", name);
|
|
|
|
|
String pathToExpectedMD5File = getMD5Path(expectedMD5, "[No DB file found]");
|
|
|
|
|
String pathToFileMD5File = getMD5Path(filemd5sum, "[No DB file found]");
|
2010-06-03 06:26:32 +08:00
|
|
|
System.out.printf("##### Path to expected file (MD5=%s): %s%n", expectedMD5, pathToExpectedMD5File);
|
|
|
|
|
System.out.printf("##### Path to calculated file (MD5=%s): %s%n", filemd5sum, pathToFileMD5File);
|
2010-06-01 00:06:16 +08:00
|
|
|
System.out.printf("##### Diff command: diff %s %s%n", pathToExpectedMD5File, pathToFileMD5File);
|
|
|
|
|
|
|
|
|
|
// todo -- add support for simple inline display of the first N differences for text file
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-09 09:02:04 +08:00
|
|
|
Assert.assertEquals(name + " Mismatching MD5s", expectedMD5, filemd5sum);
|
2009-10-21 07:31:13 +08:00
|
|
|
System.out.println(String.format(" => %s PASSED", name));
|
2009-09-05 03:13:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return filemd5sum;
|
2010-03-05 04:20:58 +08:00
|
|
|
} catch (Exception e) {
|
2010-03-05 06:46:15 +08:00
|
|
|
throw new RuntimeException("Failed to read bytes from calls file: " + resultsFile, e);
|
2009-09-05 03:13:37 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-05 04:20:58 +08:00
|
|
|
public List<String> assertMatchingMD5s(final String name, List<File> resultFiles, List<String> expectedMD5s) {
|
2009-09-05 03:13:37 +08:00
|
|
|
List<String> md5s = new ArrayList<String>();
|
2010-03-05 04:20:58 +08:00
|
|
|
for (int i = 0; i < resultFiles.size(); i++) {
|
2009-09-05 03:13:37 +08:00
|
|
|
String md5 = assertMatchingMD5(name, resultFiles.get(i), expectedMD5s.get(i));
|
|
|
|
|
md5s.add(i, md5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return md5s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static byte[] getBytesFromFile(File file) throws IOException {
|
|
|
|
|
InputStream is = new FileInputStream(file);
|
|
|
|
|
|
|
|
|
|
// Get the size of the file
|
|
|
|
|
long length = file.length();
|
|
|
|
|
|
|
|
|
|
if (length > Integer.MAX_VALUE) {
|
|
|
|
|
// File is too large
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create the byte array to hold the data
|
2010-03-05 04:20:58 +08:00
|
|
|
byte[] bytes = new byte[(int) length];
|
2009-09-05 03:13:37 +08:00
|
|
|
|
|
|
|
|
// Read in the bytes
|
|
|
|
|
int offset = 0;
|
|
|
|
|
int numRead = 0;
|
|
|
|
|
while (offset < bytes.length
|
2010-03-05 04:20:58 +08:00
|
|
|
&& (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
|
2009-09-05 03:13:37 +08:00
|
|
|
offset += numRead;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ensure all the bytes have been read in
|
|
|
|
|
if (offset < bytes.length) {
|
2010-03-05 04:20:58 +08:00
|
|
|
throw new IOException("Could not completely read file " + file.getName());
|
2009-09-05 03:13:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Close the input stream and return bytes
|
|
|
|
|
is.close();
|
|
|
|
|
return bytes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class WalkerTestSpec {
|
|
|
|
|
String args = "";
|
|
|
|
|
int nOutputFiles = -1;
|
|
|
|
|
List<String> md5s = null;
|
2009-10-20 05:54:53 +08:00
|
|
|
List<String> exts = null;
|
2009-09-05 03:13:37 +08:00
|
|
|
|
2010-03-05 04:20:58 +08:00
|
|
|
protected Map<String, File> auxillaryFiles = new HashMap<String, File>();
|
2010-03-05 00:02:21 +08:00
|
|
|
|
2009-09-05 03:13:37 +08:00
|
|
|
public WalkerTestSpec(String args, int nOutputFiles, List<String> md5s) {
|
|
|
|
|
this.args = args;
|
|
|
|
|
this.nOutputFiles = nOutputFiles;
|
|
|
|
|
this.md5s = md5s;
|
|
|
|
|
}
|
2009-10-20 05:54:53 +08:00
|
|
|
|
|
|
|
|
public WalkerTestSpec(String args, int nOutputFiles, List<String> exts, List<String> md5s) {
|
|
|
|
|
this.args = args;
|
|
|
|
|
this.nOutputFiles = nOutputFiles;
|
|
|
|
|
this.md5s = md5s;
|
|
|
|
|
this.exts = exts;
|
|
|
|
|
}
|
2010-03-05 00:02:21 +08:00
|
|
|
|
|
|
|
|
public void addAuxFile(String expectededMD5sum, File outputfile) {
|
2010-03-05 04:20:58 +08:00
|
|
|
auxillaryFiles.put(expectededMD5sum, outputfile);
|
2010-03-05 00:02:21 +08:00
|
|
|
}
|
2009-09-05 03:13:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected boolean parameterize() {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-05 06:26:57 +08:00
|
|
|
protected Pair<List<File>, List<String>> executeTest(final String name, WalkerTestSpec spec) {
|
2010-06-01 00:06:16 +08:00
|
|
|
ensureMd5DbDirectory(); // ensure the md5 directory exists
|
|
|
|
|
|
2009-09-05 03:13:37 +08:00
|
|
|
List<File> tmpFiles = new ArrayList<File>();
|
2010-03-05 04:20:58 +08:00
|
|
|
for (int i = 0; i < spec.nOutputFiles; i++) {
|
|
|
|
|
String ext = spec.exts == null ? ".tmp" : "." + spec.exts.get(i);
|
|
|
|
|
File fl = createTempFile(String.format("walktest.tmp_param.%d", i), ext);
|
|
|
|
|
tmpFiles.add(fl);
|
2009-09-05 03:13:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final String args = String.format(spec.args, tmpFiles.toArray());
|
2009-10-21 07:31:13 +08:00
|
|
|
System.out.println(Utils.dupString('-', 80));
|
2009-09-05 06:26:57 +08:00
|
|
|
|
2010-03-05 00:02:21 +08:00
|
|
|
List<String> md5s = new LinkedList<String>();
|
|
|
|
|
md5s.addAll(spec.md5s);
|
|
|
|
|
|
|
|
|
|
// check to see if they included any auxillary files, if so add them to the list
|
|
|
|
|
for (String md5 : spec.auxillaryFiles.keySet()) {
|
|
|
|
|
md5s.add(md5);
|
|
|
|
|
tmpFiles.add(spec.auxillaryFiles.get(md5));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return executeTest(name, md5s, tmpFiles, args);
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-05 04:20:58 +08:00
|
|
|
public File createTempFile(String name, String extension) {
|
|
|
|
|
try {
|
|
|
|
|
File fl = File.createTempFile(name, extension);
|
2010-03-05 04:29:42 +08:00
|
|
|
fl.deleteOnExit();
|
2010-03-05 04:20:58 +08:00
|
|
|
return fl;
|
|
|
|
|
} catch (IOException ex) {
|
|
|
|
|
throw new StingException("Cannot create temp file: " + ex.getMessage(), ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-03-05 00:02:21 +08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* execute the test, given the following:
|
2010-03-05 04:20:58 +08:00
|
|
|
* @param name the name of the test
|
|
|
|
|
* @param md5s the list of md5s
|
2010-03-05 00:02:21 +08:00
|
|
|
* @param tmpFiles the temp file corresponding to the md5 list
|
2010-03-05 04:20:58 +08:00
|
|
|
* @param args the argument list
|
2010-03-05 00:02:21 +08:00
|
|
|
* @return a pair of file and string lists
|
|
|
|
|
*/
|
|
|
|
|
private Pair<List<File>, List<String>> executeTest(String name, List<String> md5s, List<File> tmpFiles, String args) {
|
2009-09-05 03:13:37 +08:00
|
|
|
CommandLineGATK instance = new CommandLineGATK();
|
2009-11-24 10:34:48 +08:00
|
|
|
String[] command;
|
|
|
|
|
|
|
|
|
|
// special case for ' and " so we can allow expressions
|
2010-03-05 04:20:58 +08:00
|
|
|
if (args.indexOf('\'') != -1)
|
2009-11-24 10:34:48 +08:00
|
|
|
command = escapeExpressions(args, "'");
|
2010-03-05 04:20:58 +08:00
|
|
|
else if (args.indexOf('\"') != -1)
|
2009-11-24 10:34:48 +08:00
|
|
|
command = escapeExpressions(args, "\"");
|
|
|
|
|
else
|
|
|
|
|
command = args.split(" ");
|
|
|
|
|
|
2010-03-05 04:20:58 +08:00
|
|
|
if (outputFileLocation != null) {
|
|
|
|
|
String[] cmd2 = Arrays.copyOf(command, command.length + 2);
|
|
|
|
|
cmd2[command.length] = "-o";
|
|
|
|
|
cmd2[command.length + 1] = this.outputFileLocation.getAbsolutePath();
|
|
|
|
|
command = cmd2;
|
|
|
|
|
}
|
|
|
|
|
System.out.println(String.format("Executing test %s with GATK arguments: %s", name, Utils.join(" ",command)));
|
2009-09-05 03:13:37 +08:00
|
|
|
|
2010-08-10 10:57:23 +08:00
|
|
|
// add the logging level to each of the integration test commands
|
|
|
|
|
String[] cmd2 = Arrays.copyOf(command, command.length + 2);
|
|
|
|
|
cmd2[command.length] = "-l";
|
|
|
|
|
cmd2[command.length+1] = "WARN";
|
|
|
|
|
|
|
|
|
|
// run the executable
|
|
|
|
|
CommandLineExecutable.start(instance, cmd2);
|
|
|
|
|
|
|
|
|
|
// catch failures from the integration test
|
2010-03-05 04:20:58 +08:00
|
|
|
if (CommandLineExecutable.result != 0) {
|
2009-09-05 06:26:57 +08:00
|
|
|
throw new RuntimeException("Error running the GATK with arguments: " + args);
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-05 00:02:21 +08:00
|
|
|
return new Pair<List<File>, List<String>>(tmpFiles, assertMatchingMD5s(name, tmpFiles, md5s));
|
|
|
|
|
}
|
2009-11-24 10:34:48 +08:00
|
|
|
|
|
|
|
|
private static String[] escapeExpressions(String args, String delimiter) {
|
|
|
|
|
String[] command = {};
|
|
|
|
|
String[] split = args.split(delimiter);
|
2010-03-05 04:20:58 +08:00
|
|
|
for (int i = 0; i < split.length - 1; i += 2) {
|
2009-11-24 10:34:48 +08:00
|
|
|
command = Utils.concatArrays(command, split[i].trim().split(" "));
|
2010-03-05 04:20:58 +08:00
|
|
|
command = Utils.concatArrays(command, new String[]{split[i + 1]});
|
2009-11-24 10:34:48 +08:00
|
|
|
}
|
2010-03-05 04:20:58 +08:00
|
|
|
return Utils.concatArrays(command, split[split.length - 1].trim().split(" "));
|
2009-09-05 03:13:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
2010-04-08 14:14:15 +08:00
|
|
|
public void testWalkerUnitTest() {
|
2009-10-21 07:31:13 +08:00
|
|
|
//System.out.println("WalkerTest is just a framework");
|
2009-09-05 03:13:37 +08:00
|
|
|
}
|
|
|
|
|
}
|