6203 subscriptionvalidatinginterceptor allows invalid url for rest hook endpoint (#6225)
* use SearchParamater validator in package installer (#6112)
* Ensure ' ' is treated as '+' in timezones with offsets. (#6115)
* Use lockless mode when adding index on Azure Sql server (#6100)
* Use lockless mode when adding index on Azure Sql server
Use try-catch for Online add-index on Sql Server.
This avoids having to map out the entire matrix of Sql Server product names and ONLINE index support.
Warnings in docs, and cleanups
* make consent service dont call willSeeResource on children if parent resource is AUTHORIZED or REJECT (#6127)
* fix hfj search migration task (#6143)
* fix migration task
* changelog
* changelog
* code review
* spotless
---------
Co-authored-by: jdar <justin.dar@smiledigitalhealth.com>
* Enhance migration for MSSQL to change the collation for HFJ_RESOURCE.FHIR_ID to case sensitive (#6135)
* MSSQL: Migrate HFJ_RESOURCE.FHIR_ID to new collation: SQL_Latin1_General_CP1_CS_AS
* Spotless.
* Enhance test. Fix case in ResourceSearchView to defend against future migration to case insensitive collation.
* Remove TODOs. Add comment to ResourceSearchView explaining why all columns are uppercase. Changelog.
* Update hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/6146-mssql-hfj-resource-fhir-id-colllation.yaml
Code reviewer suggestion
Co-authored-by: Michael Buckley <michaelabuckley@gmail.com>
* Code review fixes: Make changes conditional on the collation including _CI_, otherwise, leave it alone.
---------
Co-authored-by: Michael Buckley <michaelabuckley@gmail.com>
* Common API for FHIR Data Access (#6141)
* Add initial interface for common FHIR API
* Fix formatting
* Update javadocs
* Address code review comments
* Add path value to _id search parameter and other missing search param… (#6128)
* Add path value to _id search parameter and other missing search parameters to IAnyResource.
* Adjust tests and remove now unnecessary addition of meta parameters which are now provided by IAnyResource
* Revert unneeded change
* _security param is not token but uri
* Add tests for new defined resource-level standard parameters
* Adjust test
---------
Co-authored-by: juan.marchionatto <juan.marchionatto@smilecdr.com>
* update to online (#6157)
* SEARCH_UUID should be non-null (#6165)
Avoid using constants in migrations because it creates false history.
* Handle 400 and 404 codes returned by remote terminology operation. (#6151)
* Handle 400 and 404 codes returned by remote terminology operation.
* Some simplification
* Adjust changelog
* Add a comment to explain alternate solution which can be reused.
* fix concepts with no display element for $apply-codesystem-delta-add and $apply-codesystem-delta-remove (#6164)
* allow transaction with update conditional urls (#6155)
* Revert "Add path value to _id search parameter and other missing search param…" (#6171)
This reverts commit 2275eba1a0
.
* 7 2 2 mb (#6160)
* Enhance RuleBuilder code to support multiple instances (#5852)
* Overhaul bulk export permissions.
* Overhaul bulk export permissions.
* Small tweak to rule builder.
* Cleanup validation.
* Cleanup validation.
* Code review feedback.
* Postgres terminology service hard coded column names migration (#5866)
* updating parent pids column name
* updating name of the fullTestField Search
* updating name of the fullTestField Search
* fixing typo.
* failing test.
* - Moving FullTextField annotation from getter method and adding it to the newly added VC property of the entity;
- reverting the name of the FullTextField entity to its previous name of 'myParentPids';
- reverting the name of the lucene index to search on in the terminology service.
- updating the changelog;
* making spotless happy
---------
Co-authored-by: peartree <etienne.poirier@smilecdr.com>
* 5879 back porting fix for issue 5877 (attempting to update a tokenparam with a value greater than 200 characters raises an sqlexception) to release rel_7_2 (#5881)
* initial failing test.
* solution
* adding changelog
* spotless
* moving changelog from 7_4_0 to 7_2_0 and deleting 7_4_0 folder.
---------
Co-authored-by: peartree <etienne.poirier@smilecdr.com>
* Expose BaseRequestPartitionHelperSvc validateAndNormalize methods (#5811)
* Expose BaseRequestPartitionHelperSvc validate and normalize methods
* Compilation errors
* change mock test to jpa test
* change mock test to jpa test
* validateAndNormalizePartitionIds
* validateAndNormalizePartitionNames
* validateAndNormalizePartitionIds validation + bug fix
* validateAndNormalizePartitionNames validation
* fix test
* version bump
* Ensure a non-numeric FHIR ID doesn't result in a NumberFormatException when processing survivorship rules (#5883)
* Add failing test as well as commented out potential solution.
* Fix for NumberFormatException.
* Add conditional test for survivorship rules.
* Spotless.
* Add changelog.
* Code review feedback.
* updating documentation (#5889)
* Ensure temp file ends with "." and then suffix. (#5894)
* bugfix to https://github.com/hapifhir/hapi-fhir-jpaserver-starter/issues/675 (#5892)
Co-authored-by: Jens Kristian Villadsen <jenskristianvilladsen@gmail.com>
* Enhance mdm interceptor (#5899)
* Add MDM Transaction Context for further downstream processing giving interceptors a better chance of figuring out what happened.
* Added javadoc
* Cahngelog
* spotless
---------
Co-authored-by: Jens Kristian Villadsen <jenskristianvilladsen@gmail.com>
* Fix BaseHapiFhirResourceDao $meta method to use HapiTransactionService instead of @Transaction (#5896)
* Try making ResourceTable.myTags EAGER instead of LAZY and see if it breaks anything.
* Try making ResourceTable.myTags EAGER instead of LAZY and see if it breaks anything.
* Ensure BaseHapiFhirResourceDao#metaGetOperation uses HapiTransactionService instead of @Transactional in order to resolve megascale $meta bug.
* Add changelog.
* Update hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5898-ld-megascale-meta-operation-fails-hapi-0389.yaml
Commit code reviewer suggestion.
Co-authored-by: Tadgh <garygrantgraham@gmail.com>
---------
Co-authored-by: Tadgh <garygrantgraham@gmail.com>
* Fix query chained on sort bug where we over-filter results (#5903)
* Failing test.
* Ensure test cleanup doesn't fail by deleting Patients before Practitioners.
* Implement fix.
* Spotless.
* Clean up unit test and add changelog. Fix unit test.
* Fix changelog file.
* Apply suggestions from code review
Apply code review suggestions.
Co-authored-by: Michael Buckley <michaelabuckley@gmail.com>
* Spotless
---------
Co-authored-by: Michael Buckley <michaelabuckley@gmail.com>
* cve fix (#5906)
Co-authored-by: Long Ma <long@smilecdr.com>
* Fixing issues with postgres LOB migration. (#5895)
* Fixing issues with postgres LOB migration.
* addressing code review comments for audit/transaction logs.
* test and implementation for BinaryStorageEntity migration post code review.
* test and implementation for BinaryStorageEntity migration post code review.
* test and implementation for TermConcept
migration post code review.
* applying spotless
* test and implementation for TermConceptProperty
migration post code review.
* test and implementation for TermValueSetConcept
migration post code review.
* fixing migration version
* fixing migration task
* changelog
* fixing changelog
* Minor renames
* addressing comments and suggestions from second code review.
* passing tests
* fixing more tests
---------
Co-authored-by: peartree <etienne.poirier@smilecdr.com>
Co-authored-by: Tadgh <garygrantgraham@gmail.com>
* 6051 bulk export security errors (#5915)
* Enhance RuleBuilder code to support multiple instances (#5852)
* Overhaul bulk export permissions.
* Overhaul bulk export permissions.
* Small tweak to rule builder.
* Cleanup validation.
* Cleanup validation.
* Code review feedback.
* Postgres terminology service hard coded column names migration (#5866)
* updating parent pids column name
* updating name of the fullTestField Search
* updating name of the fullTestField Search
* fixing typo.
* failing test.
* - Moving FullTextField annotation from getter method and adding it to the newly added VC property of the entity;
- reverting the name of the FullTextField entity to its previous name of 'myParentPids';
- reverting the name of the lucene index to search on in the terminology service.
- updating the changelog;
* making spotless happy
---------
Co-authored-by: peartree <etienne.poirier@smilecdr.com>
* 5879 back porting fix for issue 5877 (attempting to update a tokenparam with a value greater than 200 characters raises an sqlexception) to release rel_7_2 (#5881)
* initial failing test.
* solution
* adding changelog
* spotless
* moving changelog from 7_4_0 to 7_2_0 and deleting 7_4_0 folder.
---------
Co-authored-by: peartree <etienne.poirier@smilecdr.com>
* Expose BaseRequestPartitionHelperSvc validateAndNormalize methods (#5811)
* Expose BaseRequestPartitionHelperSvc validate and normalize methods
* Compilation errors
* change mock test to jpa test
* change mock test to jpa test
* validateAndNormalizePartitionIds
* validateAndNormalizePartitionNames
* validateAndNormalizePartitionIds validation + bug fix
* validateAndNormalizePartitionNames validation
* fix test
* version bump
* Ensure a non-numeric FHIR ID doesn't result in a NumberFormatException when processing survivorship rules (#5883)
* Add failing test as well as commented out potential solution.
* Fix for NumberFormatException.
* Add conditional test for survivorship rules.
* Spotless.
* Add changelog.
* Code review feedback.
* updating documentation (#5889)
* Ensure temp file ends with "." and then suffix. (#5894)
* bugfix to https://github.com/hapifhir/hapi-fhir-jpaserver-starter/issues/675 (#5892)
Co-authored-by: Jens Kristian Villadsen <jenskristianvilladsen@gmail.com>
* Enhance mdm interceptor (#5899)
* Add MDM Transaction Context for further downstream processing giving interceptors a better chance of figuring out what happened.
* Added javadoc
* Cahngelog
* spotless
---------
Co-authored-by: Jens Kristian Villadsen <jenskristianvilladsen@gmail.com>
* Fix BaseHapiFhirResourceDao $meta method to use HapiTransactionService instead of @Transaction (#5896)
* Try making ResourceTable.myTags EAGER instead of LAZY and see if it breaks anything.
* Try making ResourceTable.myTags EAGER instead of LAZY and see if it breaks anything.
* Ensure BaseHapiFhirResourceDao#metaGetOperation uses HapiTransactionService instead of @Transactional in order to resolve megascale $meta bug.
* Add changelog.
* Update hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5898-ld-megascale-meta-operation-fails-hapi-0389.yaml
Commit code reviewer suggestion.
Co-authored-by: Tadgh <garygrantgraham@gmail.com>
---------
Co-authored-by: Tadgh <garygrantgraham@gmail.com>
* Fix query chained on sort bug where we over-filter results (#5903)
* Failing test.
* Ensure test cleanup doesn't fail by deleting Patients before Practitioners.
* Implement fix.
* Spotless.
* Clean up unit test and add changelog. Fix unit test.
* Fix changelog file.
* Apply suggestions from code review
Apply code review suggestions.
Co-authored-by: Michael Buckley <michaelabuckley@gmail.com>
* Spotless
---------
Co-authored-by: Michael Buckley <michaelabuckley@gmail.com>
* cve fix (#5906)
Co-authored-by: Long Ma <long@smilecdr.com>
* Fixing issues with postgres LOB migration. (#5895)
* Fixing issues with postgres LOB migration.
* addressing code review comments for audit/transaction logs.
* test and implementation for BinaryStorageEntity migration post code review.
* test and implementation for BinaryStorageEntity migration post code review.
* test and implementation for TermConcept
migration post code review.
* applying spotless
* test and implementation for TermConceptProperty
migration post code review.
* test and implementation for TermValueSetConcept
migration post code review.
* fixing migration version
* fixing migration task
* changelog
* fixing changelog
* Minor renames
* addressing comments and suggestions from second code review.
* passing tests
* fixing more tests
---------
Co-authored-by: peartree <etienne.poirier@smilecdr.com>
Co-authored-by: Tadgh <garygrantgraham@gmail.com>
* refactor bulk export rule, add concept of appliestoallpatients, fix tests
* spotless
* Cahgnelog, tests
* more tests
* refactor style checks
---------
Co-authored-by: Luke deGruchy <luke.degruchy@smilecdr.com>
Co-authored-by: Etienne Poirier <33007955+epeartree@users.noreply.github.com>
Co-authored-by: peartree <etienne.poirier@smilecdr.com>
Co-authored-by: Nathan Doef <n.doef@protonmail.com>
Co-authored-by: TipzCM <leif.stawnyczy@gmail.com>
Co-authored-by: dotasek <david.otasek@smilecdr.com>
Co-authored-by: Jens Kristian Villadsen <jenskristianvilladsen@gmail.com>
Co-authored-by: Michael Buckley <michaelabuckley@gmail.com>
Co-authored-by: longma1 <32119004+longma1@users.noreply.github.com>
Co-authored-by: Long Ma <long@smilecdr.com>
* Convert a few nulls to aggressive denies
* Change chain sort syntax for MS SQL (#5917)
* Change sort type on chains
* Change sort type on chains
* Test for MS SQL
* Comments
* Version bump
* Updating version to: 7.2.1 post release.
* Fix queries with chained sort with Lucene by checking supported SortSpecs (#5958)
* First commit with very rough solution.
* Solidify solutions for both requirements. Add new tests. Enhance others.
* Spotless.
* Add new chained sort spec algorithm. Add new Msg.codes. Finalize tests. Update docs. Add changelog.
* pom remove the snapshot
* Updating version to: 7.2.2 post release.
* cherry-picked pr 6051
* changelog fix
* cherry-picked 6027
* docs and changelog
* merge fix for issue with infinite cache refresh loop
* Use lockless mode when adding index on Azure Sql server (#6100) (#6129)
* Use lockless mode when adding index on Azure Sql server
Use try-catch for Online add-index on Sql Server.
This avoids having to map out the entire matrix of Sql Server product names and ONLINE index support.
Warnings in docs, and cleanups
* added fix for 6133
* failing Test
* Add fix
* spotless
* Remove useless file
* Fix claeaner
* cleanup
* Remove dead class
* Changelog
* test description
* Add test. Fix broken logic.
* fix quantity search parameter test to pass
* reverted test testDirectPathWholeResourceNotIndexedWorks in FhirResourceDaoR4SearchWithElasticSearchIT
* spotless
* cleanup mistake during merge
* added missing imports
* fix more mergeback oopsies
* bump to 7.3.13-snapshot
---------
Co-authored-by: Luke deGruchy <luke.degruchy@smilecdr.com>
Co-authored-by: Etienne Poirier <33007955+epeartree@users.noreply.github.com>
Co-authored-by: peartree <etienne.poirier@smilecdr.com>
Co-authored-by: Nathan Doef <n.doef@protonmail.com>
Co-authored-by: TipzCM <leif.stawnyczy@gmail.com>
Co-authored-by: dotasek <david.otasek@smilecdr.com>
Co-authored-by: Jens Kristian Villadsen <jenskristianvilladsen@gmail.com>
Co-authored-by: Tadgh <garygrantgraham@gmail.com>
Co-authored-by: Michael Buckley <michaelabuckley@gmail.com>
Co-authored-by: Long Ma <long@smilecdr.com>
Co-authored-by: markiantorno <markiantorno@gmail.com>
* Patient validate operation with remote terminology service enabled returns 400 bad request (#6124)
* Patient $validate operation with Remote Terminology Service enabled returns 400 Bad Request - failing test
* Patient $validate operation with Remote Terminology Service enabled returns 400 Bad Request - implementation
* - Changing method accessibility from default to public to allow method overwriting. (#6172)
Co-authored-by: peartree <etienne.poirier@smilecdr.com>
* applying Taha Attari's fix on branch merging to rel_7_4 (#6177)
Co-authored-by: peartree <etienne.poirier@smilecdr.com>
* Automated Migration Testing (HAPI-FHIR) V7_4_0 (#6170)
* Automated Migration Testing (HAPI-FHIR) - updated test migration scripts for 7_4_0
* Automated Migration Testing (HAPI-FHIR) - updated test migration scripts for 7_2_0
* To provide the target resource partitionId and partitionDate in the resourceLinlk (#6149)
* initial POC.
* addressing comments from first code review
* Adding tests
* adding changelog and spotless
* fixing tests
* spotless
---------
Co-authored-by: peartree <etienne.poirier@smilecdr.com>
* applying patch (#6190)
Co-authored-by: peartree <etienne.poirier@smilecdr.com>
* cve for 08 release (#6197)
Co-authored-by: Long Ma <long@smilecdr.com>
* Search param path missing for _id param (#6175)
* Add path tp _id search param and definitions for _lastUpdated _tag, _profile and _security
* Add tests and changelog
* Increase snapshot version
* Irrelevant change to force new build
---------
Co-authored-by: juan.marchionatto <juan.marchionatto@smilecdr.com>
* Reverting to core fhir-test-cases 1.1.14; (#6194)
re-enabling FhirPatchCoreTest
Co-authored-by: peartree <etienne.poirier@smilecdr.com>
* initial failing test
* providing capability to tailor resthook endpoint url validation through supplied regex
* adding necessary import.
* conformance with spotless
* adding tests
* adding test for payload
* spotless
* adding changelogs
* passing all tests
* passing all tests
* no-op commit to kickstart the pipeline.
* - slight modification to the solution;
- spotless;
* pre-code review submission.
* moving validator instantiation to the submitter configuration so it is create along side the subscriptionValidatorInterceptor
* last min tweeking before submission for review.
* fixing spotless post merging in master
---------
Co-authored-by: Emre Dincturk <74370953+mrdnctrk@users.noreply.github.com>
Co-authored-by: Luke deGruchy <luke.degruchy@smilecdr.com>
Co-authored-by: Michael Buckley <michaelabuckley@gmail.com>
Co-authored-by: jdar8 <69840459+jdar8@users.noreply.github.com>
Co-authored-by: jdar <justin.dar@smiledigitalhealth.com>
Co-authored-by: Luke deGruchy <luke.degruchy@smiledigitalhealth.com>
Co-authored-by: JP <jonathan.i.percival@gmail.com>
Co-authored-by: jmarchionatto <60409882+jmarchionatto@users.noreply.github.com>
Co-authored-by: juan.marchionatto <juan.marchionatto@smilecdr.com>
Co-authored-by: TipzCM <leif.stawnyczy@gmail.com>
Co-authored-by: Martha Mitran <marthamitran@gmail.com>
Co-authored-by: longma1 <32119004+longma1@users.noreply.github.com>
Co-authored-by: peartree <etienne.poirier@smilecdr.com>
Co-authored-by: Nathan Doef <n.doef@protonmail.com>
Co-authored-by: dotasek <david.otasek@smilecdr.com>
Co-authored-by: Jens Kristian Villadsen <jenskristianvilladsen@gmail.com>
Co-authored-by: Tadgh <garygrantgraham@gmail.com>
Co-authored-by: Long Ma <long@smilecdr.com>
Co-authored-by: markiantorno <markiantorno@gmail.com>
Co-authored-by: volodymyr-korzh <132366313+volodymyr-korzh@users.noreply.github.com>
This commit is contained in:
parent
48d8fac6ea
commit
5e48e38b1d
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
type: fix
|
||||
issue: 6203
|
||||
title: "Previously, the SubscriptionValidatingInterceptor would allow the creation/update of a REST hook subscription
|
||||
where the endpoint URL property is not prefixed with http[s]. This issue is fixed."
|
|
@ -27,9 +27,13 @@ import java.util.Collections;
|
|||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public abstract class BaseSubscriptionSettings {
|
||||
public static final String DEFAULT_EMAIL_FROM_ADDRESS = "noreply@unknown.com";
|
||||
public static final String DEFAULT_WEBSOCKET_CONTEXT_PATH = "/websocket";
|
||||
public static final String DEFAULT_RESTHOOK_ENDPOINTURL_VALIDATION_REGEX =
|
||||
"((((http?|https?)://))([-%()_.!~*';/?:@&=+$,A-Za-z0-9])+)";
|
||||
|
||||
private final Set<Subscription.SubscriptionChannelType> mySupportedSubscriptionTypes = new HashSet<>();
|
||||
private String myEmailFromAddress = DEFAULT_EMAIL_FROM_ADDRESS;
|
||||
|
@ -45,6 +49,13 @@ public abstract class BaseSubscriptionSettings {
|
|||
*/
|
||||
private boolean myAllowOnlyInMemorySubscriptions = false;
|
||||
|
||||
/**
|
||||
* @since 7.6.0
|
||||
*
|
||||
* Regex To perform validation on the endpoint URL for Subscription of type RESTHOOK.
|
||||
*/
|
||||
private String myRestHookEndpointUrlValidationRegex = DEFAULT_RESTHOOK_ENDPOINTURL_VALIDATION_REGEX;
|
||||
|
||||
/**
|
||||
* This setting indicates which subscription channel types are supported by the server. Any subscriptions submitted
|
||||
* to the server matching these types will be activated.
|
||||
|
@ -235,4 +246,32 @@ public abstract class BaseSubscriptionSettings {
|
|||
public void setTriggerSubscriptionsForNonVersioningChanges(boolean theTriggerSubscriptionsForNonVersioningChanges) {
|
||||
myTriggerSubscriptionsForNonVersioningChanges = theTriggerSubscriptionsForNonVersioningChanges;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the regex expression to perform endpoint URL validation If rest-hook subscriptions are supported.
|
||||
* Default value is {@link #DEFAULT_RESTHOOK_ENDPOINTURL_VALIDATION_REGEX}.
|
||||
* @since 7.6.0
|
||||
*/
|
||||
public String getRestHookEndpointUrlValidationRegex() {
|
||||
return myRestHookEndpointUrlValidationRegex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the regex expression that will be used to validate the endpoint URL.
|
||||
* Set to NULL or EMPTY for no endpoint URL validation.
|
||||
*
|
||||
* @since 7.6.0
|
||||
*/
|
||||
public void setRestHookEndpointUrlValidationRegex(String theRestHookEndpointUrlValidationgRegex) {
|
||||
myRestHookEndpointUrlValidationRegex = theRestHookEndpointUrlValidationgRegex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether an endpoint validation Regex was set for URL validation.
|
||||
*
|
||||
* @since 7.6.0
|
||||
*/
|
||||
public boolean hasRestHookEndpointUrlValidationRegex() {
|
||||
return isNotBlank(myRestHookEndpointUrlValidationRegex);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ package ca.uhn.fhir.jpa.subscription.config;
|
|||
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionStrategyEvaluator;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionQueryValidator;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.validator.SubscriptionQueryValidator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
|
|
|
@ -30,6 +30,10 @@ import ca.uhn.fhir.jpa.subscription.model.config.SubscriptionModelConfig;
|
|||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionMatcherInterceptor;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionSubmitInterceptorLoader;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionValidatingInterceptor;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.validator.IChannelTypeValidator;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.validator.RegexEndpointUrlValidationStrategy;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.validator.RestHookChannelValidator;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.validator.SubscriptionChannelTypeValidatorFactory;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.svc.ResourceModifiedSubmitterSvc;
|
||||
import ca.uhn.fhir.jpa.subscription.triggering.ISubscriptionTriggeringSvc;
|
||||
import ca.uhn.fhir.jpa.subscription.triggering.SubscriptionTriggeringSvcImpl;
|
||||
|
@ -43,6 +47,10 @@ import org.springframework.context.annotation.Configuration;
|
|||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static ca.uhn.fhir.jpa.subscription.submit.interceptor.validator.RestHookChannelValidator.noOpEndpointUrlValidationStrategy;
|
||||
|
||||
/**
|
||||
* This Spring config should be imported by a system that submits resources to the
|
||||
* matching queue for processing
|
||||
|
@ -103,4 +111,23 @@ public class SubscriptionSubmitterConfig {
|
|||
return new AsyncResourceModifiedSubmitterSvc(
|
||||
theIResourceModifiedMessagePersistenceSvc, theResourceModifiedConsumer);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IChannelTypeValidator restHookChannelValidator(SubscriptionSettings theSubscriptionSettings) {
|
||||
RestHookChannelValidator.IEndpointUrlValidationStrategy iEndpointUrlValidationStrategy =
|
||||
noOpEndpointUrlValidationStrategy;
|
||||
|
||||
if (theSubscriptionSettings.hasRestHookEndpointUrlValidationRegex()) {
|
||||
String endpointUrlValidationRegex = theSubscriptionSettings.getRestHookEndpointUrlValidationRegex();
|
||||
iEndpointUrlValidationStrategy = new RegexEndpointUrlValidationStrategy(endpointUrlValidationRegex);
|
||||
}
|
||||
|
||||
return new RestHookChannelValidator(iEndpointUrlValidationStrategy);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SubscriptionChannelTypeValidatorFactory subscriptionChannelTypeValidatorFactory(
|
||||
List<IChannelTypeValidator> theValidorList) {
|
||||
return new SubscriptionChannelTypeValidatorFactory(theValidorList);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,8 +36,10 @@ import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionStrategyE
|
|||
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionCanonicalizer;
|
||||
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscription;
|
||||
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscriptionChannelType;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.validator.IChannelTypeValidator;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.validator.SubscriptionChannelTypeValidatorFactory;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.validator.SubscriptionQueryValidator;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||
|
@ -87,6 +89,9 @@ public class SubscriptionValidatingInterceptor {
|
|||
@Autowired
|
||||
private SubscriptionQueryValidator mySubscriptionQueryValidator;
|
||||
|
||||
@Autowired
|
||||
private SubscriptionChannelTypeValidatorFactory mySubscriptionChannelTypeValidatorFactory;
|
||||
|
||||
@Hook(Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED)
|
||||
public void resourcePreCreate(
|
||||
IBaseResource theResource, RequestDetails theRequestDetails, RequestPartitionId theRequestPartitionId) {
|
||||
|
@ -149,7 +154,7 @@ public class SubscriptionValidatingInterceptor {
|
|||
break;
|
||||
}
|
||||
|
||||
validatePermissions(theSubscription, subscription, theRequestDetails, theRequestPartitionId, thePointcut);
|
||||
validatePermissions(theSubscription, theRequestDetails, theRequestPartitionId, thePointcut);
|
||||
|
||||
mySubscriptionCanonicalizer.setMatchingStrategyTag(theSubscription, null);
|
||||
|
||||
|
@ -167,7 +172,7 @@ public class SubscriptionValidatingInterceptor {
|
|||
|
||||
try {
|
||||
SubscriptionMatchingStrategy strategy = mySubscriptionStrategyEvaluator.determineStrategy(subscription);
|
||||
if (!(SubscriptionMatchingStrategy.IN_MEMORY == strategy)
|
||||
if (SubscriptionMatchingStrategy.IN_MEMORY != strategy
|
||||
&& mySubscriptionSettings.isOnlyAllowInMemorySubscriptions()) {
|
||||
throw new InvalidRequestException(
|
||||
Msg.code(2367)
|
||||
|
@ -236,7 +241,6 @@ public class SubscriptionValidatingInterceptor {
|
|||
|
||||
protected void validatePermissions(
|
||||
IBaseResource theSubscription,
|
||||
CanonicalSubscription theCanonicalSubscription,
|
||||
RequestDetails theRequestDetails,
|
||||
RequestPartitionId theRequestPartitionId,
|
||||
Pointcut thePointcut) {
|
||||
|
@ -319,27 +323,11 @@ public class SubscriptionValidatingInterceptor {
|
|||
protected void validateChannelType(CanonicalSubscription theSubscription) {
|
||||
if (theSubscription.getChannelType() == null) {
|
||||
throw new UnprocessableEntityException(Msg.code(20) + "Subscription.channel.type must be populated");
|
||||
} else if (theSubscription.getChannelType() == CanonicalSubscriptionChannelType.RESTHOOK) {
|
||||
validateChannelPayload(theSubscription);
|
||||
validateChannelEndpoint(theSubscription);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
protected void validateChannelEndpoint(CanonicalSubscription theResource) {
|
||||
if (isBlank(theResource.getEndpointUrl())) {
|
||||
throw new UnprocessableEntityException(
|
||||
Msg.code(21) + "Rest-hook subscriptions must have Subscription.channel.endpoint defined");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
protected void validateChannelPayload(CanonicalSubscription theResource) {
|
||||
if (!isBlank(theResource.getPayloadString())
|
||||
&& EncodingEnum.forContentType(theResource.getPayloadString()) == null) {
|
||||
throw new UnprocessableEntityException(Msg.code(1985) + "Invalid value for Subscription.channel.payload: "
|
||||
+ theResource.getPayloadString());
|
||||
}
|
||||
IChannelTypeValidator iChannelTypeValidator =
|
||||
mySubscriptionChannelTypeValidatorFactory.getValidatorForChannelType(theSubscription.getChannelType());
|
||||
iChannelTypeValidator.validateChannelType(theSubscription);
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
|
@ -371,4 +359,10 @@ public class SubscriptionValidatingInterceptor {
|
|||
mySubscriptionStrategyEvaluator = theSubscriptionStrategyEvaluator;
|
||||
mySubscriptionQueryValidator = new SubscriptionQueryValidator(myDaoRegistry, theSubscriptionStrategyEvaluator);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void setSubscriptionChannelTypeValidatorFactoryForUnitTest(
|
||||
SubscriptionChannelTypeValidatorFactory theSubscriptionChannelTypeValidatorFactory) {
|
||||
mySubscriptionChannelTypeValidatorFactory = theSubscriptionChannelTypeValidatorFactory;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package ca.uhn.fhir.jpa.subscription.submit.interceptor.validator;
|
||||
|
||||
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscription;
|
||||
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscriptionChannelType;
|
||||
|
||||
public interface IChannelTypeValidator {
|
||||
|
||||
void validateChannelType(CanonicalSubscription theSubscription);
|
||||
|
||||
CanonicalSubscriptionChannelType getSubscriptionChannelType();
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package ca.uhn.fhir.jpa.subscription.submit.interceptor.validator;
|
||||
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import jakarta.annotation.Nonnull;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
public class RegexEndpointUrlValidationStrategy implements RestHookChannelValidator.IEndpointUrlValidationStrategy {
|
||||
|
||||
private final Pattern myEndpointUrlValidationPattern;
|
||||
|
||||
public RegexEndpointUrlValidationStrategy(@Nonnull String theEndpointUrlValidationRegex) {
|
||||
try {
|
||||
myEndpointUrlValidationPattern = Pattern.compile(theEndpointUrlValidationRegex);
|
||||
} catch (PatternSyntaxException e) {
|
||||
throw new IllegalArgumentException(
|
||||
Msg.code(2546) + " invalid synthax for provided regex " + theEndpointUrlValidationRegex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateEndpointUrl(String theEndpointUrl) {
|
||||
Matcher matcher = myEndpointUrlValidationPattern.matcher(theEndpointUrl);
|
||||
|
||||
if (!matcher.matches()) {
|
||||
throw new UnprocessableEntityException(
|
||||
Msg.code(2545) + "Failed validation for endpoint URL: " + theEndpointUrl);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package ca.uhn.fhir.jpa.subscription.submit.interceptor.validator;
|
||||
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscription;
|
||||
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscriptionChannelType;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import jakarta.annotation.Nonnull;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
/**
|
||||
*
|
||||
* Definition of a REST Hook channel validator that perform checks on the channel payload and endpoint URL.
|
||||
*
|
||||
* The channel payload will always evaluate in the same manner where endpoint URL validation can be extended beyond the
|
||||
* minimal validation perform by this class.
|
||||
*
|
||||
* At a minimum, this class ensures that the provided URL is not blank or null. Supplemental validation(s) should be
|
||||
* encapsulated into a {@link IEndpointUrlValidationStrategy} and provided with the arg constructor.
|
||||
*
|
||||
*/
|
||||
public class RestHookChannelValidator implements IChannelTypeValidator {
|
||||
|
||||
private final IEndpointUrlValidationStrategy myEndpointUrlValidationStrategy;
|
||||
|
||||
/**
|
||||
* Constructor for a validator where the endpoint URL will
|
||||
*/
|
||||
public RestHookChannelValidator() {
|
||||
this(noOpEndpointUrlValidationStrategy);
|
||||
}
|
||||
|
||||
public RestHookChannelValidator(@Nonnull IEndpointUrlValidationStrategy theEndpointUrlValidationStrategy) {
|
||||
myEndpointUrlValidationStrategy = theEndpointUrlValidationStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateChannelType(CanonicalSubscription theSubscription) {
|
||||
validateChannelPayload(theSubscription);
|
||||
validateChannelEndpoint(theSubscription);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CanonicalSubscriptionChannelType getSubscriptionChannelType() {
|
||||
return CanonicalSubscriptionChannelType.RESTHOOK;
|
||||
}
|
||||
|
||||
protected void validateChannelEndpoint(@Nonnull CanonicalSubscription theCanonicalSubscription) {
|
||||
String endpointUrl = theCanonicalSubscription.getEndpointUrl();
|
||||
|
||||
if (isBlank(endpointUrl)) {
|
||||
throw new UnprocessableEntityException(
|
||||
Msg.code(21) + "Rest-hook subscriptions must have Subscription.channel.endpoint defined");
|
||||
}
|
||||
|
||||
myEndpointUrlValidationStrategy.validateEndpointUrl(endpointUrl);
|
||||
}
|
||||
|
||||
protected void validateChannelPayload(CanonicalSubscription theResource) {
|
||||
if (!isBlank(theResource.getPayloadString())
|
||||
&& EncodingEnum.forContentType(theResource.getPayloadString()) == null) {
|
||||
throw new UnprocessableEntityException(Msg.code(1985) + "Invalid value for Subscription.channel.payload: "
|
||||
+ theResource.getPayloadString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A concrete instantiation of this interface should provide tailored validation of an endpoint URL
|
||||
* throwing {@link RuntimeException} upon validation failure.
|
||||
*/
|
||||
public interface IEndpointUrlValidationStrategy {
|
||||
void validateEndpointUrl(String theEndpointUrl);
|
||||
}
|
||||
|
||||
public static final IEndpointUrlValidationStrategy noOpEndpointUrlValidationStrategy = theEndpointUrl -> {};
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package ca.uhn.fhir.jpa.subscription.submit.interceptor.validator;
|
||||
|
||||
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscription;
|
||||
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscriptionChannelType;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class SubscriptionChannelTypeValidatorFactory {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(SubscriptionChannelTypeValidatorFactory.class);
|
||||
|
||||
private final Map<CanonicalSubscriptionChannelType, IChannelTypeValidator> myValidators =
|
||||
new EnumMap<>(CanonicalSubscriptionChannelType.class);
|
||||
|
||||
public SubscriptionChannelTypeValidatorFactory(@Nonnull List<IChannelTypeValidator> theValidorList) {
|
||||
theValidorList.forEach(this::addChannelTypeValidator);
|
||||
}
|
||||
|
||||
public IChannelTypeValidator getValidatorForChannelType(CanonicalSubscriptionChannelType theChannelType) {
|
||||
return myValidators.getOrDefault(theChannelType, getNoopValidatorForChannelType(theChannelType));
|
||||
}
|
||||
|
||||
public void addChannelTypeValidator(IChannelTypeValidator theValidator) {
|
||||
myValidators.put(theValidator.getSubscriptionChannelType(), theValidator);
|
||||
}
|
||||
|
||||
private IChannelTypeValidator getNoopValidatorForChannelType(CanonicalSubscriptionChannelType theChannelType) {
|
||||
return new IChannelTypeValidator() {
|
||||
@Override
|
||||
public void validateChannelType(CanonicalSubscription theSubscription) {
|
||||
ourLog.debug(
|
||||
"No validator for channel type {} was registered, will perform no-op validation.",
|
||||
theChannelType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CanonicalSubscriptionChannelType getSubscriptionChannelType() {
|
||||
return theChannelType;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@
|
|||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
package ca.uhn.fhir.jpa.subscription.submit.interceptor;
|
||||
package ca.uhn.fhir.jpa.subscription.submit.interceptor.validator;
|
||||
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
|
@ -23,7 +23,7 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.searchparam.matcher.SearchParamMatcher;
|
||||
import ca.uhn.fhir.jpa.subscription.config.SubscriptionConfig;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionQueryValidator;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.validator.SubscriptionQueryValidator;
|
||||
import ca.uhn.fhir.jpa.util.MemoryCacheService;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
|
|
@ -25,7 +25,7 @@ import ca.uhn.fhir.interceptor.api.Hook;
|
|||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionMatchingStrategy;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionQueryValidator;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.validator.SubscriptionQueryValidator;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
|
|
@ -15,7 +15,7 @@ import ca.uhn.fhir.jpa.subscription.match.config.SubscriptionProcessorConfig;
|
|||
import ca.uhn.fhir.jpa.subscription.match.deliver.email.IEmailSender;
|
||||
import ca.uhn.fhir.jpa.model.config.SubscriptionSettings;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.config.SubscriptionSubmitterConfig;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionQueryValidator;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.validator.SubscriptionQueryValidator;
|
||||
import ca.uhn.fhir.subscription.api.IResourceModifiedMessagePersistenceSvc;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
|
|
@ -4,15 +4,19 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.model.entity.StorageSettings;
|
||||
import ca.uhn.fhir.jpa.model.config.SubscriptionSettings;
|
||||
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionStrategyEvaluator;
|
||||
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionCanonicalizer;
|
||||
import ca.uhn.fhir.jpa.model.config.SubscriptionSettings;
|
||||
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscriptionChannelType;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.validator.IChannelTypeValidator;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.validator.RegexEndpointUrlValidationStrategy;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.validator.RestHookChannelValidator;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.validator.SubscriptionChannelTypeValidatorFactory;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.validator.SubscriptionQueryValidator;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.SimpleBundleProvider;
|
||||
|
@ -29,11 +33,13 @@ import org.junit.jupiter.api.Test;
|
|||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.mockito.Mock;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.boot.test.mock.mockito.SpyBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
@ -49,6 +55,8 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
|||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(SpringExtension.class)
|
||||
|
@ -70,6 +78,9 @@ public class SubscriptionValidatingInterceptorTest {
|
|||
private IFhirResourceDao<SubscriptionTopic> mySubscriptionTopicDao;
|
||||
private FhirContext myFhirContext;
|
||||
|
||||
@SpyBean
|
||||
private SubscriptionChannelTypeValidatorFactory mySubscriptionChannelTypeValidatorFactory;
|
||||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
setFhirContext(FhirVersionEnum.R4B);
|
||||
|
@ -79,8 +90,9 @@ public class SubscriptionValidatingInterceptorTest {
|
|||
@ParameterizedTest
|
||||
@MethodSource("subscriptionByFhirVersion345")
|
||||
public void testEmptySub(IBaseResource theSubscription) {
|
||||
setFhirContext(theSubscription);
|
||||
|
||||
try {
|
||||
setFhirContext(theSubscription);
|
||||
mySubscriptionValidatingInterceptor.resourcePreCreate(theSubscription, null, null);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
|
@ -92,8 +104,9 @@ public class SubscriptionValidatingInterceptorTest {
|
|||
@ParameterizedTest
|
||||
@MethodSource("subscriptionByFhirVersion34") // R5 subscriptions don't have criteria
|
||||
public void testEmptyCriteria(IBaseResource theSubscription) {
|
||||
initSubscription(theSubscription);
|
||||
|
||||
try {
|
||||
initSubscription(theSubscription);
|
||||
mySubscriptionValidatingInterceptor.resourcePreCreate(theSubscription, null, null);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
|
@ -105,9 +118,10 @@ public class SubscriptionValidatingInterceptorTest {
|
|||
@ParameterizedTest
|
||||
@MethodSource("subscriptionByFhirVersion34")
|
||||
public void testBadCriteria(IBaseResource theSubscription) {
|
||||
initSubscription(theSubscription);
|
||||
SubscriptionUtil.setCriteria(myFhirContext, theSubscription, "Patient");
|
||||
|
||||
try {
|
||||
initSubscription(theSubscription);
|
||||
SubscriptionUtil.setCriteria(myFhirContext, theSubscription, "Patient");
|
||||
mySubscriptionValidatingInterceptor.resourcePreCreate(theSubscription, null, null);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
|
@ -118,9 +132,10 @@ public class SubscriptionValidatingInterceptorTest {
|
|||
@ParameterizedTest
|
||||
@MethodSource("subscriptionByFhirVersion34")
|
||||
public void testBadChannel(IBaseResource theSubscription) {
|
||||
initSubscription(theSubscription);
|
||||
SubscriptionUtil.setCriteria(myFhirContext, theSubscription, "Patient?");
|
||||
|
||||
try {
|
||||
initSubscription(theSubscription);
|
||||
SubscriptionUtil.setCriteria(myFhirContext, theSubscription, "Patient?");
|
||||
mySubscriptionValidatingInterceptor.resourcePreCreate(theSubscription, null, null);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
|
@ -131,10 +146,11 @@ public class SubscriptionValidatingInterceptorTest {
|
|||
@ParameterizedTest
|
||||
@MethodSource("subscriptionByFhirVersion345")
|
||||
public void testEmptyEndpoint(IBaseResource theSubscription) {
|
||||
initSubscription(theSubscription);
|
||||
SubscriptionUtil.setCriteria(myFhirContext, theSubscription, "Patient?");
|
||||
SubscriptionUtil.setChannelType(myFhirContext, theSubscription, "message");
|
||||
|
||||
try {
|
||||
initSubscription(theSubscription);
|
||||
SubscriptionUtil.setCriteria(myFhirContext, theSubscription, "Patient?");
|
||||
SubscriptionUtil.setChannelType(myFhirContext, theSubscription, "message");
|
||||
mySubscriptionValidatingInterceptor.resourcePreCreate(theSubscription, null, null);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
|
@ -223,8 +239,27 @@ public class SubscriptionValidatingInterceptorTest {
|
|||
SimpleBundleProvider simpleBundleProvider = new SimpleBundleProvider(List.of(topic));
|
||||
when(mySubscriptionTopicDao.search(any(), any())).thenReturn(simpleBundleProvider);
|
||||
mySubscriptionValidatingInterceptor.validateSubmittedSubscription(badSub, null, null, Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED);
|
||||
|
||||
verify(mySubscriptionChannelTypeValidatorFactory, times(1)).getValidatorForChannelType(CanonicalSubscriptionChannelType.MESSAGE);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"acme.corp",
|
||||
"https://acme.corp/badstuff-%%$^&& iuyi",
|
||||
"ftp://acme.corp"})
|
||||
public void testRestHookEndpointValidation_whenProvidedWithBadURLs(String theBadUrl) {
|
||||
try {
|
||||
Subscription subscriptionWithBadEndpoint = createSubscription();
|
||||
subscriptionWithBadEndpoint.getChannel().setEndpoint(theBadUrl);
|
||||
|
||||
mySubscriptionValidatingInterceptor.validateSubmittedSubscription(subscriptionWithBadEndpoint, null, null, Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED);
|
||||
fail("");
|
||||
} catch (Exception e) {
|
||||
verify(mySubscriptionChannelTypeValidatorFactory, times(1)).getValidatorForChannelType(CanonicalSubscriptionChannelType.RESTHOOK);
|
||||
assertThat(e.getMessage()).startsWith(Msg.code(2545));
|
||||
}
|
||||
}
|
||||
|
||||
private void initSubscription(IBaseResource theSubscription) {
|
||||
setFhirContext(theSubscription);
|
||||
|
@ -295,9 +330,22 @@ public class SubscriptionValidatingInterceptorTest {
|
|||
}
|
||||
|
||||
@Bean
|
||||
SubscriptionQueryValidator subscriptionQueryValidator(DaoRegistry theDaoRegistry, SubscriptionStrategyEvaluator theSubscriptionStrategyEvaluator) {
|
||||
SubscriptionQueryValidator subscriptionQueryValidator(DaoRegistry theDaoRegistry, SubscriptionStrategyEvaluator theSubscriptionStrategyEvaluator) {
|
||||
return new SubscriptionQueryValidator(theDaoRegistry, theSubscriptionStrategyEvaluator);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IChannelTypeValidator restHookChannelValidator() {
|
||||
String regex = new SubscriptionSettings().getRestHookEndpointUrlValidationRegex();
|
||||
RegexEndpointUrlValidationStrategy regexEndpointUrlValidationStrategy = new RegexEndpointUrlValidationStrategy(regex);
|
||||
return new RestHookChannelValidator(regexEndpointUrlValidationStrategy);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SubscriptionChannelTypeValidatorFactory subscriptionChannelTypeValidatorFactory(
|
||||
List<IChannelTypeValidator> theValidorList) {
|
||||
return new SubscriptionChannelTypeValidatorFactory(theValidorList);
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
|
@ -307,7 +355,7 @@ public class SubscriptionValidatingInterceptorTest {
|
|||
subscription.setCriteria("Patient?");
|
||||
final Subscription.SubscriptionChannelComponent channel = subscription.getChannel();
|
||||
channel.setType(Subscription.SubscriptionChannelType.RESTHOOK);
|
||||
channel.setEndpoint("channel");
|
||||
channel.setEndpoint("http://acme.corp/");
|
||||
return subscription;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
package ca.uhn.fhir.jpa.subscription.submit.interceptor.validator;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.model.config.SubscriptionSettings;
|
||||
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionCanonicalizer;
|
||||
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscription;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.r4.model.Subscription;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.hl7.fhir.r4.model.Subscription.SubscriptionStatus.REQUESTED;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
public class RestHookChannelValidatorTest {
|
||||
private final FhirContext myCtx = FhirContext.forR4();
|
||||
private final SubscriptionSettings mySubscriptionSettings = new SubscriptionSettings();
|
||||
private final SubscriptionCanonicalizer mySubscriptionCanonicalizer= new SubscriptionCanonicalizer(myCtx, mySubscriptionSettings);
|
||||
|
||||
private final String NO_PAYLOAD = StringUtils.EMPTY;
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("urlAndExpectedEvaluationResultProvider")
|
||||
public void testRestHookChannelValidation_withUrl(String theUrl, boolean theExpectedValidationResult){
|
||||
RegexEndpointUrlValidationStrategy regexEndpointUrlValidationStrategy = new RegexEndpointUrlValidationStrategy(SubscriptionSettings.DEFAULT_RESTHOOK_ENDPOINTURL_VALIDATION_REGEX);
|
||||
RestHookChannelValidator restHookChannelValidator = new RestHookChannelValidator(regexEndpointUrlValidationStrategy);
|
||||
|
||||
CanonicalSubscription subscription = createSubscription(theUrl, NO_PAYLOAD);
|
||||
doValidateUrlAndAssert(restHookChannelValidator, subscription, theExpectedValidationResult);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("urlAndExpectedEvaluationResultProviderForNoUrlValidation")
|
||||
public void testRestHookChannelValidation_withNoUrlValidation(String theUrl, boolean theExpectedValidationResult){
|
||||
RestHookChannelValidator restHookChannelValidator = new RestHookChannelValidator();
|
||||
|
||||
CanonicalSubscription subscription = createSubscription(theUrl, NO_PAYLOAD);
|
||||
doValidateUrlAndAssert(restHookChannelValidator, subscription, theExpectedValidationResult);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("payloadAndExpectedEvaluationResultProvider")
|
||||
public void testRestHookChannelValidation_withPayload(String thePayload, boolean theExpectedValidationResult){
|
||||
RestHookChannelValidator restHookChannelValidator = new RestHookChannelValidator();
|
||||
|
||||
CanonicalSubscription subscription = createSubscription("https://acme.org", thePayload);
|
||||
doValidatePayloadAndAssert(restHookChannelValidator, subscription, theExpectedValidationResult);
|
||||
}
|
||||
|
||||
private void doValidatePayloadAndAssert(RestHookChannelValidator theRestHookChannelValidator, CanonicalSubscription theSubscription, boolean theExpectedValidationResult) {
|
||||
boolean validationResult = true;
|
||||
|
||||
try {
|
||||
theRestHookChannelValidator.validateChannelPayload(theSubscription);
|
||||
} catch (Exception e){
|
||||
validationResult = false;
|
||||
}
|
||||
|
||||
if( validationResult != theExpectedValidationResult){
|
||||
String message = String.format("Validation result for payload %s was expected to be %b but was %b", theSubscription.getEndpointUrl(), theExpectedValidationResult, validationResult);
|
||||
fail(message);
|
||||
}
|
||||
}
|
||||
|
||||
private void doValidateUrlAndAssert(RestHookChannelValidator theRestHookChannelValidator, CanonicalSubscription theSubscription, boolean theExpectedValidationResult) {
|
||||
boolean validationResult = true;
|
||||
|
||||
try {
|
||||
theRestHookChannelValidator.validateChannelEndpoint(theSubscription);
|
||||
} catch (Exception e){
|
||||
validationResult = false;
|
||||
}
|
||||
|
||||
if( validationResult != theExpectedValidationResult){
|
||||
String message = String.format("Validation result for URL %s was expected to be %b but was %b", theSubscription.getEndpointUrl(), theExpectedValidationResult, validationResult);
|
||||
fail(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private CanonicalSubscription createSubscription(String theUrl, String thePayload) {
|
||||
final Subscription subscription = new Subscription();
|
||||
subscription.setStatus(REQUESTED);
|
||||
subscription.setCriteria("Patient?");
|
||||
final Subscription.SubscriptionChannelComponent channel = subscription.getChannel();
|
||||
channel.setType(Subscription.SubscriptionChannelType.RESTHOOK);
|
||||
channel.setEndpoint(theUrl);
|
||||
channel.setPayload(thePayload);
|
||||
return mySubscriptionCanonicalizer.canonicalize(subscription);
|
||||
}
|
||||
|
||||
static Stream<Arguments> urlAndExpectedEvaluationResultProvider() {
|
||||
return Stream.of(
|
||||
Arguments.of("http://www.acme.corp/fhir", true),
|
||||
Arguments.of("http://acme.corp/fhir", true),
|
||||
Arguments.of("http://acme.corp:8000/fhir", true),
|
||||
Arguments.of("http://acme.corp:8000/fhir/", true),
|
||||
Arguments.of("http://acme.corp/fhir/", true),
|
||||
Arguments.of("https://foo.bar.com", true),
|
||||
Arguments.of("http://localhost:8000", true),
|
||||
Arguments.of("http://localhost:8000/", true),
|
||||
Arguments.of("http://localhost:8000/fhir", true),
|
||||
Arguments.of("http://localhost:8000/fhir/", true),
|
||||
Arguments.of("acme.corp", false),
|
||||
Arguments.of("https://acme.corp/badstuff-%%$^&& iuyi", false),
|
||||
Arguments.of("ftp://acme.corp", false));
|
||||
}
|
||||
|
||||
static Stream<Arguments> urlAndExpectedEvaluationResultProviderForNoUrlValidation() {
|
||||
return Stream.of(
|
||||
Arguments.of(null, false),
|
||||
Arguments.of("", false),
|
||||
Arguments.of(" ", false),
|
||||
Arguments.of("something", true));
|
||||
}
|
||||
|
||||
static Stream<Arguments> payloadAndExpectedEvaluationResultProvider() {
|
||||
return Stream.of(
|
||||
Arguments.of(null, true),
|
||||
Arguments.of("", true),
|
||||
Arguments.of(" ", true),
|
||||
Arguments.of("application/json", true),
|
||||
Arguments.of("garbage/fhir", false));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,17 +1,19 @@
|
|||
package ca.uhn.fhir.jpa.subscription;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.model.config.SubscriptionSettings;
|
||||
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
|
||||
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionMatchingStrategy;
|
||||
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionStrategyEvaluator;
|
||||
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionCanonicalizer;
|
||||
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscription;
|
||||
import ca.uhn.fhir.jpa.model.config.SubscriptionSettings;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionValidatingInterceptor;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.validator.RegexEndpointUrlValidationStrategy;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.validator.RestHookChannelValidator;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.interceptor.validator.SubscriptionChannelTypeValidatorFactory;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||
|
@ -29,9 +31,13 @@ import org.mockito.Mock;
|
|||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static ca.uhn.fhir.jpa.subscription.submit.interceptor.validator.RestHookChannelValidator.IEndpointUrlValidationStrategy;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.isA;
|
||||
|
@ -57,6 +63,9 @@ public class SubscriptionValidatingInterceptorTest {
|
|||
private IRequestPartitionHelperSvc myRequestPartitionHelperSvc;
|
||||
@Mock
|
||||
private SubscriptionSettings mySubscriptionSettings;
|
||||
|
||||
private SubscriptionChannelTypeValidatorFactory mySubscriptionChannelTypeValidatorFactory;
|
||||
|
||||
private SubscriptionCanonicalizer mySubscriptionCanonicalizer;
|
||||
|
||||
@BeforeEach
|
||||
|
@ -69,6 +78,11 @@ public class SubscriptionValidatingInterceptorTest {
|
|||
mySvc.setFhirContext(myCtx);
|
||||
mySvc.setSubscriptionSettingsForUnitTest(mySubscriptionSettings);
|
||||
mySvc.setRequestPartitionHelperSvcForUnitTest(myRequestPartitionHelperSvc);
|
||||
|
||||
IEndpointUrlValidationStrategy iEndpointUrlValidationStrategy = new RegexEndpointUrlValidationStrategy(SubscriptionSettings.DEFAULT_RESTHOOK_ENDPOINTURL_VALIDATION_REGEX);
|
||||
mySubscriptionChannelTypeValidatorFactory = new SubscriptionChannelTypeValidatorFactory(List.of(new RestHookChannelValidator(iEndpointUrlValidationStrategy)));
|
||||
|
||||
mySvc.setSubscriptionChannelTypeValidatorFactoryForUnitTest(mySubscriptionChannelTypeValidatorFactory);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -85,7 +99,7 @@ public class SubscriptionValidatingInterceptorTest {
|
|||
|
||||
@Test
|
||||
public void testValidate_RestHook_Populated() {
|
||||
when(myDaoRegistry.isResourceTypeSupported(eq("Patient"))).thenReturn(true);
|
||||
when(myDaoRegistry.isResourceTypeSupported("Patient")).thenReturn(true);
|
||||
|
||||
Subscription subscription = new Subscription();
|
||||
subscription.setStatus(Subscription.SubscriptionStatus.ACTIVE);
|
||||
|
@ -99,7 +113,7 @@ public class SubscriptionValidatingInterceptorTest {
|
|||
|
||||
@Test
|
||||
public void testValidate_RestHook_ResourceTypeNotSupported() {
|
||||
when(myDaoRegistry.isResourceTypeSupported(eq("Patient"))).thenReturn(false);
|
||||
when(myDaoRegistry.isResourceTypeSupported("Patient")).thenReturn(false);
|
||||
|
||||
Subscription subscription = new Subscription();
|
||||
subscription.setStatus(Subscription.SubscriptionStatus.ACTIVE);
|
||||
|
@ -118,7 +132,7 @@ public class SubscriptionValidatingInterceptorTest {
|
|||
|
||||
@Test
|
||||
public void testValidate_RestHook_MultitypeResourceTypeNotSupported() {
|
||||
when(myDaoRegistry.isResourceTypeSupported(eq("Patient"))).thenReturn(false);
|
||||
when(myDaoRegistry.isResourceTypeSupported("Patient")).thenReturn(false);
|
||||
|
||||
Subscription subscription = new Subscription();
|
||||
subscription.setStatus(Subscription.SubscriptionStatus.ACTIVE);
|
||||
|
@ -137,7 +151,7 @@ public class SubscriptionValidatingInterceptorTest {
|
|||
|
||||
@Test
|
||||
public void testValidate_RestHook_NoEndpoint() {
|
||||
when(myDaoRegistry.isResourceTypeSupported(eq("Patient"))).thenReturn(true);
|
||||
when(myDaoRegistry.isResourceTypeSupported("Patient")).thenReturn(true);
|
||||
|
||||
Subscription subscription = new Subscription();
|
||||
subscription.setStatus(Subscription.SubscriptionStatus.ACTIVE);
|
||||
|
@ -156,7 +170,7 @@ public class SubscriptionValidatingInterceptorTest {
|
|||
|
||||
@Test
|
||||
public void testValidate_RestHook_NoType() {
|
||||
when(myDaoRegistry.isResourceTypeSupported(eq("Patient"))).thenReturn(true);
|
||||
when(myDaoRegistry.isResourceTypeSupported("Patient")).thenReturn(true);
|
||||
|
||||
Subscription subscription = new Subscription();
|
||||
subscription.setStatus(Subscription.SubscriptionStatus.ACTIVE);
|
||||
|
@ -174,7 +188,7 @@ public class SubscriptionValidatingInterceptorTest {
|
|||
|
||||
@Test
|
||||
public void testValidate_RestHook_NoPayload() {
|
||||
when(myDaoRegistry.isResourceTypeSupported(eq("Patient"))).thenReturn(true);
|
||||
when(myDaoRegistry.isResourceTypeSupported("Patient")).thenReturn(true);
|
||||
|
||||
Subscription subscription = new Subscription();
|
||||
subscription.setStatus(Subscription.SubscriptionStatus.ACTIVE);
|
||||
|
@ -203,7 +217,7 @@ public class SubscriptionValidatingInterceptorTest {
|
|||
|
||||
@Test
|
||||
public void testValidate_Cross_Partition_Subscription() {
|
||||
when(myDaoRegistry.isResourceTypeSupported(eq("Patient"))).thenReturn(true);
|
||||
when(myDaoRegistry.isResourceTypeSupported("Patient")).thenReturn(true);
|
||||
when(mySubscriptionSettings.isCrossPartitionSubscriptionEnabled()).thenReturn(true);
|
||||
when(myRequestPartitionHelperSvc.determineCreatePartitionForRequest(isA(RequestDetails.class), isA(Subscription.class), eq("Subscription"))).thenReturn(RequestPartitionId.defaultPartition());
|
||||
|
||||
|
@ -222,8 +236,8 @@ public class SubscriptionValidatingInterceptorTest {
|
|||
// is invalid
|
||||
assertDoesNotThrow(() -> mySvc.resourcePreCreate(subscription, requestDetails, null));
|
||||
Mockito.verify(mySubscriptionSettings, times(1)).isCrossPartitionSubscriptionEnabled();
|
||||
Mockito.verify(myDaoRegistry, times(1)).isResourceTypeSupported(eq("Patient"));
|
||||
Mockito.verify(myRequestPartitionHelperSvc, times(1)).determineCreatePartitionForRequest(isA(RequestDetails.class), isA(Subscription.class), eq("Subscription"));
|
||||
Mockito.verify(myDaoRegistry, times(1)).isResourceTypeSupported("Patient");
|
||||
Mockito.verify(myRequestPartitionHelperSvc, times(1)).determineCreatePartitionForRequest(isA(RequestDetails.class), isA(Subscription.class),eq("Subscription"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -275,7 +289,7 @@ public class SubscriptionValidatingInterceptorTest {
|
|||
|
||||
@Test
|
||||
public void testValidate_Cross_Partition_System_Subscription_Without_Setting() {
|
||||
when(myDaoRegistry.isResourceTypeSupported(eq("Patient"))).thenReturn(true);
|
||||
when(myDaoRegistry.isResourceTypeSupported("Patient")).thenReturn(true);
|
||||
|
||||
Subscription subscription = new Subscription();
|
||||
subscription.setStatus(Subscription.SubscriptionStatus.ACTIVE);
|
||||
|
@ -292,14 +306,14 @@ public class SubscriptionValidatingInterceptorTest {
|
|||
// is invalid
|
||||
mySvc.resourcePreCreate(subscription, requestDetails, null);
|
||||
Mockito.verify(mySubscriptionSettings, never()).isCrossPartitionSubscriptionEnabled();
|
||||
Mockito.verify(myDaoRegistry, times(1)).isResourceTypeSupported(eq("Patient"));
|
||||
Mockito.verify(myRequestPartitionHelperSvc, never()).determineCreatePartitionForRequest(isA(RequestDetails.class), isA(Patient.class), eq("Patient"));
|
||||
Mockito.verify(myDaoRegistry, times(1)).isResourceTypeSupported("Patient");
|
||||
Mockito.verify(myRequestPartitionHelperSvc, never()).determineCreatePartitionForRequest(isA(RequestDetails.class), isA(Patient.class),eq("Patient"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscriptionUpdate() {
|
||||
// setup
|
||||
when(myDaoRegistry.isResourceTypeSupported(eq("Patient"))).thenReturn(true);
|
||||
when(myDaoRegistry.isResourceTypeSupported("Patient")).thenReturn(true);
|
||||
when(mySubscriptionSettings.isCrossPartitionSubscriptionEnabled()).thenReturn(true);
|
||||
lenient()
|
||||
.when(myRequestPartitionHelperSvc.determineReadPartitionForRequestForRead(isA(RequestDetails.class), isA(String.class), isA(IIdType.class)))
|
||||
|
|
Loading…
Reference in New Issue