@Test(expected = IOException.class)
  public void testAssociationWithInvalidTargetId() throws Exception {

    TestApplication app = new TestApplication();
    String mySqlPath = InstanceHelpers.computeInstancePath(app.getMySqlVm());
    this.mngr.associateTargetWith("invalid", app, mySqlPath);
  }
  @Test
  public void testLocking_ByOneInstance() throws Exception {

    TestApplication app = new TestApplication();
    String instancePath = InstanceHelpers.computeInstancePath(app.getMySqlVm());
    Assert.assertEquals(0, this.mngr.listAllTargets().size());

    String targetId = this.mngr.createTarget("prop: ok\nid=tid\nhandler: h");
    this.mngr.associateTargetWith(targetId, app, instancePath);

    Map<String, String> props = this.mngr.lockAndGetTarget(app, app.getMySqlVm());
    Assert.assertEquals(2, props.size());
    Assert.assertEquals("ok", props.get("prop"));
    Assert.assertEquals("h", props.get("handler"));

    Assert.assertEquals(1, this.mngr.listAllTargets().size());
    try {
      this.mngr.deleteTarget(targetId);
      Assert.fail("A target is locked <=> We cannot delete it.");

    } catch (UnauthorizedActionException e) {
      // nothing
    }

    this.mngr.unlockTarget(app, app.getMySqlVm());
    Assert.assertEquals(1, this.mngr.listAllTargets().size());

    this.mngr.deleteTarget(targetId);
    Assert.assertEquals(0, this.mngr.listAllTargets().size());
  }
  @Test
  public void testAssociationWithComponentName() throws Exception {

    // Setup
    TestApplication app = new TestApplication();
    String componentName = "@" + app.getMySqlVm().getComponent().getName();
    String mySqlPath = InstanceHelpers.computeInstancePath(app.getMySqlVm());
    String tomcatPath = InstanceHelpers.computeInstancePath(app.getTomcatVm());

    // Create only an association with a component
    String targetId = this.mngr.createTarget("prop: ok\nid: abc\nhandler: h");
    this.mngr.associateTargetWith(targetId, app, componentName);

    Assert.assertNull(this.mngr.findTargetId(app, null, true));
    Assert.assertEquals(targetId, this.mngr.findTargetId(app, componentName, true));

    Assert.assertEquals(targetId, this.mngr.findTargetId(app, tomcatPath));
    Assert.assertNull(targetId, this.mngr.findTargetId(app, tomcatPath, true));

    Assert.assertEquals(targetId, this.mngr.findTargetId(app, mySqlPath));
    Assert.assertNull(targetId, this.mngr.findTargetId(app, mySqlPath, true));

    // Now, set a default target for the application and another one for a specific instance
    String tid1 = this.mngr.createTarget("prop: ok\nid: tid1\nhandler: h");
    String tid2 = this.mngr.createTarget("prop: ok\nid: tid2\nhandler: h");

    this.mngr.associateTargetWith(tid1, app, null);
    this.mngr.associateTargetWith(tid2, app, mySqlPath);

    Assert.assertEquals(tid1, this.mngr.findTargetId(app, null));
    Assert.assertEquals(tid1, this.mngr.findTargetId(app, null, true));

    Assert.assertEquals(tid2, this.mngr.findTargetId(app, mySqlPath));
    Assert.assertEquals(tid2, this.mngr.findTargetId(app, mySqlPath, true));

    Assert.assertEquals(targetId, this.mngr.findTargetId(app, tomcatPath));
    Assert.assertNull(targetId, this.mngr.findTargetId(app, tomcatPath, true));

    Assert.assertEquals(targetId, this.mngr.findTargetId(app, componentName));
    Assert.assertEquals(targetId, this.mngr.findTargetId(app, componentName, true));

    // Dissociate the component and the target
    this.mngr.dissociateTargetFrom(app, componentName);

    Assert.assertEquals(tid1, this.mngr.findTargetId(app, null));
    Assert.assertEquals(tid1, this.mngr.findTargetId(app, null, true));

    Assert.assertEquals(tid2, this.mngr.findTargetId(app, mySqlPath));
    Assert.assertEquals(tid2, this.mngr.findTargetId(app, mySqlPath, true));

    // We inherit the default target
    Assert.assertEquals(tid1, this.mngr.findTargetId(app, tomcatPath));
    Assert.assertNull(tid1, this.mngr.findTargetId(app, tomcatPath, true));

    // And no more binding for the component...
    Assert.assertNull(targetId, this.mngr.findTargetId(app, componentName, true));

    // ... except it inherits the default application target.
    Assert.assertEquals(tid1, this.mngr.findTargetId(app, componentName));
  }
  @Test
  public void testFindScriptResources() throws Exception {

    // Prepare our resources
    TestApplication app = new TestApplication();
    String targetId1 = this.mngr.createTarget("id: tid1\nhandler: h");
    String targetId2 = this.mngr.createTarget("id: tid2\nhandler: h");

    this.mngr.associateTargetWith(targetId1, app, null);
    this.mngr.associateTargetWith(targetId2, app, null);

    File dir1 =
        new File(
            this.configurationMngr.getWorkingDirectory(),
            ConfigurationUtils.TARGETS + "/" + targetId1);
    File dir2 =
        new File(
            this.configurationMngr.getWorkingDirectory(),
            ConfigurationUtils.TARGETS + "/" + targetId2);
    Utils.createDirectory(dir1);
    Utils.createDirectory(dir2);
    Utils.writeStringInto(
        "#!/bin/bash\necho Bonjour le monde cruel > toto.txt", new File(dir1, "target-script.sh"));
    Utils.writeStringInto("#!/bin/bash\necho touch toto.txt", new File(dir2, "target-script.py"));

    Assert.assertEquals(1, this.mngr.findScriptResources(targetId1).size());
    Assert.assertEquals(1, this.mngr.findScriptResources(app, app.getMySql()).size());
  }
  @Test(expected = IOException.class)
  public void testLocking_noTarget() throws Exception {

    TestApplication app = new TestApplication();
    Assert.assertEquals(0, this.mngr.listAllTargets().size());
    this.mngr.lockAndGetTarget(app, app.getMySqlVm());
  }
  @Test
  public void verifyAssociationsPersistenceOnDissociation() throws Exception {

    // Unit test for #579
    // One target manager => write associations.
    String targetId_1 = this.mngr.createTarget("id: t1\nhandler: h");
    String targetId_2 = this.mngr.createTarget("id: t2\nhandler: h");
    TestApplication app = new TestApplication();
    String path = InstanceHelpers.computeInstancePath(app.getMySqlVm());

    this.mngr.associateTargetWith(targetId_1, app, null);
    this.mngr.associateTargetWith(targetId_2, app, path);

    Assert.assertEquals(targetId_1, this.mngr.findTargetId(app, null, true));
    Assert.assertEquals(targetId_2, this.mngr.findTargetId(app, path, true));

    // Create another manager and verify the associations
    ITargetsMngr newMngr = new TargetsMngrImpl(this.configurationMngr);
    Assert.assertEquals(targetId_1, newMngr.findTargetId(app, null, true));
    Assert.assertEquals(targetId_2, newMngr.findTargetId(app, path, true));

    // Now, dissociate target_2 and the root instance
    this.mngr.dissociateTargetFrom(app, path);
    Assert.assertEquals(targetId_1, this.mngr.findTargetId(app, null, true));
    Assert.assertNull(this.mngr.findTargetId(app, path, true));

    // Create another manager and verify the associations
    newMngr = new TargetsMngrImpl(this.configurationMngr);
    Assert.assertEquals(targetId_1, newMngr.findTargetId(app, null, true));
    Assert.assertNull(newMngr.findTargetId(app, path, true));
  }
  @Test
  public void testCopyOriginalMapping_withException() throws Exception {

    // Check that when the association fails for one instance,
    // it does not prevent others from being processed.

    TestApplication app = new TestApplication();
    String instancePath = InstanceHelpers.computeInstancePath(app.getMySqlVm());
    String tomcatPath = InstanceHelpers.computeInstancePath(app.getTomcatVm());

    String t1 = this.mngr.createTarget("prop: ok\nid: t1\nhandler: h");
    String t2 = this.mngr.createTarget("prop: ok\nid: t2\nhandler: h");

    // Association is on the template
    Assert.assertNull(this.mngr.findTargetId(app, instancePath));
    this.mngr.associateTargetWith(t1, app.getTemplate(), instancePath);
    this.mngr.associateTargetWith(t1, app.getTemplate(), tomcatPath);

    // Set a new default for the application
    this.mngr.associateTargetWith(t2, app, null);
    Assert.assertEquals(t2, this.mngr.findTargetId(app, instancePath));
    Assert.assertEquals(t2, this.mngr.findTargetId(app, tomcatPath));

    // Change the state
    app.getMySqlVm().setStatus(InstanceStatus.DEPLOYED_STARTED);

    // The mapping won't be overwritten for the running instance
    this.mngr.copyOriginalMapping(app);
    Assert.assertEquals(t2, this.mngr.findTargetId(app, instancePath));
    Assert.assertEquals(t1, this.mngr.findTargetId(app, tomcatPath));
  }
  @Test
  public void testRestoreCache() throws Exception {

    Assert.assertEquals(0, ((TargetsMngrImpl) this.mngr).targetIds.size());
    Assert.assertEquals("1", this.mngr.createTarget("prop: ok\nid: 1\nhandler: h"));
    Assert.assertEquals("2", this.mngr.createTarget("prop: ok\nid: 2\nhandler: h"));
    Assert.assertEquals("abc", this.mngr.createTarget("prop: ok\nid: abc\nhandler: h"));
    Assert.assertEquals("4", this.mngr.createTarget("prop: ok\nid: 4\nhandler: h"));
    Assert.assertEquals(4, ((TargetsMngrImpl) this.mngr).targetIds.size());

    // Delete a valid and an invalid ones
    this.mngr.deleteTarget("abc");
    this.mngr.deleteTarget("invalid-id");
    Assert.assertEquals(3, ((TargetsMngrImpl) this.mngr).targetIds.size());

    // Create a new manager and check restoration works
    this.mngr = new TargetsMngrImpl(this.configurationMngr);
    Assert.assertEquals(3, ((TargetsMngrImpl) this.mngr).targetIds.size());

    // Add associations and make sure it works
    TestApplication app = new TestApplication();
    String instancePath = InstanceHelpers.computeInstancePath(app.getMySqlVm());

    Assert.assertNull(this.mngr.findTargetId(app, instancePath));
    this.mngr.associateTargetWith("4", app, instancePath);
    Assert.assertEquals("4", this.mngr.findTargetId(app, instancePath));

    // Create another manager
    this.mngr = new TargetsMngrImpl(this.configurationMngr);
    Assert.assertEquals("hop", this.mngr.createTarget("id: hop\nprop: ok\nhandler: h"));
    Assert.assertEquals("4", this.mngr.findTargetId(app, instancePath));
    Assert.assertEquals(4, ((TargetsMngrImpl) this.mngr).targetIds.size());
  }
  @Test
  public void testHints_noHint() throws Exception {

    TestApplication app1 = new TestApplication();
    app1.name("app1");
    TestApplication app2 = new TestApplication();
    app2.name("app2");

    String t1 =
        this.mngr.createTarget(
            "id: t1\nprop: ok\nname: target 1\ndescription: t1's target\nhandler: h");
    String t2 = this.mngr.createTarget("id: t2\nprop: ok\nhandler: docker");

    List<TargetWrapperDescriptor> beans = this.mngr.listPossibleTargets(app1);
    Assert.assertEquals(2, beans.size());

    TargetWrapperDescriptor b1 = beans.get(0);
    Assert.assertEquals(t1, b1.getId());
    Assert.assertEquals("target 1", b1.getName());
    Assert.assertEquals("t1's target", b1.getDescription());
    Assert.assertNotNull(b1.getHandler());
    Assert.assertFalse(b1.isDefault());

    TargetWrapperDescriptor b2 = beans.get(1);
    Assert.assertEquals(t2, b2.getId());
    Assert.assertEquals("docker", b2.getHandler());
    Assert.assertNull(b2.getName());
    Assert.assertNull(b2.getDescription());
    Assert.assertFalse(b2.isDefault());

    Assert.assertEquals(2, this.mngr.listPossibleTargets(app2).size());
  }
  @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(expected = UnauthorizedActionException.class)
  public void testDisssociations_onADeployedInstance() throws Exception {

    TestApplication app = new TestApplication();
    String instancePath = InstanceHelpers.computeInstancePath(app.getMySqlVm());
    app.getMySqlVm().setStatus(InstanceStatus.DEPLOYED_STARTED);

    this.mngr.dissociateTargetFrom(app, instancePath);
  }
  @Test(expected = UnauthorizedActionException.class)
  public void testAssociations_onADeployedInstance() throws Exception {

    TestApplication app = new TestApplication();
    String instancePath = InstanceHelpers.computeInstancePath(app.getMySqlVm());
    app.getMySqlVm().setStatus(InstanceStatus.DEPLOYED_STARTED);

    String targetId = this.mngr.createTarget("prop: ok\nid: tid\nhandler: h");
    this.mngr.associateTargetWith(targetId, app, instancePath);
  }
  @Test
  public void testDisssociationWithInvalidTargetId() throws Exception {

    TestApplication app = new TestApplication();
    String mySqlPath = InstanceHelpers.computeInstancePath(app.getMySqlVm());

    // No association
    this.mngr.dissociateTargetFrom(app, mySqlPath);
    // No exception
  }
  @Test
  public void testLoadUpdateAndRemove() throws Exception {

    // Create an application
    TestApplication app = new TestApplication();
    app.setDirectory(this.folder.newFolder());

    // Create rule files
    File autonomicRulesDir = new File(app.getDirectory(), Constants.PROJECT_DIR_RULES_AUTONOMIC);
    Assert.assertTrue(autonomicRulesDir.mkdir());

    File f = new File(autonomicRulesDir, "rule1.invalid-ext");
    Assert.assertTrue(f.createNewFile());

    f = new File(autonomicRulesDir, "rule2" + Constants.FILE_EXT_RULE);
    Utils.writeStringInto("rule \"test1\"\nwhen event1 then cmd1 end", f);

    f = new File(autonomicRulesDir, "rule3" + Constants.FILE_EXT_RULE);
    Utils.writeStringInto("rule \"test2\"\nwhen event2 then invalid syntax", f);

    // Load the rules
    Assert.assertEquals(0, this.autonomicMngr.appNameToContext.size());
    this.autonomicMngr.loadApplicationRules(app);
    Assert.assertEquals(1, this.autonomicMngr.appNameToContext.size());

    AutonomicApplicationContext ctx = this.autonomicMngr.appNameToContext.get(app.getName());
    Assert.assertNotNull(ctx);
    Assert.assertEquals(1, ctx.ruleNameToRule.size());
    Assert.assertNotNull(ctx.ruleNameToRule.get("test1"));

    // Update the invalid rule
    Utils.writeStringInto("rule \"test2\"\nwhen event2 then cmd2 end", f);
    this.autonomicMngr.refreshApplicationRules(app, "rule3");
    Assert.assertEquals(1, this.autonomicMngr.appNameToContext.size());

    Assert.assertEquals(2, ctx.ruleNameToRule.size());
    Assert.assertNotNull(ctx.ruleNameToRule.get("test1"));
    Assert.assertNotNull(ctx.ruleNameToRule.get("test2"));

    // Reload the first one
    Rule oldRule1 = ctx.ruleNameToRule.remove("test1");
    this.autonomicMngr.refreshApplicationRules(app, "rule2" + Constants.FILE_EXT_RULE);

    Assert.assertEquals(1, this.autonomicMngr.appNameToContext.size());
    Assert.assertEquals(2, ctx.ruleNameToRule.size());
    Assert.assertNotNull(ctx.ruleNameToRule.get("test1"));
    Assert.assertNotNull(ctx.ruleNameToRule.get("test2"));
    Assert.assertNotSame(oldRule1, ctx.ruleNameToRule.get("test1"));

    // Unload the rules
    this.autonomicMngr.unloadApplicationRules(app);
    Assert.assertEquals(0, this.autonomicMngr.appNameToContext.size());
  }
  @Test
  public void testFindRawTargetProperties_withProperties() throws Exception {

    TestApplication app = new TestApplication();
    String instancePath = InstanceHelpers.computeInstancePath(app.getMySqlVm());
    String targetId = this.mngr.createTarget("prop: ok\nid: tid\nhandler: h");
    this.mngr.associateTargetWith(targetId, app, instancePath);

    Map<String, String> props = this.mngr.findRawTargetProperties(app, instancePath);
    Assert.assertEquals(2, props.size());
    Assert.assertEquals("ok", props.get("prop"));
    Assert.assertEquals("h", props.get("handler"));
  }
  @Test
  public void testHints_removeHintOnApplication() throws Exception {

    TestApplication app1 = new TestApplication();
    app1.name("app1");
    TestApplication app2 = new TestApplication();
    app2.name("app2");

    String t1 =
        this.mngr.createTarget(
            "id: t1\nprop: ok\nname: target 1\ndescription: t1's target\nhandler: h");
    String t2 = this.mngr.createTarget("id: t2\nprop: ok\nhandler: docker\nhandler: h");

    // Hint between app1 and t1.
    // t1 has now a scope, which includes app1.
    // Therefore, t1 should not be listed for app2 (not in the scope).
    this.mngr.addHint(t1, app1);

    List<TargetWrapperDescriptor> beans = this.mngr.listPossibleTargets(app1);
    Assert.assertEquals(2, beans.size());

    beans = this.mngr.listPossibleTargets(app2);
    Assert.assertEquals(1, beans.size());

    // Remove the hint on the WRONG application => nothing changes
    this.mngr.removeHint(t1, app2);

    beans = this.mngr.listPossibleTargets(app1);
    Assert.assertEquals(2, beans.size());

    beans = this.mngr.listPossibleTargets(app2);
    Assert.assertEquals(1, beans.size());

    // Remove the hint on the WRONG application => nothing changes
    this.mngr.removeHint(t2, app1);

    beans = this.mngr.listPossibleTargets(app1);
    Assert.assertEquals(2, beans.size());

    beans = this.mngr.listPossibleTargets(app2);
    Assert.assertEquals(1, beans.size());

    // Remove the hint on the one we used
    this.mngr.removeHint(t1, app1);

    beans = this.mngr.listPossibleTargets(app1);
    Assert.assertEquals(2, beans.size());

    beans = this.mngr.listPossibleTargets(app2);
    Assert.assertEquals(2, beans.size());
  }
  @Test
  public void testAssociations() throws Exception {

    TestApplication app = new TestApplication();
    String mySqlPath = InstanceHelpers.computeInstancePath(app.getMySqlVm());
    String tomcatPath = InstanceHelpers.computeInstancePath(app.getTomcatVm());

    // Only MySQL has an associated target
    String targetId = this.mngr.createTarget("prop: ok\nid: abc\nhandler: h");
    this.mngr.associateTargetWith(targetId, app, mySqlPath);

    String associatedId = this.mngr.findTargetId(app, mySqlPath);
    Assert.assertEquals(targetId, associatedId);

    // There is no value for Tomcat, nor default target for the application
    Assert.assertNull(this.mngr.findTargetId(app, tomcatPath));

    // Let's define a default target for the whole application
    String defaultTargetId = this.mngr.createTarget("prop: ok\nid: def\nhandler: h");
    this.mngr.associateTargetWith(defaultTargetId, app, null);

    associatedId = this.mngr.findTargetId(app, mySqlPath);
    Assert.assertEquals(targetId, associatedId);

    associatedId = this.mngr.findTargetId(app, mySqlPath, true);
    Assert.assertEquals(targetId, associatedId);

    associatedId = this.mngr.findTargetId(app, tomcatPath);
    Assert.assertEquals(defaultTargetId, associatedId);
    Assert.assertNull(this.mngr.findTargetId(app, tomcatPath, true));

    // Remove the custom association for MySQL
    this.mngr.dissociateTargetFrom(app, mySqlPath);
    associatedId = this.mngr.findTargetId(app, mySqlPath);
    Assert.assertEquals(defaultTargetId, associatedId);
    Assert.assertNull(this.mngr.findTargetId(app, mySqlPath, true));

    // Make sure we cannot delete a default target
    this.mngr.dissociateTargetFrom(app, null);
    associatedId = this.mngr.findTargetId(app, mySqlPath);
    Assert.assertEquals(defaultTargetId, associatedId);

    // Make sure we can override a default target
    this.mngr.associateTargetWith(targetId, app, null);
    associatedId = this.mngr.findTargetId(app, mySqlPath);
    Assert.assertEquals(targetId, associatedId);

    associatedId = this.mngr.findTargetId(app, tomcatPath);
    Assert.assertEquals(targetId, associatedId);
  }
  @Test
  public void testLoadRules_noAutonomicDir() throws Exception {

    // Create an application
    TestApplication app = new TestApplication();
    app.setDirectory(this.folder.newFolder());

    // Load the rules
    Assert.assertEquals(0, this.autonomicMngr.appNameToContext.size());
    this.autonomicMngr.loadApplicationRules(app);
    Assert.assertEquals(1, this.autonomicMngr.appNameToContext.size());

    AutonomicApplicationContext ctx = this.autonomicMngr.appNameToContext.get(app.getName());
    Assert.assertNotNull(ctx);
    Assert.assertEquals(0, ctx.ruleNameToRule.size());
  }
  @Test
  public void testHints_hintOnApplication() throws Exception {

    TestApplication app1 = new TestApplication();
    app1.name("app1");
    TestApplication app2 = new TestApplication();
    app2.name("app2");

    String t1 =
        this.mngr.createTarget(
            "id: t1\nprop: ok\nname: target 1\ndescription: t1's target\nhandler: h");
    String t2 = this.mngr.createTarget("id: t2\nprop: ok\nhandler: docker");

    // Hint between app1 and t1.
    // t1 has now a scope, which includes app1.
    // Therefore, t1 should not be listed for app2 (not in the scope).
    this.mngr.addHint(t1, app1);

    List<TargetWrapperDescriptor> beans = this.mngr.listPossibleTargets(app1);
    Assert.assertEquals(2, beans.size());

    TargetWrapperDescriptor b1 = beans.get(0);
    Assert.assertEquals(t1, b1.getId());
    Assert.assertEquals("target 1", b1.getName());
    Assert.assertEquals("t1's target", b1.getDescription());
    Assert.assertNotNull(b1.getHandler());
    Assert.assertFalse(b1.isDefault());

    TargetWrapperDescriptor b2 = beans.get(1);
    Assert.assertEquals(t2, b2.getId());
    Assert.assertEquals("docker", b2.getHandler());
    Assert.assertNull(b2.getName());
    Assert.assertNull(b2.getDescription());
    Assert.assertFalse(b2.isDefault());

    beans = this.mngr.listPossibleTargets(app2);
    Assert.assertEquals(1, beans.size());

    b2 = beans.get(0);
    Assert.assertEquals(t2, b2.getId());
    Assert.assertEquals("docker", b2.getHandler());
    Assert.assertNull(b2.getName());
    Assert.assertNull(b2.getDescription());
    Assert.assertFalse(b2.isDefault());
  }
  @Test
  public void testCopyOriginalMapping_onDefault() throws Exception {

    TestApplication app = new TestApplication();
    String instancePath = InstanceHelpers.computeInstancePath(app.getMySqlVm());
    String t1 = this.mngr.createTarget("prop: ok\nid: t1\nhandler: h");
    String t2 = this.mngr.createTarget("prop: ok\nid: t2\nhandler: h");

    // Association is on the template and BY DEFAULT
    Assert.assertNull(this.mngr.findTargetId(app, instancePath));
    this.mngr.associateTargetWith(t1, app.getTemplate(), null);
    Assert.assertNull(this.mngr.findTargetId(app, instancePath));

    this.mngr.copyOriginalMapping(app);
    Assert.assertEquals(t1, this.mngr.findTargetId(app, instancePath));

    // We can override the association
    this.mngr.associateTargetWith(t2, app, instancePath);
    Assert.assertEquals(t2, this.mngr.findTargetId(app, instancePath));
  }
  @Test
  public void testCopyOriginalMapping_withComponents() throws Exception {

    TestApplication app = new TestApplication();
    String instancePath = InstanceHelpers.computeInstancePath(app.getMySqlVm());
    String t1 = this.mngr.createTarget("prop: ok\nid: t1\nhandler: h");
    String t2 = this.mngr.createTarget("prop: ok\nid: t2\nhandler: h");

    // Association is on the template and BY DEFAULT
    Assert.assertNull(this.mngr.findTargetId(app, instancePath));
    this.mngr.associateTargetWith(t1, app.getTemplate(), null);

    Assert.assertNull(this.mngr.findTargetId(app.getTemplate(), instancePath, true));
    Assert.assertEquals(t1, this.mngr.findTargetId(app.getTemplate(), instancePath, false));
    Assert.assertNull(this.mngr.findTargetId(app, instancePath, true));
    Assert.assertNull(this.mngr.findTargetId(app, instancePath, false));

    this.mngr.associateTargetWith(
        t2, app.getTemplate(), "@" + app.getMySqlVm().getComponent().getName());

    Assert.assertNull(this.mngr.findTargetId(app.getTemplate(), instancePath, true));
    Assert.assertEquals(t2, this.mngr.findTargetId(app.getTemplate(), instancePath, false));
    Assert.assertNull(this.mngr.findTargetId(app, instancePath, true));
    Assert.assertNull(this.mngr.findTargetId(app, instancePath, false));

    // Copy the mapping
    this.mngr.copyOriginalMapping(app);
    Assert.assertNull(this.mngr.findTargetId(app, instancePath, true));
    Assert.assertEquals(t2, this.mngr.findTargetId(app, instancePath, false));

    // Remove the component association
    this.mngr.dissociateTargetFrom(app, "@" + app.getMySqlVm().getComponent().getName());
    Assert.assertNull(this.mngr.findTargetId(app, instancePath, true));
    Assert.assertEquals(t1, this.mngr.findTargetId(app, instancePath, false));

    // We can override the association
    this.mngr.associateTargetWith(t2, app, instancePath);
    Assert.assertEquals(t2, this.mngr.findTargetId(app, instancePath, true));
    Assert.assertEquals(t2, this.mngr.findTargetId(app, instancePath, false));
  }
  @Test
  public void testRefreshRules_unknownRule() throws Exception {

    // Create an application
    TestApplication app = new TestApplication();
    app.setDirectory(this.folder.newFolder());

    // Create the autonomic directory
    File autonomicRulesDir = new File(app.getDirectory(), Constants.PROJECT_DIR_RULES_AUTONOMIC);
    Assert.assertTrue(autonomicRulesDir.mkdir());

    // Load the rules
    Assert.assertEquals(0, this.autonomicMngr.appNameToContext.size());
    this.autonomicMngr.loadApplicationRules(app);
    Assert.assertEquals(1, this.autonomicMngr.appNameToContext.size());

    AutonomicApplicationContext ctx = this.autonomicMngr.appNameToContext.get(app.getName());
    Assert.assertNotNull(ctx);
    Assert.assertEquals(0, ctx.ruleNameToRule.size());

    // Try to refresh an invalid rule
    this.autonomicMngr.refreshApplicationRules(app, "unknown");
    Assert.assertEquals(0, ctx.ruleNameToRule.size());
  }
  @Test
  public void testTargetsLocking_whenCreatingMachines_noException() 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());

    IInstancesMngr mngr =
        new InstancesMngrImpl(
            messagingMngr, notificationMngr, targetsMngr, randomMngr, targetConfigurator);
    ((InstancesMngrImpl) mngr).setTargetHandlerResolver(new TestTargetResolver());

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

    // We want to make sure target locking is correctly invoked by the instances manager.
    // So, we store requests to lock or unlock a target for a given instance.
    final Map<Instance, Integer> instancePathToLock = new HashMap<>();
    Mockito.when(targetsMngr.lockAndGetTarget(app, app.getMySqlVm()))
        .thenAnswer(
            new Answer<Map<String, String>>() {

              @Override
              public Map<String, String> answer(InvocationOnMock invocation) throws Throwable {

                Instance inst = invocation.getArgumentAt(1, Instance.class);
                Integer count = instancePathToLock.get(inst);
                count = count == null ? 1 : count + 1;
                instancePathToLock.put(inst, count);

                Map<String, String> result = new HashMap<>(0);
                return result;
              }
            });

    Mockito.doAnswer(
            new Answer<Object>() {
              @Override
              public Object answer(InvocationOnMock invocation) throws Throwable {

                Instance inst = invocation.getArgumentAt(1, Instance.class);
                Integer count = instancePathToLock.get(inst);
                count = count == null ? 0 : count - 1;
                if (count > 0) instancePathToLock.put(inst, count);
                else instancePathToLock.remove(inst);

                return null;
              }
            })
        .when(targetsMngr)
        .unlockTarget(app, app.getMySqlVm());

    // Let's run assertions now
    Assert.assertEquals(0, instancePathToLock.size());
    Assert.assertEquals(InstanceStatus.NOT_DEPLOYED, app.getMySqlVm().getStatus());
    mngr.changeInstanceState(ma, app.getMySqlVm(), InstanceStatus.DEPLOYED_STARTED);
    Assert.assertEquals(1, instancePathToLock.size());

    Integer lockCount = instancePathToLock.get(app.getMySqlVm());
    Assert.assertNotNull(lockCount);
    Assert.assertEquals(1, lockCount.intValue());
    Assert.assertEquals(InstanceStatus.DEPLOYING, app.getMySqlVm().getStatus());

    Mockito.verify(targetConfigurator)
        .reportCandidate(Mockito.any(TargetHandlerParameters.class), Mockito.eq(app.getMySqlVm()));

    // Release the machine
    mngr.changeInstanceState(ma, app.getMySqlVm(), InstanceStatus.NOT_DEPLOYED);
    Assert.assertEquals(InstanceStatus.NOT_DEPLOYED, app.getMySqlVm().getStatus());
    Assert.assertEquals(0, instancePathToLock.size());
  }
  @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 testNotificationsWhenUndeployingScopedInstances_changeInstanceState()
      throws Exception {

    // Prepare stuff
    final TestApplication app = new TestApplication();
    final Map<Instance, List<InstanceStatus>> instanceToStatusHistory = new HashMap<>();
    INotificationMngr notificationMngr =
        new NotificationMngrImpl() {
          @Override
          public void instance(Instance instance, Application application, EventType eventType) {

            Assert.assertEquals(EventType.CHANGED, eventType);
            Assert.assertEquals(app, application);

            List<InstanceStatus> status = instanceToStatusHistory.get(instance);
            if (status == null) {
              status = new ArrayList<>();
              instanceToStatusHistory.put(instance, status);
            }

            status.add(instance.getStatus());
          }
        };

    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());

    IInstancesMngr mngr =
        new InstancesMngrImpl(
            messagingMngr, notificationMngr, targetsMngr, randomMngr, targetConfigurator);
    ((InstancesMngrImpl) mngr).setTargetHandlerResolver(new TestTargetResolver());

    // Make one of our VM being fully deployed
    ManagedApplication ma = new ManagedApplication(app);
    app.getTomcatVm().setStatus(InstanceStatus.DEPLOYED_STARTED);
    app.getTomcat().setStatus(InstanceStatus.DEPLOYED_STARTED);
    app.getWar().setStatus(InstanceStatus.DEPLOYED_STARTED);

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

    // Stop everything
    mngr.changeInstanceState(ma, app.getTomcatVm(), InstanceStatus.NOT_DEPLOYED);

    // Check notifications
    Assert.assertEquals(3, instanceToStatusHistory.size());
    List<InstanceStatus> statusHistory = instanceToStatusHistory.get(app.getTomcatVm());
    Assert.assertNotNull(statusHistory);
    Assert.assertEquals(
        Arrays.asList(InstanceStatus.UNDEPLOYING, InstanceStatus.NOT_DEPLOYED), statusHistory);

    statusHistory = instanceToStatusHistory.get(app.getTomcat());
    Assert.assertNotNull(statusHistory);
    Assert.assertEquals(Arrays.asList(InstanceStatus.NOT_DEPLOYED), statusHistory);

    statusHistory = instanceToStatusHistory.get(app.getWar());
    Assert.assertNotNull(statusHistory);
    Assert.assertEquals(Arrays.asList(InstanceStatus.NOT_DEPLOYED), statusHistory);

    Mockito.verify(targetConfigurator, Mockito.only())
        .cancelCandidate(Mockito.any(TargetHandlerParameters.class), Mockito.eq(app.getTomcatVm()));
  }
  @Test
  public void testFindUsageStatistics() throws Exception {

    // Setup
    TestApplication app = new TestApplication();
    Instance newRootInstance = new Instance("newRoot").component(app.getMySqlVm().getComponent());
    app.getRootInstances().add(newRootInstance);

    String t1 = this.mngr.createTarget("prop: ok\nid: t1\nhandler: h");
    String t2 = this.mngr.createTarget("prop: ok\nid: t2\nhandler: h");
    String t3 = this.mngr.createTarget("prop: ok\nid: t3\nhandler: h");

    this.mngr.associateTargetWith(t1, app, InstanceHelpers.computeInstancePath(app.getMySqlVm()));
    this.mngr.associateTargetWith(t1, app, InstanceHelpers.computeInstancePath(newRootInstance));
    this.mngr.associateTargetWith(t2, app, null);

    // Checks
    List<TargetUsageItem> items = this.mngr.findUsageStatistics(t1);
    Assert.assertEquals(1, items.size());

    TargetUsageItem item = items.get(0);
    Assert.assertEquals(app.getName(), item.getName());
    Assert.assertNull(item.getQualifier());
    Assert.assertFalse(item.isUsing());
    Assert.assertTrue(item.isReferencing());

    items = this.mngr.findUsageStatistics(t2);
    Assert.assertEquals(1, items.size());

    item = items.get(0);
    Assert.assertEquals(app.getName(), item.getName());
    Assert.assertNull(item.getQualifier());
    Assert.assertFalse(item.isUsing());
    Assert.assertTrue(item.isReferencing());

    items = this.mngr.findUsageStatistics(t3);
    Assert.assertEquals(0, items.size());

    // Mark one as used
    this.mngr.lockAndGetTarget(app, app.getTomcatVm());

    items = this.mngr.findUsageStatistics(t1);
    Assert.assertEquals(1, items.size());

    item = items.get(0);
    Assert.assertEquals(app.getName(), item.getName());
    Assert.assertNull(item.getQualifier());
    Assert.assertFalse(item.isUsing());
    Assert.assertTrue(item.isReferencing());

    items = this.mngr.findUsageStatistics(t3);
    Assert.assertEquals(0, items.size());

    items = this.mngr.findUsageStatistics(t2);
    Assert.assertEquals(1, items.size());

    item = items.get(0);
    Assert.assertEquals(app.getName(), item.getName());
    Assert.assertNull(item.getQualifier());
    Assert.assertTrue(item.isReferencing());

    // The change is here!
    Assert.assertTrue(item.isUsing());

    // Release it
    this.mngr.unlockTarget(app, app.getTomcatVm());

    items = this.mngr.findUsageStatistics(t1);
    Assert.assertEquals(1, items.size());

    item = items.get(0);
    Assert.assertEquals(app.getName(), item.getName());
    Assert.assertNull(item.getQualifier());
    Assert.assertFalse(item.isUsing());
    Assert.assertTrue(item.isReferencing());

    items = this.mngr.findUsageStatistics(t2);
    Assert.assertEquals(1, items.size());

    item = items.get(0);
    Assert.assertEquals(app.getName(), item.getName());
    Assert.assertNull(item.getQualifier());
    Assert.assertFalse(item.isUsing());
    Assert.assertTrue(item.isReferencing());

    items = this.mngr.findUsageStatistics(t3);
    Assert.assertEquals(0, items.size());

    // Remove the association for the named instance
    this.mngr.dissociateTargetFrom(app, InstanceHelpers.computeInstancePath(app.getMySqlVm()));
    items = this.mngr.findUsageStatistics(t1);
    Assert.assertEquals(1, items.size());

    this.mngr.dissociateTargetFrom(app, InstanceHelpers.computeInstancePath(newRootInstance));
    items = this.mngr.findUsageStatistics(t1);
    Assert.assertEquals(0, items.size());

    items = this.mngr.findUsageStatistics(t2);
    Assert.assertEquals(1, items.size());

    item = items.get(0);
    Assert.assertEquals(app.getName(), item.getName());
    Assert.assertNull(item.getQualifier());
    Assert.assertFalse(item.isUsing());
    Assert.assertTrue(item.isReferencing());

    items = this.mngr.findUsageStatistics(t3);
    Assert.assertEquals(0, items.size());
  }
  @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);
  }
  @Test
  public void testApplicationWasDeleted() throws Exception {

    // Prepare the model
    TestApplication app1 = new TestApplication();
    app1.name("app1");
    TestApplication app2 = new TestApplication();
    app2.name("app2");

    String t1 =
        this.mngr.createTarget(
            "id: t1\nprop: ok\nname: target 1\ndescription: t1's target\nhandler: h");
    String t2 = this.mngr.createTarget("id: t2\nprop: ok\nhandler: docker");

    String path = InstanceHelpers.computeInstancePath(app1.getTomcatVm());

    // Create hints and associations
    this.mngr.associateTargetWith(t1, app1.getTemplate(), null);
    this.mngr.associateTargetWith(t1, app1, null);
    this.mngr.associateTargetWith(t2, app1, path);
    this.mngr.associateTargetWith(t2, app2, null);

    this.mngr.addHint(t1, app1);
    this.mngr.addHint(t2, app1);
    this.mngr.addHint(t2, app2);

    // Verify preconditions
    Assert.assertEquals(t1, this.mngr.findTargetId(app1, null));
    Assert.assertEquals(t2, this.mngr.findTargetId(app1, path));
    Assert.assertEquals(2, this.mngr.listPossibleTargets(app1).size());

    Assert.assertEquals(t2, this.mngr.findTargetId(app2, null));
    Assert.assertEquals(t2, this.mngr.findTargetId(app2, path));
    Assert.assertEquals(1, this.mngr.listPossibleTargets(app2).size());

    Assert.assertEquals(t1, this.mngr.findTargetId(app1.getTemplate(), path));
    Assert.assertEquals(0, this.mngr.listPossibleTargets(app1.getTemplate()).size());

    // Delete the application
    this.mngr.applicationWasDeleted(app1);

    // Verify post-conditions
    Assert.assertNull(this.mngr.findTargetId(app1, null));
    Assert.assertNull(this.mngr.findTargetId(app1, path));

    // t1 has not hint anymore, so it becomes global
    List<TargetWrapperDescriptor> hints = this.mngr.listPossibleTargets(app1);
    Assert.assertEquals(1, hints.size());
    Assert.assertEquals(t1, hints.get(0).getId());

    Assert.assertEquals(t2, this.mngr.findTargetId(app2, null));
    Assert.assertEquals(t2, this.mngr.findTargetId(app2, path));

    // t1 is global now
    Assert.assertEquals(2, this.mngr.listPossibleTargets(app2).size());

    // t1 is global now
    Assert.assertEquals(t1, this.mngr.findTargetId(app1.getTemplate(), path));
    Assert.assertEquals(1, this.mngr.listPossibleTargets(app1.getTemplate()).size());

    // Delete the template of app1
    this.mngr.applicationWasDeleted(app1.getTemplate());

    // Verify post-conditions
    Assert.assertNull(this.mngr.findTargetId(app1, null));
    Assert.assertNull(this.mngr.findTargetId(app1, path));
    Assert.assertEquals(1, this.mngr.listPossibleTargets(app1).size());

    Assert.assertEquals(t2, this.mngr.findTargetId(app2, null));
    Assert.assertEquals(t2, this.mngr.findTargetId(app2, path));
    Assert.assertEquals(2, this.mngr.listPossibleTargets(app2).size());

    Assert.assertNull(this.mngr.findTargetId(app1.getTemplate(), path));
    Assert.assertEquals(1, this.mngr.listPossibleTargets(app1.getTemplate()).size());

    // Delete app2
    this.mngr.applicationWasDeleted(app2);

    // Verify post-conditions
    // t2 does not have any hint anymore => it is global
    Assert.assertNull(this.mngr.findTargetId(app1, null));
    Assert.assertNull(this.mngr.findTargetId(app1, path));
    Assert.assertEquals(2, this.mngr.listPossibleTargets(app1).size());

    Assert.assertNull(this.mngr.findTargetId(app2, null));
    Assert.assertNull(this.mngr.findTargetId(app2, path));
    Assert.assertEquals(2, this.mngr.listPossibleTargets(app2).size());

    Assert.assertNull(this.mngr.findTargetId(app1.getTemplate(), path));
    Assert.assertEquals(2, this.mngr.listPossibleTargets(app1.getTemplate()).size());
  }