JobResource { @ApiOperation( value = "fetches a set of job statuses matching the given filter options", response = AsyncJobStatusDTO.class, responseContainer = "set") @ApiResponses({ @ApiResponse(code = 400, message = ""), @ApiResponse(code = 404, message = "") }) @GET @Path("/") @Produces(MediaType.APPLICATION_JSON) @Transactional public Stream<AsyncJobStatusDTO> listJobStatuses( @QueryParam("id") Set<String> ids, @QueryParam("key") Set<String> keys, @QueryParam("state") Set<String> states, @QueryParam("owner") Set<String> ownerKeys, @QueryParam("principal") Set<String> principals, @QueryParam("origin") Set<String> origins, @QueryParam("executor") Set<String> executors, @QueryParam("after") @DateFormat Date after, @QueryParam("before") @DateFormat Date before) { Set<JobState> jobStates = this.translateJobStateNames(states); Set<String> ownerIds = this.translateOwnerKeys(ownerKeys); this.validateDateRange(after, before); AsyncJobStatusQueryBuilder queryBuilder = new AsyncJobStatusQueryBuilder() .setJobIds(ids) .setJobKeys(keys) .setJobStates(jobStates) .setOwnerIds(ownerIds) .setPrincipalNames(principals) .setOrigins(origins) .setExecutors(executors) .setStartDate(after) .setEndDate(before); PageRequest pageRequest = ResteasyContext.getContextData(PageRequest.class); if (pageRequest != null) { Page<Stream<AsyncJobStatusDTO>> page = new Page<>(); page.setPageRequest(pageRequest); if (pageRequest.isPaging()) { queryBuilder.setOffset((pageRequest.getPage() - 1) * pageRequest.getPerPage()) .setLimit(pageRequest.getPerPage()); } if (pageRequest.getSortBy() != null) { queryBuilder.setOrder(Collections.singleton(new AsyncJobStatusQueryBuilder.Order( pageRequest.getSortBy(), pageRequest.getOrder() == PageRequest.Order.DESCENDING))); } page.setMaxRecords((int) this.jobCurator.getJobCount(queryBuilder)); ResteasyContext.pushContext(Page.class, page); } else { if (this.jobCurator.getJobCount(queryBuilder) > MAX_JOB_RESULTS) { String errmsg = this.i18n.tr("This endpoint does not support returning more than {0} " + "results at a time, please use paging.", MAX_JOB_RESULTS); throw new BadRequestException(errmsg); } } try { return this.jobManager.findJobs(queryBuilder).stream() .map(this.translator.getStreamMapper(AsyncJobStatus.class, AsyncJobStatusDTO.class)); } catch (InvalidOrderKeyException e) { throw new BadRequestException(e.getMessage(), e); } } @Inject  JobResource(Configuration config, I18n i18n, ModelTranslator translator, JobManager jobManager,
        AsyncJobStatusCurator jobCurator, OwnerCurator ownerCurator); @ApiOperation( value = "fetches the status of the job scheduler for this Candlepin node", response = SchedulerStatusDTO.class) @ApiResponses({ @ApiResponse(code = 400, message = ""), @ApiResponse(code = 404, message = "") }) @GET @Path("/scheduler") @Produces(MediaType.APPLICATION_JSON) @Transactional SchedulerStatusDTO getSchedulerStatus(); @ApiOperation( value = "enables or disables the job scheduler for this Candlepin node", response = SchedulerStatusDTO.class) @ApiResponses({ @ApiResponse(code = 400, message = ""), @ApiResponse(code = 404, message = "") }) @POST @Path("/scheduler") @Produces(MediaType.APPLICATION_JSON) @Transactional SchedulerStatusDTO setSchedulerStatus(
        @QueryParam("running") @DefaultValue("true") boolean running); @ApiOperation( value = "fetches a set of job statuses matching the given filter options", response = AsyncJobStatusDTO.class, responseContainer = "set") @ApiResponses({ @ApiResponse(code = 400, message = ""), @ApiResponse(code = 404, message = "") }) @GET @Path("/") @Produces(MediaType.APPLICATION_JSON) @Transactional Stream<AsyncJobStatusDTO> listJobStatuses(
        @QueryParam("id") Set<String> ids,
        @QueryParam("key") Set<String> keys,
        @QueryParam("state") Set<String> states,
        @QueryParam("owner") Set<String> ownerKeys,
        @QueryParam("principal") Set<String> principals,
        @QueryParam("origin") Set<String> origins,
        @QueryParam("executor") Set<String> executors,
        @QueryParam("after") @DateFormat Date after,
        @QueryParam("before") @DateFormat Date before); @ApiOperation( value = "fetches the job status associated with the specified job ID", response = AsyncJobStatusDTO.class) @ApiResponses({ @ApiResponse(code = 400, message = ""), @ApiResponse(code = 404, message = "") }) @GET @Path("/{job_id}") @Produces(MediaType.APPLICATION_JSON) @Transactional AsyncJobStatusDTO getJobStatus(
        @PathParam("job_id") @Verify(AsyncJobStatus.class) String jobId); @ApiOperation( value = "cancels the job associated with the specified job ID", response = AsyncJobStatusDTO.class) @ApiResponses({ @ApiResponse(code = 400, message = ""), @ApiResponse(code = 404, message = "") }) @DELETE @Path("/{job_id}") @Produces(MediaType.APPLICATION_JSON) @Transactional AsyncJobStatusDTO cancelJob(
        @PathParam("job_id") @Verify(AsyncJobStatus.class) String jobId); @ApiOperation( value = "cleans up terminal jobs matching the provided criteria", response = AsyncJobStatusDTO.class) @ApiResponses({ @ApiResponse(code = 400, message = ""), @ApiResponse(code = 404, message = "") }) @DELETE @Path("/") @Produces(MediaType.APPLICATION_JSON) @Transactional int cleanupTerminalJobs(
        @QueryParam("id") Set<String> ids,
        @QueryParam("key") Set<String> keys,
        @QueryParam("state") Set<String> states,
        @QueryParam("owner") Set<String> ownerKeys,
        @QueryParam("principal") Set<String> principals,
        @QueryParam("origin") Set<String> origins,
        @QueryParam("executor") Set<String> executors,
        @QueryParam("after") @DateFormat Date after,
        @QueryParam("before") @DateFormat Date before,
        @QueryParam("force") @DefaultValue("false") boolean force); @ApiOperation( value = "schedules a job using the specified key and job properties", response = AsyncJobStatusDTO.class) @ApiResponses({ @ApiResponse(code = 400, message = ""), @ApiResponse(code = 404, message = "") }) @POST @Path("schedule/{job_key}") @Produces(MediaType.APPLICATION_JSON) @Transactional AsyncJobStatusDTO scheduleJob(
        @PathParam("job_key") String jobKey);  }
@Test public void testListJobStatusesWithValidOwnerKeys() { Owner owner1 = this.createOwner(); Owner owner2 = this.createOwner(); Owner owner3 = this.createOwner(); Set<String> keys = Util.asSet(owner1.getKey(), owner2.getKey(), owner3.getKey()); ArgumentCaptor<AsyncJobStatusQueryBuilder> captor = ArgumentCaptor.forClass(AsyncJobStatusQueryBuilder.class); JobResource resource = this.buildJobResource(); Stream<AsyncJobStatusDTO> result = resource.listJobStatuses(null, null, null, keys, null, null, null, null, null); verify(this.jobManager, times(1)).findJobs(captor.capture()); AsyncJobStatusQueryBuilder builder = captor.getValue(); assertNotNull(builder); assertNull(builder.getJobIds()); assertNull(builder.getJobKeys()); assertNull(builder.getJobStates()); assertNull(builder.getPrincipalNames()); assertNull(builder.getOrigins()); assertNull(builder.getExecutors()); assertNull(builder.getStartDate()); assertNull(builder.getEndDate()); assertNull(builder.getOffset()); assertNull(builder.getLimit()); assertNull(builder.getOrder()); Collection<String> ownerIds = builder.getOwnerIds(); assertNotNull(ownerIds); assertEquals(3, ownerIds.size()); assertTrue(ownerIds.contains(owner1.getId())); assertTrue(ownerIds.contains(owner2.getId())); assertTrue(ownerIds.contains(owner3.getId())); }
@Test public void testListJobStatusesWithInvalidOwnerKeys() { Owner owner1 = this.createOwner(); Owner owner2 = this.createOwner(); Set<String> keys = Util.asSet("", owner1.getKey(), "bad_key", owner2.getKey(), null); Set<String> expected = Util.asSet("", owner1.getId(), "bad_key", owner2.getId(), null); ArgumentCaptor<AsyncJobStatusQueryBuilder> captor = ArgumentCaptor.forClass(AsyncJobStatusQueryBuilder.class); JobResource resource = this.buildJobResource(); Stream<AsyncJobStatusDTO> result = resource.listJobStatuses(null, null, null, keys, null, null, null, null, null); verify(this.jobManager, times(1)).findJobs(captor.capture()); AsyncJobStatusQueryBuilder builder = captor.getValue(); assertNotNull(builder); assertNull(builder.getJobIds()); assertNull(builder.getJobKeys()); assertNull(builder.getJobStates()); assertNull(builder.getPrincipalNames()); assertNull(builder.getOrigins()); assertNull(builder.getExecutors()); assertNull(builder.getStartDate()); assertNull(builder.getEndDate()); assertNull(builder.getOffset()); assertNull(builder.getLimit()); assertNull(builder.getOrder()); Collection<String> ownerIds = builder.getOwnerIds(); assertNotNull(ownerIds); assertEquals(expected.size(), ownerIds.size()); for (String id : expected) { assertTrue(ownerIds.contains(id)); } }
@Test public void testListJobStatusesConvertsNullOwnerKeyStringToNullRef() { Owner owner1 = this.createOwner(); Owner owner2 = this.createOwner(); Set<String> keys = Util.asSet(owner1.getKey(), "null", owner2.getKey()); Set<String> expected = Util.asSet(owner1.getId(), null, owner2.getId()); ArgumentCaptor<AsyncJobStatusQueryBuilder> captor = ArgumentCaptor.forClass(AsyncJobStatusQueryBuilder.class); JobResource resource = this.buildJobResource(); Stream<AsyncJobStatusDTO> result = resource.listJobStatuses(null, null, null, keys, null, null, null, null, null); verify(this.jobManager, times(1)).findJobs(captor.capture()); AsyncJobStatusQueryBuilder builder = captor.getValue(); assertNotNull(builder); assertNull(builder.getJobIds()); assertNull(builder.getJobKeys()); assertNull(builder.getJobStates()); assertNull(builder.getPrincipalNames()); assertNull(builder.getOrigins()); assertNull(builder.getExecutors()); assertNull(builder.getStartDate()); assertNull(builder.getEndDate()); assertNull(builder.getOffset()); assertNull(builder.getLimit()); assertNull(builder.getOrder()); Collection<String> ownerIds = builder.getOwnerIds(); assertNotNull(ownerIds); assertEquals(expected.size(), ownerIds.size()); for (String id : expected) { assertTrue(ownerIds.contains(id)); } }
@Test public void testListJobStatusesFailsOnInvalidDateRange() { Date start = Util.addDaysToDt(-2); Date end = Util.addDaysToDt(2); JobResource resource = this.buildJobResource(); assertThrows(BadRequestException.class, () -> resource.listJobStatuses(null, null, null, null, null, null, null, end, start)); }
@Test public void testListJobStatusesFailsOnInvalidOrderKey() { PageRequest pageRequest = new PageRequest(); pageRequest.setSortBy("bad_key"); ResteasyContext.pushContext(PageRequest.class, pageRequest); doThrow(new InvalidOrderKeyException()).when(this.jobManager).findJobs(any()); JobResource resource = this.buildJobResource(); assertThrows(BadRequestException.class, () -> resource.listJobStatuses(null, null, null, null, null, null, null, null, null)); }
@Test public void testListJobStatusesFailsWhenResultMaxLimitExceeded() { doReturn(10001L).when(this.jobCurator).getJobCount(any(AsyncJobStatusQueryBuilder.class)); JobResource resource = this.buildJobResource(); assertThrows(BadRequestException.class, () -> resource.listJobStatuses(null, null, null, null, null, null, null, null, null)); }
@Test public void testListJobStatusesDoesNotFailWhenResultMaxLimitNotExceeded() { doReturn(10000L).when(this.jobCurator).getJobCount(any(AsyncJobStatusQueryBuilder.class)); JobResource resource = this.buildJobResource(); assertDoesNotThrow(() -> resource.listJobStatuses(null, null, null, null, null, null, null, null, null)); }