@Test
  public void testExclusiveRequests() throws Exception {
    Clusters fsm = mock(Clusters.class);
    Cluster oneClusterMock = mock(Cluster.class);
    Service serviceObj = mock(Service.class);
    ServiceComponent scomp = mock(ServiceComponent.class);
    ServiceComponentHost sch = mock(ServiceComponentHost.class);
    UnitOfWork unitOfWork = mock(UnitOfWork.class);
    AgentCommandsPublisher agentCommandsPublisher = mock(AgentCommandsPublisher.class);
    when(fsm.getCluster(anyString())).thenReturn(oneClusterMock);
    when(oneClusterMock.getService(anyString())).thenReturn(serviceObj);
    when(serviceObj.getServiceComponent(anyString())).thenReturn(scomp);
    when(scomp.getServiceComponentHost(anyString())).thenReturn(sch);
    when(serviceObj.getCluster()).thenReturn(oneClusterMock);

    HashMap<String, ServiceComponentHost> hosts =
      new HashMap<>();
    String hostname1 = "hostname1";
    String hostname2 = "hostname2";
    String hostname3 = "hostname3";

    hosts.put(hostname1, sch);
    hosts.put(hostname2, sch);
    hosts.put(hostname3, sch);
    when(scomp.getServiceComponentHosts()).thenReturn(hosts);

    long requestId1 = 1;
    long requestId2 = 2;
    long requestId3 = 3;

    final List<Stage> firstStageInProgressByRequest = new ArrayList<>();
    final List<Stage> stagesInProgress = new ArrayList<>();
    int namenodeCmdTaskId = 1;

    Stage request1Stage1 = getStageWithSingleTask(hostname1, "cluster1", Role.NAMENODE,
        RoleCommand.START,
        Service.Type.HDFS, namenodeCmdTaskId, 1, (int) requestId1);

    Stage request1Stage2 = getStageWithSingleTask(hostname1, "cluster1", Role.DATANODE,
        RoleCommand.START,
        Service.Type.HDFS, 2, 2, (int) requestId1);

    Stage request2Stage1 = getStageWithSingleTask(hostname2, "cluster1", Role.DATANODE,
        RoleCommand.STOP, // Exclusive
        Service.Type.HDFS, 3, 3, (int) requestId2);

    Stage request3Stage1 = getStageWithSingleTask(hostname3, "cluster1", Role.DATANODE,
        RoleCommand.START,
        Service.Type.HDFS, 4, 4, (int) requestId3);

    firstStageInProgressByRequest.add(request1Stage1);
    firstStageInProgressByRequest.add(request2Stage1);
    firstStageInProgressByRequest.add(request3Stage1);

    stagesInProgress.add(request1Stage1);
    stagesInProgress.add(request1Stage2);
    stagesInProgress.add(request2Stage1);
    stagesInProgress.add(request3Stage1);

    Host host1 = mock(Host.class);
    when(fsm.getHost(anyString())).thenReturn(host1);
    when(host1.getState()).thenReturn(HostState.HEALTHY);
    when(host1.getHostName()).thenReturn(hostname);

    Host host2 = mock(Host.class);
    when(fsm.getHost(anyString())).thenReturn(host2);
    when(host2.getState()).thenReturn(HostState.HEALTHY);
    when(host2.getHostName()).thenReturn(hostname);

    Host host3 = mock(Host.class);
    when(fsm.getHost(anyString())).thenReturn(host3);
    when(host3.getState()).thenReturn(HostState.HEALTHY);
    when(host3.getHostName()).thenReturn(hostname);

    ActionDBAccessor db = mock(ActionDBAccessor.class);
    HostRoleCommandDAO hostRoleCommandDAOMock = mock(HostRoleCommandDAO.class);
    Mockito.doNothing().when(hostRoleCommandDAOMock).publishTaskCreateEvent(anyListOf(HostRoleCommand.class));
    when(db.getCommandsInProgressCount()).thenReturn(stagesInProgress.size());
    when(db.getFirstStageInProgressPerRequest()).thenReturn(firstStageInProgressByRequest);

    List<HostRoleCommand> requestTasks = new ArrayList<>();
    for (Stage stage : stagesInProgress) {
      requestTasks.addAll(stage.getOrderedHostRoleCommands());
    }
    when(db.getRequestTasks(anyLong())).thenReturn(requestTasks);
    when(db.getAllStages(anyLong())).thenReturn(stagesInProgress);
    doAnswer(new Answer<Void>() {
      @Override
      public Void answer(InvocationOnMock invocation) throws Throwable {
        List<CommandReport> reports = (List<CommandReport>) invocation.getArguments()[0];
        for (CommandReport report : reports) {
          String actionId = report.getActionId();
          long[] requestStageIds = StageUtils.getRequestStage(actionId);
          Long requestId = requestStageIds[0];
          Long stageId = requestStageIds[1];
          Long id = report.getTaskId();
          for (Stage stage : stagesInProgress) {
            if (requestId.equals(stage.getRequestId()) && stageId.equals(stage.getStageId())) {
              for (HostRoleCommand hostRoleCommand : stage.getOrderedHostRoleCommands()) {
                if (hostRoleCommand.getTaskId() == id) {
                  hostRoleCommand.setStatus(HostRoleStatus.valueOf(report.getStatus()));
                }
              }
            }
          }

        }

        return null;
      }
    }).when(db).updateHostRoleStates(anyCollectionOf(CommandReport.class));

    when(db.getTask(anyLong())).thenAnswer(new Answer<Object>() {
      @Override
      public Object answer(InvocationOnMock invocation) throws Throwable {
        Long taskId = (Long) invocation.getArguments()[0];
        for (Stage stage : stagesInProgress) {
          for (HostRoleCommand command : stage.getOrderedHostRoleCommands()) {
            if (taskId.equals(command.getTaskId())) {
              return command;
            }
          }
        }
        return null;
      }
    });

    final Map<Long, Boolean> startedRequests = new HashMap<>();
    doAnswer(new Answer<Void>() {
      @Override
      public Void answer(InvocationOnMock invocation) throws Throwable {
        startedRequests.put((Long)invocation.getArguments()[0], true);
        return null;
      }
    }).when(db).startRequest(anyLong());

    RequestEntity request1 = mock(RequestEntity.class);
    when(request1.isExclusive()).thenReturn(false);
    when(request1.getClusterHostInfo()).thenReturn(CLUSTER_HOST_INFO);
    RequestEntity request2 = mock(RequestEntity.class);
    when(request2.isExclusive()).thenReturn(true);
    when(request2.getClusterHostInfo()).thenReturn(CLUSTER_HOST_INFO);
    RequestEntity request3 = mock(RequestEntity.class);
    when(request3.isExclusive()).thenReturn(false);
    when(request3.getClusterHostInfo()).thenReturn(CLUSTER_HOST_INFO);

    when(db.getRequestEntity(requestId1)).thenReturn(request1);
    when(db.getRequestEntity(requestId2)).thenReturn(request2);
    when(db.getRequestEntity(requestId3)).thenReturn(request3);

    Properties properties = new Properties();
    Configuration conf = new Configuration(properties);

    ActionScheduler scheduler = spy(new ActionScheduler(100, 50, db, fsm, 3,
        new HostsMap((String) null), unitOfWork, null, conf, entityManagerProviderMock,
        hostRoleCommandDAOMock, (HostRoleCommandFactory)null, agentCommandsPublisher));

    doReturn(false).when(scheduler).wasAgentRestartedDuringOperation(any(Host.class), any(Stage.class), anyString());

    // Execution of request 1

    scheduler.doWork();

    Assert.assertTrue(startedRequests.containsKey(requestId1));
    Assert.assertFalse(startedRequests.containsKey(requestId2));
    Assert.assertFalse(startedRequests.containsKey(requestId3));

    stagesInProgress.remove(0);
    firstStageInProgressByRequest.clear();
    firstStageInProgressByRequest.add(request1Stage2);
    firstStageInProgressByRequest.add(request2Stage1);
    firstStageInProgressByRequest.add(request3Stage1);

    scheduler.doWork();

    Assert.assertTrue(startedRequests.containsKey(requestId1));
    Assert.assertFalse(startedRequests.containsKey(requestId2));
    Assert.assertFalse(startedRequests.containsKey(requestId3));

    // Execution of request 2

    stagesInProgress.remove(0);
    firstStageInProgressByRequest.clear();
    firstStageInProgressByRequest.add(request2Stage1);
    firstStageInProgressByRequest.add(request3Stage1);

    scheduler.doWork();

    Assert.assertTrue(startedRequests.containsKey(requestId1));
    Assert.assertTrue(startedRequests.containsKey(requestId2));
    Assert.assertFalse(startedRequests.containsKey(requestId3));

    // Execution of request 3

    stagesInProgress.remove(0);
    firstStageInProgressByRequest.clear();
    firstStageInProgressByRequest.add(request3Stage1);

    scheduler.doWork();

    Assert.assertTrue(startedRequests.containsKey(requestId1));
    Assert.assertTrue(startedRequests.containsKey(requestId2));
    Assert.assertTrue(startedRequests.containsKey(requestId3));

  }
Checks what happens when stage has an execution command for
host component that has been recently deleted
@throws Exception
ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionScheduler.java