001package org.hl7.fhir.validation.testexecutor; 002 003import static org.hl7.fhir.validation.testexecutor.TestModules.JUNIT4_CLASSNAMES; 004import static org.hl7.fhir.validation.testexecutor.TestModules.JUNIT5_MODULE_NAMES; 005import static org.hl7.fhir.validation.testexecutor.TestModules.VALIDATION_MODULE; 006 007import java.io.IOException; 008import java.nio.file.Files; 009import java.nio.file.Path; 010import java.nio.file.Paths; 011import java.util.Arrays; 012import java.util.HashMap; 013import java.util.List; 014import java.util.Map; 015import java.util.stream.Collectors; 016import java.util.stream.Stream; 017 018import javax.annotation.Nonnull; 019 020import org.hl7.fhir.utilities.tests.TestConfig; 021import org.hl7.fhir.utilities.tests.execution.CliTestSummary; 022import org.hl7.fhir.utilities.tests.execution.ModuleTestExecutor; 023import org.hl7.fhir.utilities.tests.execution.junit4.JUnit4TestExecutor; 024import org.hl7.fhir.utilities.tests.execution.junit5.JUnit5ModuleTestExecutor; 025 026import lombok.Getter; 027 028public class TestExecutor { 029 030 031 @Getter private final List<ModuleTestExecutor> jUnit4TestExecutors; 032 033 @Getter private final List<ModuleTestExecutor> jUnit5TestExecutors; 034 035 public TestExecutor(String[] moduleNamesArg) { 036 this(getjUnit4TestExecutors(moduleNamesArg), getjUnit5TestExecutors(moduleNamesArg)); 037 } 038 protected TestExecutor(List<ModuleTestExecutor> jUnit4TestExecutors, List<ModuleTestExecutor> jUnit5TestExecutors) { 039 this.jUnit4TestExecutors = jUnit4TestExecutors; 040 this.jUnit5TestExecutors = jUnit5TestExecutors; 041 } 042 043 public static final String TX_CACHE = "txCache"; 044 045 private static String SUMMARY_TEMPLATE = "Tests run: %d, Failures: %d, Errors: %d, Skipped: %d"; 046 private static final String DOT_PLACEHOLDER = new String(new char[53]).replace("\0", "."); 047 048 private static final int MAX_NAME_LENGTH = 50; 049 050 private String getModuleResultLine(String moduleName, CliTestSummary moduleTestSummary) { 051 return getModuleNameAndSpacer(moduleName) 052 + " " 053 + getModuleResultString(moduleTestSummary); 054 } 055 056 private String getModuleNameAndSpacer(String moduleName) { 057 return moduleName.length() < MAX_NAME_LENGTH 058 ? moduleName + " " + DOT_PLACEHOLDER.substring(moduleName.length() + 1) 059 : moduleName.substring(0, MAX_NAME_LENGTH) + "..."; 060 } 061 062 private String getModuleResultString(CliTestSummary cliTestSummary) { 063 if (cliTestSummary.getTestsFoundCount() == 0) { 064 return "NO TESTS"; 065 } 066 067 return cliTestSummary.getTestsFailedCount() == 0 && cliTestSummary.getTestsAbortedCount() == 0 068 ? "PASSED" 069 : "FAILED"; 070 } 071 072 public static boolean pathExistsAsDirectory(String directoryPath) { 073 Path path = Paths.get(directoryPath); 074 return Files.exists(path) 075 && Files.isDirectory(path); 076 } 077 078 public void executeTests(String classNameFilterArg, String txCacheDirectoryPath, String testCasesDirectoryPath) { 079 080 long start = System.currentTimeMillis(); 081 //Our lone JUnit 4 test. 082 List<ModuleTestExecutor> jUnit4TestExecutors = getJUnit4TestExecutors(); 083 084 TestConfig.getInstance().setRebuildCache(true); 085 086 setUpDirectories(txCacheDirectoryPath, testCasesDirectoryPath); 087 088 List<ModuleTestExecutor> jUnit5TestExecutors = getJUnit5TestExecutors(); 089 090 long testsFoundCount = 0; 091 long testsFailedCount = 0; 092 long testsAbortedCount = 0; 093 long testsSkippedCount = 0; 094 095 final Map<String, CliTestSummary> moduleResultMap = new HashMap<>(); 096 097 final List<ModuleTestExecutor> orderedModuleTestExecutors = Stream.concat(jUnit5TestExecutors.stream(), jUnit4TestExecutors.stream()).collect(Collectors.toList()); 098 099 for (ModuleTestExecutor moduleTestExecutor : orderedModuleTestExecutors) { 100 final CliTestSummary testExecutionSummary = moduleTestExecutor.executeTests(System.out, classNameFilterArg); 101 testsFoundCount += testExecutionSummary.getTestsFoundCount(); 102 testsFailedCount += testExecutionSummary.getTestsFailedCount(); 103 testsAbortedCount += testExecutionSummary.getTestsAbortedCount(); 104 testsSkippedCount += testExecutionSummary.getTestsSkippedCount(); 105 moduleResultMap.put(moduleTestExecutor.getModuleName(), testExecutionSummary); 106 } 107 108 System.out.println("\n\nAll Tests completed."); 109 110 for (ModuleTestExecutor moduleTestExecutor : orderedModuleTestExecutors) { 111 ModuleTestExecutor.printSummmary(System.out, moduleResultMap.get(moduleTestExecutor.getModuleName()), moduleTestExecutor.getModuleName()); 112 } 113 114 System.out.println("\nModule Results:\n"); 115 116 for (ModuleTestExecutor moduleTestExecutor : orderedModuleTestExecutors) { 117 System.out.println(getModuleResultLine(moduleTestExecutor.getModuleName(), moduleResultMap.get(moduleTestExecutor.getModuleName()))); 118 } 119 120 System.out.println(); 121 System.out.println(String.format(SUMMARY_TEMPLATE, testsFoundCount, testsFailedCount, testsAbortedCount, testsSkippedCount)); 122 System.out.println("\nCompleted in " + (System.currentTimeMillis() - start) + "ms"); 123 124 } 125 126 protected void setUpDirectories(String txCacheDirectoryPath, String testCasesDirectoryPath) { 127 if (testCasesDirectoryPath != null 128 && pathExistsAsDirectory(testCasesDirectoryPath) 129 ) { 130 TestConfig.getInstance().setFhirTestCasesDirectory(testCasesDirectoryPath); 131 } else { 132 throw new RuntimeException("fhir-test-cases directory does not exist: " + testCasesDirectoryPath); 133 } 134 try { 135 String txCacheDirectory = getOrCreateTxCacheDirectory(txCacheDirectoryPath); 136 if (!pathExistsAsDirectory(testCasesDirectoryPath)) { 137 throw new RuntimeException("txCache directory does not exist: " + txCacheDirectory); 138 } 139 TestConfig.getInstance().setTxCacheDirectory(txCacheDirectory); 140 } catch (IOException e) { 141 throw new RuntimeException("Unable to create temporary resource directory.", e); 142 } 143 } 144 145 private static String getOrCreateTxCacheDirectory(String txCacheDirectoryParam) throws IOException { 146 final String txCacheDirectory; 147 148 if (txCacheDirectoryParam != null) { 149 txCacheDirectory = txCacheDirectoryParam; 150 } else { 151 txCacheDirectory = Files.createTempDirectory("validator-test-tx-cache").toFile().getAbsolutePath(); 152 TxCacheResourceExtractor.extractTxCacheResources(txCacheDirectory); 153 } 154 155 return txCacheDirectory; 156 } 157 158 @Nonnull 159 public static List<ModuleTestExecutor> getjUnit5TestExecutors(String[] moduleNamesArg) { 160 final String[] moduleNames = moduleNamesArg == null ? JUNIT5_MODULE_NAMES : moduleNamesArg; 161 return Arrays.stream(moduleNames) 162 .map(moduleName -> JUnit5ModuleTestExecutor.getStandardModuleTestExecutor(moduleName)) 163 .collect(Collectors.toList()); 164 } 165 166 @Nonnull 167 public static List<ModuleTestExecutor> getjUnit4TestExecutors(String[] moduleNamesArg) { 168 169 final List<ModuleTestExecutor> jUnit4TestExecutors = Arrays.asList(new JUnit4TestExecutor(VALIDATION_MODULE, JUNIT4_CLASSNAMES)); 170 171 if (moduleNamesArg == null) { 172 return jUnit4TestExecutors; 173 } 174 175 return Arrays.stream(moduleNamesArg).anyMatch(moduleName -> VALIDATION_MODULE.equals(moduleName)) 176 ? jUnit4TestExecutors 177 : Arrays.asList(); 178 } 179}