You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2016/01/26 13:04:51 UTC

[20/21] syncope git commit: [SYNCOPE-152] Moving console IT under fit/core-reference in order to speed-up the total build time

http://git-wip-us.apache.org/repos/asf/syncope/blob/17d5d892/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
new file mode 100644
index 0000000..27db9db
--- /dev/null
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
@@ -0,0 +1,454 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.syncope.fit;
+
+import static org.junit.Assert.assertNotNull;
+
+import java.io.InputStream;
+import java.net.URI;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+import java.util.UUID;
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.directory.InitialDirContext;
+import javax.sql.DataSource;
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.Response;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.client.lib.SyncopeClientFactoryBean;
+import org.apache.syncope.common.lib.patch.AnyObjectPatch;
+import org.apache.syncope.common.lib.patch.AttrPatch;
+import org.apache.syncope.common.lib.patch.GroupPatch;
+import org.apache.syncope.common.lib.patch.UserPatch;
+import org.apache.syncope.common.lib.policy.AbstractPolicyTO;
+import org.apache.syncope.common.lib.to.AbstractSchemaTO;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.ResourceTO;
+import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.syncope.common.lib.to.ProvisioningResult;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.ConnConfProperty;
+import org.apache.syncope.common.lib.types.PatchOperation;
+import org.apache.syncope.common.lib.types.SchemaType;
+import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.common.rest.api.service.AnyObjectService;
+import org.apache.syncope.common.rest.api.service.AnyTypeClassService;
+import org.apache.syncope.common.rest.api.service.AnyTypeService;
+import org.apache.syncope.common.rest.api.service.CamelRouteService;
+import org.apache.syncope.common.rest.api.service.ConfigurationService;
+import org.apache.syncope.common.rest.api.service.ConnectorService;
+import org.apache.syncope.common.rest.api.service.DomainService;
+import org.apache.syncope.common.rest.api.service.LoggerService;
+import org.apache.syncope.common.rest.api.service.NotificationService;
+import org.apache.syncope.common.rest.api.service.PolicyService;
+import org.apache.syncope.common.rest.api.service.ReportService;
+import org.apache.syncope.common.rest.api.service.ResourceService;
+import org.apache.syncope.common.rest.api.service.GroupService;
+import org.apache.syncope.common.rest.api.service.RealmService;
+import org.apache.syncope.common.rest.api.service.RelationshipTypeService;
+import org.apache.syncope.common.rest.api.service.RoleService;
+import org.apache.syncope.common.rest.api.service.SchemaService;
+import org.apache.syncope.common.rest.api.service.SecurityQuestionService;
+import org.apache.syncope.common.rest.api.service.SyncopeService;
+import org.apache.syncope.common.rest.api.service.TaskService;
+import org.apache.syncope.common.rest.api.service.UserSelfService;
+import org.apache.syncope.common.rest.api.service.UserService;
+import org.apache.syncope.common.rest.api.service.UserWorkflowService;
+import org.apache.syncope.common.rest.api.service.WorkflowService;
+import org.identityconnectors.common.security.Encryptor;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(locations = { "classpath:testJDBCContext.xml" })
+public abstract class AbstractITCase {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(AbstractITCase.class);
+
+    protected static final String ADMIN_UNAME = "admin";
+
+    protected static final String ADMIN_PWD = "password";
+
+    protected static final String ADDRESS = "http://localhost:9080/syncope/rest";
+
+    protected static final String ENV_KEY_CONTENT_TYPE = "jaxrsContentType";
+
+    protected static final String RESOURCE_NAME_WS1 = "ws-target-resource-1";
+
+    protected static final String RESOURCE_NAME_WS2 = "ws-target-resource-2";
+
+    protected static final String RESOURCE_NAME_LDAP = "resource-ldap";
+
+    protected static final String RESOURCE_NAME_TESTDB = "resource-testdb";
+
+    protected static final String RESOURCE_NAME_TESTDB2 = "resource-testdb2";
+
+    protected static final String RESOURCE_NAME_CSV = "resource-csv";
+
+    protected static final String RESOURCE_NAME_DBSYNC = "resource-db-sync";
+
+    protected static final String RESOURCE_NAME_DBVIRATTR = "resource-db-virattr";
+
+    protected static final String RESOURCE_NAME_NOPROPAGATION = "ws-target-resource-nopropagation";
+
+    protected static final String RESOURCE_NAME_NOPROPAGATION2 = "ws-target-resource-nopropagation2";
+
+    protected static final String RESOURCE_NAME_NOPROPAGATION3 = "ws-target-resource-nopropagation3";
+
+    protected static final String RESOURCE_NAME_NOPROPAGATION4 = "ws-target-resource-nopropagation4";
+
+    protected static final String RESOURCE_NAME_RESETSYNCTOKEN = "ws-target-resource-update-resetsynctoken";
+
+    protected static final String RESOURCE_NAME_TIMEOUT = "ws-target-resource-timeout";
+
+    protected static final String RESOURCE_NAME_MAPPINGS1 = "ws-target-resource-list-mappings-1";
+
+    protected static final String RESOURCE_NAME_MAPPINGS2 = "ws-target-resource-list-mappings-2";
+
+    protected static final String RESOURCE_NAME_CREATE = "ws-target-resource-create";
+
+    protected static final String RESOURCE_NAME_CREATE_SINGLE = "ws-target-resource-create-single";
+
+    protected static final String RESOURCE_NAME_CREATE_WRONG = "ws-target-resource-create-wrong";
+
+    protected static final String RESOURCE_NAME_DELETE = "ws-target-resource-delete";
+
+    protected static final String RESOURCE_NAME_UPDATE = "ws-target-resource-update";
+
+    protected static final String RESOURCE_NAME_CREATE_NONE = "ws-target-resource-create-none";
+
+    protected static final String RESOURCE_NAME_DBSCRIPTED = "resource-db-scripted";
+
+    protected static String ANONYMOUS_UNAME;
+
+    protected static String ANONYMOUS_KEY;
+
+    protected static SyncopeClientFactoryBean clientFactory;
+
+    protected static SyncopeClient adminClient;
+
+    protected static SyncopeService syncopeService;
+
+    protected static DomainService domainService;
+
+    protected static AnyTypeClassService anyTypeClassService;
+
+    protected static AnyTypeService anyTypeService;
+
+    protected static RelationshipTypeService relationshipTypeService;
+
+    protected static RealmService realmService;
+
+    protected static AnyObjectService anyObjectService;
+
+    protected static RoleService roleService;
+
+    protected static UserService userService;
+
+    protected static UserSelfService userSelfService;
+
+    protected static UserWorkflowService userWorkflowService;
+
+    protected static GroupService groupService;
+
+    protected static ResourceService resourceService;
+
+    protected static ConfigurationService configurationService;
+
+    protected static ConnectorService connectorService;
+
+    protected static LoggerService loggerService;
+
+    protected static ReportService reportService;
+
+    protected static TaskService taskService;
+
+    protected static WorkflowService workflowService;
+
+    protected static NotificationService notificationService;
+
+    protected static SchemaService schemaService;
+
+    protected static PolicyService policyService;
+
+    protected static SecurityQuestionService securityQuestionService;
+
+    protected static CamelRouteService camelRouteService;
+
+    @Autowired
+    protected DataSource testDataSource;
+
+    @BeforeClass
+    public static void securitySetup() {
+        InputStream propStream = null;
+        try {
+            propStream = Encryptor.class.getResourceAsStream("/security.properties");
+            Properties props = new Properties();
+            props.load(propStream);
+
+            ANONYMOUS_UNAME = props.getProperty("anonymousUser");
+            ANONYMOUS_KEY = props.getProperty("anonymousKey");
+        } catch (Exception e) {
+            LOG.error("Could not read secretKey", e);
+        } finally {
+            IOUtils.closeQuietly(propStream);
+        }
+
+        assertNotNull(ANONYMOUS_UNAME);
+        assertNotNull(ANONYMOUS_KEY);
+    }
+
+    @BeforeClass
+    public static void restSetup() {
+        clientFactory = new SyncopeClientFactoryBean().setAddress(ADDRESS);
+
+        String envContentType = System.getProperty(ENV_KEY_CONTENT_TYPE);
+        if (StringUtils.isNotBlank(envContentType)) {
+            clientFactory.setContentType(envContentType);
+        }
+        LOG.info("Performing IT with content type {}", clientFactory.getContentType().getMediaType());
+
+        adminClient = clientFactory.create(ADMIN_UNAME, ADMIN_PWD);
+
+        syncopeService = adminClient.getService(SyncopeService.class);
+        domainService = adminClient.getService(DomainService.class);
+        anyTypeClassService = adminClient.getService(AnyTypeClassService.class);
+        anyTypeService = adminClient.getService(AnyTypeService.class);
+        relationshipTypeService = adminClient.getService(RelationshipTypeService.class);
+        realmService = adminClient.getService(RealmService.class);
+        anyObjectService = adminClient.getService(AnyObjectService.class);
+        roleService = adminClient.getService(RoleService.class);
+        userService = adminClient.getService(UserService.class);
+        userSelfService = adminClient.getService(UserSelfService.class);
+        userWorkflowService = adminClient.getService(UserWorkflowService.class);
+        groupService = adminClient.getService(GroupService.class);
+        resourceService = adminClient.getService(ResourceService.class);
+        configurationService = adminClient.getService(ConfigurationService.class);
+        connectorService = adminClient.getService(ConnectorService.class);
+        loggerService = adminClient.getService(LoggerService.class);
+        reportService = adminClient.getService(ReportService.class);
+        taskService = adminClient.getService(TaskService.class);
+        policyService = adminClient.getService(PolicyService.class);
+        workflowService = adminClient.getService(WorkflowService.class);
+        notificationService = adminClient.getService(NotificationService.class);
+        schemaService = adminClient.getService(SchemaService.class);
+        securityQuestionService = adminClient.getService(SecurityQuestionService.class);
+        camelRouteService = adminClient.getService(CamelRouteService.class);
+    }
+
+    protected static String getUUIDString() {
+        return UUID.randomUUID().toString().substring(0, 8);
+    }
+
+    protected static AttrTO attrTO(final String schema, final String value) {
+        return new AttrTO.Builder().schema(schema).value(value).build();
+    }
+
+    protected static AttrPatch attrAddReplacePatch(final String schema, final String value) {
+        return new AttrPatch.Builder().operation(PatchOperation.ADD_REPLACE).attrTO(attrTO(schema, value)).build();
+    }
+
+    public <T> T getObject(final URI location, final Class<?> serviceClass, final Class<T> resultClass) {
+        WebClient webClient = WebClient.fromClient(WebClient.client(adminClient.getService(serviceClass)));
+        webClient.accept(clientFactory.getContentType().getMediaType()).to(location.toASCIIString(), false);
+
+        return webClient.get(resultClass);
+    }
+
+    @SuppressWarnings("unchecked")
+    protected <T extends AbstractSchemaTO> T createSchema(final SchemaType type, final T schemaTO) {
+        Response response = schemaService.create(type, schemaTO);
+        if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
+            Exception ex = clientFactory.getExceptionMapper().fromResponse(response);
+            if (ex != null) {
+                throw (RuntimeException) ex;
+            }
+        }
+
+        return (T) getObject(response.getLocation(), SchemaService.class, schemaTO.getClass());
+    }
+
+    protected RoleTO createRole(final RoleTO roleTO) {
+        Response response = roleService.create(roleTO);
+        if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
+            Exception ex = clientFactory.getExceptionMapper().fromResponse(response);
+            if (ex != null) {
+                throw (RuntimeException) ex;
+            }
+        }
+        return getObject(response.getLocation(), RoleService.class, RoleTO.class);
+    }
+
+    protected UserTO readUser(final String username) {
+        return userService.read(Long.valueOf(userService.getUserKey(username).getHeaderString(RESTHeaders.USER_KEY)));
+    }
+
+    protected ProvisioningResult<UserTO> createUser(final UserTO userTO) {
+        return createUser(userTO, true);
+    }
+
+    protected ProvisioningResult<UserTO> createUser(final UserTO userTO, final boolean storePassword) {
+        Response response = userService.create(userTO, storePassword);
+        if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
+            Exception ex = clientFactory.getExceptionMapper().fromResponse(response);
+            if (ex != null) {
+                throw (RuntimeException) ex;
+            }
+        }
+        return response.readEntity(new GenericType<ProvisioningResult<UserTO>>() {
+        });
+    }
+
+    protected ProvisioningResult<UserTO> updateUser(final UserPatch userPatch) {
+        return userService.update(userPatch).
+                readEntity(new GenericType<ProvisioningResult<UserTO>>() {
+                });
+    }
+
+    protected ProvisioningResult<UserTO> deleteUser(final Long key) {
+        return userService.delete(key).
+                readEntity(new GenericType<ProvisioningResult<UserTO>>() {
+                });
+    }
+
+    protected ProvisioningResult<AnyObjectTO> createAnyObject(final AnyObjectTO anyObjectTO) {
+        Response response = anyObjectService.create(anyObjectTO);
+        if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
+            Exception ex = clientFactory.getExceptionMapper().fromResponse(response);
+            if (ex != null) {
+                throw (RuntimeException) ex;
+            }
+        }
+        return response.readEntity(new GenericType<ProvisioningResult<AnyObjectTO>>() {
+        });
+    }
+
+    protected ProvisioningResult<AnyObjectTO> updateAnyObject(final AnyObjectPatch anyObjectPatch) {
+        return anyObjectService.update(anyObjectPatch).
+                readEntity(new GenericType<ProvisioningResult<AnyObjectTO>>() {
+                });
+    }
+
+    protected ProvisioningResult<AnyObjectTO> deleteAnyObject(final Long key) {
+        return anyObjectService.delete(key).
+                readEntity(new GenericType<ProvisioningResult<AnyObjectTO>>() {
+                });
+    }
+
+    protected ProvisioningResult<GroupTO> createGroup(final GroupTO groupTO) {
+        Response response = groupService.create(groupTO);
+        if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
+            Exception ex = clientFactory.getExceptionMapper().fromResponse(response);
+            if (ex != null) {
+                throw (RuntimeException) ex;
+            }
+        }
+        return response.readEntity(new GenericType<ProvisioningResult<GroupTO>>() {
+        });
+    }
+
+    protected ProvisioningResult<GroupTO> updateGroup(final GroupPatch groupPatch) {
+        return groupService.update(groupPatch).
+                readEntity(new GenericType<ProvisioningResult<GroupTO>>() {
+                });
+    }
+
+    protected ProvisioningResult<GroupTO> deleteGroup(final Long key) {
+        return groupService.delete(key).
+                readEntity(new GenericType<ProvisioningResult<GroupTO>>() {
+                });
+    }
+
+    @SuppressWarnings("unchecked")
+    protected <T extends AbstractPolicyTO> T createPolicy(final T policy) {
+        Response response = policyService.create(policy);
+        if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
+            Exception ex = clientFactory.getExceptionMapper().fromResponse(response);
+            if (ex != null) {
+                throw (RuntimeException) ex;
+            }
+        }
+        return (T) getObject(response.getLocation(), PolicyService.class, policy.getClass());
+    }
+
+    protected ResourceTO createResource(final ResourceTO resourceTO) {
+        Response response = resourceService.create(resourceTO);
+        if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
+            Exception ex = clientFactory.getExceptionMapper().fromResponse(response);
+            if (ex != null) {
+                throw (RuntimeException) ex;
+            }
+        }
+        return getObject(response.getLocation(), ResourceService.class, ResourceTO.class);
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes", "UseOfObsoleteCollectionType" })
+    protected InitialDirContext getLdapResourceDirContext(final String bindDn, final String bindPwd)
+            throws NamingException {
+        ResourceTO ldapRes = resourceService.read(RESOURCE_NAME_LDAP);
+        final Map<String, ConnConfProperty> ldapConnConf =
+                connectorService.read(ldapRes.getConnector(), Locale.ENGLISH.getLanguage()).getConfMap();
+
+        Properties env = new Properties();
+        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
+        env.put(Context.PROVIDER_URL, "ldap://" + ldapConnConf.get("host").getValues().get(0)
+                + ":" + ldapConnConf.get("port").getValues().get(0) + "/");
+        env.put(Context.SECURITY_AUTHENTICATION, "simple");
+        env.put(Context.SECURITY_PRINCIPAL,
+                bindDn == null ? ldapConnConf.get("principal").getValues().get(0) : bindDn);
+        env.put(Context.SECURITY_CREDENTIALS,
+                bindPwd == null ? ldapConnConf.get("credentials").getValues().get(0) : bindPwd);
+
+        return new InitialDirContext(env);
+    }
+
+    protected Object getLdapRemoteObject(final String bindDn, final String bindPwd, final String objectDn) {
+        InitialDirContext ctx = null;
+        try {
+            ctx = getLdapResourceDirContext(bindDn, bindPwd);
+            return ctx.lookup(objectDn);
+        } catch (Exception e) {
+            return null;
+        } finally {
+            if (ctx != null) {
+                try {
+                    ctx.close();
+                } catch (NamingException e) {
+                    // ignore
+                }
+            }
+        }
+    }
+
+    protected Object getLdapRemoteObject(final String objectDn) {
+        return getLdapRemoteObject(null, null, objectDn);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17d5d892/fit/core-reference/src/test/java/org/apache/syncope/fit/ActivitiDetector.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/ActivitiDetector.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/ActivitiDetector.java
new file mode 100644
index 0000000..9a939c7
--- /dev/null
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/ActivitiDetector.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.syncope.fit;
+
+import org.apache.syncope.common.rest.api.service.SyncopeService;
+
+public class ActivitiDetector {
+
+    public static boolean isActivitiEnabledForUsers(final SyncopeService syncopeService) {
+        return syncopeService.info().getUserWorkflowAdapter().contains("Activiti");
+    }
+
+    public static boolean isActivitiEnabledForGroups(final SyncopeService syncopeService) {
+        return syncopeService.info().getGroupWorkflowAdapter().contains("Activiti");
+    }
+
+    public static boolean isActivitiEnabledForAnyObjects(final SyncopeService syncopeService) {
+        return syncopeService.info().getAnyObjectWorkflowAdapter().contains("Activiti");
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17d5d892/fit/core-reference/src/test/java/org/apache/syncope/fit/CamelDetector.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/CamelDetector.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/CamelDetector.java
new file mode 100644
index 0000000..5f9a81c
--- /dev/null
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/CamelDetector.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.syncope.fit;
+
+import org.apache.syncope.common.rest.api.service.SyncopeService;
+
+public class CamelDetector {
+
+    public static boolean isCamelEnabledForUsers(final SyncopeService syncopeService) {
+        return syncopeService.info().getUserProvisioningManager().contains("Camel");
+    }
+
+    public static boolean isCamelEnabledForGroups(final SyncopeService syncopeService) {
+        return syncopeService.info().getGroupProvisioningManager().contains("Camel");
+    }
+
+    public static boolean isCamelEnabledForAnyObjects(final SyncopeService syncopeService) {
+        return syncopeService.info().getAnyObjectProvisioningManager().contains("Camel");
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17d5d892/fit/core-reference/src/test/java/org/apache/syncope/fit/cli/CLIITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/cli/CLIITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/cli/CLIITCase.java
new file mode 100644
index 0000000..33e3ad3
--- /dev/null
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/cli/CLIITCase.java
@@ -0,0 +1,278 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.syncope.fit.cli;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.SystemUtils;
+import org.apache.syncope.client.cli.Command;
+import org.apache.syncope.client.cli.commands.connector.ConnectorCommand;
+import org.apache.syncope.client.cli.commands.entitlement.EntitlementCommand;
+import org.apache.syncope.client.cli.commands.group.GroupCommand;
+import org.apache.syncope.client.cli.commands.install.InstallCommand;
+import org.apache.syncope.client.cli.commands.policy.PolicyCommand;
+import org.apache.syncope.client.cli.commands.report.ReportCommand;
+import org.apache.syncope.client.cli.commands.role.RoleCommand;
+import org.apache.syncope.client.cli.commands.user.UserCommand;
+import org.apache.syncope.fit.AbstractITCase;
+import org.apache.syncope.fit.core.ExceptionMapperITCase;
+import org.junit.BeforeClass;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+@FixMethodOrder(MethodSorters.JVM)
+public class CLIITCase extends AbstractITCase {
+
+    private static final String SCRIPT_FILENAME = "syncopeadm";
+
+    private static ProcessBuilder PROCESS_BUILDER;
+
+    @BeforeClass
+    public static void install() {
+        Properties props = new Properties();
+        InputStream propStream = null;
+        try {
+            propStream = ExceptionMapperITCase.class.getResourceAsStream("/cli-test.properties");
+            props.load(propStream);
+
+            File workDir = new File(props.getProperty("cli-work.dir"));
+            PROCESS_BUILDER = new ProcessBuilder();
+            PROCESS_BUILDER.directory(workDir);
+
+            PROCESS_BUILDER.command(getCommand(
+                    new InstallCommand().getClass().getAnnotation(Command.class).name(),
+                    InstallCommand.Options.SETUP_DEBUG.getOptionName()));
+            Process process = PROCESS_BUILDER.start();
+            process.waitFor();
+
+            File cliPropertiesFile = new File(workDir + File.separator + "cli.properties");
+            assertTrue(cliPropertiesFile.exists());
+        } catch (IOException | InterruptedException e) {
+            fail(e.getMessage());
+        } finally {
+            IOUtils.closeQuietly(propStream);
+        }
+    }
+
+    private static String[] getCommand(final String... arguments) {
+        List<String> command = new ArrayList<>();
+
+        if (SystemUtils.IS_OS_WINDOWS) {
+            command.add("cmd");
+            command.add(SCRIPT_FILENAME + ".bat");
+        } else {
+            command.add("/bin/bash");
+            command.add(SCRIPT_FILENAME + ".sh");
+        }
+
+        CollectionUtils.addAll(command, arguments);
+
+        return command.toArray(new String[command.size()]);
+    }
+
+    @Test
+    public void runScriptWithoutOptions() {
+        try {
+            PROCESS_BUILDER.command(getCommand());
+            Process process = PROCESS_BUILDER.start();
+
+            String result = IOUtils.toString(process.getInputStream());
+            assertTrue(result.startsWith("\nUsage: Main [options]"));
+            assertTrue(result.contains(
+                    new EntitlementCommand().getClass().getAnnotation(Command.class).name()
+                    + " "
+                    + EntitlementCommand.EntitlementOptions.HELP.getOptionName()));
+            assertTrue(result.contains(
+                    new GroupCommand().getClass().getAnnotation(Command.class).name()
+                    + " "
+                    + GroupCommand.GroupOptions.HELP.getOptionName()));
+            process.destroy();
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+    }
+
+    @Test
+    public void entitlementCount() {
+        try {
+            PROCESS_BUILDER.command(getCommand(
+                    new EntitlementCommand().getClass().getAnnotation(Command.class).name(),
+                    EntitlementCommand.EntitlementOptions.LIST.getOptionName()));
+            Process process = PROCESS_BUILDER.start();
+
+            long entitlements = IterableUtils.countMatches(IOUtils.readLines(process.getInputStream()),
+                    new Predicate<String>() {
+
+                @Override
+                public boolean evaluate(final String line) {
+                    return line.startsWith("-");
+                }
+            });
+            assertEquals(syncopeService.info().getEntitlements().size(), entitlements);
+
+            process.destroy();
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+    }
+
+    @Test
+    public void connectorCount() {
+        try {
+            PROCESS_BUILDER.command(getCommand(
+                    new ConnectorCommand().getClass().getAnnotation(Command.class).name(),
+                    ConnectorCommand.ConnectorOptions.LIST_BUNDLES.getOptionName()));
+            Process process = PROCESS_BUILDER.start();
+
+            long bundles = IterableUtils.countMatches(IOUtils.readLines(process.getInputStream()),
+                    new Predicate<String>() {
+
+                @Override
+                public boolean evaluate(final String line) {
+                    return line.startsWith(" > BUNDLE NAME:");
+                }
+            });
+            assertEquals(connectorService.getBundles(null).size(), bundles);
+
+            process.destroy();
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+    }
+
+    @Test
+    public void userRead() {
+        final long userId1 = 1;
+        final long userId2 = 2;
+        final long userId3 = 3;
+        final long userId4 = 4;
+        final long userId5 = 5;
+        try {
+            PROCESS_BUILDER.command(getCommand(
+                    new UserCommand().getClass().getAnnotation(Command.class).name(),
+                    UserCommand.UserOptions.READ_BY_ID.getOptionName(),
+                    String.valueOf(userId1)));
+            Process process = PROCESS_BUILDER.start();
+            String result = IOUtils.toString(process.getInputStream());
+            assertTrue(result.contains("username: " + userService.read(userId1).getUsername()));
+            process.destroy();
+
+            PROCESS_BUILDER.command(getCommand(
+                    new UserCommand().getClass().getAnnotation(Command.class).name(),
+                    UserCommand.UserOptions.READ_BY_ID.getOptionName(),
+                    String.valueOf(userId1), String.valueOf(userId2),
+                    String.valueOf(userId3), String.valueOf(userId4), String.valueOf(userId5)));
+            Process process2 = PROCESS_BUILDER.start();
+            long users = IterableUtils.countMatches(IOUtils.readLines(process2.getInputStream()),
+                    new Predicate<String>() {
+
+                @Override
+                public boolean evaluate(final String line) {
+                    return line.startsWith(" > USER ID:");
+                }
+            });
+            assertEquals(5, users);
+
+            process2.destroy();
+
+            PROCESS_BUILDER.command(getCommand(
+                    new UserCommand().getClass().getAnnotation(Command.class).name(),
+                    UserCommand.UserOptions.READ_BY_ID.getOptionName(),
+                    String.valueOf(userId1), String.valueOf(userId2),
+                    String.valueOf(userId3), String.valueOf(userId4), String.valueOf(userId5)));
+            Process process3 = PROCESS_BUILDER.start();
+            String result3 = IOUtils.toString(process3.getInputStream());
+            assertTrue(
+                    result3.contains("username: " + userService.read(userId1).getUsername())
+                    && result3.contains("username: " + userService.read(userId2).getUsername())
+                    && result3.contains("username: " + userService.read(userId3).getUsername())
+                    && result3.contains("username: " + userService.read(userId4).getUsername())
+                    && result3.contains("username: " + userService.read(userId5).getUsername()));
+            process3.destroy();
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+    }
+
+    @Test
+    public void roleRead() {
+        final String roleId = "Search for realm evenTwo";
+        try {
+            PROCESS_BUILDER.command(getCommand(
+                    new RoleCommand().getClass().getAnnotation(Command.class).name(),
+                    RoleCommand.RoleOptions.READ.getOptionName(),
+                    roleId));
+            final Process process = PROCESS_BUILDER.start();
+            final String result = IOUtils.toString(process.getInputStream());
+            assertTrue(result.contains(roleService.read(roleId).getEntitlements().iterator().next()));
+
+            process.destroy();
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+    }
+
+    @Test
+    public void reportNotExists() {
+        try {
+            PROCESS_BUILDER.command(getCommand(
+                    new ReportCommand().getClass().getAnnotation(Command.class).name(),
+                    ReportCommand.ReportOptions.READ.getOptionName(),
+                    "2"));
+            final Process process = PROCESS_BUILDER.start();
+            final String result = IOUtils.toString(process.getInputStream());
+            assertTrue(result.contains("- Report 2 doesn't exist"));
+
+            process.destroy();
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+    }
+
+    @Test
+    public void policyError() {
+        try {
+            PROCESS_BUILDER.command(getCommand(
+                    new PolicyCommand().getClass().getAnnotation(Command.class).name(),
+                    PolicyCommand.PolicyOptions.READ.getOptionName(),
+                    "wrong"));
+            final Process process = PROCESS_BUILDER.start();
+            final String result = IOUtils.toString(process.getInputStream());
+            assertTrue(result.contains(
+                    "- Error reading wrong. It isn't a valid policy value because it isn't a boolean value"));
+
+            process.destroy();
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17d5d892/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AbstractConsoleITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AbstractConsoleITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AbstractConsoleITCase.java
new file mode 100644
index 0000000..b557bdd
--- /dev/null
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AbstractConsoleITCase.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.syncope.fit.console;
+
+import java.lang.reflect.InvocationTargetException;
+import javax.servlet.ServletContext;
+import org.apache.syncope.client.console.SyncopeConsoleApplication;
+import org.apache.syncope.client.console.init.ClassPathScanImplementationLookup;
+import org.apache.syncope.client.console.init.ConsoleInitializer;
+import org.apache.syncope.client.console.init.MIMETypesLoader;
+import org.apache.syncope.client.console.pages.Login;
+import org.apache.syncope.fit.AbstractITCase;
+import org.apache.wicket.Component;
+import org.apache.wicket.core.util.lang.PropertyResolver;
+import org.apache.wicket.markup.repeater.OddEvenItem;
+import org.apache.wicket.util.tester.FormTester;
+import org.apache.wicket.util.tester.WicketTester;
+import org.apache.wicket.util.visit.IVisit;
+import org.apache.wicket.util.visit.IVisitor;
+import org.junit.Before;
+
+public abstract class AbstractConsoleITCase extends AbstractITCase {
+
+    protected static final String KEY = "key";
+
+    protected WicketTester wicketTester;
+
+    protected SyncopeConsoleApplication testApplicaton;
+
+    @Before
+    public void setUp() {
+
+        testApplicaton = new SyncopeConsoleApplication() {
+
+            @Override
+            protected void init() {
+                final ServletContext ctx = getServletContext();
+                final ClassPathScanImplementationLookup lookup = new ClassPathScanImplementationLookup();
+                lookup.load();
+                ctx.setAttribute(ConsoleInitializer.CLASSPATH_LOOKUP, lookup);
+
+                final MIMETypesLoader mimeTypes = new MIMETypesLoader();
+                mimeTypes.load();
+                ctx.setAttribute(ConsoleInitializer.MIMETYPES_LOADER, mimeTypes);
+
+                super.init();
+            }
+        };
+
+        wicketTester = new WicketTester(testApplicaton);
+    }
+
+    protected void doLogin(final String user, final String passwd) {
+        wicketTester.startPage(Login.class);
+        wicketTester.assertRenderedPage(Login.class);
+
+        FormTester formTester = wicketTester.newFormTester("login");
+        formTester.setValue("username", user);
+        formTester.setValue("password", passwd);
+        formTester.submit("submit");
+    }
+
+    protected Component findComponentByProp(final String property, final String searchPath, final String key) {
+        Component component = wicketTester.getComponentFromLastRenderedPage(searchPath);
+
+        Component result = component.getPage().
+                visitChildren(OddEvenItem.class, new IVisitor<OddEvenItem<?>, Component>() {
+
+                    @Override
+                    public void component(final OddEvenItem<?> object, final IVisit<Component> visit) {
+
+                        try {
+                            if (PropertyResolver.getPropertyGetter(
+                                    property, object.getModelObject()).invoke(object.getModelObject()).equals(key)) {
+                                visit.stop(object);
+                            }
+                        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+                            LOG.error("Error invoke method", ex);
+                        }
+                    }
+                });
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17d5d892/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AbstractTypesITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AbstractTypesITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AbstractTypesITCase.java
new file mode 100644
index 0000000..b385ab2
--- /dev/null
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AbstractTypesITCase.java
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.syncope.fit.console;
+
+import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
+import org.apache.syncope.client.console.pages.Types;
+import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.AjaxFallbackDataTable;
+import org.apache.wicket.util.tester.FormTester;
+import org.junit.Before;
+
+public abstract class AbstractTypesITCase extends AbstractConsoleITCase {
+
+    protected static final String PLAIN_DATATABLE_PATH = "content:tabbedPanel:panel:"
+            + "collapsePanel:tabs:0:body:content:searchContainer:resultTable";
+
+    protected static final String DATATABLE_PATH =
+            "content:tabbedPanel:panel:searchContainer:resultTable";
+
+    @Before
+    public void login() {
+        doLogin(ADMIN_UNAME, ADMIN_PWD);
+    }
+
+    protected void browsingToRelationshipType() {
+
+        wicketTester.clickLink("configurationLI:configurationUL:typesLI:types");
+        wicketTester.assertRenderedPage(Types.class);
+
+        wicketTester.clickLink("content:tabbedPanel:tabs-container:tabs:0:link");
+        wicketTester.assertComponent(DATATABLE_PATH + ":tablePanel:groupForm:checkgroup:dataTable",
+                AjaxFallbackDataTable.class);
+    }
+
+    protected void browsingToAnyTypes() {
+
+        wicketTester.clickLink("configurationLI:configurationUL:typesLI:types");
+        wicketTester.assertRenderedPage(Types.class);
+
+        wicketTester.clickLink("content:tabbedPanel:tabs-container:tabs:1:link");
+        wicketTester.assertComponent(DATATABLE_PATH + ":tablePanel:groupForm:checkgroup:dataTable",
+                AjaxFallbackDataTable.class);
+    }
+
+    protected void browsingToAnyTypeClasses() {
+
+        wicketTester.clickLink("configurationLI:configurationUL:typesLI:types");
+        wicketTester.assertRenderedPage(Types.class);
+
+        wicketTester.clickLink("content:tabbedPanel:tabs-container:tabs:2:link");
+        wicketTester.assertComponent(DATATABLE_PATH + ":tablePanel:groupForm:checkgroup:dataTable",
+                AjaxFallbackDataTable.class);
+    }
+
+    protected void browsingToPlainSchemas() {
+
+        wicketTester.clickLink("configurationLI:configurationUL:typesLI:types");
+        wicketTester.assertRenderedPage(Types.class);
+
+        wicketTester.clickLink("content:tabbedPanel:tabs-container:tabs:3:link");
+        wicketTester.assertComponent(PLAIN_DATATABLE_PATH + ":tablePanel:groupForm:checkgroup:dataTable",
+                AjaxFallbackDataTable.class);
+    }
+
+    protected void createPlainSchema(final String key) {
+        browsingToPlainSchemas();
+        wicketTester.clickLink("content:tabbedPanel:panel:collapsePanel:tabs:0:body:content:container:content:add");
+
+        wicketTester.assertComponent(
+                "content:tabbedPanel:panel:collapsePanel:tabs:0:body:content:modal", Modal.class);
+
+        final FormTester formTester = wicketTester.newFormTester("content:tabbedPanel:panel:"
+                + "collapsePanel:tabs:0:body:content:modal:form");
+        formTester.setValue("content:details:form:key:textField", key);
+        formTester.setValue("content:details:form:type:dropDownChoiceField", "3");
+
+        wicketTester.clickLink("content:tabbedPanel:panel:"
+                + "collapsePanel:tabs:0:body:content:modal:dialog:footer:inputs:0:submit");
+
+        wicketTester.assertInfoMessages("Operation executed successfully");
+
+        wicketTester.cleanupFeedbackMessages();
+    }
+
+    protected void createAnyTypeClassWithoutSchema(final String name) {
+        browsingToAnyTypeClasses();
+
+        wicketTester.clickLink("content:tabbedPanel:panel:container:content:add");
+        wicketTester.assertComponent(
+                "content:tabbedPanel:panel:modal", Modal.class);
+
+        final FormTester formTester = wicketTester.newFormTester("content:tabbedPanel:panel:modal:form");
+        formTester.setValue("content:anyTypeClassDetailsPanel:form:key:textField", name);
+
+        wicketTester.clickLink("content:tabbedPanel:panel:modal:dialog:footer:inputs:0:submit");
+        wicketTester.assertInfoMessages("Operation executed successfully");
+
+        wicketTester.clearFeedbackMessages();
+    }
+
+    protected void createAnyType(final String name) {
+        browsingToAnyTypes();
+
+        wicketTester.clickLink("content:tabbedPanel:panel:container:content:add");
+        wicketTester.assertComponent(
+                "content:tabbedPanel:panel:modal", Modal.class);
+
+        final FormTester formTester = wicketTester.newFormTester("content:tabbedPanel:panel:modal:form");
+        formTester.setValue("content:anyTypeDetailsPanel:container:form:key:textField", name);
+
+        wicketTester.clickLink("content:tabbedPanel:panel:modal:dialog:footer:inputs:0:submit");
+        wicketTester.assertInfoMessages("Operation executed successfully");
+
+        wicketTester.clearFeedbackMessages();
+    }
+
+    protected void createRelationshipType(final String name) {
+        browsingToRelationshipType();
+
+        wicketTester.clickLink("content:tabbedPanel:panel:container:content:add");
+
+        wicketTester.assertComponent(
+                "content:tabbedPanel:panel:modal", Modal.class);
+
+        final FormTester formTester = wicketTester.newFormTester("content:tabbedPanel:panel:modal:form");
+        formTester.setValue("content:relationshipTypeDetails:container:form:key:textField", name);
+        formTester.setValue(
+                "content:relationshipTypeDetails:container:form:description:textField", "test relationshipType");
+
+        wicketTester.clickLink("content:tabbedPanel:panel:modal:dialog:footer:inputs:0:submit");
+        wicketTester.assertInfoMessages("Operation executed successfully");
+
+        wicketTester.clearFeedbackMessages();
+        wicketTester.assertRenderedPage(Types.class);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17d5d892/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AjaxPalettePanelITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AjaxPalettePanelITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AjaxPalettePanelITCase.java
new file mode 100644
index 0000000..9f44034
--- /dev/null
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AjaxPalettePanelITCase.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.syncope.fit.console;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxPalettePanel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.util.ListModel;
+import org.apache.wicket.util.tester.FormTester;
+import org.junit.Test;
+
+public class AjaxPalettePanelITCase extends AbstractConsoleITCase {
+
+    private static final IModel<List<String>> SELECTED = new ListModel<>(new ArrayList<>(Arrays.asList("A", "D")));
+
+    private static final ListModel<String> ALL = new ListModel<>(new ArrayList<>(Arrays.asList("A", "B", "C", "D")));
+
+    @Test
+    public void isRendered() {
+        TestPage<String, AjaxPalettePanel<String>> testPage =
+                new TestPage.Builder<String, AjaxPalettePanel<String>>().build(
+                        new AjaxPalettePanel.Builder<String>().setAllowOrder(true).build(
+                        TestPage.FIELD, SELECTED, ALL));
+        wicketTester.startPage(testPage);
+
+        FormTester formTester = wicketTester.newFormTester(testPage.getForm().getId());
+        formTester.submit();
+
+        Collection<String> list = testPage.getFieldPanel().getModelCollection();
+        assertEquals(2, list.size());
+        Iterator<String> iterator = list.iterator();
+        assertEquals("A", iterator.next());
+        assertEquals("D", iterator.next());
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17d5d892/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AjaxTextFieldITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AjaxTextFieldITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AjaxTextFieldITCase.java
new file mode 100644
index 0000000..8d51194
--- /dev/null
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AjaxTextFieldITCase.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.syncope.fit.console;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
+import org.apache.wicket.util.string.Strings;
+import org.apache.wicket.util.tester.FormTester;
+import org.apache.wicket.validation.validator.StringValidator;
+import org.junit.Test;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+
+public class AjaxTextFieldITCase extends AbstractConsoleITCase {
+
+    private final IModel<String> textModel = Model.of((String) null);
+
+    @Test
+    public void emptyInputConvertedToNull() {
+        TestPage<String, AjaxTextFieldPanel> testPage =
+                new TestPage.Builder<String, AjaxTextFieldPanel>().build(
+                        new AjaxTextFieldPanel(TestPage.FIELD, TestPage.FIELD, textModel));
+        wicketTester.startPage(testPage);
+        FormTester formTester = wicketTester.newFormTester(testPage.getForm().getId());
+        formTester.setValue("field:textField", "");
+        formTester.submit();
+        assertNull(testPage.getFieldPanel().getField().getDefaultModelObject());
+    }
+
+    @Test
+    public void valueAttribute() {
+        TestPage<String, AjaxTextFieldPanel> testPage =
+                new TestPage.Builder<String, AjaxTextFieldPanel>().build(
+                        new AjaxTextFieldPanel(TestPage.FIELD, TestPage.FIELD, textModel));
+        String text = "sometext";
+        textModel.setObject(text);
+        wicketTester.startPage(testPage);
+        assertTrue(wicketTester.getLastResponseAsString().contains(Strings.escapeMarkup(text)));
+    }
+
+    @Test
+    public void nullIsNotValidated() {
+        TestPage<String, AjaxTextFieldPanel> testPage =
+                new TestPage.Builder<String, AjaxTextFieldPanel>().build(
+                        new AjaxTextFieldPanel(TestPage.FIELD, TestPage.FIELD, textModel));
+        testPage.getFieldPanel().getField().setRequired(false);
+        testPage.getFieldPanel().getField().add(StringValidator.minimumLength(2));
+        wicketTester.startPage(testPage);
+        FormTester formTester = wicketTester.newFormTester(testPage.getForm().getId());
+        formTester.setValue("field:textField", "");
+        formTester.submit();
+        assertNull(testPage.getFieldPanel().getDefaultModelObject());
+        assertTrue(testPage.getFieldPanel().getField().isValid());
+    }
+
+    @Test
+    public void requiredAttribute() {
+        TestPage<String, AjaxTextFieldPanel> testPage =
+                new TestPage.Builder<String, AjaxTextFieldPanel>().build(
+                        new AjaxTextFieldPanel(TestPage.FIELD, TestPage.FIELD, textModel));
+        testPage.getFieldPanel().setOutputMarkupId(true);
+        testPage.getFieldPanel().getField().setRequired(true);
+        wicketTester.startPage(testPage);
+        wicketTester.assertLabel("form:field:field-label", "field");
+        wicketTester.assertVisible("form:field:required");
+        wicketTester.assertVisible("form:field:externalAction");
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17d5d892/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AnyTypeClassesITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AnyTypeClassesITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AnyTypeClassesITCase.java
new file mode 100644
index 0000000..14cb876
--- /dev/null
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AnyTypeClassesITCase.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.syncope.fit.console;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
+import org.apache.syncope.client.console.pages.Types;
+import org.apache.syncope.client.console.panels.AjaxDataTablePanel;
+import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.AjaxFallbackDataTable;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
+import org.apache.syncope.client.console.wicket.markup.html.form.IndicatingOnConfirmAjaxLink;
+import org.apache.wicket.Component;
+import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxLink;
+import org.apache.wicket.util.tester.FormTester;
+import org.junit.Test;
+
+public class AnyTypeClassesITCase extends AbstractTypesITCase {
+
+    @Test
+    public void read() {
+        browsingToAnyTypeClasses();
+
+        Component result = findComponentByProp(KEY, DATATABLE_PATH, "csv");
+        wicketTester.assertLabel(
+                result.getPageRelativePath() + ":cells:1:cell", "csv");
+
+        wicketTester.assertComponent(
+                result.getPageRelativePath() + ":cells:6:cell:panelEdit:editLink", IndicatingAjaxLink.class);
+
+        wicketTester.clickLink(
+                result.getPageRelativePath() + ":cells:6:cell:panelEdit:editLink");
+
+        wicketTester.assertComponent(
+                "content:tabbedPanel:panel:modal", BaseModal.class);
+    }
+
+    @Test
+    public void create() {
+        browsingToAnyTypeClasses();
+        final String anyTypeClassTest = "anyTypeClassTest";
+
+        wicketTester.clickLink("content:tabbedPanel:panel:container:content:add");
+
+        wicketTester.assertComponent(
+                "content:tabbedPanel:panel:modal", Modal.class);
+
+        final FormTester formTester = wicketTester.newFormTester("content:tabbedPanel:panel:modal:form");
+        formTester.setValue("content:anyTypeClassDetailsPanel:form:key:textField", anyTypeClassTest);
+        formTester.setValue(
+                "content:anyTypeClassDetailsPanel:form:container:derSchemas:paletteField:recorder", "mderiveddata");
+
+        wicketTester.clickLink("content:tabbedPanel:panel:modal:dialog:footer:inputs:0:submit");
+        wicketTester.assertInfoMessages("Operation executed successfully");
+
+        wicketTester.clearFeedbackMessages();
+        wicketTester.assertRenderedPage(Types.class);
+
+        wicketTester.clickLink("content:tabbedPanel:tabs-container:tabs:2:link");
+        wicketTester.assertComponent(DATATABLE_PATH + ":tablePanel:groupForm:checkgroup:dataTable",
+                AjaxFallbackDataTable.class);
+
+        wicketTester.assertComponent(DATATABLE_PATH, AjaxDataTablePanel.class);
+
+        Component result = findComponentByProp(KEY, DATATABLE_PATH, anyTypeClassTest);
+
+        wicketTester.assertLabel(result.getPageRelativePath() + ":cells:4:cell", "[mderiveddata]");
+    }
+
+    @Test
+    public void update() {
+        final String plainSchema = "anyPlainSchema";
+        createPlainSchema(plainSchema);
+        browsingToAnyTypeClasses();
+
+        wicketTester.assertComponent(
+                DATATABLE_PATH
+                + ":tablePanel:groupForm:checkgroup:dataTable:"
+                + "body:rows:1:cells:6:cell:panelEdit:editLink", IndicatingAjaxLink.class);
+
+        wicketTester.clickLink(
+                DATATABLE_PATH
+                + ":tablePanel:groupForm:checkgroup:dataTable:body:rows:1:cells:6:cell:panelEdit:editLink");
+
+        final FormTester formTester =
+                wicketTester.newFormTester("content:tabbedPanel:panel:modal:form");
+        formTester.setValue(
+                "content:anyTypeClassDetailsPanel:form:container:plainSchemas:paletteField:recorder", plainSchema);
+
+        wicketTester.clickLink("content:tabbedPanel:panel:modal:dialog:footer:inputs:0:submit");
+        wicketTester.assertInfoMessages("Operation executed successfully");
+    }
+
+    @Test
+    public void delete() {
+        final String anyTypeClassName = "zStringDelete";
+        createAnyTypeClassWithoutSchema(anyTypeClassName);
+        browsingToAnyTypeClasses();
+        wicketTester.assertComponent(DATATABLE_PATH, AjaxDataTablePanel.class);
+
+        Component result = findComponentByProp(KEY, DATATABLE_PATH, anyTypeClassName);
+
+        assertNotNull(result);
+        wicketTester.assertComponent(
+                result.getPageRelativePath() + ":cells:6:cell:panelDelete:deleteLink",
+                IndicatingOnConfirmAjaxLink.class);
+
+        wicketTester.getRequest().addParameter("confirm", "true");
+        wicketTester.clickLink(
+                wicketTester.getComponentFromLastRenderedPage(
+                        result.getPageRelativePath() + ":cells:6:cell:panelDelete:deleteLink"));
+
+        wicketTester.executeAjaxEvent(wicketTester.getComponentFromLastRenderedPage(
+                result.getPageRelativePath() + ":cells:6:cell:panelDelete:deleteLink"), "click");
+        wicketTester.assertInfoMessages("Operation executed successfully");
+
+        wicketTester.cleanupFeedbackMessages();
+        result = findComponentByProp(KEY, DATATABLE_PATH, anyTypeClassName);
+
+        assertNull(result);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17d5d892/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AnyTypesITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AnyTypesITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AnyTypesITCase.java
new file mode 100644
index 0000000..e468476
--- /dev/null
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AnyTypesITCase.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.syncope.fit.console;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
+import org.apache.syncope.client.console.pages.Types;
+import org.apache.syncope.client.console.panels.AjaxDataTablePanel;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
+import org.apache.syncope.client.console.wicket.markup.html.form.IndicatingOnConfirmAjaxLink;
+import org.apache.wicket.Component;
+import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxLink;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.util.tester.FormTester;
+import org.junit.Test;
+
+public class AnyTypesITCase extends AbstractTypesITCase {
+
+    @Test
+    public void read() {
+        browsingToAnyTypes();
+        wicketTester.assertComponent(
+                DATATABLE_PATH
+                + ":tablePanel:groupForm:"
+                + "checkgroup:dataTable:body:rows:1:cells:1:cell", Label.class);
+
+        Component result = findComponentByProp(KEY, DATATABLE_PATH, "GROUP");
+
+        wicketTester.assertComponent(
+                result.getPageRelativePath() + ":cells:4:cell:panelEdit:editLink", IndicatingAjaxLink.class);
+
+        wicketTester.clickLink(
+                result.getPageRelativePath() + ":cells:4:cell:panelEdit:editLink");
+
+        wicketTester.assertComponent(
+                "content:tabbedPanel:panel:modal", BaseModal.class);
+    }
+
+    @Test
+    public void create() {
+        browsingToAnyTypes();
+        final String anyTypeTest = "anyTypeTest2";
+
+        wicketTester.clickLink("content:tabbedPanel:panel:container:content:add");
+
+        wicketTester.assertComponent(
+                "content:tabbedPanel:panel:modal", Modal.class);
+
+        final FormTester formTester = wicketTester.newFormTester("content:tabbedPanel:panel:modal:form");
+        formTester.setValue("content:anyTypeDetailsPanel:container:form:key:textField", anyTypeTest);
+        formTester.setValue(
+                "content:anyTypeDetailsPanel:container:form:classes:paletteField:recorder", "csv");
+
+        wicketTester.clickLink("content:tabbedPanel:panel:modal:dialog:footer:inputs:0:submit");
+        wicketTester.assertInfoMessages("Operation executed successfully");
+
+        wicketTester.clearFeedbackMessages();
+        wicketTester.assertRenderedPage(Types.class);
+
+        wicketTester.clickLink("content:tabbedPanel:tabs-container:tabs:1:link");
+        wicketTester.assertComponent(DATATABLE_PATH, AjaxDataTablePanel.class);
+
+        Component result = findComponentByProp(KEY, DATATABLE_PATH, anyTypeTest);
+
+        wicketTester.assertLabel(result.getPageRelativePath() + ":cells:1:cell", anyTypeTest);
+        wicketTester.assertLabel(result.getPageRelativePath() + ":cells:3:cell", "[csv]");
+    }
+
+    @Test
+    public void update() {
+        final String name = "anyTypeClassUpdate";
+        createAnyTypeClassWithoutSchema(name);
+        browsingToAnyTypes();
+
+        wicketTester.assertComponent(
+                DATATABLE_PATH
+                + ":tablePanel:groupForm:checkgroup:dataTable:"
+                + "body:rows:1:cells:4:cell:panelEdit:editLink", IndicatingAjaxLink.class);
+
+        wicketTester.clickLink(
+                DATATABLE_PATH
+                + ":tablePanel:groupForm:checkgroup:dataTable:body:rows:1:cells:4:cell:panelEdit:editLink");
+
+        final FormTester formTester =
+                wicketTester.newFormTester("content:tabbedPanel:panel:modal:form");
+        formTester.setValue(
+                "content:anyTypeDetailsPanel:container:form:classes:paletteField:recorder", name + ",minimal group");
+
+        wicketTester.clickLink("content:tabbedPanel:panel:modal:dialog:footer:inputs:0:submit");
+        wicketTester.assertInfoMessages("Operation executed successfully");
+    }
+
+    @Test
+    public void delete() {
+        final String name = "anyTypeDelete";
+        createAnyType(name);
+        browsingToAnyTypes();
+
+        wicketTester.assertComponent(DATATABLE_PATH, AjaxDataTablePanel.class);
+        Component result = findComponentByProp(KEY, DATATABLE_PATH, name);
+
+        assertNotNull(result);
+        wicketTester.assertComponent(
+                result.getPageRelativePath() + ":cells:4:cell:panelDelete:deleteLink",
+                IndicatingOnConfirmAjaxLink.class);
+
+        wicketTester.getRequest().addParameter("confirm", "true");
+        wicketTester.clickLink(
+                wicketTester.getComponentFromLastRenderedPage(
+                        result.getPageRelativePath() + ":cells:4:cell:panelDelete:deleteLink"));
+
+        wicketTester.executeAjaxEvent(wicketTester.getComponentFromLastRenderedPage(
+                result.getPageRelativePath() + ":cells:4:cell:panelDelete:deleteLink"), "onclick");
+        wicketTester.assertInfoMessages("Operation executed successfully");
+
+        wicketTester.cleanupFeedbackMessages();
+        result = findComponentByProp(KEY, DATATABLE_PATH, name);
+
+        assertNull(result);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17d5d892/fit/core-reference/src/test/java/org/apache/syncope/fit/console/BaseITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/BaseITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/BaseITCase.java
new file mode 100644
index 0000000..7a83927
--- /dev/null
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/BaseITCase.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.syncope.fit.console;
+
+import org.apache.syncope.client.console.pages.Dashboard;
+import org.apache.syncope.client.console.pages.Layouts;
+import org.apache.syncope.client.console.pages.Login;
+import org.apache.syncope.client.console.pages.Logs;
+import org.apache.syncope.client.console.pages.Notifications;
+import org.apache.syncope.client.console.pages.Policies;
+import org.apache.syncope.client.console.pages.Realms;
+import org.apache.syncope.client.console.pages.Reports;
+import org.apache.syncope.client.console.pages.Roles;
+import org.apache.syncope.client.console.pages.SecurityQuestions;
+import org.apache.syncope.client.console.pages.Types;
+import org.apache.syncope.client.console.pages.Workflow;
+import org.apache.syncope.client.console.topology.Topology;
+import org.junit.Test;
+
+public class BaseITCase extends AbstractConsoleITCase {
+
+    @Test
+    public void loginPage() {
+        wicketTester.startPage(Login.class);
+        wicketTester.assertRenderedPage(Login.class);
+    }
+
+    @Test
+    public void successfullyLogin() {
+        doLogin(ADMIN_UNAME, ADMIN_PWD);
+        wicketTester.assertRenderedPage(Dashboard.class);
+    }
+
+    @Test
+    public void unsuccessfullyLogin() {
+        doLogin(ADMIN_UNAME, ADMIN_PWD + 1);
+        wicketTester.assertRenderedPage(Login.class);
+    }
+
+    @Test
+    public void browsingBookmarkablePageLink() {
+        doLogin(ADMIN_UNAME, ADMIN_PWD);
+        wicketTester.assertRenderedPage(Dashboard.class);
+
+        wicketTester.clickLink("realmsLI:realms");
+        wicketTester.assertRenderedPage(Realms.class);
+
+        wicketTester.clickLink("topologyLI:topology");
+        wicketTester.assertRenderedPage(Topology.class);
+
+        wicketTester.clickLink("reportsLI:reports");
+        wicketTester.assertRenderedPage(Reports.class);
+
+        wicketTester.clickLink("configurationLI:configurationUL:workflowLI:workflow");
+        wicketTester.assertRenderedPage(Workflow.class);
+
+        wicketTester.clickLink("configurationLI:configurationUL:logsLI:logs");
+        wicketTester.assertRenderedPage(Logs.class);
+
+        wicketTester.clickLink("configurationLI:configurationUL:securityquestionsLI:securityquestions");
+        wicketTester.assertRenderedPage(SecurityQuestions.class);
+
+        wicketTester.clickLink("configurationLI:configurationUL:typesLI:types");
+        wicketTester.assertRenderedPage(Types.class);
+
+        wicketTester.clickLink("configurationLI:configurationUL:rolesLI:roles");
+        wicketTester.assertRenderedPage(Roles.class);
+
+        wicketTester.clickLink("configurationLI:configurationUL:policiesLI:policies");
+        wicketTester.assertRenderedPage(Policies.class);
+
+        wicketTester.clickLink("configurationLI:configurationUL:layoutsLI:layouts");
+        wicketTester.assertRenderedPage(Layouts.class);
+
+        wicketTester.clickLink("configurationLI:configurationUL:notificationsLI:notifications");
+        wicketTester.assertRenderedPage(Notifications.class);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17d5d892/fit/core-reference/src/test/java/org/apache/syncope/fit/console/RelationshipTypeITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/RelationshipTypeITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/RelationshipTypeITCase.java
new file mode 100644
index 0000000..6eea05b
--- /dev/null
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/RelationshipTypeITCase.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.syncope.fit.console;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import org.apache.syncope.client.console.panels.AjaxDataTablePanel;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
+import org.apache.syncope.client.console.wicket.markup.html.form.IndicatingOnConfirmAjaxLink;
+import org.apache.wicket.Component;
+import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxLink;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.util.tester.FormTester;
+import org.junit.Test;
+
+public class RelationshipTypeITCase extends AbstractTypesITCase {
+
+    @Test
+    public void read() {
+        browsingToRelationshipType();
+
+        Component result = findComponentByProp(KEY, DATATABLE_PATH, "inclusion");
+
+        wicketTester.assertComponent(
+                result.getPageRelativePath() + ":cells:1:cell", Label.class);
+
+        wicketTester.assertComponent(
+                result.getPageRelativePath() + ":cells:3:cell:panelEdit:editLink", IndicatingAjaxLink.class);
+
+        wicketTester.clickLink(
+                result.getPageRelativePath() + ":cells:3:cell:panelEdit:editLink");
+
+        wicketTester.assertComponent(
+                "content:tabbedPanel:panel:modal", BaseModal.class);
+    }
+
+    @Test
+    public void create() {
+        final String name = "relationshipTypeTest";
+        createRelationshipType(name);
+        browsingToRelationshipType();
+
+        wicketTester.assertComponent(DATATABLE_PATH, AjaxDataTablePanel.class);
+
+        Component result = findComponentByProp(KEY, DATATABLE_PATH, name);
+
+        wicketTester.assertLabel(result.getPageRelativePath() + ":cells:1:cell", name);
+        wicketTester.assertLabel(result.getPageRelativePath() + ":cells:2:cell", "test relationshipType");
+    }
+
+    @Test
+    public void update() {
+        final String name = "relationshipTypeUpdate";
+        createRelationshipType(name);
+        browsingToRelationshipType();
+
+        wicketTester.assertComponent(
+                DATATABLE_PATH
+                + ":tablePanel:groupForm:checkgroup:dataTable:"
+                + "body:rows:1:cells:3:cell:panelEdit:editLink", IndicatingAjaxLink.class);
+
+        wicketTester.clickLink(
+                DATATABLE_PATH
+                + ":tablePanel:groupForm:checkgroup:dataTable:body:rows:1:cells:3:cell:panelEdit:editLink");
+
+        final FormTester formTester =
+                wicketTester.newFormTester("content:tabbedPanel:panel:modal:form");
+        formTester.setValue(
+                "content:relationshipTypeDetails:container:form:description:textField", "new description");
+
+        wicketTester.clickLink("content:tabbedPanel:panel:modal:dialog:footer:inputs:0:submit");
+        wicketTester.assertInfoMessages("Operation executed successfully");
+    }
+
+    @Test
+    public void delete() {
+        final String name = "relationshipTypeDelete";
+        createRelationshipType(name);
+        browsingToRelationshipType();
+
+        wicketTester.assertComponent(DATATABLE_PATH, AjaxDataTablePanel.class);
+
+        Component result = findComponentByProp(KEY, DATATABLE_PATH, name);
+
+        assertNotNull(result);
+        wicketTester.assertComponent(
+                result.getPageRelativePath() + ":cells:3:cell:panelDelete:deleteLink",
+                IndicatingOnConfirmAjaxLink.class);
+
+        wicketTester.getRequest().addParameter("confirm", "true");
+        wicketTester.clickLink(
+                wicketTester.getComponentFromLastRenderedPage(
+                        result.getPageRelativePath() + ":cells:3:cell:panelDelete:deleteLink"));
+
+        wicketTester.executeAjaxEvent(wicketTester.getComponentFromLastRenderedPage(
+                result.getPageRelativePath() + ":cells:3:cell:panelDelete:deleteLink"), "onclick");
+        wicketTester.assertInfoMessages("Operation executed successfully");
+
+        wicketTester.cleanupFeedbackMessages();
+        result = findComponentByProp(KEY, DATATABLE_PATH, name);
+
+        assertNull(result);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17d5d892/fit/core-reference/src/test/java/org/apache/syncope/fit/console/SchemasITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/SchemasITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/SchemasITCase.java
new file mode 100644
index 0000000..f731ca9
--- /dev/null
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/SchemasITCase.java
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.syncope.fit.console;
+
+import static org.junit.Assert.assertNull;
+
+import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
+import org.apache.syncope.client.console.pages.Types;
+import org.apache.syncope.client.console.panels.AjaxDataTablePanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.IndicatingOnConfirmAjaxLink;
+import org.apache.wicket.Component;
+import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxLink;
+import org.apache.wicket.markup.html.form.DropDownChoice;
+import org.apache.wicket.util.tester.FormTester;
+import org.junit.Test;
+
+public class SchemasITCase extends AbstractTypesITCase {
+
+    @Test
+    public void readPlainSchema() {
+        browsingToPlainSchemas();
+        wicketTester.assertLabel(
+                PLAIN_DATATABLE_PATH
+                + ":tablePanel:groupForm:"
+                + "checkgroup:dataTable:body:rows:1:cells:1:cell", "aLong");
+
+        wicketTester.assertComponent(
+                PLAIN_DATATABLE_PATH
+                + ":tablePanel:groupForm:checkgroup:dataTable:"
+                + "body:rows:1:cells:7:cell:panelEdit:editLink", IndicatingAjaxLink.class);
+
+        wicketTester.clickLink(
+                PLAIN_DATATABLE_PATH
+                + ":tablePanel:groupForm:checkgroup:dataTable:"
+                + "body:rows:1:cells:7:cell:panelEdit:editLink");
+
+        wicketTester.assertComponent(
+                "content:tabbedPanel:"
+                + "panel:collapsePanel:tabs:0:body:content:modal:"
+                + "form:content:kindForm:kind:dropDownChoiceField", DropDownChoice.class);
+    }
+
+    @Test
+    public void createPlainSchema() {
+        browsingToPlainSchemas();
+        wicketTester.clickLink("content:tabbedPanel:panel:collapsePanel:tabs:0:body:content:container:content:add");
+
+        wicketTester.assertComponent(
+                "content:tabbedPanel:panel:collapsePanel:tabs:0:body:content:modal", Modal.class);
+
+        final FormTester formTester = wicketTester.newFormTester("content:tabbedPanel:panel:"
+                + "collapsePanel:tabs:0:body:content:modal:form");
+        formTester.setValue("content:details:form:key:textField", "zBoolean");
+        formTester.setValue("content:details:form:type:dropDownChoiceField", "3");
+
+        wicketTester.clickLink("content:tabbedPanel:panel:"
+                + "collapsePanel:tabs:0:body:content:modal:dialog:footer:inputs:0:submit");
+
+        wicketTester.assertInfoMessages("Operation executed successfully");
+
+        wicketTester.cleanupFeedbackMessages();
+        wicketTester.assertRenderedPage(Types.class);
+    }
+
+    @Test
+    public void updatePlainSchema() {
+        browsingToPlainSchemas();
+
+        Component result = findComponentByProp(KEY, PLAIN_DATATABLE_PATH, "firstname");
+
+        wicketTester.assertLabel(
+                result.getPageRelativePath() + ":cells:1:cell", "firstname");
+
+        wicketTester.clickLink(
+                result.getPageRelativePath() + ":cells:7:cell:panelEdit:editLink");
+
+        wicketTester.assertComponent(
+                "content:tabbedPanel:"
+                + "panel:collapsePanel:tabs:0:body:content:modal:"
+                + "form:content:kindForm:kind:dropDownChoiceField", DropDownChoice.class);
+
+        final FormTester formTester =
+                wicketTester.newFormTester("content:tabbedPanel:panel:collapsePanel:tabs:0:body:content:modal:form");
+        formTester.setValue("content:details:form:multivalue:checkboxField", "true");
+
+        wicketTester.clickLink("content:tabbedPanel:panel:"
+                + "collapsePanel:tabs:0:body:content:modal:dialog:footer:inputs:0:submit", true);
+
+        wicketTester.assertInfoMessages("Operation executed successfully");
+    }
+
+    @Test
+    public void deletePlainSchema() {
+        browsingToPlainSchemas();
+        //create new Plain Schema
+        final String schemaName = "zStringDelete";
+        wicketTester.clickLink("content:tabbedPanel:panel:collapsePanel:tabs:0:body:content:container:content:add");
+
+        wicketTester.assertComponent(
+                "content:tabbedPanel:panel:collapsePanel:tabs:0:body:content:modal", Modal.class);
+
+        final FormTester formTester = wicketTester.newFormTester("content:tabbedPanel:panel:"
+                + "collapsePanel:tabs:0:body:content:modal:form");
+        formTester.setValue("content:details:form:key:textField", schemaName);
+        formTester.setValue("content:details:form:type:dropDownChoiceField", "0");
+
+        wicketTester.clickLink("content:tabbedPanel:panel:"
+                + "collapsePanel:tabs:0:body:content:modal:dialog:footer:inputs:0:submit");
+
+        wicketTester.assertInfoMessages("Operation executed successfully");;
+
+        wicketTester.cleanupFeedbackMessages();
+
+        //delete plain schema
+        wicketTester.clickLink(
+                PLAIN_DATATABLE_PATH
+                + ":tablePanel:groupForm:checkgroup:"
+                + "dataTable:topToolbars:toolbars:1:span:navigator:last");
+
+        wicketTester.assertComponent(PLAIN_DATATABLE_PATH, AjaxDataTablePanel.class);
+
+        Component result = findComponentByProp(KEY, PLAIN_DATATABLE_PATH, schemaName);
+
+        wicketTester.assertComponent(
+                result.getPageRelativePath() + ":cells:7:cell:panelDelete:deleteLink",
+                IndicatingOnConfirmAjaxLink.class);
+
+        wicketTester.getRequest().addParameter("confirm", "true");
+        wicketTester.clickLink(
+                wicketTester.getComponentFromLastRenderedPage(
+                        result.getPageRelativePath() + ":cells:7:cell:panelDelete:deleteLink"));
+
+        wicketTester.executeAjaxEvent(wicketTester.getComponentFromLastRenderedPage(
+                result.getPageRelativePath() + ":cells:7:cell:panelDelete:deleteLink"), "onclick");
+        wicketTester.assertInfoMessages("Operation executed successfully");
+        wicketTester.cleanupFeedbackMessages();
+
+        assertNull(findComponentByProp(KEY, PLAIN_DATATABLE_PATH, schemaName));
+    }
+}