Search in sources :

Example 1 with SingleValidationMessage

use of ca.uhn.fhir.validation.SingleValidationMessage in project synthea by synthetichealth.

the class FHIRR4ExporterTest method testFHIRR4Export.

@Test
public void testFHIRR4Export() throws Exception {
    TestHelper.loadTestProperties();
    Generator.DEFAULT_STATE = Config.get("test_state.default", "Massachusetts");
    Config.set("exporter.baseDirectory", tempFolder.newFolder().toString());
    FhirContext ctx = FhirR4.getContext();
    IParser parser = ctx.newJsonParser().setPrettyPrint(true);
    ValidationResources validator = new ValidationResources();
    List<String> errors = ParallelTestingService.runInParallel((person) -> {
        List<String> validationErrors = new ArrayList<String>();
        TestHelper.exportOff();
        FhirR4.TRANSACTION_BUNDLE = person.randBoolean();
        FhirR4.USE_US_CORE_IG = person.randBoolean();
        FhirR4.USE_SHR_EXTENSIONS = false;
        String fhirJson = FhirR4.convertToFHIRJson(person, System.currentTimeMillis());
        // (these should have been converted into URIs)
        if (fhirJson.contains("SNOMED-CT")) {
            validationErrors.add("JSON contains unconverted references to 'SNOMED-CT' (should be URIs)");
        }
        // Let's crack open the Bundle and validate
        // each individual entry.resource to get context-sensitive error
        // messages...
        // IMPORTANT: this approach significantly reduces memory usage when compared to
        // validating the entire bundle at a time, but means that validating references
        // is impossible.
        // As of 2021-01-05, validating the bundle didn't validate references anyway,
        // but at some point we may want to do that.
        Bundle bundle = parser.parseResource(Bundle.class, fhirJson);
        for (Bundle.BundleEntryComponent entry : bundle.getEntry()) {
            ValidationResult eresult = validator.validateR4(entry.getResource());
            if (!eresult.isSuccessful()) {
                for (SingleValidationMessage emessage : eresult.getMessages()) {
                    boolean valid = false;
                    if (emessage.getSeverity() == ResultSeverityEnum.INFORMATION || emessage.getSeverity() == ResultSeverityEnum.WARNING) {
                        /*
               * Ignore warnings.
               */
                        valid = true;
                    } else if (emessage.getMessage().contains("us-core-documentreference-type")) {
                        /*
               * The instance validator does not expand intentional value sets like this one.
               */
                        valid = true;
                    } else if (emessage.getMessage().contains("@ AllergyIntolerance ait-2")) {
                        /*
               * The ait-2 invariant:
               * Description:
               * AllergyIntolerance.clinicalStatus SHALL NOT be present
               * if verification Status is entered-in-error
               * Expression:
               * verificationStatus!='entered-in-error' or clinicalStatus.empty()
               */
                        valid = true;
                    } else if (emessage.getMessage().contains("@ ExplanationOfBenefit dom-3")) {
                        /*
               * For some reason, it doesn't like the contained ServiceRequest and contained
               * Coverage resources in the ExplanationOfBenefit, both of which are
               * properly referenced. Running $validate on test servers finds this valid...
               */
                        valid = true;
                    } else if (emessage.getMessage().contains("per-1: If present, start SHALL have a lower value than end")) {
                        /*
               * The per-1 invariant does not account for daylight savings time... so, if the
               * daylight savings switch happens between the start and end, the validation
               * fails, even if it is valid.
               */
                        // ignore this error
                        valid = true;
                    } else if (emessage.getMessage().contains("Unknown extension http://hl7.org/fhir/us/core") || emessage.getMessage().contains("Unknown extension http://synthetichealth") || emessage.getMessage().contains("not be resolved, so has not been checked")) {
                        /*
               * Despite setting instanceValidator.setAnyExtensionsAllowed(true) and
               * instanceValidator.setErrorForUnknownProfiles(false), the FHIR validator still
               * reports these as errors
               */
                        // ignore this error
                        valid = true;
                    }
                    if (!valid) {
                        System.out.println(parser.encodeResourceToString(entry.getResource()));
                        System.out.println("ERROR: " + emessage.getMessage());
                        validationErrors.add(emessage.getMessage());
                    }
                }
            }
        }
        if (!validationErrors.isEmpty()) {
            Exporter.export(person, System.currentTimeMillis());
        }
        return validationErrors;
    });
    assertTrue("Validation of exported FHIR bundle failed: " + String.join("|", errors), errors.size() == 0);
}
Also used : FhirContext(ca.uhn.fhir.context.FhirContext) SingleValidationMessage(ca.uhn.fhir.validation.SingleValidationMessage) Bundle(org.hl7.fhir.r4.model.Bundle) ArrayList(java.util.ArrayList) BundleEntryComponent(org.hl7.fhir.r4.model.Bundle.BundleEntryComponent) ValidationResult(ca.uhn.fhir.validation.ValidationResult) IParser(ca.uhn.fhir.parser.IParser) Test(org.junit.Test)

Example 2 with SingleValidationMessage

use of ca.uhn.fhir.validation.SingleValidationMessage in project synthea by synthetichealth.

the class HospitalExporterTestStu3 method testFHIRExport.

@Test
public void testFHIRExport() throws Exception {
    FhirContext ctx = FhirStu3.getContext();
    FhirValidator validator = ctx.newValidator();
    validator.setValidateAgainstStandardSchema(true);
    validator.setValidateAgainstStandardSchematron(true);
    File tempOutputFolder = tempFolder.newFolder();
    Config.set("exporter.baseDirectory", tempOutputFolder.toString());
    Config.set("exporter.hospital.fhir_stu3.export", "true");
    Config.set("exporter.fhir.transaction_bundle", "true");
    // set this manually, in case it has already been loaded.
    FhirStu3.TRANSACTION_BUNDLE = true;
    TestHelper.loadTestProperties();
    Generator.DEFAULT_STATE = Config.get("test_state.default", "Massachusetts");
    Location location = new Location(Generator.DEFAULT_STATE, null);
    Provider.clear();
    Provider.loadProviders(location, 1L);
    assertNotNull(Provider.getProviderList());
    assertFalse(Provider.getProviderList().isEmpty());
    Provider.getProviderList().get(0).incrementEncounters(EncounterType.WELLNESS, 0);
    HospitalExporterStu3.export(0L);
    File expectedExportFolder = tempOutputFolder.toPath().resolve("fhir_stu3").toFile();
    assertTrue(expectedExportFolder.exists() && expectedExportFolder.isDirectory());
    File expectedExportFile = expectedExportFolder.toPath().resolve("hospitalInformation0.json").toFile();
    assertTrue(expectedExportFile.exists() && expectedExportFile.isFile());
    FileReader fileReader = new FileReader(expectedExportFile.getPath());
    BufferedReader bufferedReader = new BufferedReader(fileReader);
    StringBuilder fhirJson = new StringBuilder();
    String line = null;
    while ((line = bufferedReader.readLine()) != null) {
        fhirJson.append(line);
    }
    bufferedReader.close();
    IBaseResource resource = ctx.newJsonParser().parseResource(fhirJson.toString());
    ValidationResult result = validator.validateWithResult(resource);
    if (result.isSuccessful() == false) {
        for (SingleValidationMessage message : result.getMessages()) {
            System.out.println(message.getSeverity().toString() + ": " + message.getMessage());
        }
    }
    assertTrue(result.isSuccessful());
}
Also used : FhirContext(ca.uhn.fhir.context.FhirContext) SingleValidationMessage(ca.uhn.fhir.validation.SingleValidationMessage) BufferedReader(java.io.BufferedReader) FileReader(java.io.FileReader) FhirValidator(ca.uhn.fhir.validation.FhirValidator) IBaseResource(org.hl7.fhir.instance.model.api.IBaseResource) ValidationResult(ca.uhn.fhir.validation.ValidationResult) File(java.io.File) Location(org.mitre.synthea.world.geography.Location) Test(org.junit.Test)

Example 3 with SingleValidationMessage

use of ca.uhn.fhir.validation.SingleValidationMessage in project synthea by synthetichealth.

the class FHIRDSTU2ExporterTest method testFHIRDSTU2Export.

@Test
public void testFHIRDSTU2Export() throws Exception {
    TestHelper.loadTestProperties();
    Generator.DEFAULT_STATE = Config.get("test_state.default", "Massachusetts");
    Config.set("exporter.baseDirectory", tempFolder.newFolder().toString());
    FhirContext ctx = FhirDstu2.getContext();
    IParser parser = ctx.newJsonParser().setPrettyPrint(true);
    FhirValidator validator = ctx.newValidator();
    validator.setValidateAgainstStandardSchema(true);
    validator.setValidateAgainstStandardSchematron(true);
    List<String> errors = ParallelTestingService.runInParallel((person) -> {
        List<String> validationErrors = new ArrayList<String>();
        Config.set("exporter.fhir_dstu2.export", "true");
        FhirDstu2.TRANSACTION_BUNDLE = person.randBoolean();
        String fhirJson = FhirDstu2.convertToFHIRJson(person, System.currentTimeMillis());
        // (these should have been converted into URIs)
        if (fhirJson.contains("SNOMED-CT")) {
            validationErrors.add("JSON contains unconverted references to 'SNOMED-CT' (should be URIs)");
        }
        // let's crack open the Bundle and validate
        // each individual entry.resource to get context-sensitive error
        // messages...
        Bundle bundle = parser.parseResource(Bundle.class, fhirJson);
        for (Entry entry : bundle.getEntry()) {
            ValidationResult eresult = validator.validateWithResult(entry.getResource());
            if (!eresult.isSuccessful()) {
                for (SingleValidationMessage emessage : eresult.getMessages()) {
                    if (emessage.getMessage().contains("start SHALL have a lower value than end")) {
                        continue;
                    }
                    System.out.println(parser.encodeResourceToString(entry.getResource()));
                    System.out.println("ERROR: " + emessage.getMessage());
                    validationErrors.add(emessage.getMessage());
                }
            }
            if (entry.getResource() instanceof DiagnosticReport) {
                DiagnosticReport report = (DiagnosticReport) entry.getResource();
                if (report.getPerformer().isEmpty()) {
                    validationErrors.add("Performer is a required field on DiagnosticReport!");
                }
            }
        }
        if (!validationErrors.isEmpty()) {
            Exporter.export(person, System.currentTimeMillis());
        }
        return validationErrors;
    });
    assertTrue("Validation of exported FHIR bundle failed: " + String.join("|", errors), errors.size() == 0);
}
Also used : FhirContext(ca.uhn.fhir.context.FhirContext) Entry(ca.uhn.fhir.model.dstu2.resource.Bundle.Entry) SingleValidationMessage(ca.uhn.fhir.validation.SingleValidationMessage) Bundle(ca.uhn.fhir.model.dstu2.resource.Bundle) ArrayList(java.util.ArrayList) DiagnosticReport(org.hl7.fhir.dstu3.model.DiagnosticReport) FhirValidator(ca.uhn.fhir.validation.FhirValidator) ValidationResult(ca.uhn.fhir.validation.ValidationResult) IParser(ca.uhn.fhir.parser.IParser) Test(org.junit.Test)

Example 4 with SingleValidationMessage

use of ca.uhn.fhir.validation.SingleValidationMessage in project synthea by synthetichealth.

the class FHIRSTU3ExporterTest method testFHIRSTU3Export.

@Test
public void testFHIRSTU3Export() throws Exception {
    TestHelper.loadTestProperties();
    Generator.DEFAULT_STATE = Config.get("test_state.default", "Massachusetts");
    Config.set("exporter.baseDirectory", tempFolder.newFolder().toString());
    FhirContext ctx = FhirStu3.getContext();
    IParser parser = ctx.newJsonParser().setPrettyPrint(true);
    FhirValidator validator = ctx.newValidator();
    validator.setValidateAgainstStandardSchema(true);
    validator.setValidateAgainstStandardSchematron(true);
    ValidationResources validationResources = new ValidationResources();
    List<String> errors = ParallelTestingService.runInParallel((person) -> {
        List<String> validationErrors = new ArrayList<String>();
        TestHelper.exportOff();
        Config.set("exporter.fhir_stu3.export", "true");
        Config.set("exporter.fhir.use_shr_extensions", "true");
        FhirStu3.TRANSACTION_BUNDLE = person.randBoolean();
        String fhirJson = FhirStu3.convertToFHIRJson(person, System.currentTimeMillis());
        // (these should have been converted into URIs)
        if (fhirJson.contains("SNOMED-CT")) {
            validationErrors.add("JSON contains unconverted references to 'SNOMED-CT' (should be URIs)");
        }
        // let's crack open the Bundle and validate
        // each individual entry.resource to get context-sensitive error
        // messages...
        Bundle bundle = parser.parseResource(Bundle.class, fhirJson);
        for (BundleEntryComponent entry : bundle.getEntry()) {
            ValidationResult eresult = validator.validateWithResult(entry.getResource());
            if (!eresult.isSuccessful()) {
                for (SingleValidationMessage emessage : eresult.getMessages()) {
                    boolean valid = false;
                    if (emessage.getMessage().contains("@ Observation obs-7")) {
                        /*
               * The obs-7 invariant basically says that Observations should have values, unless
               * they are made of components. This test replaces an invalid XPath expression
               * that was causing correct instances to fail validation.
               */
                        valid = validateObs7((Observation) entry.getResource());
                    } else if (emessage.getMessage().contains("@ Condition con-4")) {
                        /*
               * The con-4 invariant says "If condition is abated, then clinicalStatus must be
               * either inactive, resolved, or remission" which is very clear and sensical.
               * However, the XPath expression does not evaluate correctly for valid instances,
               * so we must manually validate.
               */
                        valid = validateCon4((Condition) entry.getResource());
                    } else if (emessage.getMessage().contains("@ MedicationRequest mps-1")) {
                        /*
               * The mps-1 invariant says MedicationRequest.requester.onBehalfOf can only be
               * specified if MedicationRequest.requester.agent is practitioner or device.
               * But the invariant is poorly written and does not correctly handle references
               * starting with "urn:uuid"
               */
                        // ignore this error
                        valid = true;
                    } else if (emessage.getMessage().contains("per-1: If present, start SHALL have a lower value than end")) {
                        /*
               * The per-1 invariant does not account for daylight savings time... so, if the
               * daylight savings switch happens between the start and end, the validation
               * fails, even if it is valid.
               */
                        // ignore this error
                        valid = true;
                    }
                    if (!valid) {
                        System.out.println(parser.encodeResourceToString(entry.getResource()));
                        System.out.println("ERROR: " + emessage.getMessage());
                        validationErrors.add(emessage.getMessage());
                    }
                }
            }
            // Check ExplanationOfBenefit Resources against BlueButton
            if (entry.getResource().fhirType().equals("ExplanationOfBenefit")) {
                ValidationResult bbResult = validationResources.validateSTU3(entry.getResource());
                for (SingleValidationMessage message : bbResult.getMessages()) {
                    if (message.getMessage().contains("extension https://bluebutton.cms.gov/assets")) {
                        /*
               * The instance validator complains about the BlueButton extensions, ignore
               */
                        continue;
                    } else if (message.getSeverity() == ResultSeverityEnum.ERROR) {
                        if (!(message.getMessage().contains("Element 'ExplanationOfBenefit.id': minimum required = 1, but only found 0") || message.getMessage().contains("Could not verify slice for profile"))) {
                            // For some reason the validator is not detecting the IDs on the resources,
                            // even though they appear to be present while debugging and during normal
                            // operations.
                            System.out.println(message.getSeverity() + ": " + message.getMessage());
                            Assert.fail(message.getSeverity() + ": " + message.getMessage());
                        }
                    }
                }
            }
        }
        if (!validationErrors.isEmpty()) {
            Exporter.export(person, System.currentTimeMillis());
        }
        return validationErrors;
    });
    assertTrue("Validation of exported FHIR bundle failed: " + String.join("|", errors), errors.size() == 0);
}
Also used : FhirContext(ca.uhn.fhir.context.FhirContext) SingleValidationMessage(ca.uhn.fhir.validation.SingleValidationMessage) Bundle(org.hl7.fhir.dstu3.model.Bundle) ArrayList(java.util.ArrayList) FhirValidator(ca.uhn.fhir.validation.FhirValidator) ValidationResult(ca.uhn.fhir.validation.ValidationResult) BundleEntryComponent(org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent) Observation(org.hl7.fhir.dstu3.model.Observation) IParser(ca.uhn.fhir.parser.IParser) Test(org.junit.Test)

Example 5 with SingleValidationMessage

use of ca.uhn.fhir.validation.SingleValidationMessage in project synthea by synthetichealth.

the class HospitalExporterTestR4 method testFHIRExport.

@Test
public void testFHIRExport() throws Exception {
    FhirContext ctx = FhirR4.getContext();
    FhirValidator validator = ctx.newValidator();
    validator.setValidateAgainstStandardSchema(true);
    validator.setValidateAgainstStandardSchematron(true);
    File tempOutputFolder = tempFolder.newFolder();
    Config.set("exporter.baseDirectory", tempOutputFolder.toString());
    Config.set("exporter.hospital.fhir.export", "true");
    Config.set("exporter.fhir.transaction_bundle", "true");
    // set this manually, in case it has already been loaded.
    FhirR4.TRANSACTION_BUNDLE = true;
    TestHelper.loadTestProperties();
    Generator.DEFAULT_STATE = Config.get("test_state.default", "Massachusetts");
    Location location = new Location(Generator.DEFAULT_STATE, null);
    Provider.clear();
    Provider.loadProviders(location, 1L);
    assertNotNull(Provider.getProviderList());
    assertFalse(Provider.getProviderList().isEmpty());
    Provider.getProviderList().get(0).incrementEncounters(EncounterType.WELLNESS, 0);
    HospitalExporterR4.export(new Generator(), 0L);
    File expectedExportFolder = tempOutputFolder.toPath().resolve("fhir").toFile();
    assertTrue(expectedExportFolder.exists() && expectedExportFolder.isDirectory());
    File expectedExportFile = expectedExportFolder.toPath().resolve("hospitalInformation0.json").toFile();
    assertTrue(expectedExportFile.exists() && expectedExportFile.isFile());
    FileReader fileReader = new FileReader(expectedExportFile.getPath());
    BufferedReader bufferedReader = new BufferedReader(fileReader);
    StringBuilder fhirJson = new StringBuilder();
    String line = null;
    while ((line = bufferedReader.readLine()) != null) {
        fhirJson.append(line);
    }
    bufferedReader.close();
    IBaseResource resource = ctx.newJsonParser().parseResource(fhirJson.toString());
    ValidationResult result = validator.validateWithResult(resource);
    if (result.isSuccessful() == false) {
        for (SingleValidationMessage message : result.getMessages()) {
            System.out.println(message.getSeverity().toString() + ": " + message.getMessage());
        }
    }
    assertTrue(result.isSuccessful());
}
Also used : FhirContext(ca.uhn.fhir.context.FhirContext) SingleValidationMessage(ca.uhn.fhir.validation.SingleValidationMessage) BufferedReader(java.io.BufferedReader) FileReader(java.io.FileReader) FhirValidator(ca.uhn.fhir.validation.FhirValidator) IBaseResource(org.hl7.fhir.instance.model.api.IBaseResource) ValidationResult(ca.uhn.fhir.validation.ValidationResult) File(java.io.File) Location(org.mitre.synthea.world.geography.Location) Generator(org.mitre.synthea.engine.Generator) Test(org.junit.Test)

Aggregations

SingleValidationMessage (ca.uhn.fhir.validation.SingleValidationMessage)7 ValidationResult (ca.uhn.fhir.validation.ValidationResult)7 FhirContext (ca.uhn.fhir.context.FhirContext)6 Test (org.junit.Test)6 FhirValidator (ca.uhn.fhir.validation.FhirValidator)5 ArrayList (java.util.ArrayList)4 IParser (ca.uhn.fhir.parser.IParser)3 BufferedReader (java.io.BufferedReader)3 File (java.io.File)3 FileReader (java.io.FileReader)3 IBaseResource (org.hl7.fhir.instance.model.api.IBaseResource)3 Location (org.mitre.synthea.world.geography.Location)3 Bundle (ca.uhn.fhir.model.dstu2.resource.Bundle)1 Entry (ca.uhn.fhir.model.dstu2.resource.Bundle.Entry)1 Bundle (org.hl7.fhir.dstu3.model.Bundle)1 BundleEntryComponent (org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent)1 DiagnosticReport (org.hl7.fhir.dstu3.model.DiagnosticReport)1 Observation (org.hl7.fhir.dstu3.model.Observation)1 Bundle (org.hl7.fhir.r4.model.Bundle)1 BundleEntryComponent (org.hl7.fhir.r4.model.Bundle.BundleEntryComponent)1