1 package org.broadinstitute.hellbender.utils.config; 2 3 import org.broadinstitute.barclay.argparser.Argument; 4 import org.broadinstitute.barclay.argparser.CommandLineProgramProperties; 5 import org.broadinstitute.hellbender.CommandLineProgramTest; 6 import org.broadinstitute.hellbender.cmdline.StandardArgumentDefinitions; 7 import org.broadinstitute.hellbender.cmdline.TestProgramGroup; 8 import org.broadinstitute.hellbender.engine.GATKTool; 9 import org.broadinstitute.hellbender.exceptions.GATKException; 10 import org.broadinstitute.hellbender.testutils.ArgumentsBuilder; 11 import org.testng.Assert; 12 import org.testng.annotations.DataProvider; 13 import org.testng.annotations.Test; 14 15 import java.io.*; 16 import java.nio.file.Path; 17 import java.nio.file.Paths; 18 import java.util.*; 19 import java.util.stream.Collectors; 20 21 /** 22 * Integration test 23 * Created by jonn on 12/7/17. 24 */ 25 public class ConfigIntegrationTest extends CommandLineProgramTest { 26 27 @CommandLineProgramProperties( 28 summary = "Dummy empty command line that requires a reference .", 29 oneLineSummary = "empty class", 30 programGroup = TestProgramGroup.class 31 ) 32 public static class DummyGatkTool extends GATKTool { 33 34 public static final String SYSTEM_VAR_ARG_LONG_NAME = "SystemVar"; 35 public static final String SYSTEM_OUT_FILE_ARG_LONG_NAME = "SysOutFile"; 36 37 @Argument( 38 doc = "Output file with only the configuration settings in it.", 39 fullName = StandardArgumentDefinitions.OUTPUT_LONG_NAME, 40 shortName = StandardArgumentDefinitions.OUTPUT_SHORT_NAME 41 ) 42 private File outputFilePath; 43 44 @Argument( 45 doc = "System properties to save to system properties output file.", 46 fullName = SYSTEM_VAR_ARG_LONG_NAME 47 ) 48 private List<String> systemPropertiesToSave; 49 50 @Argument( 51 doc = "Output file with only the specified system properties in it.", 52 fullName = SYSTEM_OUT_FILE_ARG_LONG_NAME 53 ) 54 private File systemPropertiesOutputFile; 55 56 @Override traverse()57 public void traverse() { 58 59 // Create our config and dump the config settings: 60 final GATKConfig gatkConfig = ConfigFactory.getInstance().getGATKConfig(); 61 ConfigFactory.dumpConfigSettings( gatkConfig, outputFilePath.toPath() ); 62 63 final Properties systemProperties = new Properties(); 64 for (final String propName : systemPropertiesToSave) { 65 systemProperties.put( propName, System.getProperty(propName) ); 66 } 67 68 try ( final PrintStream systemOutPrintStream = new PrintStream(systemPropertiesOutputFile)) { 69 systemProperties.store(systemOutPrintStream, ""); 70 } 71 catch ( final IOException ex ) { 72 throw new GATKException("Could not open output file for system properties.", ex); 73 } 74 } 75 } 76 listProperties(final Properties props)77 private void listProperties(final Properties props) { 78 79 final List<String> propKeys = props.keySet().stream() 80 .map(Object::toString) 81 .sorted() 82 .collect(Collectors.toCollection(ArrayList::new)); 83 84 System.out.println("-- listing properties --"); 85 for ( final String key : propKeys ) { 86 System.out.print(key); 87 System.out.print("="); 88 System.out.println(props.get(key)); 89 } 90 } 91 92 @Override getTestedClassName()93 public String getTestedClassName() { 94 return DummyGatkTool.class.getSimpleName(); 95 } 96 97 @DataProvider provideForTestToolWithConfigValidation()98 private Object[][] provideForTestToolWithConfigValidation() { 99 100 return new Object[][] { 101 // Default config file (because nothing can be loaded): 102 { getSafeNonExistentPath("nonExistentConfig.config") }, 103 104 // Config file with overrides: 105 { Paths.get(publicTestDir + "org/broadinstitute/hellbender/utils/config/" + "TestGATKConfigOverrides.properties") }, 106 }; 107 } 108 109 @Test(dataProvider = "provideForTestToolWithConfigValidation", 110 singleThreaded = true) testToolWithConfigValidation(final Path configFilePath)111 public void testToolWithConfigValidation(final Path configFilePath) { 112 113 // Grab the properties so we can reset them later: 114 // NOTE: CLONE HERE IS ABSOLUTELY NECESSARY OR THIS WILL FAIL VERY VERY HARD! 115 final Properties systemProperties = (Properties)System.getProperties().clone(); 116 // System.out.println("================================================================================"); 117 // listProperties(systemProperties); 118 // System.out.println("================================================================================"); 119 120 try { 121 final File tmpConfigPropsFile = getSafeNonExistentFile("ConfigIntegrationTest.config.properties"); 122 final File tmpSystemPropsFile = getSafeNonExistentFile("ConfigIntegrationTest.system.properties"); 123 124 // Add in some system options. 125 // None of these should be masked by the options of the same name in the config file. 126 final Map<String, String> systemPropertiesToQuery = new HashMap<>(); 127 systemPropertiesToQuery.put("gatk_stacktrace_on_user_exception", "true"); 128 systemPropertiesToQuery.put("samjdk.compression_level", "7777"); 129 130 for (final Map.Entry<String, String> entry : systemPropertiesToQuery.entrySet()) { 131 System.setProperty(entry.getKey(), entry.getValue()); 132 } 133 134 // Create some arguments for our command: 135 final ArgumentsBuilder args = new ArgumentsBuilder(); 136 137 args.add(StandardArgumentDefinitions.GATK_CONFIG_FILE_OPTION, configFilePath.toUri().toString()); 138 args.add(DummyGatkTool.SYSTEM_OUT_FILE_ARG_LONG_NAME, tmpSystemPropsFile.toString()); 139 args.addOutput(tmpConfigPropsFile); 140 141 // Add in our system properties to check: 142 for ( final String sysProp : systemPropertiesToQuery.keySet() ) { 143 args.add(DummyGatkTool.SYSTEM_VAR_ARG_LONG_NAME, sysProp); 144 } 145 146 // Run our command: 147 runCommandLine(args); 148 149 // ========================================================================================================= 150 // Now we get to read in the file's contents and compare them to our config settings: 151 final Properties configProperties = new Properties(); 152 try ( final FileInputStream inputStream = new FileInputStream(tmpConfigPropsFile) ) { 153 configProperties.load(inputStream); 154 } 155 catch ( final Exception ex ) { 156 throw new GATKException("Test error!", ex); 157 } 158 159 final Properties systemPropertiesPostToolRun = new Properties(); 160 try ( final FileInputStream inputStream = new FileInputStream(tmpSystemPropsFile) ) { 161 systemPropertiesPostToolRun.load(inputStream); 162 } 163 catch ( final Exception ex ) { 164 throw new GATKException("Test error!", ex); 165 } 166 167 // Create a config object to compare with the properties: 168 final GATKConfig config = ConfigFactory.getInstance().createConfigFromFile(configFilePath.toString(), GATKConfig.class); 169 170 // Get the config properties: 171 final LinkedHashMap<String, Object> configMap = ConfigFactory.getConfigMap(config, false); 172 173 // Compare the configuration properties and assert their equality: 174 for ( final Map.Entry<String, Object> entry : configMap.entrySet() ) { 175 Assert.assertEquals(configProperties.getProperty(entry.getKey()), String.valueOf(entry.getValue())); 176 } 177 178 // Compare the system properties and assert their equality: 179 for ( final String sysPropKey : systemPropertiesToQuery.keySet() ) { 180 Assert.assertEquals(systemPropertiesPostToolRun.getProperty(sysPropKey), systemPropertiesToQuery.get(sysPropKey)); 181 } 182 183 // Make sure they have the same size: 184 Assert.assertEquals(configProperties.size(), configMap.size()); 185 186 } 187 // ========================================================================================================= 188 // Now we have to reset our system options: 189 finally { 190 // Clear our system properties: 191 final List<Object> keyList = new ArrayList<>(System.getProperties().keySet()); 192 for ( final Object key : keyList ) { 193 System.clearProperty(key.toString()); 194 } 195 196 // Set back the old System Properties: 197 System.setProperties(systemProperties); 198 } 199 } 200 } 201