Merge pull request #1640 from hapifhir/do-20240122-base-engine
Maintain a map of pre-built ValidationEngine instances
This commit is contained in:
commit
53ab71f118
|
@ -164,4 +164,17 @@ class I18nBaseTest {
|
||||||
assertNull(enLocale.getRootKeyFromPlural(rootKey + "_many"));
|
assertNull(enLocale.getRootKeyFromPlural(rootKey + "_many"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMessagesChangeWhenLocaleDoes() {
|
||||||
|
I18nTestClass i18nInstance = new I18nTestClass();
|
||||||
|
i18nInstance.setLocale(Locale.forLanguageTag("de"));
|
||||||
|
|
||||||
|
String deMessage = i18nInstance.formatMessage(I18nConstants.ERROR_PARSING_JSON_, "test");
|
||||||
|
assertEquals("Fehler beim Parsen von JSON: test", deMessage);
|
||||||
|
|
||||||
|
i18nInstance.setLocale(Locale.forLanguageTag("en"));
|
||||||
|
String enMessage = i18nInstance.formatMessage(I18nConstants.ERROR_PARSING_JSON_, "test");
|
||||||
|
assertEquals("Error parsing JSON: test", enMessage);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -316,7 +316,7 @@ public class IgLoader implements IValidationEngineLoader {
|
||||||
|
|
||||||
public void scanForIgVersion(String src,
|
public void scanForIgVersion(String src,
|
||||||
boolean recursive,
|
boolean recursive,
|
||||||
VersionSourceInformation versions) throws Exception {
|
VersionSourceInformation versions) throws IOException {
|
||||||
Map<String, ByteProvider> source = loadIgSourceForVersion(src, recursive, true, versions);
|
Map<String, ByteProvider> source = loadIgSourceForVersion(src, recursive, true, versions);
|
||||||
if (source != null) {
|
if (source != null) {
|
||||||
if (source.containsKey("version.info")) {
|
if (source.containsKey("version.info")) {
|
||||||
|
|
|
@ -105,7 +105,7 @@ public class ValidatorCli {
|
||||||
public static final String JAVA_DISABLED_PROXY_SCHEMES = "jdk.http.auth.proxying.disabledSchemes";
|
public static final String JAVA_DISABLED_PROXY_SCHEMES = "jdk.http.auth.proxying.disabledSchemes";
|
||||||
public static final String JAVA_USE_SYSTEM_PROXIES = "java.net.useSystemProxies";
|
public static final String JAVA_USE_SYSTEM_PROXIES = "java.net.useSystemProxies";
|
||||||
|
|
||||||
private static ValidationService validationService = new ValidationService();
|
private final static ValidationService validationService = new ValidationService();
|
||||||
|
|
||||||
protected ValidationService myValidationService;
|
protected ValidationService myValidationService;
|
||||||
|
|
||||||
|
@ -408,8 +408,4 @@ public class ValidatorCli {
|
||||||
return validationEngine;
|
return validationEngine;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void validateScan(CliContext cliContext, ValidationEngine validator) throws Exception {
|
|
||||||
Scanner validationScanner = new Scanner(validator.getContext(), validator.getValidator(null), validator.getIgLoader(), validator.getFhirPathEngine());
|
|
||||||
validationScanner.validateScan(cliContext.getOutput(), cliContext.getSources());
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -24,6 +24,8 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
*/
|
*/
|
||||||
public class CliContext {
|
public class CliContext {
|
||||||
|
|
||||||
|
@JsonProperty("baseEngine")
|
||||||
|
private String baseEngine = null;
|
||||||
@JsonProperty("doNative")
|
@JsonProperty("doNative")
|
||||||
private boolean doNative = false;
|
private boolean doNative = false;
|
||||||
@JsonProperty("hintAboutNonMustSupport")
|
@JsonProperty("hintAboutNonMustSupport")
|
||||||
|
@ -161,6 +163,16 @@ public class CliContext {
|
||||||
@JsonProperty("bestPracticeLevel")
|
@JsonProperty("bestPracticeLevel")
|
||||||
private BestPracticeWarningLevel bestPracticeLevel = BestPracticeWarningLevel.Warning;
|
private BestPracticeWarningLevel bestPracticeLevel = BestPracticeWarningLevel.Warning;
|
||||||
|
|
||||||
|
@JsonProperty("baseEngine")
|
||||||
|
public String getBaseEngine() {
|
||||||
|
return baseEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonProperty("baseEngine")
|
||||||
|
public CliContext setBaseEngine(String baseEngine) {
|
||||||
|
this.baseEngine = baseEngine;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@JsonProperty("map")
|
@JsonProperty("map")
|
||||||
public String getMap() {
|
public String getMap() {
|
||||||
|
@ -771,7 +783,8 @@ public class CliContext {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
CliContext that = (CliContext) o;
|
CliContext that = (CliContext) o;
|
||||||
return doNative == that.doNative &&
|
return Objects.equals(baseEngine, that.baseEngine) &&
|
||||||
|
doNative == that.doNative &&
|
||||||
hintAboutNonMustSupport == that.hintAboutNonMustSupport &&
|
hintAboutNonMustSupport == that.hintAboutNonMustSupport &&
|
||||||
recursive == that.recursive &&
|
recursive == that.recursive &&
|
||||||
doDebug == that.doDebug &&
|
doDebug == that.doDebug &&
|
||||||
|
@ -824,7 +837,7 @@ public class CliContext {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(doNative, extensions, hintAboutNonMustSupport, recursive, doDebug, assumeValidRestReferences, canDoNative, noInternalCaching,
|
return Objects.hash(baseEngine, doNative, extensions, hintAboutNonMustSupport, recursive, doDebug, assumeValidRestReferences, canDoNative, noInternalCaching,
|
||||||
noExtensibleBindingMessages, noInvariants, displayWarnings, wantInvariantsInMessages, map, output, outputSuffix, htmlOutput, txServer, sv, txLog, txCache, mapLog, lang, srcLang, tgtLang, fhirpath, snomedCT,
|
noExtensibleBindingMessages, noInvariants, displayWarnings, wantInvariantsInMessages, map, output, outputSuffix, htmlOutput, txServer, sv, txLog, txCache, mapLog, lang, srcLang, tgtLang, fhirpath, snomedCT,
|
||||||
targetVer, igs, questionnaireMode, level, profiles, sources, inputs, mode, locale, locations, crumbTrails, forPublication, showTimes, allowExampleUrls, outputStyle, jurisdiction, noUnicodeBiDiControlChars, watchMode, watchScanDelay, watchSettleTime, bestPracticeLevel,
|
targetVer, igs, questionnaireMode, level, profiles, sources, inputs, mode, locale, locations, crumbTrails, forPublication, showTimes, allowExampleUrls, outputStyle, jurisdiction, noUnicodeBiDiControlChars, watchMode, watchScanDelay, watchSettleTime, bestPracticeLevel,
|
||||||
htmlInMarkdownCheck, allowDoubleQuotesInFHIRPath, checkIPSCodes);
|
htmlInMarkdownCheck, allowDoubleQuotesInFHIRPath, checkIPSCodes);
|
||||||
|
@ -833,7 +846,8 @@ public class CliContext {
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "CliContext{" +
|
return "CliContext{" +
|
||||||
"doNative=" + doNative +
|
"baseEngine=" + baseEngine +
|
||||||
|
", doNative=" + doNative +
|
||||||
", extensions=" + extensions +
|
", extensions=" + extensions +
|
||||||
", hintAboutNonMustSupport=" + hintAboutNonMustSupport +
|
", hintAboutNonMustSupport=" + hintAboutNonMustSupport +
|
||||||
", recursive=" + recursive +
|
", recursive=" + recursive +
|
||||||
|
|
|
@ -117,6 +117,11 @@ public class PassiveExpiringSessionCache implements SessionCache {
|
||||||
return cachedSessions.keySet();
|
return cachedSessions.keySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cleanUp() {
|
||||||
|
removeExpiredSessions();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Session ids generated internally are UUID {@link String}.
|
* Session ids generated internally are UUID {@link String}.
|
||||||
* @return A new {@link String} session id.
|
* @return A new {@link String} session id.
|
||||||
|
|
|
@ -23,9 +23,6 @@ public interface SessionCache {
|
||||||
*/
|
*/
|
||||||
String cacheSession(String sessionId, ValidationEngine validationEngine);
|
String cacheSession(String sessionId, ValidationEngine validationEngine);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the passed in {@link String} id exists in the set of stored session id.
|
* Checks if the passed in {@link String} id exists in the set of stored session id.
|
||||||
* @param sessionId The {@link String} id to search for.
|
* @param sessionId The {@link String} id to search for.
|
||||||
|
@ -46,4 +43,9 @@ public interface SessionCache {
|
||||||
*/
|
*/
|
||||||
Set<String> getSessionIds();
|
Set<String> getSessionIds();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs any pending maintenance operations needed by the cache.
|
||||||
|
* */
|
||||||
|
public void cleanUp();
|
||||||
|
|
||||||
}
|
}
|
|
@ -2,7 +2,6 @@ package org.hl7.fhir.validation.cli.services;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
|
@ -11,6 +10,7 @@ import java.lang.management.MemoryMXBean;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
@ -75,25 +75,41 @@ public class ValidationService {
|
||||||
private final SessionCache sessionCache;
|
private final SessionCache sessionCache;
|
||||||
private String runDate;
|
private String runDate;
|
||||||
|
|
||||||
|
private final Map<String, ValidationEngine> baseEngines = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public void putBaseEngine(String key, CliContext cliContext) throws IOException, URISyntaxException {
|
||||||
|
if (cliContext.getSv() == null) {
|
||||||
|
throw new IllegalArgumentException("Cannot create a base engine without an explicit version");
|
||||||
|
}
|
||||||
|
String definitions = VersionUtilities.packageForVersion(cliContext.getSv()) + "#" + VersionUtilities.getCurrentVersion(cliContext.getSv());
|
||||||
|
|
||||||
|
ValidationEngine baseEngine = buildValidationEngine(cliContext, definitions, new TimeTracker());
|
||||||
|
baseEngines.put(key, baseEngine);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValidationEngine getBaseEngine(String key) {
|
||||||
|
return baseEngines.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getBaseEngineKeys() { return baseEngines.keySet(); }
|
||||||
|
|
||||||
|
public boolean hasBaseEngineForKey(String key) { return baseEngines.containsKey(key); }
|
||||||
|
|
||||||
public ValidationService() {
|
public ValidationService() {
|
||||||
sessionCache = new PassiveExpiringSessionCache();
|
sessionCache = new PassiveExpiringSessionCache();
|
||||||
runDate = new SimpleDateFormat("hh:mm:ss", new Locale("en", "US")).format(new Date());
|
runDate = new SimpleDateFormat("hh:mm:ss", new Locale("en", "US")).format(new Date());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public ValidationService(SessionCache cache) {
|
public ValidationService(SessionCache cache) {
|
||||||
this.sessionCache = cache;
|
this.sessionCache = cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValidationResponse validateSources(ValidationRequest request) throws Exception {
|
public ValidationResponse validateSources(ValidationRequest request) throws Exception {
|
||||||
if (request.getCliContext().getSv() == null) {
|
|
||||||
String sv = determineVersion(request.getCliContext(), request.sessionId);
|
|
||||||
request.getCliContext().setSv(sv);
|
|
||||||
}
|
|
||||||
|
|
||||||
String definitions = VersionUtilities.packageForVersion(request.getCliContext().getSv()) + "#" + VersionUtilities.getCurrentVersion(request.getCliContext().getSv());
|
|
||||||
|
|
||||||
TimeTracker timeTracker = new TimeTracker();
|
TimeTracker timeTracker = new TimeTracker();
|
||||||
String sessionId = initializeValidator(request.getCliContext(), definitions, timeTracker, request.sessionId);
|
String sessionId = initializeValidator(request.getCliContext(), null, timeTracker, request.sessionId);
|
||||||
ValidationEngine validator = sessionCache.fetchSessionValidatorEngine(sessionId);
|
ValidationEngine validator = sessionCache.fetchSessionValidatorEngine(sessionId);
|
||||||
|
|
||||||
if (request.getCliContext().getProfiles().size() > 0) {
|
if (request.getCliContext().getProfiles().size() > 0) {
|
||||||
|
@ -180,7 +196,7 @@ public class ValidationService {
|
||||||
return outcome;
|
return outcome;
|
||||||
}
|
}
|
||||||
|
|
||||||
public VersionSourceInformation scanForVersions(CliContext cliContext) throws Exception {
|
public VersionSourceInformation scanForVersions(CliContext cliContext) throws IOException {
|
||||||
VersionSourceInformation versions = new VersionSourceInformation();
|
VersionSourceInformation versions = new VersionSourceInformation();
|
||||||
IgLoader igLoader = new IgLoader(
|
IgLoader igLoader = new IgLoader(
|
||||||
new FilesystemPackageCacheManager.Builder().build(),
|
new FilesystemPackageCacheManager.Builder().build(),
|
||||||
|
@ -473,16 +489,42 @@ public class ValidationService {
|
||||||
if (sessionId != null) {
|
if (sessionId != null) {
|
||||||
System.out.println("No such cached session exists for session id " + sessionId + ", re-instantiating validator.");
|
System.out.println("No such cached session exists for session id " + sessionId + ", re-instantiating validator.");
|
||||||
}
|
}
|
||||||
System.out.println("Building new validator engine from CliContext");
|
sessionCache.cleanUp();
|
||||||
ValidationEngine validator = buildValidationEngine(cliContext, definitions, tt);
|
if (cliContext.getSv() == null) {
|
||||||
sessionId = sessionCache.cacheSession(validator);
|
String sv = determineVersion(cliContext);
|
||||||
|
cliContext.setSv(sv);
|
||||||
|
}
|
||||||
|
final String engineDefinitions = definitions != null ? definitions : VersionUtilities.packageForVersion(cliContext.getSv()) + "#" + VersionUtilities.getCurrentVersion(cliContext.getSv());
|
||||||
|
|
||||||
|
ValidationEngine validationEngine = getValidationEngineFromCliContext(cliContext, engineDefinitions, tt);
|
||||||
|
sessionId = sessionCache.cacheSession(validationEngine);
|
||||||
System.out.println("Cached new session. Cache size = " + sessionCache.getSessionIds().size());
|
System.out.println("Cached new session. Cache size = " + sessionCache.getSessionIds().size());
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
System.out.println("Cached session exists for session id " + sessionId + ", returning stored validator session id. Cache size = " + sessionCache.getSessionIds().size());
|
System.out.println("Cached session exists for session id " + sessionId + ", returning stored validator session id. Cache size = " + sessionCache.getSessionIds().size());
|
||||||
}
|
}
|
||||||
return sessionId;
|
return sessionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ValidationEngine getValidationEngineFromCliContext(CliContext cliContext, String definitions, TimeTracker tt) throws Exception {
|
||||||
|
ValidationEngine validationEngine;
|
||||||
|
if (cliContext.getBaseEngine() != null && hasBaseEngineForKey(cliContext.getBaseEngine())) {
|
||||||
|
validationEngine = new ValidationEngine(getBaseEngine(cliContext.getBaseEngine()));
|
||||||
|
/* As a service, it wouldn't be efficient to have a base validation engine
|
||||||
|
* for every language. So we just use the baseEngine and set the language
|
||||||
|
* manually afterward.
|
||||||
|
*/
|
||||||
|
validationEngine.setLanguage(cliContext.getLang());
|
||||||
|
validationEngine.setLocale(cliContext.getLocale());
|
||||||
|
} else {
|
||||||
|
if (definitions == null) {
|
||||||
|
throw new IllegalArgumentException("Cannot create a validator engine (definitions == null)");
|
||||||
|
}
|
||||||
|
validationEngine = buildValidationEngine(cliContext, definitions, tt);
|
||||||
|
}
|
||||||
|
return validationEngine;
|
||||||
|
}
|
||||||
|
|
||||||
protected ValidationEngine.ValidationEngineBuilder getValidationEngineBuilder() {
|
protected ValidationEngine.ValidationEngineBuilder getValidationEngineBuilder() {
|
||||||
return new ValidationEngine.ValidationEngineBuilder();
|
return new ValidationEngine.ValidationEngineBuilder();
|
||||||
}
|
}
|
||||||
|
@ -564,12 +606,7 @@ public class ValidationService {
|
||||||
System.out.println(" Package Summary: "+ validationEngine.getContext().loadedPackageSummary());
|
System.out.println(" Package Summary: "+ validationEngine.getContext().loadedPackageSummary());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String determineVersion(CliContext cliContext) throws IOException {
|
||||||
public String determineVersion(CliContext cliContext) throws Exception {
|
|
||||||
return determineVersion(cliContext, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String determineVersion(CliContext cliContext, String sessionId) throws Exception {
|
|
||||||
if (cliContext.getMode() != EngineMode.VALIDATION && cliContext.getMode() != EngineMode.INSTALL) {
|
if (cliContext.getMode() != EngineMode.VALIDATION && cliContext.getMode() != EngineMode.INSTALL) {
|
||||||
return "5.0";
|
return "5.0";
|
||||||
}
|
}
|
||||||
|
@ -588,7 +625,7 @@ public class ValidationService {
|
||||||
System.out.println("-> use version " + versions.version());
|
System.out.println("-> use version " + versions.version());
|
||||||
return versions.version();
|
return versions.version();
|
||||||
}
|
}
|
||||||
throw new Exception("-> Multiple versions found. Specify a particular version using the -version parameter");
|
throw new IllegalArgumentException("-> Multiple versions found. Specify a particular version using the -version parameter");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void generateSpreadsheet(CliContext cliContext, ValidationEngine validator) throws Exception {
|
public void generateSpreadsheet(CliContext cliContext, ValidationEngine validator) throws Exception {
|
||||||
|
|
|
@ -44,7 +44,7 @@ import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.ArgumentMatchers;
|
import org.mockito.ArgumentMatchers;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
class ValidationServiceTest {
|
class ValidationServiceTests {
|
||||||
|
|
||||||
final String DUMMY_SOURCE = "dummySource";
|
final String DUMMY_SOURCE = "dummySource";
|
||||||
final String DUMMY_SOURCE1 = "dummySource1";
|
final String DUMMY_SOURCE1 = "dummySource1";
|
||||||
|
@ -54,34 +54,74 @@ class ValidationServiceTest {
|
||||||
|
|
||||||
final String DUMMY_SV = "1.2.3";
|
final String DUMMY_SV = "1.2.3";
|
||||||
|
|
||||||
|
@DisplayName("Test validation session persists in session cache")
|
||||||
@Test
|
@Test
|
||||||
void validateSources() throws Exception {
|
void validationSessionTest() throws Exception {
|
||||||
TestingUtilities.injectCorePackageLoader();
|
TestingUtilities.injectCorePackageLoader();
|
||||||
SessionCache sessionCache = Mockito.spy(new PassiveExpiringSessionCache());
|
SessionCache sessionCache = Mockito.spy(new PassiveExpiringSessionCache());
|
||||||
ValidationService myService = new ValidationService(sessionCache);
|
ValidationService myService = Mockito.spy(new ValidationService(sessionCache));
|
||||||
|
|
||||||
String resource = IOUtils.toString(getFileFromResourceAsStream("detected_issues.json"), StandardCharsets.UTF_8);
|
List<FileInfo> filesToValidate = getFilesToValidate();
|
||||||
List<FileInfo> filesToValidate = new ArrayList<>();
|
|
||||||
filesToValidate.add(new FileInfo().setFileName("test_resource.json").setFileContent(resource).setFileType(Manager.FhirFormat.JSON.getExtension()));
|
|
||||||
|
|
||||||
ValidationRequest request = new ValidationRequest().setCliContext(new CliContext().setTxServer(FhirSettings.getTxFhirDevelopment()).setTxCache(getTerminologyCacheDirectory("validationService"))).setFilesToValidate(filesToValidate);
|
ValidationRequest request = new ValidationRequest().setCliContext(new CliContext().setTxServer(FhirSettings.getTxFhirDevelopment()).setTxCache(getTerminologyCacheDirectory("validationService"))).setFilesToValidate(filesToValidate);
|
||||||
// Validation run 1...nothing cached yet
|
// Validation run 1...nothing cached yet
|
||||||
myService.validateSources(request);
|
myService.validateSources(request);
|
||||||
verify(sessionCache, Mockito.times(1)).cacheSession(ArgumentMatchers.any(ValidationEngine.class));
|
verify(sessionCache, Mockito.times(1)).cacheSession(ArgumentMatchers.any(ValidationEngine.class));
|
||||||
|
verify(sessionCache, Mockito.times(1)).cleanUp();
|
||||||
|
verify(myService, Mockito.times(1)).buildValidationEngine(any(), any(), any());
|
||||||
Set<String> sessionIds = sessionCache.getSessionIds();
|
Set<String> sessionIds = sessionCache.getSessionIds();
|
||||||
if (sessionIds.stream().findFirst().isPresent()) {
|
if (sessionIds.stream().findFirst().isPresent()) {
|
||||||
// Verify that after 1 run there is only one entry within the cache
|
// Verify that after 1 run there is only one entry within the cache
|
||||||
Assertions.assertEquals(1, sessionIds.size());
|
Assertions.assertEquals(1, sessionIds.size());
|
||||||
myService.validateSources(request);
|
myService.validateSources(request.setSessionId(sessionIds.stream().findFirst().get()));
|
||||||
// Verify that the cache has been called on once with the id created in the first run
|
// Verify that the cache has been called on twice with the id created in the first run
|
||||||
verify(sessionCache, Mockito.times(1)).fetchSessionValidatorEngine(sessionIds.stream().findFirst().get());
|
verify(sessionCache, Mockito.times(2)).fetchSessionValidatorEngine(sessionIds.stream().findFirst().get());
|
||||||
|
verify(sessionCache, Mockito.times(1)).cleanUp();
|
||||||
|
verify(myService, Mockito.times(1)).buildValidationEngine(any(), any(), any());
|
||||||
} else {
|
} else {
|
||||||
// If no sessions exist within the cache after a run, we auto-fail.
|
// If no sessions exist within the cache after a run, we auto-fail.
|
||||||
fail();
|
fail();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DisplayName("Test validation session will inherit a base validation engine")
|
||||||
|
@Test
|
||||||
|
void validationSessionBaseEngineTest() throws Exception {
|
||||||
|
TestingUtilities.injectCorePackageLoader();
|
||||||
|
|
||||||
|
ValidationService myService = Mockito.spy(new ValidationService());
|
||||||
|
|
||||||
|
CliContext baseContext = new CliContext().setBaseEngine("myDummyKey").setSv("4.0.1").setTxServer(FhirSettings.getTxFhirDevelopment()).setTxCache(getTerminologyCacheDirectory("validationService"));
|
||||||
|
myService.putBaseEngine("myDummyKey", baseContext);
|
||||||
|
verify(myService, Mockito.times(1)).buildValidationEngine(any(), any(), any());
|
||||||
|
|
||||||
|
{
|
||||||
|
final List<FileInfo> filesToValidate = getFilesToValidate();
|
||||||
|
final ValidationRequest request = new ValidationRequest().setCliContext(new CliContext().setSv("4.0.1")).setFilesToValidate(filesToValidate);
|
||||||
|
myService.validateSources(request);
|
||||||
|
|
||||||
|
verify(myService, Mockito.times(0)).getBaseEngine("myDummyKey");
|
||||||
|
verify(myService, Mockito.times(2)).buildValidationEngine(any(), any(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
final List<FileInfo> filesToValidate = getFilesToValidate();
|
||||||
|
final ValidationRequest request = new ValidationRequest().setCliContext(new CliContext().setBaseEngine("myDummyKey")).setFilesToValidate(filesToValidate);
|
||||||
|
myService.validateSources(request);
|
||||||
|
|
||||||
|
verify(myService, Mockito.times(1)).getBaseEngine("myDummyKey");
|
||||||
|
verify(myService, Mockito.times(2)).buildValidationEngine(any(), any(), any());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<FileInfo> getFilesToValidate() throws IOException {
|
||||||
|
List<FileInfo> filesToValidate = new ArrayList<>();
|
||||||
|
String resource = IOUtils.toString(getFileFromResourceAsStream("detected_issues.json"), StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
filesToValidate.add(new FileInfo().setFileName("test_resource.json").setFileContent(resource).setFileType(Manager.FhirFormat.JSON.getExtension()));
|
||||||
|
return filesToValidate;
|
||||||
|
}
|
||||||
|
|
||||||
private InputStream getFileFromResourceAsStream(String fileName) {
|
private InputStream getFileFromResourceAsStream(String fileName) {
|
||||||
// The class loader that loaded the class
|
// The class loader that loaded the class
|
||||||
ClassLoader classLoader = getClass().getClassLoader();
|
ClassLoader classLoader = getClass().getClassLoader();
|
|
@ -1,5 +1,6 @@
|
||||||
package org.hl7.fhir.validation.tests;
|
package org.hl7.fhir.validation.tests;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -18,6 +19,7 @@ import org.hl7.fhir.validation.IgLoader;
|
||||||
import org.hl7.fhir.validation.ValidationEngine;
|
import org.hl7.fhir.validation.ValidationEngine;
|
||||||
import org.hl7.fhir.validation.tests.utilities.TestUtilities;
|
import org.hl7.fhir.validation.tests.utilities.TestUtilities;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
public class ValidationEngineTests {
|
public class ValidationEngineTests {
|
||||||
|
@ -27,6 +29,88 @@ public class ValidationEngineTests {
|
||||||
|
|
||||||
public static boolean inbuild;
|
public static boolean inbuild;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("A ValidationEngine copied from another validation engine shouldn't interfere with the original during validations")
|
||||||
|
void validateWithParallelCopiedEngine() throws Exception {
|
||||||
|
|
||||||
|
final String INPUT_1 = "patient-duplicate.json";
|
||||||
|
final String INPUT_2 = "patient-lang1.json";
|
||||||
|
final String INPUT_3 = "patient-id-bad-1.json";
|
||||||
|
|
||||||
|
final String[] ISSUE_CODES_1 = { "invalid" };
|
||||||
|
final String[] ISSUE_CODES_2 = {"business-rule"};
|
||||||
|
final String[] ISSUE_CODES_3 = {"invalid", "invariant"};
|
||||||
|
|
||||||
|
ValidationEngine originalEngine = TestUtilities.getValidationEngine("hl7.fhir.r4.core#4.0.1", DEF_TX, FhirPublication.R4, "4.0.1");
|
||||||
|
|
||||||
|
final ValidationEngine[] validationEngines = new ValidationEngine[10];
|
||||||
|
validationEngines[0] = originalEngine;
|
||||||
|
|
||||||
|
final OperationOutcome[] outcomes = new OperationOutcome[validationEngines.length];
|
||||||
|
|
||||||
|
for (int i = 1; i < validationEngines.length; i++) {
|
||||||
|
validationEngines[i] = new ValidationEngine(originalEngine);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String[] testInputs = {
|
||||||
|
INPUT_1,
|
||||||
|
INPUT_1,
|
||||||
|
INPUT_2,
|
||||||
|
INPUT_3,
|
||||||
|
INPUT_1,
|
||||||
|
INPUT_2,
|
||||||
|
INPUT_3,
|
||||||
|
INPUT_1,
|
||||||
|
INPUT_2,
|
||||||
|
INPUT_3
|
||||||
|
};
|
||||||
|
// Pick 3 validation cases
|
||||||
|
final String[][] testCodes = {
|
||||||
|
ISSUE_CODES_1,
|
||||||
|
ISSUE_CODES_1,
|
||||||
|
ISSUE_CODES_2,
|
||||||
|
ISSUE_CODES_3,
|
||||||
|
ISSUE_CODES_1,
|
||||||
|
ISSUE_CODES_2,
|
||||||
|
ISSUE_CODES_3,
|
||||||
|
ISSUE_CODES_1,
|
||||||
|
ISSUE_CODES_2,
|
||||||
|
ISSUE_CODES_3
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
List<Thread> threads = new ArrayList<>();
|
||||||
|
for (int i = 0; i < validationEngines.length; i++) {
|
||||||
|
final int index = i;
|
||||||
|
Thread t = new Thread(() -> {
|
||||||
|
try {
|
||||||
|
final String testInput = testInputs[index];
|
||||||
|
outcomes[index] = validationEngines[index].validate(FhirFormat.JSON, TestingUtilities.loadTestResourceStream("validator", testInput), null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
System.err.println("Thread " + index + " failed");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
t.start();
|
||||||
|
threads.add(t);
|
||||||
|
}
|
||||||
|
threads.forEach(t -> {
|
||||||
|
try {
|
||||||
|
t.join();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (int i = 0; i < outcomes.length; i++) {
|
||||||
|
assertEquals(testCodes[i].length, outcomes[i].getIssue().size());
|
||||||
|
for (int j = 0; j < outcomes[i].getIssue().size(); j++) {
|
||||||
|
System.out.print(i + " " + j);
|
||||||
|
assertEquals(testCodes[i][j], outcomes[i].getIssue().get(j).getCode().toCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test401Xml() throws Exception {
|
public void test401Xml() throws Exception {
|
||||||
if (!TestUtilities.silent)
|
if (!TestUtilities.silent)
|
||||||
|
|
Loading…
Reference in New Issue