1616
1717import java .net .URI ;
1818import java .time .ZoneOffset ;
19+ import java .util .List ;
20+ import java .util .Properties ;
1921import java .util .UUID ;
2022
2123import javax .ws .rs .client .Entity ;
2224import javax .ws .rs .client .WebTarget ;
2325import javax .ws .rs .core .Response ;
2426
27+ import org .testng .annotations .BeforeClass ;
2528import org .testng .annotations .Test ;
2629
2730import org .linuxforhealth .fhir .client .FHIRParameters ;
3033import org .linuxforhealth .fhir .model .resource .Bundle ;
3134import org .linuxforhealth .fhir .model .resource .Observation ;
3235import org .linuxforhealth .fhir .model .resource .OperationOutcome ;
36+ import org .linuxforhealth .fhir .model .resource .OperationOutcome .Issue ;
3337import org .linuxforhealth .fhir .model .resource .Patient ;
3438import org .linuxforhealth .fhir .model .test .TestUtil ;
3539import org .linuxforhealth .fhir .model .type .Boolean ;
4448import org .linuxforhealth .fhir .model .type .Reference ;
4549import org .linuxforhealth .fhir .model .type .code .AdministrativeGender ;
4650import org .linuxforhealth .fhir .model .type .code .BundleType ;
51+ import org .linuxforhealth .fhir .model .type .code .IssueSeverity ;
52+ import org .linuxforhealth .fhir .model .type .code .IssueType ;
4753import org .linuxforhealth .fhir .model .type .code .ObservationStatus ;
4854import org .linuxforhealth .fhir .model .util .FHIRUtil ;
4955
@@ -60,6 +66,15 @@ public class ServerSpecTest extends FHIRServerTestBase {
6066 private Patient savedPatient ;
6167 @ SuppressWarnings ("unused" )
6268 private Observation savedObservation ;
69+
70+ private boolean updateCreateEnabled ;
71+
72+ @ BeforeClass
73+ public void setUp () throws Exception {
74+ Properties testProperties = TestUtil .readTestProperties ("test.properties" );
75+ setUp (testProperties );
76+ updateCreateEnabled = isUpdateCreateSupported ();
77+ }
6378
6479 @ Test (groups = { "server-spec" })
6580 public void testCreatePatient () throws Exception {
@@ -696,6 +711,82 @@ public void testConditionalUpdateObservation2() throws Exception {
696711 "Input resource 'id' attribute must match the id of the search result resource" );
697712
698713 }
714+
715+ /**
716+ * Test conditional update when :
717+ * 1. No matches, no id provided.
718+ * 2. No matches, id provided and doesn't already exist and update/create is enabled.
719+ * 3. No matches, id provided and doesn't already exist and update/create is not enabled.
720+ * 4. No matches, id provided and id already exists.
721+ * @throws Exception
722+ */
723+ @ Test (groups = { "server-spec" }, dependsOnMethods = { "testConditionalCreateObservation" })
724+ public void testConditionalUpdateObservation3 () throws Exception {
725+ String fakePatientRef = "Patient/" + UUID .randomUUID ().toString ();
726+ String obsId = UUID .randomUUID ().toString ();
727+ Observation obs = TestUtil .readLocalResource ("Observation1.json" );
728+ Observation obsWithNoId = obs .toBuilder ()
729+ .subject (Reference .builder ().reference (fakePatientRef ).build ())
730+ .build ();
731+ Observation obsWithId = obs .toBuilder ()
732+ .subject (Reference .builder ().reference (fakePatientRef ).build ())
733+ .id (obsId )
734+ .build ();
735+ Observation obsWithExistingId = obs .toBuilder ()
736+ .subject (Reference .builder ().reference (fakePatientRef ).build ())
737+ .id (savedObservation .getId ())
738+ .build ();
739+ String randomObsId = UUID .randomUUID ().toString ();
740+ // Test conditional update when : No matches, no id provided.
741+ // Expected output: The resource is created successfully.
742+ FHIRParameters query = new FHIRParameters ().searchParam ("_id" , obsId );
743+ FHIRResponse response = client .conditionalUpdate (obsWithNoId , query );
744+ assertNotNull (response );
745+ assertResponse (response .getResponse (), Response .Status .CREATED .getStatusCode ());
746+ String locationURI = response .getLocation ();
747+ assertNotNull (locationURI );
748+ if (updateCreateEnabled ) {
749+ // Test conditional update when : No matches, id provided and doesn't already exist and update/create is enabled.
750+ // Expected output : The resource is created successfully.The server treats the interaction as an Update as Create interaction.
751+ query = new FHIRParameters ().searchParam ("_id" , obsId );
752+ response = client .conditionalUpdate (obsWithId , query );
753+ assertNotNull (response );
754+ assertResponse (response .getResponse (), Response .Status .CREATED .getStatusCode ());
755+ locationURI = response .getLocation ();
756+ assertNotNull (locationURI );
757+ } else {
758+ // No matches, id provided and doesn't already exist and update/create is not enabled.
759+ // Expected output : Should be rejected with error message.
760+ query = new FHIRParameters ().searchParam ("_id" , randomObsId );
761+ response = client .conditionalUpdate (obsWithId , query );
762+ assertNotNull (response );
763+ assertResponse (response .getResponse (), Response .Status .METHOD_NOT_ALLOWED .getStatusCode ());
764+ String expectedErrorMsg = "Resource 'Observation/" + obsWithId .getId () + "' not found." ;
765+ OperationOutcome operationOutcome = response .getResource (OperationOutcome .class );
766+ assertNotNull (operationOutcome );
767+ List <Issue > issues = operationOutcome .getIssue ();
768+ assertEquals (issues .size (), 1 );
769+ assertEquals (issues .get (0 ).getDetails ().getText ().getValue (), expectedErrorMsg );
770+ assertEquals (issues .get (0 ).getSeverity (), IssueSeverity .FATAL );
771+ assertEquals (issues .get (0 ).getCode (), IssueType .NOT_FOUND );
772+ }
773+
774+ // Test conditional update when : No matches, id provided and id already exists.
775+ // Expected output : Should be rejected with 409 Conflict error message.
776+ query = new FHIRParameters ().searchParam ("_id" , randomObsId );
777+ response = client .conditionalUpdate (obsWithExistingId , query );
778+ assertNotNull (response );
779+ assertResponse (response .getResponse (), Response .Status .CONFLICT .getStatusCode ());
780+ OperationOutcome operationOutcome = response .getResource (OperationOutcome .class );
781+ assertNotNull (operationOutcome );
782+ List <Issue > issues = operationOutcome .getIssue ();
783+ assertEquals (issues .size (), 1 );
784+ String expectedErrorMsg = "Conflict error! The search criteria specified for a conditional update operation did not return any results"
785+ + " but the input resource with id: " + obsWithExistingId .getId () + " already exists." ;
786+ assertEquals (issues .get (0 ).getDetails ().getText ().getValue (), expectedErrorMsg );
787+ assertEquals (issues .get (0 ).getSeverity (), IssueSeverity .FATAL );
788+ assertEquals (issues .get (0 ).getCode (), IssueType .CONFLICT );
789+ }
699790
700791 // Test: retrieve Patient with _summary=true.
701792 @ Test (groups = { "server-spec" }, dependsOnMethods ={"testCreatePatient" })
0 commit comments