Merge pull request #376 from hapifhir/smoke_tests

Smoke tests
This commit is contained in:
Mark Iantorno
2022-05-29 09:28:43 -04:00
committed by GitHub
8 changed files with 620 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
# JPA Server Starter Smoke Tests
---
When updating the supporting HAPI-FHIR version, or making changes to the JPA server starter code itself, it is recommended to run basic smoke tests to ensure the basic functionality of the server is maintained. The goal of these tests is
to provide users a quick way to run groups of tests that correspond to various sections within the
[HAPI-FHIR documentation][Link-HAPI-FHIR-docs].
### Requirements
Tests are written in IntelliJ [HTTP Client Request files][Link-HTTP-Client-Req-Intro]. Ultimate edition of IntelliJ
is required to run these tests.
For more details on integrated tooling and request syntax, there is [documentation available][Link-HTTP-Client-Req-Exploring]
on the jetbrains website, in addition to the [API reference][Link-HTTP-Client-Req-API].
### Formatting
Each test file corresponds to a given section within the hapifhir documentation as close as possible. For
example, there is a `plain_server.rest` file, which attemps to smoke test all basic functionality outlined in the section
[within the docs][Link-HAPI-FHIR-docs-plain-server].
Individual tests are formatted as follows:
```javascript
### Test Title Here
# <link to relevant documentation>
REST-OPERATION ENDPOINT-URL
// Verification Steps
```
To run these tests against a specific server, configure the server details within the `http-client.env.json` file. By default, we provide the following:
```json
{
"default": {
"host": "localhost:8080",
"username": "username",
"password": "password"
}
}
```
### Running the Tests
Within IntelliJ, right click the file you wish to run tests in and select the `Run All` option from the menu.
**Important:** Tests may not work individually when run. Often times, tests need to be run sequentially, as they depend
on resources/references from previous tests to complete. _(An example of this would be adding a Patient, saving the id,
then using that saved id to test if we can successfully PATCH that Patient resource. Without that saved id from the
previous test creating that patient, the PATCH test will fail.)_
[Link-HAPI-FHIR-docs]: https://hapifhir.io/hapi-fhir/docs/
[Link-HAPI-FHIR-docs-plain-server]: https://hapifhir.io/hapi-fhir/docs/server_plain/server_types.html
[Link-HTTP-Client-Req-Intro]: https://www.jetbrains.com/help/idea/http-client-in-product-code-editor.html
[Link-HTTP-Client-Req-Exploring]: https://www.jetbrains.com/help/idea/exploring-http-syntax.html
[Link-HTTP-Client-Req-API]: https://www.jetbrains.com/help/idea/http-response-handling-api-reference.html

View File

@@ -0,0 +1,7 @@
{
"default": {
"host": "localhost:8080",
"username": "username",
"password": "password"
}
}

View File

@@ -0,0 +1,223 @@
### Create Single Patient
# https://hapifhir.io/hapi-fhir/docs/server_plain/rest_operations.html#type_create
POST http://{{host}}/fhir/Patient
Content-Type: application/json
< smoketestfiles/patient_create.json
> {%
client.test("Patient created successfully", function() {
client.assert(response.status === 201, "Response status is not 201");
});
client.test("Response content-type is json", function() {
const type = response.contentType.mimeType;
client.assert(type === "application/fhir+json", "Expected 'application/fhir+json' but received '" + type + "'");
});
client.test("Response resourceType is Patient", function() {
const resourceType = response.body.resourceType;
client.assert(resourceType === "Patient", "Expected 'Patient' but received '" + resourceType + "'");
});
client.global.set("single_patient_id", response.body.id);
client.global.set("single_patient_family_name", response.body.name[0].family);
%}
### Search Single Patient
# https://hapifhir.io/hapi-fhir/docs/server_plain/rest_operations.html#type_search
GET http://{{host}}/fhir/Patient?name={{single_patient_family_name}}&_id={{single_patient_id}}
> {%
client.test("Patient search successful", function() {
client.assert(response.status === 200, "Response status is not 200");
});
client.test("Response content-type is json", function() {
const type = response.contentType.mimeType;
client.assert(type === "application/fhir+json", "Expected 'application/fhir+json' but received '" + type + "'");
});
client.test("Response resourceType is Bundle", function() {
const resourceType = response.body.resourceType;
client.assert(resourceType === "Bundle", "Expected 'Bundle' but received '" + resourceType + "'");
});
client.test("Total patients found is 1", function() {
const totalFound = response.body.total;
client.assert(totalFound === 1, "Expected '1' match but found '" + totalFound + "'");
});
%}
### Delete Patient
# https://hapifhir.io/hapi-fhir/docs/server_plain/rest_operations.html#instance_delete
DELETE http://{{host}}/fhir/Patient/{{single_patient_id}}
> {%
client.test("Patient deleted successfully", function() {
client.assert(response.status === 200, "Response status is not 200");
});
client.test("Response content-type is json", function() {
const type = response.contentType.mimeType;
client.assert(type === "application/fhir+json", "Expected 'application/fhir+json' but received '" + type + "'");
});
client.test("Response resourceType is OperationOutcome", function() {
const resourceType = response.body.resourceType;
client.assert(resourceType === "OperationOutcome", "Expected 'OperationOutcome' but received '" + resourceType + "'");
});
%}
### Batch Patient Create
# https://hapifhir.io/hapi-fhir/docs/server_plain/rest_operations.html#system_transaction
POST http://{{host}}/fhir/
Content-Type: application/json
< smoketestfiles/patient_batch_create.json
> {%
client.test("Bundle transaction completed successfully", function() {
client.assert(response.status === 200, "Response status is not 200");
});
client.test("Response content-type is json", function() {
const type = response.contentType.mimeType;
client.assert(type === "application/fhir+json", "Expected 'application/fhir+json' but received '" + type + "'");
});
client.test("Response resourceType is Bundle", function() {
const resourceType = response.body.resourceType;
client.assert(resourceType === "Bundle", "Expected 'Bundle' but received '" + resourceType + "'");
});
client.test("All patient additions successful", function() {
for (var index = 0; index < response.body.entry.length; index++) {
client.assert(response.body.entry[index].response.status === "201 Created", "Expected '201 Created' for patient index " + index + " but received '" + response.body.entry[index].response.status + "'");
}
});
const batch_patient_location = response.body.entry[0].response.location;
const indexOfHistory = batch_patient_location.lastIndexOf("/_history");
trimmed_location = batch_patient_location.substring(0, indexOfHistory);
trimmed_location = trimmed_location.replace("Patient/", "")
client.global.set("batch_patient_id", trimmed_location);
%}
### Update - Instance
# https://hapifhir.io/hapi-fhir/docs/server_plain/rest_operations.html#instance_update
PUT http://{{host}}/fhir/Patient/{{batch_patient_id}}
Content-Type: application/json
< smoketestfiles/patient_update.json
> {%
client.test("Bundle transaction completed successfully", function() {
client.assert(response.status === 200, "Response status is not 200");
});
client.test("Response content-type is json", function() {
const type = response.contentType.mimeType;
client.assert(type === "application/fhir+json", "Expected 'application/fhir+json' but received '" + type + "'");
});
client.test("Response resourceType is Patient", function() {
const resourceType = response.body.resourceType;
client.assert(resourceType === "Patient", "Expected 'Patient' but received '" + resourceType + "'");
});
client.test("Test last name updated", function() {
const familyName = response.body.name[0].family;
client.assert(familyName === "Iantoryes", "Expected updated family name 'Iantoryes' but received '" + familyName + "'");
});
client.test("Test version number updated", function() {
const versionId = response.body.meta.versionId;
client.assert(versionId === "2", "Expected updated versionId name '2' but received '" + versionId + "'");
});
%}
### Patch - Instance
# https://hapifhir.io/hapi-fhir/docs/server_plain/rest_operations.html#instance-level-patch
PATCH http://{{host}}/fhir/Patient/{{batch_patient_id}}
Content-Type: application/json-patch+json
< smoketestfiles/patient_patch.json
> {%
client.test("Patch operation completed successfully", function() {
client.assert(response.status === 200, "Response status is not 200");
});
client.test("Response content-type is json", function() {
const type = response.contentType.mimeType;
client.assert(type === "application/fhir+json", "Expected 'application/fhir+json' but received '" + type + "'");
});
client.test("Response resourceType is Patient", function() {
const resourceType = response.body.resourceType;
client.assert(resourceType === "Patient", "Expected 'Patient' but received '" + resourceType + "'");
});
client.test("Test active field patched", function() {
const active = response.body.active;
client.assert(active === false, "Expected updated active 'false' but received '" + active + "'");
});
%}
### History - Server/Type/Instance
# https://hapifhir.io/hapi-fhir/docs/server_plain/rest_operations.html#history
GET http://{{host}}/fhir/Patient/{{batch_patient_id}}/_history
> {%
client.test("History completed successfully", function() {
client.assert(response.status === 200, "Response status is not 200");
});
client.test("Response content-type is json", function() {
const type = response.contentType.mimeType;
client.assert(type === "application/fhir+json", "Expected 'application/fhir+json' but received '" + type + "'");
});
client.test("Response resourceType is Bundle", function() {
const resourceType = response.body.resourceType;
client.assert(resourceType === "Bundle", "Expected 'Bundle' but received '" + resourceType + "'");
});
client.test("Test receive history type", function() {
const type = response.body.type;
client.assert(type === "history", "Expected type 'history' but received '" + type + "'");
});
%}
### Capability Statement
# https://hapifhir.io/hapi-fhir/docs/server_plain/rest_operations.html#system_capabilities
GET http://{{host}}/fhir/metadata
> {%
client.test("CapabilityStatement fetched successfully", function() {
client.assert(response.status === 200, "Response status is not 200");
});
client.test("Response content-type is json", function() {
const type = response.contentType.mimeType;
client.assert(type === "application/fhir+json", "Expected 'application/fhir+json' but received '" + type + "'");
});
client.test("Response resourceType is CapabilityStatement", function() {
const resourceType = response.body.resourceType;
client.assert(resourceType === "CapabilityStatement", "Expected 'CapabilityStatement' but received '" + resourceType + "'");
});
%}
### Extended Operations - everything
# https://hapifhir.io/hapi-fhir/docs/server_plain/rest_operations_operations.html
GET http://{{host}}/fhir/Patient/{{batch_patient_id}}/$everything
> {%
client.test("$everything operation successful", function() {
client.assert(response.status === 200, "Response status is not 200");
});
client.test("Response content-type is json", function() {
const type = response.contentType.mimeType;
client.assert(type === "application/fhir+json", "Expected 'application/fhir+json' but received '" + type + "'");
});
client.test("Response resourceType is Bundle", function() {
const resourceType = response.body.resourceType;
client.assert(resourceType === "Bundle", "Expected 'Bundle' but received '" + resourceType + "'");
});
%}
### Extended Operations - validate
# https://hapifhir.io/hapi-fhir/docs/server_plain/rest_operations_operations.html
POST http://{{host}}/fhir/Patient/{{batch_patient_id}}/$validate
> {%
client.test("$validate operation successful", function() {
client.assert(response.status === 200, "Response status is not 200");
});
client.test("Response content-type is json", function() {
const type = response.contentType.mimeType;
client.assert(type === "application/fhir+json", "Expected 'application/fhir+json' but received '" + type + "'");
});
client.test("Response resourceType is OperationOutcome", function() {
const resourceType = response.body.resourceType;
client.assert(resourceType === "OperationOutcome", "Expected 'OperationOutcome' but received '" + resourceType + "'");
});
%}

View File

@@ -0,0 +1,85 @@
{
"resourceType": "Bundle",
"id": "bundle-transaction",
"meta": {
"lastUpdated": "2014-08-18T01:43:30Z"
},
"type": "transaction",
"entry": [
{
"resource": {
"resourceType": "Patient",
"text": {
"status": "generated",
"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\">Some narrative</div>"
},
"active": true,
"name": [
{
"use": "official",
"family": "Iantorno",
"given": [
"Mark"
]
}
],
"gender": "male",
"birthDate": "1983-06-23"
},
"request": {
"method": "POST",
"url": "Patient"
}
},
{
"resource": {
"resourceType": "Patient",
"text": {
"status": "generated",
"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\">Some narrative</div>"
},
"active": true,
"name": [
{
"use": "official",
"family": "Iantorno",
"given": [
"Alexander"
]
}
],
"gender": "male",
"birthDate": "1993-08-16"
},
"request": {
"method": "POST",
"url": "Patient"
}
},
{
"resource": {
"resourceType": "Patient",
"text": {
"status": "generated",
"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\">Some narrative</div>"
},
"active": true,
"name": [
{
"use": "official",
"family": "Cash",
"given": [
"Johnny"
]
}
],
"gender": "male",
"birthDate": "1932-02-26"
},
"request": {
"method": "POST",
"url": "Patient"
}
}
]
}

View File

@@ -0,0 +1,162 @@
{
"resourceType": "Patient",
"id": "example",
"text": {
"status": "generated",
"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\">\n\t\t\t<table>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>Name</td>\n\t\t\t\t\t\t<td>Peter James \n <b>Chalmers</b> (&quot;Jim&quot;)\n </td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>Address</td>\n\t\t\t\t\t\t<td>534 Erewhon, Pleasantville, Vic, 3999</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>Contacts</td>\n\t\t\t\t\t\t<td>Home: unknown. Work: (03) 5555 6473</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>Id</td>\n\t\t\t\t\t\t<td>MRN: 12345 (Acme Healthcare)</td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t</div>"
},
"identifier": [
{
"use": "usual",
"type": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
"code": "MR"
}
]
},
"system": "urn:oid:1.2.36.146.595.217.0.1",
"value": "12345",
"period": {
"start": "2001-05-06"
},
"assigner": {
"display": "Acme Healthcare"
}
}
],
"active": true,
"name": [
{
"use": "official",
"family": "Chalmers",
"given": [
"Peter",
"James"
]
},
{
"use": "usual",
"given": [
"Jim"
]
},
{
"use": "maiden",
"family": "Windsor",
"given": [
"Peter",
"James"
],
"period": {
"end": "2002"
}
}
],
"telecom": [
{
"use": "home"
},
{
"system": "phone",
"value": "(03) 5555 6473",
"use": "work",
"rank": 1
},
{
"system": "phone",
"value": "(03) 3410 5613",
"use": "mobile",
"rank": 2
},
{
"system": "phone",
"value": "(03) 5555 8834",
"use": "old",
"period": {
"end": "2014"
}
}
],
"gender": "male",
"birthDate": "1974-12-25",
"_birthDate": {
"extension": [
{
"url": "http://hl7.org/fhir/StructureDefinition/patient-birthTime",
"valueDateTime": "1974-12-25T14:35:45-05:00"
}
]
},
"deceasedBoolean": false,
"address": [
{
"use": "home",
"type": "both",
"text": "534 Erewhon St PeasantVille, Rainbow, Vic 3999",
"line": [
"534 Erewhon St"
],
"city": "PleasantVille",
"district": "Rainbow",
"state": "Vic",
"postalCode": "3999",
"period": {
"start": "1974-12-25"
}
}
],
"contact": [
{
"relationship": [
{
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/v2-0131",
"code": "N"
}
]
}
],
"name": {
"family": "du Marché",
"_family": {
"extension": [
{
"url": "http://hl7.org/fhir/StructureDefinition/humanname-own-prefix",
"valueString": "VV"
}
]
},
"given": [
"Bénédicte"
]
},
"telecom": [
{
"system": "phone",
"value": "+33 (237) 998327"
}
],
"address": {
"use": "home",
"type": "both",
"line": [
"534 Erewhon St"
],
"city": "PleasantVille",
"district": "Rainbow",
"state": "Vic",
"postalCode": "3999",
"period": {
"start": "1974-12-25"
}
},
"gender": "female",
"period": {
"start": "2012"
}
}
]
}

View File

@@ -0,0 +1,7 @@
[
{
"op": "add",
"path": "/active",
"value": false
}
]

View File

@@ -0,0 +1,63 @@
{
"resourceType": "MessageHeader",
"id": "{{batch_patient_id}}",
"text": {
"status": "generated",
"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\">\n\t\t\t<p>Update Person resource for Peter James CHALMERS (Jim), MRN: 12345 (Acme Healthcare)</p>\n\t\t</div>"
},
"eventCoding": {
"system": "http://example.org/fhir/message-events",
"code": "admin-notify"
},
"destination": [
{
"name": "Acme Message Gateway",
"target": {
"reference": "Device/example"
},
"endpoint": "llp:10.11.12.14:5432",
"receiver": {
"reference": "http://acme.com/ehr/fhir/Practitioner/2323-33-4"
}
}
],
"sender": {
"reference": "Organization/1"
},
"enterer": {
"reference": "Practitioner/example"
},
"author": {
"reference": "Practitioner/example"
},
"source": {
"name": "Acme Central Patient Registry",
"software": "FooBar Patient Manager",
"version": "3.1.45.AABB",
"contact": {
"system": "phone",
"value": "+1 (555) 123 4567"
},
"endpoint": "llp:10.11.12.13:5432"
},
"reason": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/message-reasons-encounter",
"code": "admit"
}
]
},
"response": {
"identifier": {
"value": "5015fe84-8e76-4526-89d8-44b322e8d4fb"
},
"code": "ok"
},
"focus": [
{
"reference": "Patient/example"
}
],
"definition": "http:////acme.com/ehr/fhir/messagedefinition/patientrequest"
}

View File

@@ -0,0 +1,20 @@
{
"resourceType": "Patient",
"id": "{{batch_patient_id}}",
"text": {
"status": "generated",
"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\">Some narrative</div>"
},
"active": true,
"name": [
{
"use": "official",
"family": "Iantoryes",
"given": [
"Mark"
]
}
],
"gender": "male",
"birthDate": "1983-06-23"
}