/*
* Copyright (c) 2010-2017 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.evolveum.midpoint.provisioning.ucf.impl.connid;
import static com.evolveum.midpoint.test.IntegrationTestTools.display;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertFalse;
import static org.testng.AssertJUnit.assertNotNull;
import static org.testng.AssertJUnit.assertTrue;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import javax.xml.namespace.QName;
import com.evolveum.midpoint.prism.schema.PrismSchemaImpl;
import com.evolveum.midpoint.schema.processor.*;
import org.springframework.test.context.ContextConfiguration;
import org.testng.AssertJUnit;
import org.testng.annotations.Test;
import org.w3c.dom.Document;
import com.evolveum.icf.dummy.connector.DummyConnector;
import com.evolveum.icf.dummy.resource.DummyAccount;
import com.evolveum.icf.dummy.resource.DummySyncStyle;
import com.evolveum.midpoint.prism.Item;
import com.evolveum.midpoint.prism.PrismContainer;
import com.evolveum.midpoint.prism.PrismContainerDefinition;
import com.evolveum.midpoint.prism.PrismContainerValue;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.PrismObjectDefinition;
import com.evolveum.midpoint.prism.PrismProperty;
import com.evolveum.midpoint.prism.PrismPropertyDefinition;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.prism.schema.PrismSchema;
import com.evolveum.midpoint.prism.schema.SchemaRegistry;
import com.evolveum.midpoint.prism.util.PrismAsserts;
import com.evolveum.midpoint.prism.util.PrismTestUtil;
import com.evolveum.midpoint.provisioning.ucf.api.Change;
import com.evolveum.midpoint.provisioning.ucf.api.ConnectorInstance;
import com.evolveum.midpoint.provisioning.ucf.api.ResultHandler;
import com.evolveum.midpoint.schema.SchemaConstantsGenerated;
import com.evolveum.midpoint.schema.constants.MidPointConstants;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.statistics.ConnectorOperationalStatus;
import com.evolveum.midpoint.schema.util.ObjectTypeUtil;
import com.evolveum.midpoint.schema.util.ResourceTypeUtil;
import com.evolveum.midpoint.schema.util.ShadowUtil;
import com.evolveum.midpoint.test.IntegrationTestTools;
import com.evolveum.midpoint.test.util.TestUtil;
import com.evolveum.midpoint.util.DOMUtil;
import com.evolveum.midpoint.util.exception.CommunicationException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ConnectorConfigurationType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ConnectorType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowKindType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType;
import com.evolveum.prism.xml.ns._public.types_3.PolyStringType;
/**
* Simple UCF tests. No real resource, just basic setup and sanity.
*
* @author Radovan Semancik
*
* This is an UCF test. It shold not need repository or other things from the midPoint spring context
* except from the provisioning beans. But due to a general issue with spring context initialization
* this is a lesser evil for now (MID-392)
*/
@ContextConfiguration(locations = { "classpath:ctx-ucf-connid-test.xml" })
public class TestUcfDummy extends AbstractUcfDummyTest {
private static Trace LOGGER = TraceManager.getTrace(TestUcfDummy.class);
@Test
public void test000PrismContextSanity() throws Exception {
final String TEST_NAME = "test000PrismContextSanity";
TestUtil.displayTestTile(TEST_NAME);
SchemaRegistry schemaRegistry = PrismTestUtil.getPrismContext().getSchemaRegistry();
PrismSchema schemaIcfc = schemaRegistry.findSchemaByNamespace(SchemaConstants.NS_ICF_CONFIGURATION);
assertNotNull("ICFC schema not found in the context ("+SchemaConstants.NS_ICF_CONFIGURATION+")", schemaIcfc);
PrismContainerDefinition<ConnectorConfigurationType> configurationPropertiesDef =
schemaIcfc.findContainerDefinitionByElementName(SchemaConstants.CONNECTOR_SCHEMA_CONFIGURATION_PROPERTIES_ELEMENT_QNAME);
assertNotNull("icfc:configurationProperties not found in icfc schema ("+
SchemaConstants.CONNECTOR_SCHEMA_CONFIGURATION_PROPERTIES_ELEMENT_QNAME+")", configurationPropertiesDef);
PrismSchema schemaIcfs = schemaRegistry.findSchemaByNamespace(SchemaConstants.NS_ICF_SCHEMA);
assertNotNull("ICFS schema not found in the context ("+SchemaConstants.NS_ICF_SCHEMA+")", schemaIcfs);
}
@Test
public void test001ResourceSanity() throws Exception {
final String TEST_NAME = "test001ResourceSanity";
TestUtil.displayTestTile(TEST_NAME);
display("Resource", resource);
assertEquals("Wrong oid", "ef2bc95b-76e0-59e2-86d6-9999dddddddd", resource.getOid());
// assertEquals("Wrong version", "42", resource.getVersion());
PrismObjectDefinition<ResourceType> resourceDefinition = resource.getDefinition();
assertNotNull("No resource definition", resourceDefinition);
PrismAsserts.assertObjectDefinition(resourceDefinition, new QName(SchemaConstantsGenerated.NS_COMMON, "resource"),
ResourceType.COMPLEX_TYPE, ResourceType.class);
assertEquals("Wrong class in resource", ResourceType.class, resource.getCompileTimeClass());
ResourceType resourceType = resource.asObjectable();
assertNotNull("asObjectable resulted in null", resourceType);
assertPropertyValue(resource, "name", PrismTestUtil.createPolyString("Dummy Resource"));
assertPropertyDefinition(resource, "name", PolyStringType.COMPLEX_TYPE, 0, 1);
PrismContainer<?> configurationContainer = resource.findContainer(ResourceType.F_CONNECTOR_CONFIGURATION);
assertContainerDefinition(configurationContainer, "configuration", ConnectorConfigurationType.COMPLEX_TYPE, 1, 1);
PrismContainerValue<?> configContainerValue = configurationContainer.getValue();
List<Item<?,?>> configItems = configContainerValue.getItems();
assertEquals("Wrong number of config items", 2, configItems.size());
PrismContainer<?> dummyConfigPropertiesContainer = configurationContainer.findContainer(
SchemaConstants.CONNECTOR_SCHEMA_CONFIGURATION_PROPERTIES_ELEMENT_QNAME);
assertNotNull("No icfc:configurationProperties container", dummyConfigPropertiesContainer);
List<Item<?,?>> dummyConfigPropItems = dummyConfigPropertiesContainer.getValue().getItems();
assertEquals("Wrong number of dummy ConfigPropItems items", 4, dummyConfigPropItems.size());
}
@Test
public void test002ConnectorSchema() throws Exception {
final String TEST_NAME = "test002ConnectorSchema";
TestUtil.displayTestTile(TEST_NAME);
PrismSchema connectorSchema = connectorFactory.generateConnectorConfigurationSchema(connectorType);
IntegrationTestTools.assertConnectorSchemaSanity(connectorSchema, "generated", true);
assertEquals("Unexpected number of definitions", 3, connectorSchema.getDefinitions().size());
Document xsdSchemaDom = connectorSchema.serializeToXsd();
assertNotNull("No serialized connector schema", xsdSchemaDom);
display("Serialized XSD connector schema", DOMUtil.serializeDOMToString(xsdSchemaDom));
// Try to re-parse
PrismSchema reparsedConnectorSchema = PrismSchemaImpl.parse(DOMUtil.getFirstChildElement(xsdSchemaDom), true, "schema fetched from "+cc, PrismTestUtil.getPrismContext());
IntegrationTestTools.assertConnectorSchemaSanity(reparsedConnectorSchema, "re-parsed", true);
// TODO: 3 definitions would be cleaner. But we can live with this
assertEquals("Unexpected number of definitions in re-parsed schema", 6, reparsedConnectorSchema.getDefinitions().size());
}
/**
* Test listing connectors. Very simple. Just test that the list is
* non-empty and that there are mandatory values filled in.
* @throws CommunicationException
*/
@Test
public void test010ListConnectors() throws Exception {
final String TEST_NAME = "test010ListConnectors";
TestUtil.displayTestTile(TEST_NAME);
OperationResult result = new OperationResult(TestUcfDummy.class+"."+TEST_NAME);
Set<ConnectorType> connectors = connectorFactory.listConnectors(null, result);
System.out.println("---------------------------------------------------------------------");
assertNotNull(connectors);
assertFalse(connectors.isEmpty());
for (ConnectorType connector : connectors) {
assertNotNull(connector.getName());
System.out.println("CONNECTOR OID=" + connector.getOid() + ", name=" + connector.getName() + ", version="
+ connector.getConnectorVersion());
System.out.println("--");
System.out.println(ObjectTypeUtil.dump(connector));
System.out.println("--");
}
System.out.println("---------------------------------------------------------------------");
assertEquals("Unexpected number of connectors discovered", 6, connectors.size());
}
@Test
public void test020CreateConfiguredConnector() throws Exception {
final String TEST_NAME = "test020CreateConfiguredConnector";
TestUtil.displayTestTile(TEST_NAME);
cc = connectorFactory.createConnectorInstance(connectorType, ResourceTypeUtil.getResourceNamespace(resourceType),
"test connector");
assertNotNull("Failed to instantiate connector", cc);
OperationResult result = new OperationResult(TestUcfDummy.class.getName() + "." + TEST_NAME);
PrismContainerValue<ConnectorConfigurationType> configContainer = resourceType.getConnectorConfiguration().asPrismContainerValue();
display("Configuration container", configContainer);
// WHEN
cc.configure(configContainer, result);
// THEN
result.computeStatus();
TestUtil.assertSuccess(result);
}
@Test
public void test022ConnectorStatsConfigured() throws Exception {
final String TEST_NAME = "test022ConnectorStatsConfigured";
TestUtil.displayTestTile(TEST_NAME);
// WHEN
ConnectorOperationalStatus operationalStatus = cc.getOperationalStatus();
// THEN
display("Connector operational status", operationalStatus);
assertNotNull("null operational status", operationalStatus);
assertEquals("Wrong connectorClassName", DummyConnector.class.getName(), operationalStatus.getConnectorClassName());
assertEquals("Wrong poolConfigMinSize", null, operationalStatus.getPoolConfigMinSize());
assertEquals("Wrong poolConfigMaxSize", (Integer)10, operationalStatus.getPoolConfigMaxSize());
assertEquals("Wrong poolConfigMinIdle", (Integer)1, operationalStatus.getPoolConfigMinIdle());
assertEquals("Wrong poolConfigMaxIdle", (Integer)10, operationalStatus.getPoolConfigMaxIdle());
assertEquals("Wrong poolConfigWaitTimeout", (Long)150000L, operationalStatus.getPoolConfigWaitTimeout());
assertEquals("Wrong poolConfigMinEvictableIdleTime", (Long)120000L, operationalStatus.getPoolConfigMinEvictableIdleTime());
assertEquals("Wrong poolStatusNumIdle", (Integer)0, operationalStatus.getPoolStatusNumIdle());
assertEquals("Wrong poolStatusNumActive", (Integer)0, operationalStatus.getPoolStatusNumActive());
}
@Test
public void test030ResourceSchema() throws Exception {
final String TEST_NAME = "test030ResourceSchema";
TestUtil.displayTestTile(TEST_NAME);
OperationResult result = new OperationResult(TestUcfDummy.class + "." + TEST_NAME);
cc = connectorFactory.createConnectorInstance(connectorType, ResourceTypeUtil.getResourceNamespace(resourceType),
"test connector");
assertNotNull("Failed to instantiate connector", cc);
PrismContainerValue<ConnectorConfigurationType> configContainer = resourceType.getConnectorConfiguration().asPrismContainerValue();
display("Configuration container", configContainer);
cc.configure(configContainer, result);
// WHEN
resourceSchema = cc.fetchResourceSchema(null, result);
// THEN
display("Generated resource schema", resourceSchema);
assertEquals("Unexpected number of definitions", 4, resourceSchema.getDefinitions().size());
dummyResourceCtl.assertDummyResourceSchemaSanityExtended(resourceSchema, resourceType);
Document xsdSchemaDom = resourceSchema.serializeToXsd();
assertNotNull("No serialized resource schema", xsdSchemaDom);
display("Serialized XSD resource schema", DOMUtil.serializeDOMToString(xsdSchemaDom));
// Try to re-parse
ResourceSchema reparsedResourceSchema = ResourceSchemaImpl.parse(DOMUtil.getFirstChildElement(xsdSchemaDom),
"serialized schema", PrismTestUtil.getPrismContext());
display("Re-parsed resource schema", reparsedResourceSchema);
assertEquals("Unexpected number of definitions in re-parsed schema", 4, reparsedResourceSchema.getDefinitions().size());
dummyResourceCtl.assertDummyResourceSchemaSanityExtended(reparsedResourceSchema, resourceType);
}
@Test
public void test031ResourceSchemaAccountObjectClass() throws Exception {
final String TEST_NAME = "test031ResourceSchemaAccountObjectClass";
TestUtil.displayTestTile(TEST_NAME);
OperationResult result = new OperationResult(TestUcfDummy.class + "." + TEST_NAME);
cc = connectorFactory.createConnectorInstance(connectorType, ResourceTypeUtil.getResourceNamespace(resourceType), "test connector");
assertNotNull("Failed to instantiate connector", cc);
PrismContainerValue<ConnectorConfigurationType> configContainer = resourceType.getConnectorConfiguration().asPrismContainerValue();
display("Configuration container", configContainer);
cc.configure(configContainer, result);
List<QName> objectClassesToGenerate = new ArrayList<QName>();
QName accountObjectClass = new QName(resource.asObjectable().getNamespace(), "AccountObjectClass");
objectClassesToGenerate.add(accountObjectClass);
// WHEN
resourceSchema = cc.fetchResourceSchema(objectClassesToGenerate, result);
// THEN
display("Generated resource schema", resourceSchema);
assertEquals("Unexpected number of definitions", 1, resourceSchema.getDefinitions().size());
assertEquals("Unexpected number of object class definitions", 1, resourceSchema.getObjectClassDefinitions().size());
display("RESOURCE SCHEMA DEFINITION" + resourceSchema.getDefinitions().iterator().next().getTypeName());
}
@Test
public void test033ConnectorStatsInitialized() throws Exception {
final String TEST_NAME = "test033ConnectorStatsInitialized";
TestUtil.displayTestTile(TEST_NAME);
// WHEN
ConnectorOperationalStatus operationalStatus = cc.getOperationalStatus();
// THEN
display("Connector operational status", operationalStatus);
assertNotNull("null operational status", operationalStatus);
assertEquals("Wrong connectorClassName", DummyConnector.class.getName(), operationalStatus.getConnectorClassName());
assertEquals("Wrong poolConfigMinSize", null, operationalStatus.getPoolConfigMinSize());
assertEquals("Wrong poolConfigMaxSize", (Integer)10, operationalStatus.getPoolConfigMaxSize());
assertEquals("Wrong poolConfigMinIdle", (Integer)1, operationalStatus.getPoolConfigMinIdle());
assertEquals("Wrong poolConfigMaxIdle", (Integer)10, operationalStatus.getPoolConfigMaxIdle());
assertEquals("Wrong poolConfigWaitTimeout", (Long)150000L, operationalStatus.getPoolConfigWaitTimeout());
assertEquals("Wrong poolConfigMinEvictableIdleTime", (Long)120000L, operationalStatus.getPoolConfigMinEvictableIdleTime());
assertEquals("Wrong poolStatusNumIdle", (Integer)1, operationalStatus.getPoolStatusNumIdle());
assertEquals("Wrong poolStatusNumActive", (Integer)0, operationalStatus.getPoolStatusNumActive());
}
@Test
public void test040AddAccount() throws Exception {
final String TEST_NAME = "test040AddAccount";
TestUtil.displayTestTile(this, TEST_NAME);
OperationResult result = new OperationResult(this.getClass().getName() + "." + TEST_NAME);
ObjectClassComplexTypeDefinition defaultAccountDefinition = resourceSchema.findDefaultObjectClassDefinition(ShadowKindType.ACCOUNT);
ShadowType shadowType = new ShadowType();
PrismTestUtil.getPrismContext().adopt(shadowType);
shadowType.setName(PrismTestUtil.createPolyStringType(ACCOUNT_JACK_USERNAME));
ObjectReferenceType resourceRef = new ObjectReferenceType();
resourceRef.setOid(resource.getOid());
shadowType.setResourceRef(resourceRef);
shadowType.setObjectClass(defaultAccountDefinition.getTypeName());
PrismObject<ShadowType> shadow = shadowType.asPrismObject();
ResourceAttributeContainer attributesContainer = ShadowUtil.getOrCreateAttributesContainer(shadow, defaultAccountDefinition);
ResourceAttribute<String> icfsNameProp = attributesContainer.findOrCreateAttribute(SchemaConstants.ICFS_NAME);
icfsNameProp.setRealValue(ACCOUNT_JACK_USERNAME);
// WHEN
cc.addObject(shadow, null, null, result);
// THEN
DummyAccount dummyAccount = dummyResource.getAccountByUsername(ACCOUNT_JACK_USERNAME);
assertNotNull("Account "+ACCOUNT_JACK_USERNAME+" was not created", dummyAccount);
assertNotNull("Account "+ACCOUNT_JACK_USERNAME+" has no username", dummyAccount.getName());
}
@Test
public void test050Search() throws Exception {
final String TEST_NAME = "test050Search";
TestUtil.displayTestTile(TEST_NAME);
// GIVEN
final ObjectClassComplexTypeDefinition accountDefinition = resourceSchema.findDefaultObjectClassDefinition(ShadowKindType.ACCOUNT);
// Determine object class from the schema
final List<PrismObject<ShadowType>> searchResults = new ArrayList<PrismObject<ShadowType>>();
ResultHandler<ShadowType> handler = new ResultHandler<ShadowType>() {
@Override
public boolean handle(PrismObject<ShadowType> shadow) {
display("Search: found", shadow);
checkUcfShadow(shadow, accountDefinition);
searchResults.add(shadow);
return true;
}
};
OperationResult result = new OperationResult(this.getClass().getName() + "." + TEST_NAME);
// WHEN
cc.search(accountDefinition, new ObjectQuery(), handler, null, null, null, null, result);
// THEN
assertEquals("Unexpected number of search results", 1, searchResults.size());
}
private void checkUcfShadow(PrismObject<ShadowType> shadow, ObjectClassComplexTypeDefinition objectClassDefinition) {
assertNotNull("No objectClass in shadow "+shadow, shadow.asObjectable().getObjectClass());
assertEquals("Wrong objectClass in shadow "+shadow, objectClassDefinition.getTypeName(), shadow.asObjectable().getObjectClass());
Collection<ResourceAttribute<?>> attributes = ShadowUtil.getAttributes(shadow);
assertNotNull("No attributes in shadow "+shadow, attributes);
assertFalse("Empty attributes in shadow "+shadow, attributes.isEmpty());
}
@Test
public void test100FetchEmptyChanges() throws Exception {
final String TEST_NAME = "test100FetchEmptyChanges";
TestUtil.displayTestTile(this, TEST_NAME);
OperationResult result = new OperationResult(this.getClass().getName() + "." + TEST_NAME);
ObjectClassComplexTypeDefinition accountDefinition = resourceSchema.findDefaultObjectClassDefinition(ShadowKindType.ACCOUNT);
// WHEN
PrismProperty<Integer> lastToken = cc.fetchCurrentToken(accountDefinition, null, result);
assertNotNull("No last sync token", lastToken);
System.out.println("Property:");
System.out.println(lastToken.debugDump());
PrismPropertyDefinition<Integer> lastTokenDef = lastToken.getDefinition();
assertNotNull("No last sync token definition", lastTokenDef);
assertEquals("Last sync token definition has wrong type", DOMUtil.XSD_INT, lastTokenDef.getTypeName());
assertTrue("Last sync token definition is NOT dynamic", lastTokenDef.isDynamic());
// WHEN
List<Change> changes = cc.fetchChanges(accountDefinition, lastToken, null, null, result);
AssertJUnit.assertEquals(0, changes.size());
}
@Test
public void test101FetchAddChange() throws Exception {
final String TEST_NAME = "test101FetchAddChange";
TestUtil.displayTestTile(this, TEST_NAME);
OperationResult result = new OperationResult(this.getClass().getName() + "." + TEST_NAME);
ObjectClassComplexTypeDefinition accountDefinition = resourceSchema.findDefaultObjectClassDefinition(ShadowKindType.ACCOUNT);
PrismProperty<?> lastToken = cc.fetchCurrentToken(accountDefinition, null, result);
assertNotNull("No last sync token", lastToken);
// Add account to the resource
dummyResource.setSyncStyle(DummySyncStyle.DUMB);
DummyAccount newAccount = new DummyAccount("blackbeard");
newAccount.addAttributeValues("fullname", "Edward Teach");
newAccount.setEnabled(true);
newAccount.setPassword("shiverMEtimbers");
dummyResource.addAccount(newAccount);
// WHEN
List<Change> changes = cc.fetchChanges(accountDefinition, lastToken, null, null, result);
AssertJUnit.assertEquals(1, changes.size());
Change change = changes.get(0);
assertNotNull("null change", change);
PrismObject<ShadowType> currentShadow = change.getCurrentShadow();
assertNotNull("null current shadow", currentShadow);
PrismAsserts.assertParentConsistency(currentShadow);
Collection<ResourceAttribute<?>> identifiers = change.getIdentifiers();
assertNotNull("null identifiers", identifiers);
assertFalse("empty identifiers", identifiers.isEmpty());
}
@Test
public void test500SelfTest() throws Exception {
final String TEST_NAME = "test500SelfTest";
TestUtil.displayTestTile(this, TEST_NAME);
// GIVEN
OperationResult testResult = new OperationResult(TestUcfDummy.class + "." + TEST_NAME);
// WHEN
connectorFactoryIcfImpl.selfTest(testResult);
// THEN
testResult.computeStatus();
IntegrationTestTools.display(testResult);
TestUtil.assertSuccess(testResult);
}
}