/**
   * Simple call to connector test() method.
   *
   * @throws Exception
   */
  @Test
  public void test310TestConnectionNegative() throws Exception {
    final String TEST_NAME = "test310TestConnectionNegative";
    TestUtil.displayTestTile(this, TEST_NAME);
    // GIVEN

    OperationResult result = new OperationResult(TEST_NAME);

    ConnectorInstance badConnector =
        factory.createConnectorInstance(
            connectorType,
            ResourceTypeUtil.getResourceNamespace(badResourceType),
            "test connector");
    badConnector.configure(
        badResourceType.getConnectorConfiguration().asPrismContainerValue(), result);

    // WHEN

    badConnector.test(result);

    // THEN
    result.computeStatus("test failed");
    display("Test result (FAILURE EXPECTED)", result);
    AssertJUnit.assertNotNull(result);
    OperationResult connectorConnectionResult = result.getSubresults().get(1);
    AssertJUnit.assertNotNull(connectorConnectionResult);
    System.out.println(
        "Test \"connector connection\" result: "
            + connectorConnectionResult
            + " (FAILURE EXPECTED)");
    AssertJUnit.assertTrue(
        "Unexpected success of bad connector test", !connectorConnectionResult.isSuccess());
    AssertJUnit.assertTrue(!result.isSuccess());
  }
  @Test
  public void test500FetchObject() throws Exception {
    final String TEST_NAME = "test500FetchObject";
    TestUtil.displayTestTile(this, TEST_NAME);

    // GIVEN
    ResourceAttributeContainer resourceObject =
        createResourceObject("uid=Teell,ou=People,dc=example,dc=com", "Teell William", "Teell");

    OperationResult addResult = new OperationResult(this.getClass().getName() + "." + TEST_NAME);

    PrismObject<ShadowType> shadow = wrapInShadow(ShadowType.class, resourceObject);
    // Add a testing object
    cc.addObject(shadow, null, addResult);

    ObjectClassComplexTypeDefinition accountDefinition =
        resourceObject.getDefinition().getComplexTypeDefinition();

    Collection<ResourceAttribute<?>> identifiers = resourceObject.getIdentifiers();
    // Determine object class from the schema

    ResourceObjectIdentification identification =
        new ResourceObjectIdentification(accountDefinition, identifiers);
    OperationResult result = new OperationResult(this.getClass().getName() + "." + TEST_NAME);

    // WHEN
    PrismObject<ShadowType> ro = cc.fetchObject(ShadowType.class, identification, null, result);

    // THEN

    AssertJUnit.assertNotNull(ro);
    System.out.println("Fetched object " + ro);
    System.out.println("Result:");
    System.out.println(result.debugDump());
  }
  @Test
  public void test110ChangeModifyObject() throws Exception {
    final String TEST_NAME = "test110ChangeModifyObject";
    TestUtil.displayTestTile(this, TEST_NAME);

    OperationResult result = new OperationResult(this.getClass().getName() + "." + TEST_NAME);

    Collection<ResourceAttribute<?>> identifiers = addSampleResourceObject("john", "John", "Smith");

    Set<Operation> changes = new HashSet<Operation>();

    changes.add(createAddAttributeChange("employeeNumber", "123123123"));
    changes.add(createReplaceAttributeChange("sn", "Smith007"));
    changes.add(createAddAttributeChange("street", "Wall Street"));
    changes.add(createDeleteAttributeChange("givenName", "John"));

    ObjectClassComplexTypeDefinition accountDefinition =
        resourceSchema.findObjectClassDefinition(
            ProvisioningTestUtil.OBJECT_CLASS_INETORGPERSON_NAME);

    cc.modifyObject(accountDefinition, identifiers, changes, result);

    ResourceObjectIdentification identification =
        new ResourceObjectIdentification(accountDefinition, identifiers);
    PrismObject<ShadowType> shadow = cc.fetchObject(ShadowType.class, identification, null, result);
    ResourceAttributeContainer resObj = ShadowUtil.getAttributesContainer(shadow);

    AssertJUnit.assertNull(
        resObj.findAttribute(
            new QName(ResourceTypeUtil.getResourceNamespace(resourceType), "givenName")));

    String addedEmployeeNumber =
        resObj
            .findAttribute(
                new QName(ResourceTypeUtil.getResourceNamespace(resourceType), "employeeNumber"))
            .getValue(String.class)
            .getValue();
    String changedSn =
        resObj
            .findAttribute(new QName(ResourceTypeUtil.getResourceNamespace(resourceType), "sn"))
            .getValues(String.class)
            .iterator()
            .next()
            .getValue();
    String addedStreet =
        resObj
            .findAttribute(new QName(ResourceTypeUtil.getResourceNamespace(resourceType), "street"))
            .getValues(String.class)
            .iterator()
            .next()
            .getValue();

    System.out.println("changed employee number: " + addedEmployeeNumber);
    System.out.println("changed sn: " + changedSn);
    System.out.println("added street: " + addedStreet);

    AssertJUnit.assertEquals("123123123", addedEmployeeNumber);
    AssertJUnit.assertEquals("Smith007", changedSn);
    AssertJUnit.assertEquals("Wall Street", addedStreet);
  }
  @Test
  public void testAddDeleteObject() throws Exception {
    TestUtil.displayTestTile(this, "testDeleteObject");

    OperationResult result = new OperationResult(this.getClass().getName() + ".testDelete");

    Collection<ResourceAttribute<?>> identifiers = addSampleResourceObject("john", "John", "Smith");

    String uid = null;
    for (ResourceAttribute<?> resourceAttribute : identifiers) {
      if (ConnectorFactoryIcfImpl.ICFS_UID.equals(resourceAttribute.getElementName())) {
        uid = resourceAttribute.getValue(String.class).getValue();
        System.out.println("uuuuid:" + uid);
        assertNotNull(uid);
      }
    }

    ObjectClassComplexTypeDefinition accountDefinition =
        resourceSchema.findDefaultObjectClassDefinition(ShadowKindType.ACCOUNT);

    cc.deleteObject(accountDefinition, null, identifiers, result);

    PrismObject<ShadowType> resObj = null;
    try {
      resObj = cc.fetchObject(ShadowType.class, accountDefinition, identifiers, null, result);
      Assert.fail();
    } catch (ObjectNotFoundException ex) {
      AssertJUnit.assertNull(resObj);
    }
  }
  @Test
  public void test100AddDeleteObject() throws Exception {
    final String TEST_NAME = "test100AddDeleteObject";
    TestUtil.displayTestTile(this, TEST_NAME);

    OperationResult result = new OperationResult(this.getClass().getName() + "." + TEST_NAME);

    Collection<ResourceAttribute<?>> identifiers = addSampleResourceObject("john", "John", "Smith");

    String uid = null;
    for (ResourceAttribute<?> resourceAttribute : identifiers) {
      if (ConnectorFactoryIcfImpl.ICFS_UID.equals(resourceAttribute.getElementName())) {
        uid = resourceAttribute.getValue(String.class).getValue();
        System.out.println("uuuuid:" + uid);
        assertNotNull(uid);
      }
    }

    ObjectClassComplexTypeDefinition accountDefinition =
        resourceSchema.findObjectClassDefinition(
            ProvisioningTestUtil.OBJECT_CLASS_INETORGPERSON_NAME);

    cc.deleteObject(accountDefinition, null, identifiers, result);

    ResourceObjectIdentification identification =
        new ResourceObjectIdentification(accountDefinition, identifiers);
    PrismObject<ShadowType> resObj = null;
    try {
      resObj = cc.fetchObject(ShadowType.class, identification, null, result);
      Assert.fail();
    } catch (ObjectNotFoundException ex) {
      AssertJUnit.assertNull(resObj);
    }
  }
  @Test
  public void test510Search() throws Exception {
    final String TEST_NAME = "test510Search";
    TestUtil.displayTestTile(this, TEST_NAME);
    // GIVEN

    ObjectClassComplexTypeDefinition accountDefinition =
        resourceSchema.findObjectClassDefinition(
            ProvisioningTestUtil.OBJECT_CLASS_INETORGPERSON_NAME);
    // Determine object class from the schema

    ResultHandler<ShadowType> handler =
        new ResultHandler<ShadowType>() {
          @Override
          public boolean handle(PrismObject<ShadowType> object) {
            System.out.println("Search: found: " + object);
            return true;
          }
        };

    OperationResult result = new OperationResult(this.getClass().getName() + "." + TEST_NAME);

    // WHEN
    cc.search(accountDefinition, new ObjectQuery(), handler, null, null, null, result);

    // THEN

  }
  @Test
  public void testSearch() throws UcfException, SchemaException, CommunicationException {
    TestUtil.displayTestTile("testSearch");
    // GIVEN

    ObjectClassComplexTypeDefinition accountDefinition =
        resourceSchema.findDefaultObjectClassDefinition(ShadowKindType.ACCOUNT);
    // Determine object class from the schema

    ResultHandler<ShadowType> handler =
        new ResultHandler<ShadowType>() {

          @Override
          public boolean handle(PrismObject<ShadowType> object) {
            System.out.println("Search: found: " + object);
            return true;
          }
        };

    OperationResult result = new OperationResult(this.getClass().getName() + ".testSearch");

    // WHEN
    cc.search(accountDefinition, new ObjectQuery(), handler, null, result);

    // THEN

  }
  // This obviously does not work with LDAP connector
  @Test(enabled = false)
  public void testDisableAccount() throws Exception {
    TestUtil.displayTestTile(this, "testDisableAccount");

    // GIVEN
    OperationResult result = new OperationResult(this.getClass().getName() + ".testDisableAccount");

    Collection<ResourceAttribute<?>> identifiers =
        addSampleResourceObject("blackbeard", "Edward", "Teach");

    // Check precondition
    String entryUuid = getEntryUuid(identifiers);
    SearchResultEntry ldapEntryBefore = openDJController.searchAndAssertByEntryUuid(entryUuid);
    assertTrue("The account is not enabled", openDJController.isAccountEnabled(ldapEntryBefore));

    // WHEN

    Set<Operation> changes = new HashSet<Operation>();
    changes.add(createActivationChange(ActivationStatusType.DISABLED));

    ObjectClassComplexTypeDefinition accountDefinition =
        resourceSchema.findDefaultObjectClassDefinition(ShadowKindType.ACCOUNT);

    cc.modifyObject(accountDefinition, identifiers, changes, result);

    // THEN

    SearchResultEntry ldapEntryAfter = openDJController.searchAndAssertByEntryUuid(entryUuid);
    assertFalse("The account was not disabled", openDJController.isAccountEnabled(ldapEntryAfter));
  }
  @Test
  public void testFetchChanges() throws Exception {
    TestUtil.displayTestTile(this, "testFetchChanges");

    OperationResult result = new OperationResult(this.getClass().getName() + ".testFetchChanges");
    ObjectClassComplexTypeDefinition accountDefinition =
        resourceSchema.findDefaultObjectClassDefinition(ShadowKindType.ACCOUNT);
    PrismProperty lastToken = cc.fetchCurrentToken(accountDefinition, result);

    System.out.println("Property:");
    System.out.println(SchemaDebugUtil.prettyPrint(lastToken));

    System.out.println("token " + lastToken.toString());
    List<Change<ShadowType>> changes = cc.fetchChanges(accountDefinition, lastToken, null, result);
    AssertJUnit.assertEquals(0, changes.size());
  }
  @BeforeMethod
  public void initUcf() throws Exception {
    TestUtil.displayTestTile("initUcf");

    File file = new File(FILENAME_RESOURCE_OPENDJ);
    FileInputStream fis = new FileInputStream(file);

    // Resource
    PrismObject<ResourceType> resource =
        PrismTestUtil.parseObject(new File(FILENAME_RESOURCE_OPENDJ));
    resourceType = resource.asObjectable();

    // Resource: Second copy for negative test cases
    PrismObject<ResourceType> badResource =
        PrismTestUtil.parseObject(new File(FILENAME_RESOURCE_OPENDJ_BAD));
    badResourceType = badResource.asObjectable();

    // Connector
    PrismObject<ConnectorType> connector =
        PrismTestUtil.parseObject(new File(FILENAME_CONNECTOR_LDAP));
    connectorType = connector.asObjectable();

    factory = connectorFactoryIcfImpl;

    cc =
        factory.createConnectorInstance(
            connectorType, ResourceTypeUtil.getResourceNamespace(resourceType), "test connector");
    AssertJUnit.assertNotNull("Cannot create connector instance", cc);

    connectorSchema = cc.generateConnectorSchema();
    AssertJUnit.assertNotNull("Cannot generate connector schema", cc);
    display("Connector schema", connectorSchema);

    OperationResult result = new OperationResult("initUcf");
    cc.configure(resourceType.getConnectorConfiguration().asPrismContainerValue(), result);
    cc.initialize(null, null, false, result);
    // TODO: assert something

    resourceSchema = cc.fetchResourceSchema(null, result);
    display("Resource schema", resourceSchema);

    AssertJUnit.assertNotNull(resourceSchema);
  }
  @Test
  public void test200FetchChanges() throws Exception {
    final String TEST_NAME = "test200FetchChanges";
    TestUtil.displayTestTile(this, TEST_NAME);

    OperationResult result = new OperationResult(this.getClass().getName() + "." + TEST_NAME);
    ObjectClassComplexTypeDefinition accountDefinition =
        resourceSchema.findObjectClassDefinition(
            ProvisioningTestUtil.OBJECT_CLASS_INETORGPERSON_NAME);
    PrismProperty<Integer> lastToken = cc.fetchCurrentToken(accountDefinition, result);

    System.out.println("Property:");
    System.out.println(SchemaDebugUtil.prettyPrint(lastToken));
    System.out.println("token " + lastToken.toString());

    assertNotNull("No last token", lastToken);
    assertNotNull("No last token value", lastToken.getRealValue());

    List<Change<ShadowType>> changes = cc.fetchChanges(accountDefinition, lastToken, null, result);
    AssertJUnit.assertEquals(0, changes.size());
  }
  private Collection<ResourceAttribute<?>> addSampleResourceObject(
      String name, String givenName, String familyName)
      throws CommunicationException, GenericFrameworkException, SchemaException,
          ObjectAlreadyExistsException, ConfigurationException {
    OperationResult result = new OperationResult(this.getClass().getName() + ".testAdd");

    QName objectClassQname =
        new QName(
            ResourceTypeUtil.getResourceNamespace(resourceType),
            ProvisioningTestUtil.OBJECT_CLASS_INETORGPERSON_NAME);
    ObjectClassComplexTypeDefinition accountDefinition =
        resourceSchema.findObjectClassDefinition(objectClassQname);
    assertNotNull("No object class definition " + objectClassQname, accountDefinition);
    ResourceAttributeContainer resourceObject =
        accountDefinition.instantiate(ShadowType.F_ATTRIBUTES);

    ResourceAttributeDefinition<String> attributeDefinition =
        accountDefinition.findAttributeDefinition(
            new QName(
                ResourceTypeUtil.getResourceNamespace(resourceType),
                ProvisioningTestUtil.RESOURCE_OPENDJ_SECONDARY_IDENTIFIER_LOCAL_NAME));
    ResourceAttribute<String> attribute = attributeDefinition.instantiate();
    attribute.setValue(
        new PrismPropertyValue<String>("uid=" + name + ",ou=people,dc=example,dc=com"));
    resourceObject.add(attribute);

    attributeDefinition =
        accountDefinition.findAttributeDefinition(
            new QName(ResourceTypeUtil.getResourceNamespace(resourceType), "sn"));
    attribute = attributeDefinition.instantiate();
    attribute.setValue(new PrismPropertyValue(familyName));
    resourceObject.add(attribute);

    attributeDefinition =
        accountDefinition.findAttributeDefinition(
            new QName(ResourceTypeUtil.getResourceNamespace(resourceType), "cn"));
    attribute = attributeDefinition.instantiate();
    attribute.setValue(new PrismPropertyValue(givenName + " " + familyName));
    resourceObject.add(attribute);

    attributeDefinition =
        accountDefinition.findAttributeDefinition(
            new QName(ResourceTypeUtil.getResourceNamespace(resourceType), "givenName"));
    attribute = attributeDefinition.instantiate();
    attribute.setValue(new PrismPropertyValue(givenName));
    resourceObject.add(attribute);

    PrismObject<ShadowType> shadow = wrapInShadow(ShadowType.class, resourceObject);

    Set<Operation> operation = new HashSet<Operation>();
    Collection<ResourceAttribute<?>> resourceAttributes = cc.addObject(shadow, operation, result);
    return resourceAttributes;
  }
  @Test
  public void testCapabilities() throws Exception {
    TestUtil.displayTestTile("testCapabilities");
    // GIVEN

    OperationResult result = new OperationResult("testCapabilities");

    // WHEN

    Collection<Object> capabilities = cc.fetchCapabilities(result);

    // THEN
    result.computeStatus("getCapabilities failed");
    TestUtil.assertSuccess("getCapabilities failed (result)", result);
    assertFalse("Empty capabilities returned", capabilities.isEmpty());
    CredentialsCapabilityType capCred =
        CapabilityUtil.getCapability(capabilities, CredentialsCapabilityType.class);
    assertNotNull("password capability not present", capCred.getPassword());
  }
  /**
   * Simple call to connector test() method.
   *
   * @throws Exception
   */
  @Test
  public void testTestConnection() throws Exception {
    TestUtil.displayTestTile("testTestConnection");
    // GIVEN

    OperationResult result = new OperationResult("testTestConnection");

    // WHEN

    cc.test(result);

    // THEN
    result.computeStatus("test failed");
    AssertJUnit.assertNotNull(result);
    OperationResult connectorConnectionResult = result.getSubresults().get(0);
    AssertJUnit.assertNotNull(connectorConnectionResult);
    System.out.println("Test \"connector connection\" result: " + connectorConnectionResult);
    AssertJUnit.assertTrue(connectorConnectionResult.isSuccess());
    AssertJUnit.assertTrue(result.isSuccess());
  }
  @Test
  public void test600CreateAccountWithPassword() throws Exception {
    final String TEST_NAME = "test600CreateAccountWithPassword";
    TestUtil.displayTestTile(this, TEST_NAME);
    // GIVEN
    ResourceAttributeContainer resourceObject =
        createResourceObject(
            "uid=lechuck,ou=people,dc=example,dc=com", "Ghost Pirate LeChuck", "LeChuck");

    Set<Operation> additionalOperations = new HashSet<Operation>();
    ProtectedStringType ps = protector.encryptString("t4k30v3rTh3W0rld");

    //		PasswordChangeOperation passOp = new PasswordChangeOperation(ps);
    //		additionalOperations.add(passOp);

    OperationResult addResult = new OperationResult(this.getClass().getName() + "." + TEST_NAME);

    PrismObject<ShadowType> shadow = wrapInShadow(ShadowType.class, resourceObject);
    CredentialsType credentials = new CredentialsType();
    PasswordType pass = new PasswordType();
    pass.setValue(ps);
    credentials.setPassword(pass);
    shadow.asObjectable().setCredentials(credentials);

    // WHEN
    cc.addObject(shadow, additionalOperations, addResult);

    // THEN

    String entryUuid = (String) resourceObject.getIdentifier().getValue().getValue();
    SearchResultEntry entry = openDJController.searchAndAssertByEntryUuid(entryUuid);
    display("Entry before change", entry);
    String passwordAfter = OpenDJController.getAttributeValue(entry, "userPassword");

    assertNotNull(passwordAfter);

    System.out.println("Changed password: " + passwordAfter);

    // TODO
  }
  @Test
  public void test610ChangePassword() throws Exception {
    final String TEST_NAME = "test610ChangePassword";
    TestUtil.displayTestTile(this, TEST_NAME);
    // GIVEN
    ResourceAttributeContainer resourceObject =
        createResourceObject("uid=drake,ou=People,dc=example,dc=com", "Sir Francis Drake", "Drake");
    PrismObject<ShadowType> shadow = wrapInShadow(ShadowType.class, resourceObject);

    OperationResult addResult = new OperationResult(this.getClass().getName() + "." + TEST_NAME);

    // Add a testing object
    cc.addObject(shadow, null, addResult);

    String entryUuid = (String) resourceObject.getIdentifier().getValue().getValue();
    SearchResultEntry entry = openDJController.searchAndAssertByEntryUuid(entryUuid);
    display("Entry before change", entry);
    String passwordBefore = OpenDJController.getAttributeValue(entry, "userPassword");
    // We have set no password during create, therefore the password should
    // be empty
    assertNull(passwordBefore);

    ObjectClassComplexTypeDefinition accountDefinition =
        resourceObject.getDefinition().getComplexTypeDefinition();

    Collection<ResourceAttribute<?>> identifiers = resourceObject.getIdentifiers();
    // Determine object class from the schema

    OperationResult result = new OperationResult(this.getClass().getName() + ".testFetchObject");

    // WHEN

    Set<Operation> changes = new HashSet<Operation>();
    ProtectedStringType passPs = protector.encryptString("salalala");

    ItemDeltaType propMod = new ItemDeltaType();
    // create modification path
    Document doc = DOMUtil.getDocument();
    ItemPathType path = new ItemPathType("credentials/password/value");
    //		PropertyPath propPath = new PropertyPath(new
    // PropertyPath(ResourceObjectShadowType.F_CREDENTIALS), CredentialsType.F_PASSWORD);
    propMod.setPath(path);

    // set the replace value
    MapXNode passPsXnode = prismContext.getBeanConverter().marshalProtectedDataType(passPs);
    RawType value = new RawType(passPsXnode, prismContext);
    propMod.getValue().add(value);

    // set the modificaion type
    propMod.setModificationType(ModificationTypeType.REPLACE);

    PropertyDelta passDelta =
        (PropertyDelta) DeltaConvertor.createItemDelta(propMod, shadow.getDefinition());
    PropertyModificationOperation passwordModification =
        new PropertyModificationOperation(passDelta);
    changes.add(passwordModification);

    //		PasswordChangeOperation passwordChange = new PasswordChangeOperation(passPs);
    //		changes.add(passwordChange);
    cc.modifyObject(accountDefinition, identifiers, changes, result);

    // THEN

    entry = openDJController.searchAndAssertByEntryUuid(entryUuid);
    display("Entry after change", entry);

    String passwordAfter = OpenDJController.getAttributeValue(entry, "userPassword");
    assertNotNull(passwordAfter);

    System.out.println("Account password: " + passwordAfter);
  }