Skip to content

Commit 6df908e

Browse files
committed
Better Logging
1 parent 20565c9 commit 6df908e

2 files changed

Lines changed: 336 additions & 35 deletions

File tree

src/api/kafka/marathon-match-submission.handler.spec.ts

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { CompilationStatus } from '@prisma/client';
2-
import { of } from 'rxjs';
2+
import { of, throwError } from 'rxjs';
33
jest.mock('src/shared/modules/global/prisma.service', () => ({
44
PrismaService: class PrismaService {},
55
}));
@@ -177,6 +177,107 @@ describe('MarathonMatchSubmissionHandler', () => {
177177
);
178178
});
179179

180+
it('logs outbound URL details when submission-api preflight returns 403', async () => {
181+
const originalSubmissionApiUrl = process.env.SUBMISSION_API_URL;
182+
delete process.env.SUBMISSION_API_URL;
183+
const { handler, prisma, m2mService, httpService, ecsService } =
184+
createHandler();
185+
const submissionUrl =
186+
'https://api.topcoder.com/v6/submissions/submission-1';
187+
const axiosError = Object.assign(
188+
new Error('Request failed with status code 403'),
189+
{
190+
isAxiosError: true,
191+
config: {
192+
method: 'get',
193+
url: submissionUrl,
194+
},
195+
response: {
196+
status: 403,
197+
statusText: 'Forbidden',
198+
data: {
199+
message: 'Forbidden',
200+
},
201+
},
202+
},
203+
);
204+
205+
try {
206+
prisma.marathonMatchConfig.findUnique.mockResolvedValue({
207+
id: 'config-1',
208+
challengeId: 'challenge-1',
209+
active: true,
210+
submissionApiUrl: 'https://api.topcoder.com/v6',
211+
testerId: 'tester-1',
212+
taskDefinitionName: 'mm-ecs-runner',
213+
taskDefinitionVersion: '7',
214+
tester: {
215+
compilationStatus: CompilationStatus.SUCCESS,
216+
},
217+
phaseConfigs: [
218+
{
219+
id: 'phase-provisional',
220+
configType: 'PROVISIONAL',
221+
phaseId: 'submission-phase',
222+
startSeed: BigInt(500),
223+
numberOfTests: 20,
224+
},
225+
],
226+
});
227+
228+
(handler as any).getOpenPhaseResolution = jest.fn().mockResolvedValue({
229+
phaseIds: ['submission-phase'],
230+
phaseIdentifiers: ['submission-phase'],
231+
});
232+
233+
m2mService.getM2MToken.mockResolvedValue('m2m-token');
234+
httpService.get.mockReturnValue(throwError(() => axiosError));
235+
236+
await expect(
237+
handler.handle({
238+
submissionId: 'submission-1',
239+
challengeId: 'challenge-1',
240+
submissionUrl: 'https://example.com/submission.zip',
241+
memberHandle: 'tester',
242+
memberId: 'member-1',
243+
submittedDate: '2026-03-26T01:27:22.829Z',
244+
}),
245+
).rejects.toThrow('Request failed with status code 403');
246+
247+
expect(ecsService.launchScorerTask).not.toHaveBeenCalled();
248+
expect(mockLogger.log).toHaveBeenCalledWith(
249+
expect.objectContaining({
250+
message: 'Calling external API',
251+
operation: 'submission-api.get-submission',
252+
method: 'GET',
253+
url: submissionUrl,
254+
submissionId: 'submission-1',
255+
}),
256+
);
257+
expect(mockLogger.error).toHaveBeenCalledWith(
258+
expect.objectContaining({
259+
message: 'External API call failed',
260+
operation: 'submission-api.get-submission',
261+
method: 'GET',
262+
url: submissionUrl,
263+
submissionId: 'submission-1',
264+
httpError: expect.objectContaining({
265+
status: 403,
266+
method: 'GET',
267+
url: submissionUrl,
268+
responseData: '{"message":"Forbidden"}',
269+
}),
270+
}),
271+
);
272+
} finally {
273+
if (originalSubmissionApiUrl === undefined) {
274+
delete process.env.SUBMISSION_API_URL;
275+
} else {
276+
process.env.SUBMISSION_API_URL = originalSubmissionApiUrl;
277+
}
278+
}
279+
});
280+
180281
it('marks configured submissions failed when no open phase matches the stored phase config', async () => {
181282
const { handler, prisma, m2mService, httpService, ecsService } =
182283
createHandler();

0 commit comments

Comments
 (0)