RepairRunResource { @PUT @Path("/{id}/state/{state}") public Response modifyRunState( @Context UriInfo uriInfo, @PathParam("id") UUID repairRunId, @PathParam("state") Optional<String> stateStr) throws ReaperException { LOG.info("modify repair run state called with: id = {}, state = {}", repairRunId, stateStr); try { if (!stateStr.isPresent()) { return createMissingArgumentResponse("state"); } Optional<RepairRun> repairRun = context.storage.getRepairRun(repairRunId); if (!repairRun.isPresent()) { return Response.status(Status.NOT_FOUND).entity("repair run " + repairRunId + " doesn't exist").build(); } final RepairRun.RunState newState = parseRunState(stateStr.get()); final RunState oldState = repairRun.get().getRunState(); if (oldState == newState) { String msg = "given \"state\" " + stateStr + " is same as the current run state"; return Response.noContent().entity(msg).location(buildRepairRunUri(uriInfo, repairRun.get())).build(); } if ((isStarting(oldState, newState) || isResuming(oldState, newState) || isRetrying(oldState, newState)) && isUnitAlreadyRepairing(repairRun.get())) { String errMsg = "repair unit already has run " + repairRun.get().getRepairUnitId() + " in RUNNING state"; LOG.error(errMsg); return Response.status(Status.CONFLICT).entity(errMsg).build(); } if (isStarting(oldState, newState)) { return startRun(uriInfo, repairRun.get()); } else if (isPausing(oldState, newState)) { return pauseRun(uriInfo, repairRun.get()); } else if (isResuming(oldState, newState) || isRetrying(oldState, newState)) { return resumeRun(uriInfo, repairRun.get()); } else if (isAborting(oldState, newState)) { return abortRun(uriInfo, repairRun.get()); } else { String errMsg = String.format("Transition %s->%s not supported.", oldState.toString(), newState.toString()); LOG.error(errMsg); return Response.status(Status.CONFLICT).entity(errMsg).build(); } } catch (ValidationException ex) { return Response.status(Status.BAD_REQUEST).entity(ex.getMessage()).build(); } } RepairRunResource(AppContext context); @POST Response addRepairRun(
      @Context UriInfo uriInfo,
      @QueryParam("clusterName") Optional<String> clusterName,
      @QueryParam("keyspace") Optional<String> keyspace,
      @QueryParam("tables") Optional<String> tableNamesParam,
      @QueryParam("owner") Optional<String> owner,
      @QueryParam("cause") Optional<String> cause,
      @QueryParam("segmentCount") Optional<Integer> segmentCountPerNode,
      @QueryParam("repairParallelism") Optional<String> repairParallelism,
      @QueryParam("intensity") Optional<String> intensityStr,
      @QueryParam("incrementalRepair") Optional<String> incrementalRepairStr,
      @QueryParam("nodes") Optional<String> nodesToRepairParam,
      @QueryParam("datacenters") Optional<String> datacentersToRepairParam,
      @QueryParam("blacklistedTables") Optional<String> blacklistedTableNamesParam,
      @QueryParam("repairThreadCount") Optional<Integer> repairThreadCountParam); @PUT @Path("/{id}/state/{state}") Response modifyRunState(
      @Context UriInfo uriInfo,
      @PathParam("id") UUID repairRunId,
      @PathParam("state") Optional<String> stateStr); @PUT @Path("/{id}/intensity/{intensity}") Response modifyRunIntensity(
      @Context UriInfo uriInfo,
      @PathParam("id") UUID repairRunId,
      @PathParam("intensity") Optional<String> intensityStr); @PUT @Path("/{id}") @Deprecated Response oldModifyRunState(
      @Context UriInfo uriInfo,
      @PathParam("id") UUID repairRunId,
      @QueryParam("state") Optional<String> stateStr); @GET @Path("/{id}") Response getRepairRun(
      @PathParam("id") UUID repairRunId); @GET @Path("/{id}/segments") Response getRepairRunSegments(@PathParam("id") UUID repairRunId); @POST @Path("/{id}/segments/abort/{segment_id}") Response abortRepairRunSegment(@PathParam("id") UUID repairRunId, @PathParam("segment_id") UUID segmentId); @GET @Path("/cluster/{cluster_name}") Response getRepairRunsForCluster(
      @PathParam("cluster_name") String clusterName,
      @QueryParam("limit") Optional<Integer> limit); @GET Response listRepairRuns(
      @QueryParam("state") Optional<String> state,
      @QueryParam("cluster_name") Optional<String> cluster,
      @QueryParam("keyspace_name") Optional<String> keyspace,
      @QueryParam("limit") Optional<Integer> limit); @DELETE @Path("/{id}") Response deleteRepairRun(
      @PathParam("id") UUID runId,
      @QueryParam("owner") Optional<String> owner); @POST @Path("/purge") Response purgeRepairRuns();  }
@Test public void testTriggerAlreadyRunningRun() throws InterruptedException, ReaperException { DateTimeUtils.setCurrentMillisFixed(TIME_CREATE); RepairRunResource resource = new RepairRunResource(context); Response response = addDefaultRepairRun(resource); assertTrue(response.getEntity().toString(), response.getEntity() instanceof RepairRunStatus); RepairRunStatus repairRunStatus = (RepairRunStatus) response.getEntity(); UUID runId = repairRunStatus.getId(); DateTimeUtils.setCurrentMillisFixed(TIME_START); Optional<String> newState = Optional.of(RepairRun.RunState.RUNNING.toString()); resource.modifyRunState(uriInfo, runId, newState); Thread.sleep(1000); response = resource.modifyRunState(uriInfo, runId, newState); assertEquals(Response.Status.NO_CONTENT.getStatusCode(), response.getStatus()); }
@Test public void testTriggerNewRunAlreadyRunningRun() throws InterruptedException, ReaperException { DateTimeUtils.setCurrentMillisFixed(TIME_CREATE); RepairRunResource resource = new RepairRunResource(context); Response response = addDefaultRepairRun(resource); assertTrue(response.getEntity().toString(), response.getEntity() instanceof RepairRunStatus); RepairRunStatus repairRunStatus = (RepairRunStatus) response.getEntity(); UUID runId = repairRunStatus.getId(); DateTimeUtils.setCurrentMillisFixed(TIME_START); Optional<String> newState = Optional.of(RepairRun.RunState.RUNNING.toString()); resource.modifyRunState(uriInfo, runId, newState); Thread.sleep(1000); response = resource.modifyRunState(uriInfo, runId, newState); assertEquals(Response.Status.NO_CONTENT.getStatusCode(), response.getStatus()); RepairRunResource newResource = new RepairRunResource(context); Response newResponse = addDefaultRepairRun(newResource); RepairRunStatus newRepairRunStatus = (RepairRunStatus) newResponse.getEntity(); UUID newRunId = newRepairRunStatus.getId(); DateTimeUtils.setCurrentMillisFixed(TIME_START); Optional<String> newRunState = Optional.of(RepairRun.RunState.RUNNING.toString()); response = resource.modifyRunState(uriInfo, newRunId, newRunState); assertEquals(Response.Status.CONFLICT.getStatusCode(), response.getStatus()); }
@Test public void testPauseNotExistingRun() throws InterruptedException, ReaperException { RepairRunResource resource = new RepairRunResource(context); Response response = resource.modifyRunState(uriInfo, UUIDs.timeBased(), Optional.of(RepairRun.RunState.PAUSED.toString())); assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatus()); assertEquals(0, context.storage.getRepairRunsWithState(RepairRun.RunState.RUNNING).size()); }
@Test public void testTriggerNotExistingRun() throws ReaperException { RepairRunResource resource = new RepairRunResource(context); Optional<String> newState = Optional.of(RepairRun.RunState.RUNNING.toString()); Response response = resource.modifyRunState(uriInfo, UUIDs.timeBased(), newState); assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatus()); assertTrue(response.getEntity() instanceof String); assertTrue(response.getEntity().toString().contains("doesn't exist")); }