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 ;
2011-05-24 22:34:55 +08:00
import org.apache.commons.lang.StringUtils ;
2011-07-15 03:12:28 +08:00
import org.broad.tribble.FeatureCodec ;
2010-10-09 03:53:21 +08:00
import org.broad.tribble.Tribble ;
2011-07-15 03:12:28 +08:00
import org.broad.tribble.index.Index ;
2010-10-09 03:53:21 +08:00
import org.broad.tribble.index.IndexFactory ;
2012-02-23 05:45:20 +08:00
import org.broadinstitute.sting.gatk.phonehome.GATKRunReport ;
2011-06-25 00:56:04 +08:00
import org.broadinstitute.sting.utils.codecs.vcf.VCFCodec ;
2009-09-09 09:02:04 +08:00
import org.broadinstitute.sting.gatk.CommandLineExecutable ;
import org.broadinstitute.sting.gatk.CommandLineGATK ;
2011-04-08 01:03:48 +08:00
import org.broadinstitute.sting.gatk.GenomeAnalysisEngine ;
2010-09-12 23:07:38 +08:00
import org.broadinstitute.sting.utils.exceptions.ReviewedStingException ;
2010-04-20 07:00:08 +08:00
import org.broadinstitute.sting.utils.collections.Pair ;
2009-09-09 09:02:04 +08:00
import org.broadinstitute.sting.utils.Utils ;
2010-10-09 03:53:21 +08:00
import org.broadinstitute.sting.utils.exceptions.StingException ;
2010-11-02 05:31:44 +08:00
import org.testng.Assert ;
2011-04-08 01:03:48 +08:00
import org.testng.annotations.BeforeMethod ;
2009-09-05 03:13:37 +08:00
2009-09-09 09:02:04 +08:00
import java.io.File ;
2010-03-05 00:02:21 +08:00
import java.util.* ;
2009-09-05 03:13:37 +08:00
public class WalkerTest extends BaseTest {
2012-02-23 05:45:20 +08:00
private static final boolean ENABLE_PHONE_HOME_FOR_TESTS = false ;
2012-03-18 12:53:29 +08:00
private static final boolean ENABLE_ON_THE_FLY_CHECK_FOR_VCF_INDEX = false ;
2010-03-05 04:20:58 +08:00
2011-04-08 01:03:48 +08:00
@BeforeMethod
public void initializeRandomGenerator ( ) {
GenomeAnalysisEngine . resetRandomGenerator ( ) ;
}
2011-10-05 06:53:52 +08:00
public MD5DB . MD5Match assertMatchingMD5 ( final String name , final File resultsFile , final String expectedMD5 ) {
2011-07-18 22:46:01 +08:00
return MD5DB . assertMatchingMD5 ( name , resultsFile , expectedMD5 , parameterize ( ) ) ;
2009-09-05 03:13:37 +08:00
}
2010-10-09 03:53:21 +08:00
public void maybeValidateSupplementaryFile ( final String name , final File resultFile ) {
2012-03-18 12:53:29 +08:00
if ( ! ENABLE_ON_THE_FLY_CHECK_FOR_VCF_INDEX )
return ;
2010-10-09 03:53:21 +08:00
File indexFile = Tribble . indexFile ( resultFile ) ;
//System.out.println("Putative index file is " + indexFile);
if ( indexFile . exists ( ) ) {
if ( resultFile . getAbsolutePath ( ) . contains ( ".vcf" ) ) {
// todo -- currently we only understand VCF files! Blow up since we can't test them
throw new StingException ( "Found an index created for file " + resultFile + " but we can only validate VCF files. Extend this code!" ) ;
}
2011-07-16 21:22:34 +08:00
assertOnDiskIndexEqualToNewlyCreatedIndex ( indexFile , name , resultFile ) ;
2010-10-09 03:53:21 +08:00
}
}
2011-07-15 03:12:28 +08:00
2011-07-16 21:22:34 +08:00
public static void assertOnDiskIndexEqualToNewlyCreatedIndex ( final File indexFile , final String name , final File resultFile ) {
System . out . println ( "Verifying on-the-fly index " + indexFile + " for test " + name + " using file " + resultFile ) ;
Index indexFromOutputFile = IndexFactory . createIndex ( resultFile , new VCFCodec ( ) ) ;
Index dynamicIndex = IndexFactory . loadIndex ( indexFile . getAbsolutePath ( ) ) ;
2012-03-18 12:53:29 +08:00
2011-09-20 22:53:18 +08:00
if ( ! indexFromOutputFile . equalsIgnoreProperties ( dynamicIndex ) ) {
2011-07-16 21:22:34 +08:00
Assert . fail ( String . format ( "Index on disk from indexing on the fly not equal to the index created after the run completed. FileIndex %s vs. on-the-fly %s%n" ,
indexFromOutputFile . getProperties ( ) ,
dynamicIndex . getProperties ( ) ) ) ;
}
2012-03-18 12:53:29 +08:00
}
2011-07-15 03:12:28 +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 > ( ) ;
2011-10-05 06:53:52 +08:00
List < MD5DB . MD5Match > fails = new ArrayList < MD5DB . MD5Match > ( ) ;
2010-03-05 04:20:58 +08:00
for ( int i = 0 ; i < resultFiles . size ( ) ; i + + ) {
2011-10-05 06:53:52 +08:00
MD5DB . MD5Match result = assertMatchingMD5 ( name , resultFiles . get ( i ) , expectedMD5s . get ( i ) ) ;
if ( ! result . failed ) {
maybeValidateSupplementaryFile ( name , resultFiles . get ( i ) ) ;
md5s . add ( result . md5 ) ;
} else {
fails . add ( result ) ;
}
}
if ( ! fails . isEmpty ( ) ) {
for ( final MD5DB . MD5Match fail : fails ) {
logger . warn ( "Fail: " + fail . failMessage ) ;
}
Assert . fail ( "Test failed: " + name ) ;
2009-09-05 03:13:37 +08:00
}
return md5s ;
}
2011-02-18 14:26:38 +08:00
public String buildCommandLine ( String . . . arguments ) {
2011-02-14 01:58:20 +08:00
String cmdline = "" ;
for ( int argIndex = 0 ; argIndex < arguments . length ; argIndex + + ) {
cmdline + = arguments [ argIndex ] ;
if ( argIndex < arguments . length - 1 ) {
cmdline + = " " ;
}
}
return cmdline ;
}
2009-09-05 03:13:37 +08:00
public class WalkerTestSpec {
2012-02-23 05:45:20 +08:00
// Arguments implicitly included in all Walker command lines, unless explicitly
// disabled using the disableImplicitArgs() method below.
final String IMPLICIT_ARGS = ENABLE_PHONE_HOME_FOR_TESTS ?
String . format ( "-et %s" , GATKRunReport . PhoneHomeOption . STANDARD ) :
String . format ( "-et %s -K %s" , GATKRunReport . PhoneHomeOption . NO_ET , gatkKeyFile ) ;
2009-09-05 03:13:37 +08:00
String args = "" ;
int nOutputFiles = - 1 ;
List < String > md5s = null ;
2009-10-20 05:54:53 +08:00
List < String > exts = null ;
2010-09-12 22:02:43 +08:00
Class expectedException = null ;
2012-02-23 05:45:20 +08:00
boolean includeImplicitArgs = true ;
2009-09-05 03:13:37 +08:00
2011-02-01 23:25:50 +08:00
// the default output path for the integration test
private File outputFileLocation = null ;
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
2010-11-14 00:19:56 +08:00
public WalkerTestSpec ( String args , List < String > md5s ) {
this ( args , - 1 , md5s ) ;
}
2009-09-05 03:13:37 +08:00
public WalkerTestSpec ( String args , int nOutputFiles , List < String > md5s ) {
this . args = args ;
2010-11-14 00:19:56 +08:00
this . nOutputFiles = md5s . size ( ) ;
2009-09-05 03:13:37 +08:00
this . md5s = md5s ;
}
2009-10-20 05:54:53 +08:00
2010-11-14 00:19:56 +08:00
public WalkerTestSpec ( String args , List < String > exts , List < String > md5s ) {
this ( args , - 1 , exts , md5s ) ;
}
2009-10-20 05:54:53 +08:00
public WalkerTestSpec ( String args , int nOutputFiles , List < String > exts , List < String > md5s ) {
this . args = args ;
2010-11-14 00:19:56 +08:00
this . nOutputFiles = md5s . size ( ) ;
2009-10-20 05:54:53 +08:00
this . md5s = md5s ;
this . exts = exts ;
}
2010-03-05 00:02:21 +08:00
2010-09-12 22:02:43 +08:00
public WalkerTestSpec ( String args , int nOutputFiles , Class expectedException ) {
this . args = args ;
this . nOutputFiles = nOutputFiles ;
this . expectedException = expectedException ;
}
2012-02-23 05:45:20 +08:00
public String getArgsWithImplicitArgs ( ) {
return args + ( includeImplicitArgs ? " " + IMPLICIT_ARGS : "" ) ;
}
2011-02-01 23:25:50 +08:00
public void setOutputFileLocation ( File outputFileLocation ) {
this . outputFileLocation = outputFileLocation ;
}
protected File getOutputFileLocation ( ) {
return outputFileLocation ;
}
2010-09-12 22:02:43 +08:00
public boolean expectsException ( ) {
return expectedException ! = null ;
}
public Class getExpectedException ( ) {
2010-09-12 23:07:38 +08:00
if ( ! expectsException ( ) ) throw new ReviewedStingException ( "Tried to get expection for walker test that doesn't expect one" ) ;
2010-09-12 22:02:43 +08:00
return expectedException ;
}
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
}
2011-02-01 23:25:50 +08:00
2012-02-23 05:45:20 +08:00
public void disableImplicitArgs ( ) {
includeImplicitArgs = false ;
}
2009-09-05 03:13:37 +08:00
}
protected boolean parameterize ( ) {
return false ;
}
2010-10-27 04:21:38 +08:00
protected Pair < List < File > , List < String > > executeTestParallel ( final String name , WalkerTestSpec spec ) {
return executeTest ( name , spec , Arrays . asList ( 1 , 4 ) ) ;
}
protected Pair < List < File > , List < String > > executeTest ( final String name , WalkerTestSpec spec , List < Integer > parallelThreads ) {
String originalArgs = spec . args ;
Pair < List < File > , List < String > > results = null ;
for ( int nt : parallelThreads ) {
String extra = nt = = 1 ? "" : ( " -nt " + nt ) ;
spec . args = originalArgs + extra ;
results = executeTest ( name + "-nt-" + nt , spec ) ;
}
return results ;
}
2009-09-05 06:26:57 +08:00
protected Pair < List < File > , List < String > > executeTest ( final String name , WalkerTestSpec spec ) {
2011-07-18 22:46:01 +08:00
MD5DB . ensureMd5DbDirectory ( ) ; // ensure the md5 directory exists
2010-06-01 00:06:16 +08:00
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
}
2012-02-23 05:45:20 +08:00
final String args = String . format ( spec . getArgsWithImplicitArgs ( ) , 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-09-12 22:02:43 +08:00
if ( spec . expectsException ( ) ) {
// this branch handles the case were we are testing that a walker will fail as expected
2011-02-01 23:25:50 +08:00
return executeTest ( name , spec . getOutputFileLocation ( ) , null , tmpFiles , args , spec . getExpectedException ( ) ) ;
2010-09-12 22:02:43 +08:00
} else {
List < String > md5s = new LinkedList < String > ( ) ;
md5s . addAll ( spec . md5s ) ;
2010-03-05 00:02:21 +08:00
2010-09-12 22:02:43 +08:00
// 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 ) ) ;
}
2011-02-01 23:25:50 +08:00
return executeTest ( name , spec . getOutputFileLocation ( ) , md5s , tmpFiles , args , null ) ;
2010-03-05 00:02:21 +08:00
}
}
2011-05-24 22:34:55 +08:00
private void qcMD5s ( String name , List < String > md5s ) {
final String exampleMD5 = "709a1f482cce68992c637da3cff824a8" ;
for ( String md5 : md5s ) {
if ( md5 = = null )
throw new IllegalArgumentException ( "Null MD5 found in test " + name ) ;
if ( md5 . equals ( "" ) ) // ok
2011-05-27 22:00:52 +08:00
continue ;
2011-05-24 22:34:55 +08:00
if ( ! StringUtils . isAlphanumeric ( md5 ) )
throw new IllegalArgumentException ( "MD5 contains non-alphanumeric characters test " + name + " md5=" + md5 ) ;
if ( md5 . length ( ) ! = exampleMD5 . length ( ) )
throw new IllegalArgumentException ( "Non-empty MD5 of unexpected number of characters test " + name + " md5=" + md5 ) ;
}
}
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-11-23 06:59:42 +08:00
* @param expectedException the expected exception or null
2010-03-05 00:02:21 +08:00
* @return a pair of file and string lists
* /
2011-02-01 23:25:50 +08:00
private Pair < List < File > , List < String > > executeTest ( String name , File outputFileLocation , List < String > md5s , List < File > tmpFiles , String args , Class expectedException ) {
2011-05-25 03:17:18 +08:00
if ( md5s ! = null ) qcMD5s ( name , md5s ) ;
2011-05-24 22:34:55 +08:00
2010-11-23 06:59:42 +08:00
if ( outputFileLocation ! = null )
2011-02-01 23:25:50 +08:00
args + = " -o " + outputFileLocation . getAbsolutePath ( ) ;
2010-11-23 06:59:42 +08:00
executeTest ( name , args , expectedException ) ;
if ( expectedException ! = null ) {
return null ;
} else {
// we need to check MD5s
return new Pair < List < File > , List < String > > ( tmpFiles , assertMatchingMD5s ( name , tmpFiles , md5s ) ) ;
}
}
/ * *
* execute the test , given the following :
* @param name the name of the test
* @param args the argument list
* @param expectedException the expected exception or null
* /
2012-02-23 05:45:20 +08:00
private void executeTest ( String name , String args , Class expectedException ) {
2009-09-05 03:13:37 +08:00
CommandLineGATK instance = new CommandLineGATK ( ) ;
2010-11-13 04:14:28 +08:00
String [ ] command = Utils . escapeExpressions ( args ) ;
2010-08-10 10:57:23 +08:00
// run the executable
2010-09-12 22:02:43 +08:00
boolean gotAnException = false ;
2010-09-09 19:32:20 +08:00
try {
2010-11-13 04:14:28 +08:00
System . out . println ( String . format ( "Executing test %s with GATK arguments: %s" , name , Utils . join ( " " , command ) ) ) ;
CommandLineExecutable . start ( instance , command ) ;
2010-09-09 19:32:20 +08:00
} catch ( Exception e ) {
2010-09-12 22:02:43 +08:00
gotAnException = true ;
if ( expectedException ! = null ) {
// we expect an exception
System . out . println ( String . format ( "Wanted exception %s, saw %s" , expectedException , e . getClass ( ) ) ) ;
if ( expectedException . isInstance ( e ) ) {
// it's the type we expected
System . out . println ( String . format ( " => %s PASSED" , name ) ) ;
} else {
e . printStackTrace ( ) ;
Assert . fail ( String . format ( "Test %s expected exception %s but got %s instead" ,
name , expectedException , e . getClass ( ) ) ) ;
}
} else {
// we didn't expect an exception but we got one :-(
throw new RuntimeException ( e ) ;
}
2010-09-09 19:32:20 +08:00
}
2010-08-10 10:57:23 +08:00
// catch failures from the integration test
2010-09-12 22:02:43 +08:00
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 ( ) ) ) ;
} else {
if ( CommandLineExecutable . result ! = 0 ) {
throw new RuntimeException ( "Error running the GATK with arguments: " + args ) ;
}
2009-09-05 06:26:57 +08:00
}
2010-03-05 00:02:21 +08:00
}
2011-01-27 07:48:04 +08:00
protected File createTempFileFromBase ( String name ) {
File fl = new File ( name ) ;
fl . deleteOnExit ( ) ;
return fl ;
}
2010-09-01 00:18:57 +08:00
}