Skip to content

Commit

Permalink
Merge pull request hapifhir#1578 from hapifhir/do-20240319-tx-test-reuse
Browse files Browse the repository at this point in the history
Refactor terminology service tests for reuse outside core
  • Loading branch information
grahamegrieve authored Apr 10, 2024
2 parents 1f3d283 + 81f26a8 commit 890737e
Show file tree
Hide file tree
Showing 4 changed files with 314 additions and 229 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
package org.hl7.fhir.validation.special;

import com.google.gson.JsonSyntaxException;
import org.hl7.fhir.r5.formats.JsonParser;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.formats.IParser;
import org.hl7.fhir.r5.model.*;
import org.hl7.fhir.r5.terminologies.utilities.TerminologyServiceErrorClass;
import org.hl7.fhir.r5.terminologies.utilities.ValidationResult;
import org.hl7.fhir.r5.test.utils.CompareUtilities;
import org.hl7.fhir.utilities.FhirPublication;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.json.model.JsonObject;
import org.hl7.fhir.utilities.validation.ValidationOptions;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

public class TxServiceTestHelper {


public static String getDiffForValidation(String id, IWorkerContext context, String name, Resource requestParameters, String expectedResponse, String lang, String fp, JsonObject externals, boolean isCodeSystem) throws JsonSyntaxException, FileNotFoundException, IOException {
org.hl7.fhir.r5.model.Parameters p = (org.hl7.fhir.r5.model.Parameters) requestParameters;
ValueSet valueSet = null;
String valueSetUrl = null;
if (!isCodeSystem) {
if (p.hasParameter("valueSetVersion")) {
valueSetUrl = p.getParameterValue("url").primitiveValue()+"|"+p.getParameterValue("valueSetVersion").primitiveValue();
valueSet = context.fetchResource(ValueSet.class, p.getParameterValue("url").primitiveValue(), p.getParameterValue("valueSetVersion").primitiveValue());
} else {
valueSetUrl = p.getParameterValue("url").primitiveValue();
valueSet = context.fetchResource(ValueSet.class, p.getParameterValue("url").primitiveValue());
}
}
ValidationResult validationResult = null;
String code = null;
String system = null;
String version = null;
String display = null;
CodeableConcept codeableConcept = null;
org.hl7.fhir.r5.model.Parameters parameters = null;
OperationOutcome operationOutcome = null;

if (valueSet == null && valueSetUrl != null) {
String msg = context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_VALUE_SET_, valueSetUrl);
operationOutcome = new OperationOutcome();
CodeableConcept codeableConceptWhenNullValueSet = operationOutcome.addIssue().setSeverity(OperationOutcome.IssueSeverity.ERROR).setCode(OperationOutcome.IssueType.NOTFOUND).getDetails();
codeableConceptWhenNullValueSet.addCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "not-found", null);
codeableConceptWhenNullValueSet.setText(msg);
} else {
ValidationOptions options = new ValidationOptions(FhirPublication.R5);
if (p.hasParameter("displayLanguage")) {
options = options.withLanguage(p.getParameterString("displayLanguage"));
} else if (lang != null ) {
options = options.withLanguage(lang);
}
if (p.hasParameter("valueset-membership-only") && "true".equals(p.getParameterString("valueset-membership-only"))) {
options = options.withCheckValueSetOnly();
}
if (p.hasParameter("lenient-display-validation") && "true".equals(p.getParameterString("lenient-display-validation"))) {
options = options.setDisplayWarningMode(true);
}
if (p.hasParameter("activeOnly") && "true".equals(p.getParameterString("activeOnly"))) {
options = options.setActiveOnly(true);
}
context.getExpansionParameters().clearParameters("includeAlternateCodes");
for (Parameters.ParametersParameterComponent pp : p.getParameter()) {
if ("includeAlternateCodes".equals(pp.getName())) {
context.getExpansionParameters().addParameter(pp.copy());
}
}
if (p.hasParameter("code")) {
code = p.getParameterString("code");
system = p.getParameterString(isCodeSystem ? "url" : "system");
version = p.getParameterString(isCodeSystem ? "version" : "systemVersion");
display = p.getParameterString("display");
validationResult = context.validateCode(options.withGuessSystem(),
p.getParameterString(isCodeSystem ? "url" : "system"), p.getParameterString(isCodeSystem ? "version" : "systemVersion"),
p.getParameterString("code"), p.getParameterString("display"), valueSet);
} else if (p.hasParameter("coding")) {
Coding coding = (Coding) p.getParameterValue("coding");
code = coding.getCode();
system = coding.getSystem();
version = coding.getVersion();
display = coding.getDisplay();
validationResult = context.validateCode(options, coding, valueSet);
} else if (p.hasParameter("codeableConcept")) {
codeableConcept = (CodeableConcept) p.getParameterValue("codeableConcept");
validationResult = context.validateCode(options, codeableConcept, valueSet);
} else {
throw new Error("validate not done yet for this steup");
}
}
if (operationOutcome == null && validationResult != null && validationResult.getSeverity() == org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity.FATAL) {
operationOutcome = new OperationOutcome();
operationOutcome.getIssue().addAll(validationResult.getIssues());
}
if (operationOutcome != null) {
TxTesterSorters.sortOperationOutcome(operationOutcome);
TxTesterScrubbers.scrubOO(operationOutcome, false);

String actualResponse = new JsonParser().setOutputStyle(IParser.OutputStyle.PRETTY).composeString(operationOutcome);



writeDiffToFileSystem( name, expectedResponse, actualResponse);

String diff = CompareUtilities.checkJsonSrcIsSame(id, expectedResponse, actualResponse, externals);
if (diff != null) {
Utilities.createDirectory(Utilities.getDirectoryForFile(fp));
TextFile.stringToFile(actualResponse, fp);
System.out.println("Test "+name+"failed: "+diff);
}
return diff;
} else {
if (parameters == null) {
parameters = new org.hl7.fhir.r5.model.Parameters();
if (validationResult.getSystem() != null) {
parameters.addParameter("system", new UriType(validationResult.getSystem()));
} else if (system != null) {
parameters.addParameter("system", new UriType(system));
}
if (validationResult.getCode() != null) {
if (code != null && !code.equals(validationResult.getCode())) {
parameters.addParameter("code", new CodeType(code));
parameters.addParameter("normalized-code", new CodeType(validationResult.getCode()));
} else {
parameters.addParameter("code", new CodeType(validationResult.getCode()));
}
} else if (code != null) {
parameters.addParameter("code", new CodeType(code));
}
if (validationResult.getSeverity() == org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity.ERROR) {
parameters.addParameter("result", false);
} else {
parameters.addParameter("result", true);
}
if (validationResult.getMessage() != null) {
parameters.addParameter("message", validationResult.getMessage());
}
if (validationResult.getVersion() != null) {
parameters.addParameter("version", validationResult.getVersion());
} else if (version != null) {
parameters.addParameter("version", new StringType(version));
}
if (validationResult.getDisplay() != null) {
parameters.addParameter("display", validationResult.getDisplay());
} else if (display != null) {
parameters.addParameter("display", new StringType(display));
}
// if (vm.getCodeableConcept() != null) {
// res.addParameter("codeableConcept", vm.getCodeableConcept());
// } else
if (codeableConcept != null) {
parameters.addParameter("codeableConcept", codeableConcept);
}
if (validationResult.isInactive()) {
parameters.addParameter("inactive", true);
}
if (validationResult.getStatus() != null) {
parameters.addParameter("status", validationResult.getStatus());
}
if (validationResult.getUnknownSystems() != null) {
for (String s : validationResult.getUnknownSystems()) {
parameters.addParameter(validationResult.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED ? "x-caused-by-unknown-system" : "x-unknown-system", new CanonicalType(s));
}
}
if (validationResult.getIssues().size() > 0) {
operationOutcome = new OperationOutcome();
operationOutcome.getIssue().addAll(validationResult.getIssues());
parameters.addParameter().setName("issues").setResource(operationOutcome);
}
}

TxTesterSorters.sortParameters(parameters);
TxTesterScrubbers.scrubParams(parameters);

String actualResponse = new JsonParser().setOutputStyle(IParser.OutputStyle.PRETTY).composeString(parameters);

writeDiffToFileSystem(name, expectedResponse, actualResponse);

String diff = CompareUtilities.checkJsonSrcIsSame(id, expectedResponse, actualResponse, externals);
if (diff != null) {
Utilities.createDirectory(Utilities.getDirectoryForFile(fp));
TextFile.stringToFile(actualResponse, fp);
System.out.println("Test "+name+"failed: "+diff);
}
return diff;
}
}

public static void writeDiffToFileSystem(String testName, String expected, String actual) throws IOException {
String rootDirectory = System.getenv("TX_SERVICE_TEST_DIFF_TARGET");
if (rootDirectory == null || rootDirectory.isEmpty()) {
return;
}
String fullExpected = rootDirectory + "/expected/";
String fullActual = rootDirectory + "/actual/";
File expectedDirectory = new File(fullExpected);
if (!expectedDirectory.exists()) {
expectedDirectory.mkdirs();
}

File actualDirectory = new File(fullActual);
if (!actualDirectory.exists()) {
actualDirectory.mkdirs();
}
TextFile.stringToFile(expected, fullExpected + testName + ".json");
TextFile.stringToFile(actual, fullActual + testName + ".json");

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package org.hl7.fhir.validation.special;

import lombok.Getter;
import org.hl7.fhir.r5.test.utils.TestingUtilities;
import org.hl7.fhir.utilities.json.model.JsonObject;

import java.io.IOException;
import java.util.*;

public class TxTestData {

@Getter
private final JsonObject manifest;

@Getter
private final JsonObject externals;

@Getter
private final List<Object[]> testData;

private TxTestData(List<Object[]> testData, JsonObject manifest, JsonObject externals) throws IOException {
this.testData = testData;
this.manifest = manifest;
this.externals = externals;
}

public static TxTestData loadTestDataFromDefaultClassPath() throws IOException {
String contents = TestingUtilities.loadTestResource("tx", "test-cases.json");
String externalSource = TestingUtilities.loadTestResource("tx", "messages-tx.fhir.org.json");
JsonObject externals = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(externalSource);

Map<String, TxTestSetup> examples = new HashMap<String, TxTestSetup>();
JsonObject manifest = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(contents);
for (JsonObject suite : manifest.getJsonObjects("suites")) {
if (!"tx.fhir.org".equals(suite.asString("mode"))) {
String sn = suite.asString("name");
for (JsonObject test : suite.getJsonObjects("tests")) {
String tn = test.asString("name");
examples.put(sn + "." + tn, new TxTestSetup(suite, test));
}
}
}

List<String> names = new ArrayList<String>(examples.size());
names.addAll(examples.keySet());
Collections.sort(names);

List<Object[]> testData = new ArrayList<Object[]>(examples.size());
for (String id : names) {
testData.add(new Object[]{id, examples.get(id)});
}

return new TxTestData(testData, manifest, externals);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.hl7.fhir.validation.special;

import lombok.Getter;
import org.hl7.fhir.utilities.json.model.JsonObject;

public class TxTestSetup {
public TxTestSetup(JsonObject suite, JsonObject test) {
this.suite = suite;
this.test = test;
}

@Getter
private JsonObject suite;
@Getter
private JsonObject test;

}
Loading

0 comments on commit 890737e

Please sign in to comment.