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