private void finalizeTask(CeTask task, Profiler ceProfiler, CeActivityDto.Status status, @Nullable CeTaskResult taskResult, @Nullable Throwable error) { try { queue.remove(task, status, taskResult, error); } catch (Exception e) { if (error != null) { e.addSuppressed(error); } LOG.error(format("Failed to finalize task with uuid '%s' and persist its state to db", task.getUuid()), e); } finally { // finalize stopLogProfiler(ceProfiler, status); callListeners(t -> t.onEnd(task, status, taskResult, error)); } }
@Test public void remove_throws_IAE_if_exception_is_provided_but_status_is_SUCCESS() { expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("Error can be provided only when status is FAILED"); underTest.remove(mock(CeTask.class), CeActivityDto.Status.SUCCESS, null, new RuntimeException("Some error")); }
@Test public void fail_to_remove_if_not_in_queue() { CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); underTest.remove(task, CeActivityDto.Status.SUCCESS, null, null); expectedException.expect(IllegalStateException.class); underTest.remove(task, CeActivityDto.Status.SUCCESS, null, null); }
@Test public void remove_throws_IAE_if_exception_is_provided_but_status_is_CANCELED() { expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("Error can be provided only when status is FAILED"); underTest.remove(mock(CeTask.class), CeActivityDto.Status.CANCELED, null, new RuntimeException("Some error")); }
@Test public void fail_when_no_CeTaskProcessor_is_found_in_repository_without_listener() throws Exception { CeTask task = createCeTask(null); taskProcessorRepository.setNoProcessorForTask(CeTaskTypes.REPORT); when(queue.peek(anyString())).thenReturn(Optional.of(task)); assertThat(underTestNoListener.call()).isEqualTo(TASK_PROCESSED); verifyWorkerUuid(); inOrder.verify(queue).remove(task, CeActivityDto.Status.FAILED, null, null); inOrder.verifyNoMoreInteractions(); }
@Test public void log_error_when_task_was_successful_but_ending_state_can_not_be_persisted_to_db() throws Exception { CeTask ceTask = createCeTask(submitter); when(queue.peek(anyString())).thenReturn(Optional.of(ceTask)); taskProcessorRepository.setProcessorForTask(CeTaskTypes.REPORT, taskProcessor); doThrow(new RuntimeException("Simulate queue#remove failing")).when(queue).remove(ceTask, CeActivityDto.Status.SUCCESS, null, null); underTest.call(); assertThat(logTester.logs(LoggerLevel.ERROR)).containsOnly("Failed to finalize task with uuid '" + ceTask.getUuid() + "' and persist its state to db"); }
@Test public void fail_when_no_CeTaskProcessor_is_found_in_repository() throws Exception { CeTask task = createCeTask(null); taskProcessorRepository.setNoProcessorForTask(CeTaskTypes.REPORT); when(queue.peek(anyString())).thenReturn(Optional.of(task)); assertThat(underTest.call()).isEqualTo(TASK_PROCESSED); verifyWorkerUuid(); inOrder.verify(executionListener1).onStart(task); inOrder.verify(executionListener2).onStart(task); inOrder.verify(queue).remove(task, CeActivityDto.Status.FAILED, null, null); inOrder.verify(executionListener1).onEnd(task, CeActivityDto.Status.FAILED, null, null); inOrder.verify(executionListener2).onEnd(task, CeActivityDto.Status.FAILED, null, null); }
@Test public void peek_and_process_task_without_listeners() throws Exception { CeTask task = createCeTask(null); taskProcessorRepository.setProcessorForTask(task.getType(), taskProcessor); when(queue.peek(anyString())).thenReturn(Optional.of(task)); assertThat(underTestNoListener.call()).isEqualTo(TASK_PROCESSED); verifyWorkerUuid(); inOrder.verify(taskProcessor).process(task); inOrder.verify(queue).remove(task, CeActivityDto.Status.SUCCESS, null, null); inOrder.verifyNoMoreInteractions(); }
@Test public void fail_to_process_task_without_listeners() throws Exception { CeTask task = createCeTask(null); when(queue.peek(anyString())).thenReturn(Optional.of(task)); taskProcessorRepository.setProcessorForTask(task.getType(), taskProcessor); Throwable error = makeTaskProcessorFail(task); assertThat(underTestNoListener.call()).isEqualTo(TASK_PROCESSED); verifyWorkerUuid(); inOrder.verify(taskProcessor).process(task); inOrder.verify(queue).remove(task, CeActivityDto.Status.FAILED, null, error); inOrder.verifyNoMoreInteractions(); }
@Test public void peek_and_process_task() throws Exception { CeTask task = createCeTask(null); taskProcessorRepository.setProcessorForTask(task.getType(), taskProcessor); when(queue.peek(anyString())).thenReturn(Optional.of(task)); assertThat(underTest.call()).isEqualTo(TASK_PROCESSED); verifyWorkerUuid(); inOrder.verify(executionListener1).onStart(task); inOrder.verify(executionListener2).onStart(task); inOrder.verify(taskProcessor).process(task); inOrder.verify(queue).remove(task, CeActivityDto.Status.SUCCESS, null, null); inOrder.verify(executionListener1).onEnd(task, CeActivityDto.Status.SUCCESS, null, null); inOrder.verify(executionListener2).onEnd(task, CeActivityDto.Status.SUCCESS, null, null); }
@Test public void log_error_as_suppressed_when_task_failed_with_MessageException_and_ending_state_can_not_be_persisted_to_db() throws Exception { CeTask ceTask = createCeTask(submitter); when(queue.peek(anyString())).thenReturn(Optional.of(ceTask)); taskProcessorRepository.setProcessorForTask(CeTaskTypes.REPORT, taskProcessor); MessageException ex = makeTaskProcessorFail(ceTask, MessageException.of("simulate MessageException thrown by TaskProcessor#process")); RuntimeException runtimeException = new RuntimeException("Simulate queue#remove failing"); doThrow(runtimeException).when(queue).remove(ceTask, CeActivityDto.Status.FAILED, null, ex); underTest.call(); List<String> logs = logTester.logs(LoggerLevel.INFO); assertThat(logs).hasSize(2); assertThat(logs.get(0)).contains(" | submitter=" + submitter.getLogin()); assertThat(logs.get(1)).contains(String.format(" | submitter=%s | status=FAILED | time=", submitter.getLogin())); List<LogAndArguments> logAndArguments = logTester.getLogs(LoggerLevel.ERROR); assertThat(logAndArguments).hasSize(1); assertThat(logAndArguments.get(0).getFormattedMsg()).isEqualTo("Failed to finalize task with uuid '" + ceTask.getUuid() + "' and persist its state to db"); Object arg1 = logAndArguments.get(0).getArgs().get()[0]; assertThat(arg1).isSameAs(runtimeException); assertThat(((Exception) arg1).getSuppressed()).containsOnly(ex); }
@Test public void fail_to_process_task() throws Exception { CeTask task = createCeTask(null); when(queue.peek(anyString())).thenReturn(Optional.of(task)); taskProcessorRepository.setProcessorForTask(task.getType(), taskProcessor); Throwable error = makeTaskProcessorFail(task); assertThat(underTest.call()).isEqualTo(TASK_PROCESSED); verifyWorkerUuid(); inOrder.verify(executionListener1).onStart(task); inOrder.verify(executionListener2).onStart(task); inOrder.verify(taskProcessor).process(task); inOrder.verify(queue).remove(task, CeActivityDto.Status.FAILED, null, error); inOrder.verify(executionListener1).onEnd(task, CeActivityDto.Status.FAILED, null, error); inOrder.verify(executionListener2).onEnd(task, CeActivityDto.Status.FAILED, null, error); }
@Test public void remove_sets_analysisUuid_in_CeActivity_when_CeTaskResult_has_analysis_uuid() { CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); Optional<CeTask> peek = underTest.peek(WORKER_UUID_2); underTest.remove(peek.get(), CeActivityDto.Status.SUCCESS, newTaskResult(AN_ANALYSIS_UUID), null); // available in history Optional<CeActivityDto> history = db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), task.getUuid()); assertThat(history.isPresent()).isTrue(); assertThat(history.get().getAnalysisUuid()).isEqualTo("U1"); }
@Test public void remove_saves_error_message_and_stacktrace_when_exception_is_provided() { Throwable error = new NullPointerException("Fake NPE to test persistence to DB"); CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); Optional<CeTask> peek = underTest.peek(WORKER_UUID_1); underTest.remove(peek.get(), CeActivityDto.Status.FAILED, null, error); Optional<CeActivityDto> activityDto = db.getDbClient().ceActivityDao().selectByUuid(session, task.getUuid()); assertThat(activityDto).isPresent(); assertThat(activityDto.get().getErrorMessage()).isEqualTo(error.getMessage()); assertThat(activityDto.get().getErrorStacktrace()).isEqualToIgnoringWhitespace(stacktraceToString(error)); assertThat(activityDto.get().getErrorType()).isNull(); }
@Test public void test_remove() { CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); Optional<CeTask> peek = underTest.peek(WORKER_UUID_1); underTest.remove(peek.get(), CeActivityDto.Status.SUCCESS, null, null); // queue is empty assertThat(db.getDbClient().ceQueueDao().selectByUuid(db.getSession(), task.getUuid()).isPresent()).isFalse(); assertThat(underTest.peek(WORKER_UUID_2).isPresent()).isFalse(); // available in history Optional<CeActivityDto> history = db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), task.getUuid()); assertThat(history.isPresent()).isTrue(); assertThat(history.get().getStatus()).isEqualTo(CeActivityDto.Status.SUCCESS); assertThat(history.get().getIsLast()).isTrue(); assertThat(history.get().getAnalysisUuid()).isNull(); }
@Test public void log_error_when_task_failed_and_ending_state_can_not_be_persisted_to_db() throws Exception { CeTask ceTask = createCeTask(submitter); when(queue.peek(anyString())).thenReturn(Optional.of(ceTask)); taskProcessorRepository.setProcessorForTask(CeTaskTypes.REPORT, taskProcessor); IllegalStateException ex = makeTaskProcessorFail(ceTask); RuntimeException runtimeException = new RuntimeException("Simulate queue#remove failing"); doThrow(runtimeException).when(queue).remove(ceTask, CeActivityDto.Status.FAILED, null, ex); underTest.call(); List<String> logs = logTester.logs(LoggerLevel.INFO); assertThat(logs).hasSize(2); assertThat(logs.get(0)).contains(" | submitter=" + submitter.getLogin()); assertThat(logs.get(1)).contains(String.format(" | submitter=%s | status=FAILED | time=", submitter.getLogin())); List<LogAndArguments> logAndArguments = logTester.getLogs(LoggerLevel.ERROR); assertThat(logAndArguments).hasSize(2); LogAndArguments executionErrorLog = logAndArguments.get(0); assertThat(executionErrorLog.getFormattedMsg()).isEqualTo("Failed to execute task " + ceTask.getUuid()); assertThat(executionErrorLog.getArgs().get()).containsOnly(ceTask.getUuid(), ex); LogAndArguments finalizingErrorLog = logAndArguments.get(1); assertThat(finalizingErrorLog.getFormattedMsg()).isEqualTo("Failed to finalize task with uuid '" + ceTask.getUuid() + "' and persist its state to db"); Object arg1 = finalizingErrorLog.getArgs().get()[0]; assertThat(arg1).isSameAs(runtimeException); assertThat(((Exception) arg1).getSuppressed()).containsOnly(ex); }
@Test public void remove_does_not_set_analysisUuid_in_CeActivity_when_CeTaskResult_has_no_analysis_uuid() { CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); Optional<CeTask> peek = underTest.peek(WORKER_UUID_1); underTest.remove(peek.get(), CeActivityDto.Status.SUCCESS, newTaskResult(null), null); // available in history Optional<CeActivityDto> history = db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), task.getUuid()); assertThat(history.isPresent()).isTrue(); assertThat(history.get().getAnalysisUuid()).isNull(); }
@Test public void remove_saves_error_when_TypedMessageException_is_provided() { Throwable error = new TypedExceptionImpl("aType", "aMessage"); CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); Optional<CeTask> peek = underTest.peek(WORKER_UUID_1); underTest.remove(peek.get(), CeActivityDto.Status.FAILED, null, error); CeActivityDto activityDto = db.getDbClient().ceActivityDao().selectByUuid(session, task.getUuid()).get(); assertThat(activityDto.getErrorType()).isEqualTo("aType"); assertThat(activityDto.getErrorMessage()).isEqualTo("aMessage"); assertThat(activityDto.getErrorStacktrace()).isEqualToIgnoringWhitespace(stacktraceToString(error)); }
@Test public void remove_copies_workerUuid() { CeQueueDto ceQueueDto = db.getDbClient().ceQueueDao().insert(session, new CeQueueDto() .setUuid("uuid") .setTaskType("foo") .setStatus(CeQueueDto.Status.PENDING)); makeInProgress(ceQueueDto, "Dustin"); db.commit(); underTest.remove(new CeTask.Builder() .setOrganizationUuid("foo") .setUuid("uuid") .setType("bar") .build(), CeActivityDto.Status.SUCCESS, null, null); CeActivityDto dto = db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), "uuid").get(); assertThat(dto.getWorkerUuid()).isEqualTo("Dustin"); }
private void finalizeTask(CeTask task, Profiler ceProfiler, CeActivityDto.Status status, @Nullable CeTaskResult taskResult, @Nullable Throwable error) { try { queue.remove(task, status, taskResult, error); } catch (Exception e) { String errorMessage = format("Failed to finalize task with uuid '%s' and persist its state to db", task.getUuid()); if (error instanceof MessageException) { LOG.error(format("%s. Task failed with MessageException \"%s\"", errorMessage, error.getMessage()), e); } else { LOG.error(errorMessage, e); } } finally { // finalize stopActivityProfiler(ceProfiler, task, status); callListeners(t -> t.onEnd(task, status, taskResult, error)); } }