private void runScenario(
      ExecutionToken executionToken,
      HandlerManager handlerManager,
      ScenarioToken scenario,
      boolean skip)
      throws Exception {
    executionListenerSupport.notifyScenarioStarted(executionToken, scenario);
    log.info(String.format("Processing scenario: %s", scenario.getName()));

    // reset the ChorusContext for the scenario
    ChorusContext.destroy();

    handlerManager.setCurrentScenario(scenario);
    List<Object> handlerInstances = handlerManager.getOrCreateHandlersForScenario();
    handlerManager.processStartOfScope(Scope.SCENARIO, handlerInstances);

    createTimeoutTasks(
        Thread
            .currentThread()); // will interrupt or eventually kill thread / interpreter if blocked

    log.debug("Running scenario steps for Scenario " + scenario);
    StepInvokerProvider p = getStepInvokers(handlerInstances);
    stepProcessor.runSteps(executionToken, p, scenario.getSteps(), skip);

    stopTimeoutTasks();

    // the special start or end scenarios don't count in the execution stats
    if (!scenario.isStartOrEndScenario()) {
      updateExecutionStats(executionToken, scenario);
    }

    handlerManager.processEndOfScope(Scope.SCENARIO, handlerInstances);
    executionListenerSupport.notifyScenarioCompleted(executionToken, scenario);
  }
  private void runFeature(ExecutionToken executionToken, FeatureToken feature) {

    executionListenerSupport.notifyFeatureStarted(executionToken, feature);
    // notify we started, even if there are missing handlers
    // (but nothing will be done)
    // this is still important so execution listeners at least see the feature (but will show as
    // 'unimplemented')
    String config = feature.isConfiguration() ? " in config " + feature.getConfigurationName() : "";
    log.info("Running feature from file: " + feature.getFeatureFile() + config);

    // check that the required handler classes are all available and list them in order of
    // precedence
    List<Class> orderedHandlerClasses = new ArrayList<>();
    StringBuilder unavailableHandlersMessage =
        handlerClassDiscovery.findHandlerClasses(allHandlerClasses, feature, orderedHandlerClasses);
    boolean foundAllHandlerClasses = unavailableHandlersMessage.length() == 0;

    // run the scenarios in the feature
    if (foundAllHandlerClasses) {
      log.debug("The following handlers will be used " + orderedHandlerClasses);
      List<ScenarioToken> scenarios = feature.getScenarios();

      try {
        HandlerManager handlerManager =
            new HandlerManager(
                feature,
                orderedHandlerClasses,
                springContextSupport,
                subsystemManager,
                executionToken.getProfile());
        handlerManager.createFeatureScopedHandlers();
        handlerManager.processStartOfFeature();

        runScenarios(executionToken, feature, scenarios, handlerManager);

        handlerManager.processEndOfFeature();
      } catch (Exception e) {
        log.error("Exception while running feature " + feature.getName(), e);
      }

      String description =
          feature.getEndState() == EndState.PASSED
              ? " passed! "
              : feature.getEndState() == EndState.PENDING ? " pending! " : " failed! ";
      log.trace("The feature " + description);

      if (feature.getEndState() == EndState.PASSED) {
        executionToken.incrementFeaturesPassed();
      } else if (feature.getEndState() == EndState.PENDING) {
        executionToken.incrementFeaturesPending();
      } else {
        executionToken.incrementFeaturesFailed();
      }
    } else {
      log.warn(
          "The following handlers were not available, failing feature "
              + feature.getName()
              + " "
              + unavailableHandlersMessage);
      feature.setUnavailableHandlersMessage(unavailableHandlersMessage.toString());
      executionToken.incrementUnavailableHandlers();
      executionToken.incrementFeaturesFailed();
    }

    executionListenerSupport.notifyFeatureCompleted(executionToken, feature);
  }