/**
   * Tests executing of {@link Component#handleVerificationToken(String)}: verification token passed
   * properly and life cycle method call handled properly.
   *
   * @throws ComponentExecutionException on unexpected error
   * @throws ComponentException on unexpected error
   * @throws InterruptedException on unexpected error
   * @throws ExecutionException on unexpected error
   */
  @Test(timeout = TEST_TIMEOUT_500_MSEC)
  public void testHandleVerificationToken()
      throws ComponentExecutionException, ComponentException, InterruptedException,
          ExecutionException {

    final String someToken = "some-token";

    ComponentExecutionRelatedInstances compExeRelatedInstancesStub =
        createComponentExecutionRelatedInstancesStub(true);

    Component compMock = EasyMock.createStrictMock(Component.class);
    compMock.handleVerificationToken(someToken);
    EasyMock.expectLastCall();
    EasyMock.replay(compMock);
    compExeRelatedInstancesStub.component.set(compMock);

    ComponentExecutionType compExeType = ComponentExecutionType.HandleVerificationToken;
    compExeType.setVerificationToken(someToken);
    ComponentExecutor compExecutor =
        new ComponentExecutor(compExeRelatedInstancesStub, compExeType);
    compExecutor.bindComponentExecutionPermitsService(createComponentExecutionPermitServiceMock());

    compExecutor.executeByConsideringLimitations();

    assertFalse(compExeRelatedInstancesStub.compExeRelatedStates.isComponentCancelled.get());
    EasyMock.verify(compMock);
  }
  /**
   * Tests executing of {@link Component#processInputs()} in success case.
   *
   * @throws ComponentExecutionException on unexpected error
   * @throws ComponentException on unexpected error
   * @throws InterruptedException on unexpected error
   * @throws ExecutionException on unexpected error
   */
  @Test(timeout = TEST_TIMEOUT_500_MSEC)
  public void testProcessingInputsSuccess()
      throws ComponentExecutionException, ComponentException, InterruptedException,
          ExecutionException {

    ComponentExecutionRelatedInstances compExeRelatedInstancesStub =
        createComponentExecutionRelatedInstancesStub();

    Component compMock = EasyMock.createStrictMock(Component.class);
    compMock.processInputs();
    EasyMock.expectLastCall();
    EasyMock.replay(compMock);
    compExeRelatedInstancesStub.component.set(compMock);

    Capture<ComponentStateMachineEvent> compStateMachineEventCapture = new Capture<>();
    ComponentStateMachine compStateMachineMock =
        createComponentStateMachineEventForRuns(compStateMachineEventCapture);
    compExeRelatedInstancesStub.compStateMachine = compStateMachineMock;

    ComponentExecutionStorageBridge compExeStorageBridgeMock =
        createComponentExecutionStorageBridgeRunSuccess(compExeRelatedInstancesStub);
    compExeRelatedInstancesStub.compExeStorageBridge = compExeStorageBridgeMock;

    ComponentContextBridge compCtxBridgeMock =
        EasyMock.createStrictMock(ComponentContextBridge.class);
    EasyMock.expect(compCtxBridgeMock.getEndpointDatumsForExecution())
        .andStubReturn(new HashMap<String, EndpointDatum>());
    EasyMock.replay(compCtxBridgeMock);
    compExeRelatedInstancesStub.compCtxBridge = compCtxBridgeMock;

    compExeRelatedInstancesStub.compExeScheduler = createComponentExecutionSchedulerMock(false);

    ConsoleRowsSender consoleRowsSenderMock = createConsoleRowsSenderMock(null, null);
    compExeRelatedInstancesStub.consoleRowsSender = consoleRowsSenderMock;

    ComponentExecutionStatsService compExeStatsServiceMock =
        createComponentExecutionStatsServiceMock(compExeRelatedInstancesStub);

    ComponentExecutor compExecutor =
        new ComponentExecutor(compExeRelatedInstancesStub, ComponentExecutionType.ProcessInputs);
    compExecutor.bindComponentExecutionPermitsService(createComponentExecutionPermitServiceMock());
    compExecutor.bindComponentExecutionStatsService(compExeStatsServiceMock);

    compExecutor.executeByConsideringLimitations();

    assertFalse(compExeRelatedInstancesStub.compExeRelatedStates.isComponentCancelled.get());
    EasyMock.verify(compMock);
    EasyMock.verify(compStateMachineMock);
    assertEquals(
        ComponentStateMachineEventType.RUNNING, compStateMachineEventCapture.getValue().getType());
    assertEquals(
        ComponentState.PROCESSING_INPUTS,
        compStateMachineEventCapture.getValue().getNewComponentState());
    EasyMock.verify(compExeStorageBridgeMock);
    EasyMock.verify(consoleRowsSenderMock);
  }
  /**
   * Tests tearing down component in success case.
   *
   * @throws ComponentException on unexpected error
   * @throws ComponentExecutionException on unexpected error
   */
  @Test
  public void testTearDownFailure() throws ComponentException, ComponentExecutionException {

    ComponentExecutionRelatedInstances compExeRelatedInstancesStub =
        createComponentExecutionRelatedInstancesStub();

    String errorMessage = "some error in tear down";
    Component.FinalComponentState finalCompState = Component.FinalComponentState.FINISHED;
    Component compMock = EasyMock.createStrictMock(Component.class);
    compMock.tearDown(finalCompState);
    EasyMock.expectLastCall().andThrow(new RuntimeException(errorMessage));
    EasyMock.replay(compMock);
    compExeRelatedInstancesStub.component.set(compMock);

    ComponentExecutionStorageBridge compExeStorageBridgeMock =
        createComponentExecutionStorageBridgeNonRunFailure(
            compExeRelatedInstancesStub, DataModelConstants.TEAR_DOWN_RUN);
    compExeRelatedInstancesStub.compExeStorageBridge = compExeStorageBridgeMock;

    compExeRelatedInstancesStub.compExeScheduler = createComponentExecutionSchedulerMock(false);

    Capture<ConsoleRow.Type> consoleRowTypeCapture = new Capture<>();
    Capture<String> logMessageCapture = new Capture<>();
    ConsoleRowsSender consoleRowsSenderMock =
        createConsoleRowsSenderMock(consoleRowTypeCapture, logMessageCapture);
    compExeRelatedInstancesStub.consoleRowsSender = consoleRowsSenderMock;

    ComponentExecutionType compExeType = ComponentExecutionType.TearDown;
    compExeType.setFinalComponentStateAfterTearedDown(finalCompState);
    ComponentExecutor compExecutor =
        new ComponentExecutor(compExeRelatedInstancesStub, ComponentExecutionType.TearDown);

    try {
      compExecutor.executeByConsideringLimitations();
      fail("ComponentException expected");
    } catch (ComponentException e) {
      assertFailureHandling(consoleRowTypeCapture, logMessageCapture, e, errorMessage);
    }

    EasyMock.verify(compMock);
    EasyMock.verify(compExeStorageBridgeMock);
    EasyMock.verify(consoleRowsSenderMock);
  }
  /**
   * Tests tearing down component in success case.
   *
   * @throws ComponentException on unexpected error
   * @throws ComponentExecutionException on unexpected error
   */
  @Test
  public void testTearDownSuccess() throws ComponentException, ComponentExecutionException {

    Component.FinalComponentState finalCompState = Component.FinalComponentState.FINISHED;
    Component compMock = EasyMock.createStrictMock(Component.class);
    compMock.tearDown(finalCompState);
    EasyMock.expectLastCall();
    EasyMock.replay(compMock);

    ComponentExecutionRelatedInstances compExeRelatedInstancesStub =
        createComponentExecutionRelatedInstancesStub();
    compExeRelatedInstancesStub.component.set(compMock);

    ComponentExecutionType compExeType = ComponentExecutionType.TearDown;
    compExeType.setFinalComponentStateAfterTearedDown(finalCompState);
    ComponentExecutor compExecutor =
        new ComponentExecutor(compExeRelatedInstancesStub, ComponentExecutionType.TearDown);
    compExecutor.executeByConsideringLimitations();

    EasyMock.verify(compMock);
  }
  /**
   * Tests executing of {@link Component#completeStartOrProcessInputsAfterVerificationDone()} in
   * case results are rejected.
   *
   * @throws ComponentExecutionException on unexpected error
   * @throws ComponentException on unexpected error
   * @throws InterruptedException on unexpected error
   * @throws ExecutionException on unexpected error
   */
  @Test(timeout = TEST_TIMEOUT_500_MSEC)
  public void testCompleteVerificationResultsRejected()
      throws ComponentExecutionException, ComponentException, InterruptedException,
          ExecutionException {

    ComponentExecutionRelatedInstances compExeRelatedInstancesStub =
        createComponentExecutionRelatedInstancesStub(true);

    Component compMock = EasyMock.createStrictMock(Component.class);
    compMock.completeStartOrProcessInputsAfterVerificationDone();
    EasyMock.expectLastCall();
    EasyMock.replay(compMock);
    compExeRelatedInstancesStub.component.set(compMock);

    ComponentExecutionStorageBridge compExeStorageBridgeMock =
        EasyMock.createStrictMock(ComponentExecutionStorageBridge.class);
    compExeStorageBridgeMock.setComponentExecutionFinished(FinalComponentRunState.RESULTS_REJECTED);
    EasyMock.expectLastCall();
    EasyMock.replay(compExeStorageBridgeMock);
    compExeRelatedInstancesStub.compExeStorageBridge = compExeStorageBridgeMock;

    compExeRelatedInstancesStub.compExeScheduler = createComponentExecutionSchedulerMock(false);

    ConsoleRowsSender consoleRowsSenderMock = createConsoleRowsSenderMock(null, null);
    compExeRelatedInstancesStub.consoleRowsSender = consoleRowsSenderMock;

    ComponentExecutionType compExeType = ComponentExecutionType.CompleteVerification;
    compExeType.setFinalComponentStateAfterRun(FinalComponentRunState.RESULTS_REJECTED);
    ComponentExecutor compExecutor =
        new ComponentExecutor(compExeRelatedInstancesStub, compExeType);
    compExecutor.bindComponentExecutionPermitsService(createComponentExecutionPermitServiceMock());

    compExecutor.executeByConsideringLimitations();

    assertFalse(compExeRelatedInstancesStub.compExeRelatedStates.isComponentCancelled.get());
    EasyMock.verify(compMock);
    EasyMock.verify(compExeStorageBridgeMock);
    EasyMock.verify(consoleRowsSenderMock);
  }
  /**
   * Tests if the execution of the {@link Component}'s start method has no timeout.
   *
   * @throws ComponentExecutionException on unexpected error
   * @throws ComponentException on unexpected error
   */
  @Test(timeout = TEST_TIMEOUT_500_MSEC)
  public void testSartAsInitHasNoTimeout() throws ComponentExecutionException, ComponentException {
    final ComponentExecutionRelatedInstances compExeRelatedInstancesStub =
        createComponentExecutionRelatedInstancesStub();

    Component compMock = EasyMock.createStrictMock(Component.class);
    compMock.start();
    final int startMethodTimeMSec = 200;
    EasyMock.expectLastCall()
        .andAnswer(
            new IAnswer<Void>() {

              @Override
              public Void answer() throws Throwable {
                try {
                  Thread.sleep(startMethodTimeMSec);
                } catch (InterruptedException e) {
                  throw new ComponentException("Unexpected error", e);
                }
                return null;
              }
            });
    EasyMock.replay(compMock);
    compExeRelatedInstancesStub.component.set(compMock);

    Capture<ComponentStateMachineEvent> compStateMachineEventCapture = new Capture<>();
    ComponentStateMachine compStateMachineMock =
        createComponentStateMachineEventForRuns(compStateMachineEventCapture);
    compExeRelatedInstancesStub.compStateMachine = compStateMachineMock;

    ComponentExecutor compExecutor =
        new ComponentExecutor(compExeRelatedInstancesStub, ComponentExecutionType.StartAsInit);

    ComponentExecutor.waitIntervalAfterCacelledCalledMSec = WAIT_INTERVAL_100_MSEC;
    ComponentExecutor.waitIntervalNotRunMSec = WAIT_INTERVAL_100_MSEC;
    compExecutor.executeByConsideringLimitations();

    assertFalse(compExeRelatedInstancesStub.compExeRelatedStates.isComponentCancelled.get());
  }
  private void testProcessInputsFailure(Exception expectedException)
      throws ComponentExecutionException, ComponentException, InterruptedException,
          ExecutionException {
    ComponentExecutionRelatedInstances compExeRelatedInstancesStub =
        createComponentExecutionRelatedInstancesStub();

    Component compMock = EasyMock.createStrictMock(Component.class);
    compMock.processInputs();
    EasyMock.expectLastCall().andThrow(expectedException);
    compMock.completeStartOrProcessInputsAfterFailure();
    EasyMock.expectLastCall();
    EasyMock.replay(compMock);
    compExeRelatedInstancesStub.component.set(compMock);

    Capture<ComponentStateMachineEvent> compStateMachineEventCapture = new Capture<>();
    ComponentStateMachine compStateMachineMock =
        createComponentStateMachineEventForRuns(compStateMachineEventCapture);
    compExeRelatedInstancesStub.compStateMachine = compStateMachineMock;

    ComponentExecutionStorageBridge compExeStorageBridgeMock =
        createComponentExecutionStorageBridgeRunFailure(compExeRelatedInstancesStub);
    compExeRelatedInstancesStub.compExeStorageBridge = compExeStorageBridgeMock;

    ComponentContextBridge compCtxBridgeMock =
        EasyMock.createStrictMock(ComponentContextBridge.class);
    EasyMock.expect(compCtxBridgeMock.getEndpointDatumsForExecution())
        .andStubReturn(new HashMap<String, EndpointDatum>());
    EasyMock.replay(compCtxBridgeMock);
    compExeRelatedInstancesStub.compCtxBridge = compCtxBridgeMock;

    compExeRelatedInstancesStub.compExeScheduler = createComponentExecutionSchedulerMock(false);

    Capture<ConsoleRow.Type> consoleRowTypeCapture = new Capture<>();
    Capture<String> logMessageCapture = new Capture<>();
    ConsoleRowsSender consoleRowsSenderMock =
        createConsoleRowsSenderMock(consoleRowTypeCapture, logMessageCapture);
    compExeRelatedInstancesStub.consoleRowsSender = consoleRowsSenderMock;

    ComponentExecutionStatsService compExeStatsServiceMock =
        createComponentExecutionStatsServiceMock(compExeRelatedInstancesStub);

    ComponentExecutor compExecutor =
        new ComponentExecutor(compExeRelatedInstancesStub, ComponentExecutionType.ProcessInputs);
    compExecutor.bindComponentExecutionPermitsService(createComponentExecutionPermitServiceMock());
    compExecutor.bindComponentExecutionStatsService(compExeStatsServiceMock);

    try {
      compExecutor.executeByConsideringLimitations();
      fail("ComponentException expected");
    } catch (ComponentException e) {
      if (expectedException.getMessage() == null) {
        assertFailureHandling(consoleRowTypeCapture, logMessageCapture, e, "Unexpected error");
      } else {
        assertFailureHandling(
            consoleRowTypeCapture, logMessageCapture, e, expectedException.getMessage());
      }
    }

    assertFalse(compExeRelatedInstancesStub.compExeRelatedStates.isComponentCancelled.get());
    EasyMock.verify(compMock);
    EasyMock.verify(compStateMachineMock);
    assertEquals(
        ComponentStateMachineEventType.RUNNING, compStateMachineEventCapture.getValue().getType());
    assertEquals(
        ComponentState.PROCESSING_INPUTS,
        compStateMachineEventCapture.getValue().getNewComponentState());
    EasyMock.verify(compExeStorageBridgeMock);
    EasyMock.verify(consoleRowsSenderMock);
  }