@@ -27,6 +27,7 @@ describe('MarathonMatchConfigService', () => {
2727 const createService = ( ) => {
2828 const httpService = {
2929 get : jest . fn ( ) ,
30+ post : jest . fn ( ) ,
3031 } ;
3132 const ecsService = {
3233 launchScorerTask : jest . fn ( ) ,
@@ -426,6 +427,150 @@ describe('MarathonMatchConfigService', () => {
426427 ) ;
427428 } ) ;
428429
430+ it ( 'uploads a validation submission and queues scorer execution' , async ( ) => {
431+ const { service, ecsService, httpService, m2mService, prisma } =
432+ createService ( ) ;
433+ const user = {
434+ isMachine : false ,
435+ userId : '40051399' ,
436+ } as never ;
437+
438+ prisma . marathonMatchConfig . findUnique . mockResolvedValue ( {
439+ id : 'config-1' ,
440+ challengeId : '30000123' ,
441+ active : true ,
442+ submissionApiUrl : 'https://submissions.example.com/v6' ,
443+ testerId : 'tester-1' ,
444+ taskDefinitionName : 'mm-runner' ,
445+ taskDefinitionVersion : '7' ,
446+ tester : {
447+ compilationStatus : CompilationStatus . SUCCESS ,
448+ } ,
449+ phaseConfigs : [
450+ {
451+ id : 'phase-provisional' ,
452+ configType : PhaseConfigType . PROVISIONAL ,
453+ phaseId : 'provisional-phase' ,
454+ startSeed : BigInt ( 100 ) ,
455+ numberOfTests : 50 ,
456+ } ,
457+ ] ,
458+ } ) ;
459+ m2mService . getM2MToken . mockResolvedValue ( 'm2m-token' ) ;
460+ httpService . post . mockReturnValue (
461+ of ( {
462+ data : {
463+ id : 'validation-submission-1' ,
464+ } ,
465+ } ) ,
466+ ) ;
467+ ecsService . launchScorerTask . mockResolvedValue ( {
468+ taskArn : 'arn:aws:ecs:task/task-1' ,
469+ taskId : 'task-1' ,
470+ cluster : 'cluster-1' ,
471+ containerName : 'runner' ,
472+ taskDefinition : 'mm-runner:7' ,
473+ cloudWatchLogsConsoleUrl : 'https://logs.example.com/task-1' ,
474+ } ) ;
475+
476+ const result = await service . uploadTestSubmission (
477+ '30000123' ,
478+ {
479+ configType : PhaseConfigType . PROVISIONAL ,
480+ } ,
481+ {
482+ buffer : Buffer . from ( 'zip' ) ,
483+ mimetype : 'application/zip' ,
484+ originalname : 'solution.zip' ,
485+ size : 3 ,
486+ } as Express . Multer . File ,
487+ user ,
488+ ) ;
489+
490+ const postedForm = httpService . post . mock . calls [ 0 ] [ 1 ] as FormData ;
491+ expect ( result ) . toEqual ( {
492+ challengeId : '30000123' ,
493+ submissionId : 'validation-submission-1' ,
494+ configType : PhaseConfigType . PROVISIONAL ,
495+ taskArn : 'arn:aws:ecs:task/task-1' ,
496+ taskId : 'task-1' ,
497+ cloudWatchLogsConsoleUrl : 'https://logs.example.com/task-1' ,
498+ } ) ;
499+ expect ( httpService . post ) . toHaveBeenCalledWith (
500+ 'https://submissions.example.com/v6/submissions/validation-upload' ,
501+ expect . any ( FormData ) ,
502+ {
503+ headers : {
504+ Authorization : 'Bearer m2m-token' ,
505+ } ,
506+ } ,
507+ ) ;
508+ expect ( postedForm . get ( 'challengeId' ) ) . toBe ( '30000123' ) ;
509+ expect ( postedForm . get ( 'memberId' ) ) . toBe ( '40051399' ) ;
510+ expect ( postedForm . get ( 'type' ) ) . toBe ( 'CONTEST_SUBMISSION' ) ;
511+ expect ( postedForm . get ( 'submissionPhaseId' ) ) . toBe ( 'provisional-phase' ) ;
512+ expect ( ecsService . launchScorerTask ) . toHaveBeenCalledWith (
513+ '30000123' ,
514+ 'validation-submission-1' ,
515+ {
516+ taskDefinitionName : 'mm-runner' ,
517+ taskDefinitionVersion : '7' ,
518+ } ,
519+ {
520+ configType : PhaseConfigType . PROVISIONAL ,
521+ startSeed : BigInt ( 100 ) ,
522+ numberOfTests : 50 ,
523+ } ,
524+ undefined ,
525+ {
526+ memberId : '40051399' ,
527+ } ,
528+ ) ;
529+ } ) ;
530+
531+ it ( 'rejects validation submissions when the tester is not compiled' , async ( ) => {
532+ const { service, ecsService, httpService, prisma } = createService ( ) ;
533+
534+ prisma . marathonMatchConfig . findUnique . mockResolvedValue ( {
535+ id : 'config-1' ,
536+ challengeId : '30000123' ,
537+ testerId : 'tester-1' ,
538+ tester : {
539+ compilationStatus : CompilationStatus . FAILED ,
540+ compilationError : 'javac failed' ,
541+ } ,
542+ phaseConfigs : [
543+ {
544+ id : 'phase-provisional' ,
545+ configType : PhaseConfigType . PROVISIONAL ,
546+ phaseId : 'provisional-phase' ,
547+ startSeed : BigInt ( 100 ) ,
548+ numberOfTests : 50 ,
549+ } ,
550+ ] ,
551+ } ) ;
552+
553+ await expect (
554+ service . uploadTestSubmission (
555+ '30000123' ,
556+ { } ,
557+ {
558+ buffer : Buffer . from ( 'zip' ) ,
559+ mimetype : 'application/zip' ,
560+ originalname : 'solution.zip' ,
561+ size : 3 ,
562+ } as Express . Multer . File ,
563+ {
564+ isMachine : false ,
565+ userId : '40051399' ,
566+ } as never ,
567+ ) ,
568+ ) . rejects . toThrow ( BadRequestException ) ;
569+
570+ expect ( httpService . post ) . not . toHaveBeenCalled ( ) ;
571+ expect ( ecsService . launchScorerTask ) . not . toHaveBeenCalled ( ) ;
572+ } ) ;
573+
429574 it ( 'rate limits rerun scorer task launches in batches' , async ( ) => {
430575 jest . useFakeTimers ( ) ;
431576
0 commit comments