Skip to content

Commit

Permalink
[APHL-798][APHL-799] release and package should throw an error if a V…
Browse files Browse the repository at this point in the history
…alueSet doesn't have a condition (#756)

* [APHL-798][APHL-799] updated tests

* [APHL-798][APHL-799] updating tests

* [APHL-798][APHL-799] updating tests

* [APHL-798][APHL-799] updating tests

* [APHL-798][APHL-799] update test data

* update test data versions

---------

Co-authored-by: taha.attari@smilecdr.com <taha.attari@smilecdr.com>
Co-authored-by: Adam Stevenson <stevenson_adam@yahoo.com>
  • Loading branch information
3 people authored Jan 12, 2024
1 parent cef0efe commit c77ac3f
Show file tree
Hide file tree
Showing 6 changed files with 2,258 additions and 2,074 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -601,14 +601,20 @@ public Bundle createReleaseBundle(IdType idType, String releaseLabel, String ver
// removed duplicates and add
List<RelatedArtifact> distinctResolvedRelatedArtifacts = new ArrayList<>();
for (RelatedArtifact resolvedRelatedArtifact: rootArtifactAdapter.getRelatedArtifact()) {
if (!distinctResolvedRelatedArtifacts.stream().anyMatch(distinctRelatedArtifact -> distinctRelatedArtifact.getResource().equals(resolvedRelatedArtifact.getResource()) && distinctRelatedArtifact.getType().equals(resolvedRelatedArtifact.getType()))) {
boolean isDistinct = !distinctResolvedRelatedArtifacts.stream().anyMatch(distinctRelatedArtifact -> {
boolean referenceNotInArray = distinctRelatedArtifact.getResource().equals(resolvedRelatedArtifact.getResource());
boolean typeMatches = distinctRelatedArtifact.getType().equals(resolvedRelatedArtifact.getType());
return referenceNotInArray && typeMatches;
});
if (isDistinct) {
distinctResolvedRelatedArtifacts.add(resolvedRelatedArtifact);
// preserve Extensions if found
originalDependenciesWithExtensions
.stream()
.filter(originalDep -> originalDep.getResource().equals(resolvedRelatedArtifact.getResource()))
.findFirst()
.ifPresent(dep -> {
checkIfValueSetNeedsCondition(null, dep, fhirDal);
resolvedRelatedArtifact.getExtension().addAll(dep.getExtension());
originalDependenciesWithExtensions.removeIf(ra -> ra.getResource().equals(resolvedRelatedArtifact.getResource()));
});
Expand Down Expand Up @@ -840,7 +846,7 @@ public Bundle createPackageBundle(IdType id, FhirDal fhirDal, List<String> capab
}
setCorrectBundleType(count,offset,packagedBundle);
pageBundleBasedOnCountAndOffset(count, offset, packagedBundle);
handleValueSetReferenceExtensions(resource, packagedBundle.getEntry());
handleValueSetReferenceExtensions(resource, packagedBundle.getEntry(), fhirDal);
return packagedBundle;
}
/**
Expand Down Expand Up @@ -893,12 +899,35 @@ private void setCorrectBundleType(Integer count, Integer offset, Bundle bundle)
bundle.setType(BundleType.TRANSACTION);
}
}
private void checkIfValueSetNeedsCondition(MetadataResource resource, RelatedArtifact relatedArtifact, FhirDal fhirDal) throws UnprocessableEntityException {
if (resource == null
&& relatedArtifact != null
&& relatedArtifact.hasResource()
&& Canonicals.getResourceType(relatedArtifact.getResource()).equals("ValueSet")) {
List<MetadataResource> searchResults = getResourcesFromBundle(searchResourceByUrl(relatedArtifact.getResource(), fhirDal));
if (searchResults.size() > 0) {
resource = searchResults.get(0);
}
}
if (resource != null && resource.getResourceType() == ResourceType.ValueSet) {
ValueSet valueSet = (ValueSet)resource;
boolean isLeaf = !valueSet.hasCompose() || (valueSet.hasCompose() && valueSet.getCompose().getIncludeFirstRep().getValueSet().size() == 0);
Optional<Extension> maybeConditionExtension = Optional.ofNullable(relatedArtifact)
.map(RelatedArtifact::getExtension)
.map(list -> {
return list.stream().filter(ext -> ext.getUrl().equalsIgnoreCase(valueSetConditionUrl)).findFirst().orElse(null);
});
if (isLeaf && !maybeConditionExtension.isPresent()) {
throw new UnprocessableEntityException("Missing condition on ValueSet : " + valueSet.getUrl());
}
}
}
/**
* ValueSets can be part of multiple artifacts at the same time. Certain properties are tracked/managed in the manifest to avoid conflicts with other artifacts. This function sets those properties on the ValueSets themselves at export / $package time
* @param manifest the resource containing all RelatedArtifact references
* @param bundleEntries the list of packaged resources to modify according to the extensions on the manifest relatedArtifact references
*/
private void handleValueSetReferenceExtensions(MetadataResource manifest, List<BundleEntryComponent> bundleEntries) throws UnprocessableEntityException, IllegalArgumentException {
private void handleValueSetReferenceExtensions(MetadataResource manifest, List<BundleEntryComponent> bundleEntries, FhirDal fhirDal) throws UnprocessableEntityException, IllegalArgumentException {
KnowledgeArtifactAdapter<MetadataResource> adapter = new KnowledgeArtifactAdapter<MetadataResource>(manifest);
List<RelatedArtifact> relatedArtifactsWithPreservedExtension = getRelatedArtifactsWithPreservedExtensions(adapter.getDependencies());
bundleEntries.stream()
Expand All @@ -908,24 +937,20 @@ private void handleValueSetReferenceExtensions(MetadataResource manifest, List<B
// remove any existing Priority and Conditions
List<UsageContext> usageContexts = removeExistingReferenceExtensionData(valueSet.getUseContext());
valueSet.setUseContext(usageContexts);
// List<UsageContext> usageContexts = valueSet.getUseContext();
Optional<RelatedArtifact> maybeVSRelatedArtifact = relatedArtifactsWithPreservedExtension.stream().filter(ra -> Canonicals.getUrl(ra.getResource()).equals(valueSet.getUrl())).findFirst();
checkIfValueSetNeedsCondition(valueSet, maybeVSRelatedArtifact.orElse(null), fhirDal);
// If leaf valueset
if (!valueSet.hasCompose()
|| (valueSet.hasCompose() && valueSet.getCompose().getIncludeFirstRep().getValueSet().size() == 0)) {
// If Condition extension is present
maybeVSRelatedArtifact
.map(ra -> ra.getExtension())
.ifPresentOrElse(
.ifPresent(
// add Conditions
exts -> {
exts.stream()
.filter(ext -> ext.getUrl().equalsIgnoreCase(valueSetConditionUrl))
.forEach(ext -> tryAddCondition(usageContexts, (CodeableConcept) ext.getValue()));
},
// else throw error
() -> {
throw new UnprocessableEntityException("Missing condition for ValueSet : " + valueSet.getUrl());
});
}
// update Priority
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,31 @@ void release_preserve_extensions() {
Extension condition = maybeRelatedArtifactWithUseContextExtension.get().getExtensionByUrl(KnowledgeArtifactProcessor.valueSetConditionUrl);
assertTrue(((CodeableConcept) condition.getValue()).getCoding().get(0).getCode().equals("49649001"));
}

@Test
void release_test_condition_missing() {
loadTransaction("ersd-small-approved-draft-no-conditions.json");
loadResource("artifactAssessment-search-parameter.json");
Parameters params = parameters(
part("version", new StringType("1.2.3.23")),
part("versionBehavior", new StringType("default"))
);
UnprocessableEntityException noConditionExtension = null;
try {
getClient().operation()
.onInstance(specificationLibReference)
.named("$release")
.withParameters(params)
.returnResourceType(Bundle.class)
.execute();
} catch (UnprocessableEntityException e) {
// TODO: handle exception
noConditionExtension = e;
}
assertNotNull(noConditionExtension);
assertTrue(noConditionExtension.getMessage().contains("Missing condition"));
}

@Test
void release_test_artifactComment_updated() {
loadTransaction("ersd-release-missing-approvalDate-validation-bundle.json");
Expand Down Expand Up @@ -1295,6 +1320,26 @@ void packageOperation_big_bundle() {
assertTrue(packagedBundle.getEntry().size() == loadedBundle.getEntry().size());
}

@Test
void package_test_condition_missing() {
loadTransaction("ersd-small-approved-draft-no-conditions.json");
loadResource("artifactAssessment-search-parameter.json");
UnprocessableEntityException noConditionExtension = null;
try {
getClient().operation()
.onInstance(specificationLibReference)
.named("$package")
.withNoParameters(Parameters.class)
.returnResourceType(Bundle.class)
.execute();
} catch (UnprocessableEntityException e) {
// TODO: handle exception
noConditionExtension = e;
}
assertNotNull(noConditionExtension);
assertTrue(noConditionExtension.getMessage().contains("Missing condition"));
}

@Test
void validateOperation() {
Bundle ersdExampleSpecBundle = (Bundle) loadResource("ersd-bundle-example.json");
Expand Down
Loading

0 comments on commit c77ac3f

Please sign in to comment.