@Test
  public void testRestoreInstances_nonNullNonMatchingHandler() throws Exception {

    // Prepare stuff
    INotificationMngr notificationMngr = Mockito.mock(INotificationMngr.class);
    IRandomMngr randomMngr = Mockito.mock(IRandomMngr.class);
    IMessagingMngr messagingMngr = Mockito.mock(IMessagingMngr.class);
    ITargetConfigurator targetConfigurator = Mockito.mock(ITargetConfigurator.class);

    ITargetsMngr targetsMngr = Mockito.mock(ITargetsMngr.class);
    Mockito.when(
            targetsMngr.findRawTargetProperties(
                Mockito.any(Application.class), Mockito.anyString()))
        .thenReturn(new HashMap<String, String>(0));

    IConfigurationMngr configurationMngr = new ConfigurationMngrImpl();
    configurationMngr.setWorkingDirectory(this.folder.newFolder());

    final TargetHandler targetHandlerArgument = Mockito.mock(TargetHandler.class);
    Mockito.when(targetHandlerArgument.getTargetId()).thenReturn("some target id");

    final TargetHandler targetHandler = Mockito.mock(TargetHandler.class);
    Mockito.when(targetHandler.getTargetId()).thenReturn("some other target id");

    IInstancesMngr mngr =
        new InstancesMngrImpl(
            messagingMngr, notificationMngr, targetsMngr, randomMngr, targetConfigurator);
    ((InstancesMngrImpl) mngr)
        .setTargetHandlerResolver(
            new TestTargetResolver() {
              @Override
              public TargetHandler findTargetHandler(Map<String, String> targetProperties)
                  throws TargetException {
                return targetHandler;
              }
            });

    TestApplication app = new TestApplication();
    ManagedApplication ma = new ManagedApplication(app);

    // One scoped instance has a machine ID (considered as running somewhere)
    app.getMySqlVm().data.put(Instance.MACHINE_ID, "machine-id");

    // Try to restore instances
    mngr.restoreInstanceStates(ma, targetHandlerArgument);

    // The handler's ID did not match => no restoration and no use of other mocks
    Mockito.verify(targetsMngr, Mockito.only())
        .findRawTargetProperties(Mockito.eq(app), Mockito.anyString());
    Mockito.verify(targetHandler, Mockito.only()).getTargetId();
    Mockito.verify(targetHandlerArgument, Mockito.only()).getTargetId();

    Mockito.verifyZeroInteractions(messagingMngr);
    Mockito.verifyZeroInteractions(randomMngr);

    // No notification was sent since there was no change on Tomcat instances
    Mockito.verifyZeroInteractions(notificationMngr);
    Mockito.verifyZeroInteractions(targetConfigurator);
  }
  @Test
  public void testRestoreInstances_rightHandler_vmNotRunning() throws Exception {

    // Prepare stuff
    Map<String, String> targetProperties = new HashMap<>(0);

    INotificationMngr notificationMngr = Mockito.mock(INotificationMngr.class);
    IRandomMngr randomMngr = Mockito.mock(IRandomMngr.class);
    IMessagingMngr messagingMngr = Mockito.mock(IMessagingMngr.class);
    ITargetConfigurator targetConfigurator = Mockito.mock(ITargetConfigurator.class);

    ITargetsMngr targetsMngr = Mockito.mock(ITargetsMngr.class);
    Mockito.when(
            targetsMngr.findRawTargetProperties(
                Mockito.any(Application.class), Mockito.anyString()))
        .thenReturn(targetProperties);

    IConfigurationMngr configurationMngr = new ConfigurationMngrImpl();
    configurationMngr.setWorkingDirectory(this.folder.newFolder());

    final TargetHandler targetHandlerArgument = Mockito.mock(TargetHandler.class);
    Mockito.when(targetHandlerArgument.getTargetId()).thenReturn("some target id");

    IInstancesMngr mngr =
        new InstancesMngrImpl(
            messagingMngr, notificationMngr, targetsMngr, randomMngr, targetConfigurator);
    ((InstancesMngrImpl) mngr)
        .setTargetHandlerResolver(
            new TestTargetResolver() {
              @Override
              public TargetHandler findTargetHandler(Map<String, String> targetProperties)
                  throws TargetException {
                return targetHandlerArgument;
              }
            });

    TestApplication app = new TestApplication();
    ManagedApplication ma = new ManagedApplication(app);

    // One scoped instance has a machine ID (considered as running somewhere)
    app.getMySqlVm().data.put(Instance.MACHINE_ID, "machine-id");

    // Try to restore instances
    Assert.assertEquals(InstanceStatus.NOT_DEPLOYED, app.getMySqlVm().getStatus());
    app.getMySqlVm().setStatus(InstanceStatus.DEPLOYED_STARTED);

    Mockito.when(
            targetHandlerArgument.isMachineRunning(
                Mockito.any(TargetHandlerParameters.class), Mockito.eq("machine-id")))
        .thenReturn(false);

    mngr.restoreInstanceStates(ma, targetHandlerArgument);
    Assert.assertEquals(InstanceStatus.NOT_DEPLOYED, app.getMySqlVm().getStatus());

    // The handler's ID matched and the VM is NOT running => no message was sent.
    Mockito.verify(targetsMngr, Mockito.only())
        .findRawTargetProperties(Mockito.eq(app), Mockito.anyString());
    Mockito.verify(targetHandlerArgument, Mockito.times(1))
        .isMachineRunning(Mockito.any(TargetHandlerParameters.class), Mockito.eq("machine-id"));

    Mockito.verifyZeroInteractions(messagingMngr);
    Mockito.verifyZeroInteractions(randomMngr);
    Mockito.verifyZeroInteractions(targetConfigurator);

    // A notification was sent for the instance whose state changed
    Mockito.verify(notificationMngr)
        .instance(Mockito.any(Instance.class), Mockito.eq(app), Mockito.eq(EventType.CHANGED));
  }
  @Test
  public void testTargetsLocking_whenCreatingMachines_withExceptionInDeploy() throws Exception {

    // Prepare stuff
    INotificationMngr notificationMngr = Mockito.mock(INotificationMngr.class);
    ITargetsMngr targetsMngr = Mockito.mock(ITargetsMngr.class);
    IRandomMngr randomMngr = Mockito.mock(IRandomMngr.class);
    ITargetConfigurator targetConfigurator = Mockito.mock(ITargetConfigurator.class);

    IMessagingMngr messagingMngr = Mockito.mock(IMessagingMngr.class);
    Mockito.when(messagingMngr.getMessagingClient()).thenReturn(Mockito.mock(IDmClient.class));

    IConfigurationMngr configurationMngr = new ConfigurationMngrImpl();
    configurationMngr.setWorkingDirectory(this.folder.newFolder());

    final TargetHandler targetHandler = Mockito.mock(TargetHandler.class);
    Mockito.when(targetHandler.createMachine(Mockito.any(TargetHandlerParameters.class)))
        .thenThrow(new TargetException("for test"));

    IInstancesMngr mngr =
        new InstancesMngrImpl(
            messagingMngr, notificationMngr, targetsMngr, randomMngr, targetConfigurator);
    ((InstancesMngrImpl) mngr)
        .setTargetHandlerResolver(
            new TestTargetResolver() {
              @Override
              public TargetHandler findTargetHandler(Map<String, String> targetProperties)
                  throws TargetException {
                return targetHandler;
              }
            });

    TestApplication app = new TestApplication();
    ManagedApplication ma = new ManagedApplication(app);

    // We will try to create a machine. It will fail.
    // We must be sure the lock was acquired, and that it was released.
    final AtomicBoolean acquired = new AtomicBoolean(false);
    final AtomicBoolean released = new AtomicBoolean(false);

    Mockito.when(targetsMngr.lockAndGetTarget(app, app.getMySqlVm()))
        .thenAnswer(
            new Answer<Map<String, String>>() {

              @Override
              public Map<String, String> answer(InvocationOnMock invocation) throws Throwable {
                acquired.set(true);
                Map<String, String> result = new HashMap<>(0);
                return result;
              }
            });

    Mockito.doAnswer(
            new Answer<Object>() {
              @Override
              public Object answer(InvocationOnMock invocation) throws Throwable {
                released.set(true);
                return null;
              }
            })
        .when(targetsMngr)
        .unlockTarget(app, app.getMySqlVm());

    // Let's run assertions now
    Assert.assertFalse(acquired.get());
    Assert.assertFalse(released.get());
    Assert.assertEquals(InstanceStatus.NOT_DEPLOYED, app.getMySqlVm().getStatus());

    try {
      mngr.changeInstanceState(ma, app.getMySqlVm(), InstanceStatus.DEPLOYED_STARTED);
      Assert.fail("A target exception was expected.");

    } catch (Exception e) {
      // nothing
    }

    Assert.assertEquals(InstanceStatus.NOT_DEPLOYED, app.getMySqlVm().getStatus());
    Assert.assertTrue(acquired.get());
    Assert.assertTrue(released.get());

    // Since the handler failed, nothing was scheduled for post-configuration
    Mockito.verifyZeroInteractions(targetConfigurator);
  }