Skip to content
This repository has been archived by the owner on Apr 13, 2023. It is now read-only.

Commit

Permalink
test: add end to end tests for subscriptions (#578)
Browse files Browse the repository at this point in the history
  • Loading branch information
ssvegaraju authored Feb 25, 2022
1 parent 4b59859 commit d83f52f
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 20 deletions.
6 changes: 1 addition & 5 deletions integration-tests/bulkExport.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@
* SPDX-License-Identifier: Apache-2.0
*/
import BulkExportTestHelper, { ExportStatusOutput } from './bulkExportTestHelper';
import { getFhirClient, getResourcesFromBundleResponse } from './utils';
import { getFhirClient, getResourcesFromBundleResponse, sleep } from './utils';
import createGroupMembersBundle from './createGroupMembersBundle.json';

const EIGHT_MINUTES_IN_MS = 8 * 60 * 1000;
jest.setTimeout(EIGHT_MINUTES_IN_MS);

const sleep = async (milliseconds: number) => {
return new Promise((resolve) => setTimeout(resolve, milliseconds));
};

describe('Bulk Export', () => {
let bulkExportTestHelper: BulkExportTestHelper;

Expand Down
159 changes: 146 additions & 13 deletions integration-tests/subscriptions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { AxiosInstance } from 'axios';
import { v4 } from 'uuid';
import waitForExpect from 'wait-for-expect';
import { SubscriptionsHelper } from './SubscriptionsHelper';
import { getFhirClient, randomSubscription } from './utils';
import { getFhirClient, randomSubscription, sleep } from './utils';

jest.setTimeout(700_000);

Expand Down Expand Up @@ -40,6 +40,15 @@ if (SUBSCRIPTIONS_ENABLED === 'true') {
throw new Error('SUBSCRIPTIONS_API_KEY environment variable is not defined');
}
let client: AxiosInstance;
const resourceThatMatchesSubscription = {
resourceType: 'Patient',
name: [
{
given: ['Smith'],
family: 'Smith',
},
],
};

describe('FHIR Subscriptions', () => {
let subscriptionsHelper: SubscriptionsHelper;
Expand All @@ -65,27 +74,151 @@ if (SUBSCRIPTIONS_ENABLED === 'true') {
const subResource = randomSubscription(uuid);
const postResult = await client.post('Subscription', subResource);
expect(postResult.status).toEqual(201);
const resourceThatMatchesSubscription = {
resourceType: 'Patient',
name: [
{
given: ['Smith'],
family: 'Smith',
},
],
};
// post matching resource on another tenant
// post matching resource on another tenant, waiting 1 minute for subscription to enable
await sleep(60_000);
const postPatientResult = await clientAnotherTenant.post('Patient', resourceThatMatchesSubscription);
expect(postPatientResult.status).toEqual(201);
// give 2 minutes for notification to be placed in ddb table
await new Promise((r) => setTimeout(r, 120_000));
// give 1 minute for notification to be placed in ddb table
await sleep(60_000);
// make sure no notification was receieved for first tenant
const notifications = await subscriptionsHelper.getNotifications(
`${uuid}/Patient/${postPatientResult.data.id}`,
);
expect(notifications).toEqual([]);
});
}

test('invalid subscriptions', async () => {
// test for endpoints that aren't allow listed
let subResource = randomSubscription(v4());
subResource.channel.endpoint = 'https://non_allow_listed_endpoint.com';
await expect(client.post('Subscription', subResource)).rejects.toMatchObject({
response: { status: 400 },
});

// test for unsupported channel types (email, sms, and websocket)
subResource = randomSubscription(v4());
subResource.channel.type = 'email';
await expect(client.post('Subscription', subResource)).rejects.toMatchObject({
response: { status: 400 },
});
subResource.channel.type = 'sms';
await expect(client.post('Subscription', subResource)).rejects.toMatchObject({
response: { status: 400 },
});
subResource.channel.type = 'websocket';
await expect(client.post('Subscription', subResource)).rejects.toMatchObject({
response: { status: 400 },
});

// test for invalid criteria
subResource = randomSubscription(v4());
subResource.criteria = 'Patient?managing-organization=Organization/123';
await expect(client.post('Subscription', subResource)).rejects.toMatchObject({
response: { status: 400 },
});
});

test('end to end test with id notifications', async () => {
const uuid = v4();
const subResource = randomSubscription(uuid);
// 1. Create a Subscription.
const postSubscriptionResult = await client.post('Subscription', subResource);
expect(postSubscriptionResult.status).toBe(201);

// 2. Create/Update a resource that matches the subscription.
// wait for subscription to be enabled
await sleep(60_000);
const postPatientResult = await client.post('Patient', resourceThatMatchesSubscription);
expect(postPatientResult.status).toEqual(201);
let updatePatientResult = await client.put(`Patient/${postPatientResult.data.id}`, {
...resourceThatMatchesSubscription,
id: postPatientResult.data.id,
});
expect(updatePatientResult.status).toEqual(200);

// 3. Verify that notifications are received
await waitForExpect(
async () => {
const notifications = await subscriptionsHelper.getNotifications(
`/${uuid}/Patient/${postPatientResult.data.id}`,
);
expect(notifications.length).toEqual(2); // one for create, one for update
expect(notifications[0].httpMethod).toEqual('PUT');
expect(notifications[0].body).toBeNull();
expect(notifications[0].headers).toHaveProperty('x-api-key', SUBSCRIPTIONS_API_KEY);
expect(notifications[1].httpMethod).toEqual('PUT');
expect(notifications[1].body).toBeNull();
expect(notifications[1].headers).toHaveProperty('x-api-key', SUBSCRIPTIONS_API_KEY);
},
60_000,
5_000,
);

// 4. Delete the Subscription
const deleteSubscriptionResult = await client.delete(`Subscription/${postSubscriptionResult.data.id}`);
expect(deleteSubscriptionResult.status).toEqual(200);
await sleep(60_000);

// 5. Create/Update a resource that matches the subscription.
// test update:
updatePatientResult = await client.put(`Patient/${postPatientResult.data.id}`, {
...resourceThatMatchesSubscription,
id: postPatientResult.data.id,
});
expect(updatePatientResult.status).toEqual(200);
// test create:
const postAnotherPatientResult = await client.post('Patient', resourceThatMatchesSubscription);
expect(postAnotherPatientResult.status).toEqual(201);

// 6. Verify that notifications are no longer being sent
await sleep(60_000);
let notifications = await subscriptionsHelper.getNotifications(
`/${uuid}/Patient/${postPatientResult.data.id}`,
);
// we still have the two notifications from earlier in the test, but no more
expect(notifications.length).toEqual(2);
// we don't have any notifications for the newly created patient
notifications = await subscriptionsHelper.getNotifications(
`/${uuid}/Patient/${postAnotherPatientResult.data.id}`,
);
expect(notifications).toEqual([]);
});

test('end to end test with empty notifications', async () => {
const uuid = v4();
const subResource = randomSubscription(uuid, true);
// 1. Create a Subscription.
const postSubscriptionResult = await client.post('Subscription', subResource);
expect(postSubscriptionResult.status).toBe(201);

// 2. Create/Update a resource that matches the subscription.
// wait 1 min to let subscription enable
await sleep(60_000);
const postPatientResult = await client.post('Patient', resourceThatMatchesSubscription);
expect(postPatientResult.status).toEqual(201);
const updatePatientResult = await client.put(`Patient/${postPatientResult.data.id}`, {
...resourceThatMatchesSubscription,
id: postPatientResult.data.id,
});
expect(updatePatientResult.status).toEqual(200);

// 3. Verify that notifications are received
await waitForExpect(
async () => {
const notifications = await subscriptionsHelper.getNotifications(`/${uuid}`);
expect(notifications.length).toEqual(2);
expect(notifications[0].httpMethod).toEqual('POST');
expect(notifications[0].body).toBeNull();
expect(notifications[0].headers).toHaveProperty('x-api-key', SUBSCRIPTIONS_API_KEY);
expect(notifications[1].httpMethod).toEqual('POST');
expect(notifications[1].body).toBeNull();
expect(notifications[1].headers).toHaveProperty('x-api-key', SUBSCRIPTIONS_API_KEY);
},
60_000,
5_000,
);
});
});

describe('test subscription creation and deletion', () => {
Expand Down
8 changes: 6 additions & 2 deletions integration-tests/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ import createBundle from './createPatientPractitionerEncounterBundle.json';

const DEFAULT_TENANT_ID = 'tenant1';

export const sleep = async (milliseconds: number) => {
return new Promise((resolve) => setTimeout(resolve, milliseconds));
};

const getAuthParameters: (role: string, tenantId: string) => { PASSWORD: string; USERNAME: string } = (
role: string,
tenantId: string,
Expand Down Expand Up @@ -213,7 +217,7 @@ export const randomPatient = () => {
};
};

export const randomSubscription = (endpointUUID: string) => {
export const randomSubscription = (endpointUUID: string, emptyNotification = false) => {
// we checked if environment variable were defined already
return {
resourceType: 'Subscription',
Expand All @@ -225,7 +229,7 @@ export const randomSubscription = (endpointUUID: string) => {
channel: {
type: 'rest-hook',
endpoint: `${process.env.SUBSCRIPTIONS_ENDPOINT}/${endpointUUID}`,
payload: 'application/fhir+json',
payload: emptyNotification ? undefined : 'application/fhir+json',
header: [`x-api-key: ${process.env.SUBSCRIPTIONS_API_KEY}`],
},
};
Expand Down

0 comments on commit d83f52f

Please sign in to comment.