Skip to content

Commit

Permalink
fix(agent): unwrap response for $reload-config by id (#4542)
Browse files Browse the repository at this point in the history
  • Loading branch information
ThatOneBro committed May 13, 2024
1 parent 59d9e3c commit d36f34b
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 26 deletions.
2 changes: 1 addition & 1 deletion packages/core/src/outcomes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ export function badRequest(details: string, expression?: string): OperationOutco
details: {
text: details,
},
expression: expression ? [expression] : undefined,
...(expression ? { expression: [expression] } : undefined),
},
],
};
Expand Down
102 changes: 79 additions & 23 deletions packages/server/src/fhir/operations/agentreloadconfig.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import {
AgentTransmitResponse,
ContentType,
allOk,
badRequest,
serverError,
} from '@medplum/core';
import { Agent, Bundle, Parameters } from '@medplum/fhirtypes';
import { Agent, Bundle, OperationOutcome, Parameters } from '@medplum/fhirtypes';
import express from 'express';
import { randomUUID } from 'node:crypto';
import { Server } from 'node:http';
Expand Down Expand Up @@ -116,47 +117,102 @@ describe('Agent/$reload-config', () => {
.set('Authorization', 'Bearer ' + accessToken);

expect(res.status).toBe(200);
const bundle = res.body as Bundle<Parameters>;
const outcome = res.body as OperationOutcome;

expectBundleToContainOutcome(bundle, agents[0], allOk);
expect(outcome).toMatchObject<OperationOutcome>(allOk);
cleanup();
});

test('Agent error during reload', async () => {
const { cleanup } = await mockAgentResponse<AgentReloadConfigRequest, AgentError>(
agents[0],
accessToken,
'agent:reloadconfig:request',
{ type: 'agent:error', body: 'Something is broken' }
);
// Multi agent example
const handlePromises = [] as Promise<MockAgentResponseHandle>[];
for (let i = 0; i < agents.length; i++) {
handlePromises[i] = mockAgentResponse<AgentReloadConfigRequest, AgentReloadConfigResponse | AgentError>(
agents[i],
accessToken,
'agent:reloadconfig:request',
i === 0
? { type: 'agent:error', body: 'Something is broken' }
: { type: 'agent:reloadconfig:response', statusCode: 200 }
);
}
const handles = await Promise.all(handlePromises);

const res = await request(app)
.get(`/fhir/R4/Agent/${agents[0].id as string}/$reload-config`)
let res = await request(app)
.get('/fhir/R4/Agent/$reload-config')
.set('Authorization', 'Bearer ' + accessToken);

expect(res.status).toBe(200);
const bundle = res.body as Bundle<Parameters>;

expectBundleToContainOutcome(bundle, agents[0], serverError(new Error('Something is broken')));
cleanup();
for (let i = 0; i < agents.length; i++) {
if (i === 0) {
expectBundleToContainOutcome(bundle, agents[0], badRequest('Something is broken'));
continue;
}
expectBundleToContainOutcome(bundle, agents[i], allOk);
}

// Agent by ID
res = await request(app)
.get(`/fhir/R4/Agent/${agents[0].id as string}/$reload-config`)
.set('Authorization', 'Bearer ' + accessToken);

expect(res.status).toBe(400);

const outcome = res.body as OperationOutcome;
expect(outcome).toMatchObject(badRequest('Something is broken'));

for (const handle of handles) {
handle.cleanup();
}
});

test('Invalid response from agent during reload', async () => {
const { cleanup } = await mockAgentResponse<AgentReloadConfigRequest, AgentTransmitResponse>(
agents[0],
accessToken,
'agent:reloadconfig:request',
{ type: 'agent:transmit:response', remote: '8.8.8.8', contentType: ContentType.PING, body: 'PING' }
);
// Multi agent example
const handlePromises = [] as Promise<MockAgentResponseHandle>[];
for (let i = 0; i < agents.length; i++) {
handlePromises[i] = mockAgentResponse<
AgentReloadConfigRequest,
AgentReloadConfigResponse | AgentTransmitResponse
>(
agents[i],
accessToken,
'agent:reloadconfig:request',
i === 0
? { type: 'agent:transmit:response', remote: '8.8.8.8', contentType: ContentType.PING, body: 'PING' }
: { type: 'agent:reloadconfig:response', statusCode: 200 }
);
}
const handles = await Promise.all(handlePromises);

const res = await request(app)
.get(`/fhir/R4/Agent/${agents[0].id as string}/$reload-config`)
let res = await request(app)
.get('/fhir/R4/Agent/$reload-config')
.set('Authorization', 'Bearer ' + accessToken);

expect(res.status).toBe(200);
const bundle = res.body as Bundle<Parameters>;

expectBundleToContainOutcome(bundle, agents[0], serverError(new Error('Invalid response received from agent')));
cleanup();
for (let i = 0; i < agents.length; i++) {
if (i === 0) {
expectBundleToContainOutcome(bundle, agents[0], serverError(new Error('Invalid response received from agent')));
continue;
}
expectBundleToContainOutcome(bundle, agents[i], allOk);
}

// Single agent by ID
res = await request(app)
.get(`/fhir/R4/Agent/${agents[0].id as string}/$reload-config`)
.set('Authorization', 'Bearer ' + accessToken);

expect(res.status).toBe(500);

const outcome = res.body as OperationOutcome;
expect(outcome).toMatchObject<OperationOutcome>(serverError(new Error('Invalid response received from agent')));

for (const handle of handles) {
handle.cleanup();
}
});
});
4 changes: 2 additions & 2 deletions packages/server/src/fhir/operations/agentreloadconfig.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AgentReloadConfigResponse, OperationOutcomeError, serverError } from '@medplum/core';
import { AgentReloadConfigResponse, OperationOutcomeError, badRequest, serverError } from '@medplum/core';
import { FhirRequest, FhirResponse } from '@medplum/fhir-router';
import { Agent, OperationDefinition } from '@medplum/fhirtypes';
import { handleBulkAgentOperation, publishAgentRequest } from './utils/agentutils';
Expand Down Expand Up @@ -47,7 +47,7 @@ async function reloadConfig(agent: Agent): Promise<FhirResponse> {
}

if (result.type === 'agent:error') {
throw new OperationOutcomeError(serverError(new Error(result.body)));
throw new OperationOutcomeError(badRequest(result.body));
}

throw new OperationOutcomeError(serverError(new Error('Invalid response received from agent')));
Expand Down
4 changes: 4 additions & 0 deletions packages/server/src/fhir/operations/utils/agentutils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ export async function handleBulkAgentOperation(
return [badRequest('No agent(s) for given query')];
}

if (req.params.id) {
return handler(agents[0]);
}

const promises = agents.map((agent: Agent) => handler(agent));
const results = await Promise.allSettled(promises);
const entries = [] as BundleEntry<Parameters>[];
Expand Down

0 comments on commit d36f34b

Please sign in to comment.