Repository: syncope Updated Branches: refs/heads/2_0_X 79354db35 -> bb508d9fa
[SYNCOPE-1288] Task lists are now correctly sortable Project: http://git-wip-us.apache.org/repos/asf/syncope/repo Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/bb508d9f Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/bb508d9f Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/bb508d9f Branch: refs/heads/2_0_X Commit: bb508d9faf3ba5ea85fc5a377e517dcd8b9476c6 Parents: 79354db Author: skylark17 <matteo.alessandr...@tirasa.net> Authored: Thu Apr 5 15:59:48 2018 +0200 Committer: skylark17 <matteo.alessandr...@tirasa.net> Committed: Thu Apr 5 15:59:48 2018 +0200 ---------------------------------------------------------------------- .../console/reports/ReportDirectoryPanel.java | 4 +- .../tasks/ProvisioningTaskDirectoryPanel.java | 4 +- .../console/tasks/SchedTaskDirectoryPanel.java | 4 +- .../core/persistence/jpa/dao/JPATaskDAO.java | 243 ++++++++++++++++--- .../core/persistence/jpa/outer/TaskTest.java | 127 +++++----- .../syncope/fit/core/PropagationTaskITCase.java | 78 ++++++ 6 files changed, 361 insertions(+), 99 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/syncope/blob/bb508d9f/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java index e0c5d6f..ceef254 100644 --- a/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java +++ b/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java @@ -110,10 +110,10 @@ public abstract class ReportDirectoryPanel "name", this), "name", "name")); columns.add(new DatePropertyColumn<ReportTO>( - new StringResourceModel("lastExec", this), "lastExec", "lastExec")); + new StringResourceModel("lastExec", this), null, "lastExec")); columns.add(new DatePropertyColumn<ReportTO>( - new StringResourceModel("nextExec", this), "nextExec", "nextExec")); + new StringResourceModel("nextExec", this), null, "nextExec")); columns.add(new DatePropertyColumn<ReportTO>( new StringResourceModel("start", this), "start", "start")); http://git-wip-us.apache.org/repos/asf/syncope/blob/bb508d9f/client/console/src/main/java/org/apache/syncope/client/console/tasks/ProvisioningTaskDirectoryPanel.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/tasks/ProvisioningTaskDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/tasks/ProvisioningTaskDirectoryPanel.java index cacd6f7..59802b4 100644 --- a/client/console/src/main/java/org/apache/syncope/client/console/tasks/ProvisioningTaskDirectoryPanel.java +++ b/client/console/src/main/java/org/apache/syncope/client/console/tasks/ProvisioningTaskDirectoryPanel.java @@ -117,10 +117,10 @@ public abstract class ProvisioningTaskDirectoryPanel<T extends ProvisioningTaskT } columns.add(new DatePropertyColumn<T>( - new StringResourceModel("lastExec", this), "lastExec", "lastExec")); + new StringResourceModel("lastExec", this), null, "lastExec")); columns.add(new DatePropertyColumn<T>( - new StringResourceModel("nextExec", this), "nextExec", "nextExec")); + new StringResourceModel("nextExec", this), null, "nextExec")); columns.add(new PropertyColumn<T, String>( new StringResourceModel("latestExecStatus", this), "latestExecStatus", "latestExecStatus")); http://git-wip-us.apache.org/repos/asf/syncope/blob/bb508d9f/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java index a4b2d51..a57856a 100644 --- a/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java +++ b/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java @@ -164,10 +164,10 @@ public abstract class SchedTaskDirectoryPanel<T extends SchedTaskTO> }); columns.add(new DatePropertyColumn<T>( - new StringResourceModel("lastExec", this), "lastExec", "lastExec")); + new StringResourceModel("lastExec", this), null, "lastExec")); columns.add(new DatePropertyColumn<T>( - new StringResourceModel("nextExec", this), "nextExec", "nextExec")); + new StringResourceModel("nextExec", this), null, "nextExec")); columns.add(new PropertyColumn<T, String>( new StringResourceModel("latestExecStatus", this), "latestExecStatus", "latestExecStatus")); http://git-wip-us.apache.org/repos/asf/syncope/blob/bb508d9f/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPATaskDAO.java ---------------------------------------------------------------------- diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPATaskDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPATaskDAO.java index dfb7536..f6ee96c 100644 --- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPATaskDAO.java +++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPATaskDAO.java @@ -18,11 +18,17 @@ */ package org.apache.syncope.core.persistence.jpa.dao; +import java.lang.reflect.Field; +import java.util.ArrayList; import java.util.Collections; import java.util.List; +import javax.persistence.DiscriminatorValue; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; import javax.persistence.Query; import org.apache.commons.collections4.Closure; import org.apache.commons.collections4.IterableUtils; +import org.apache.commons.collections4.Predicate; import org.apache.commons.lang3.StringUtils; import org.apache.syncope.common.lib.types.AnyTypeKind; import org.apache.syncope.common.lib.types.TaskType; @@ -37,6 +43,7 @@ import org.apache.syncope.core.persistence.jpa.entity.task.JPAPushTask; import org.apache.syncope.core.persistence.jpa.entity.task.JPASchedTask; import org.apache.syncope.core.persistence.jpa.entity.task.JPAPullTask; import org.apache.syncope.core.persistence.jpa.entity.task.AbstractTask; +import org.apache.syncope.core.persistence.jpa.entity.task.JPATaskExec; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.ReflectionUtils; @@ -75,6 +82,36 @@ public class JPATaskDAO extends AbstractDAO<Task> implements TaskDAO { return result; } + private String getEntityTableName(final TaskType type) { + String result = null; + + switch (type) { + case NOTIFICATION: + result = JPANotificationTask.class.getAnnotation(DiscriminatorValue.class).value(); + break; + + case PROPAGATION: + result = JPAPropagationTask.class.getAnnotation(DiscriminatorValue.class).value(); + break; + + case PUSH: + result = JPAPushTask.class.getAnnotation(DiscriminatorValue.class).value(); + break; + + case SCHEDULED: + result = JPASchedTask.class.getAnnotation(DiscriminatorValue.class).value(); + break; + + case PULL: + result = JPAPullTask.class.getAnnotation(DiscriminatorValue.class).value(); + break; + + default: + } + + return result; + } + @Transactional(readOnly = true) @SuppressWarnings("unchecked") @Override @@ -82,7 +119,7 @@ public class JPATaskDAO extends AbstractDAO<Task> implements TaskDAO { return (T) entityManager().find(AbstractTask.class, key); } - private <T extends Task> StringBuilder buildFindAllQuery(final TaskType type) { + private <T extends Task> StringBuilder buildFindAllQueryJPA(final TaskType type) { StringBuilder builder = new StringBuilder("SELECT t FROM "). append(getEntityReference(type).getSimpleName()). append(" t WHERE "); @@ -102,7 +139,7 @@ public class JPATaskDAO extends AbstractDAO<Task> implements TaskDAO { @Override @SuppressWarnings("unchecked") public <T extends Task> List<T> findToExec(final TaskType type) { - StringBuilder queryString = buildFindAllQuery(type).append("AND "); + StringBuilder queryString = buildFindAllQueryJPA(type).append("AND "); if (type == TaskType.NOTIFICATION) { queryString.append("t.executed = 0 "); @@ -126,7 +163,9 @@ public class JPATaskDAO extends AbstractDAO<Task> implements TaskDAO { final ExternalResource resource, final Notification notification, final AnyTypeKind anyTypeKind, - final String entityKey) { + final String entityKey, + final boolean orderByTaskExecInfo, + final List<Object> queryParameters) { if (resource != null && type != TaskType.PROPAGATION && type != TaskType.PUSH && type != TaskType.PULL) { @@ -144,38 +183,135 @@ public class JPATaskDAO extends AbstractDAO<Task> implements TaskDAO { throw new IllegalArgumentException(type + " is not related to notifications"); } - StringBuilder queryString = buildFindAllQuery(type); + StringBuilder queryString = new StringBuilder("SELECT "). + append(AbstractTask.TABLE). + append(".id FROM "). + append(AbstractTask.TABLE); + if (orderByTaskExecInfo) { + queryString.append(" LEFT OUTER JOIN "). + append(JPATaskExec.TABLE). + append(" ON "). + append(AbstractTask.TABLE). + append(".id = "). + append(JPATaskExec.TABLE). + append(".task_id"); + } + queryString.append(" WHERE "). + append(AbstractTask.TABLE). + append(".DTYPE = ?1"); + queryParameters.add(getEntityTableName(type)); + if (type == TaskType.SCHEDULED) { + queryString.append(" AND "). + append(AbstractTask.TABLE). + append(".id NOT IN (SELECT ").append(AbstractTask.TABLE).append(".id FROM "). + append(AbstractTask.TABLE).append(" WHERE "). + append(AbstractTask.TABLE).append(".DTYPE = ?2)"). + append(" AND "). + append(AbstractTask.TABLE). + append(".id NOT IN (SELECT id FROM "). + append(AbstractTask.TABLE).append(" WHERE "). + append(AbstractTask.TABLE).append(".DTYPE = ?3)"); + + queryParameters.add(JPAPushTask.class.getAnnotation(DiscriminatorValue.class).value()); + queryParameters.add(JPAPullTask.class.getAnnotation(DiscriminatorValue.class).value()); + } + queryString.append(' '); if (resource != null) { - queryString.append("AND t.resource=:resource "); + queryParameters.add(resource.getKey()); + + queryString.append("AND "). + append(AbstractTask.TABLE). + append(".resource_id=?").append(queryParameters.size()); } if (notification != null) { - queryString.append("AND t.notification=:notification "); + queryParameters.add(notification.getKey()); + + queryString.append("AND "). + append(AbstractTask.TABLE). + append(".notification_id=?").append(queryParameters.size()); } if (anyTypeKind != null && entityKey != null) { - queryString.append("AND t.anyTypeKind=:anyTypeKind AND t.entityKey=:entityKey "); + queryParameters.add(anyTypeKind.name()); + queryParameters.add(entityKey); + + queryString.append("AND "). + append(AbstractTask.TABLE). + append(".anyTypeKind=?").append(queryParameters.size() - 1). + append(" AND "). + append(AbstractTask.TABLE). + append(".entityKey=?").append(queryParameters.size()); } return queryString; } private String toOrderByStatement( - final Class<? extends Task> beanClass, final List<OrderByClause> orderByClauses) { + final Class<? extends Task> beanClass, + final List<OrderByClause> orderByClauses, + final boolean orderByTaskExecInfo) { StringBuilder statement = new StringBuilder(); + if (orderByTaskExecInfo) { + statement.append(" AND ("). + append(JPATaskExec.TABLE). + append(".startDate IS NULL OR "). + append(JPATaskExec.TABLE). + append(".startDate = (SELECT MAX("). + append(JPATaskExec.TABLE). + append(".startDate) FROM "). + append(JPATaskExec.TABLE). + append(" WHERE "). + append(AbstractTask.TABLE). + append(".id = "). + append(JPATaskExec.TABLE). + append(".task_id))"); + } + statement.append(" ORDER BY "); + + StringBuilder subStatement = new StringBuilder(); for (OrderByClause clause : orderByClauses) { String field = clause.getField().trim(); - if (ReflectionUtils.findField(beanClass, field) != null) { - statement.append("t.").append(field).append(' ').append(clause.getDirection().name()); + String table = JPATaskExec.TABLE; + switch (field) { + case "latestExecStatus": + field = "status"; + break; + + case "start": + field = "startDate"; + break; + + case "end": + field = "endDate"; + break; + + default: + Field beanField = ReflectionUtils.findField(beanClass, field); + if (beanField != null + && (beanField.getAnnotation(ManyToOne.class) != null + || beanField.getAnnotation(OneToMany.class) != null)) { + field += "_id"; + } + table = AbstractTask.TABLE; } + subStatement.append(table). + append("."). + append(field). + append(' '). + append(clause.getDirection().name()). + append(','); } - if (statement.length() == 0) { - statement.append("ORDER BY t.id DESC"); + if (subStatement.length() == 0) { + statement.append(AbstractTask.TABLE). + append(".id DESC"); } else { - statement.insert(0, "ORDER BY "); + subStatement.deleteCharAt(subStatement.length() - 1); + statement.append(subStatement); } + return statement.toString(); } @@ -191,19 +327,31 @@ public class JPATaskDAO extends AbstractDAO<Task> implements TaskDAO { final int itemsPerPage, final List<OrderByClause> orderByClauses) { - StringBuilder queryString = buildFindAllQuery(type, resource, notification, anyTypeKind, entityKey). - append(toOrderByStatement(getEntityReference(type), orderByClauses)); + List<Object> queryParameters = new ArrayList<>(); - Query query = entityManager().createQuery(queryString.toString()); - if (resource != null) { - query.setParameter("resource", resource); - } - if (notification != null) { - query.setParameter("notification", notification); - } - if (anyTypeKind != null && entityKey != null) { - query.setParameter("anyTypeKind", anyTypeKind); - query.setParameter("entityKey", entityKey); + boolean orderByTaskExecInfo = IterableUtils.matchesAny(orderByClauses, new Predicate<OrderByClause>() { + + @Override + public boolean evaluate(final OrderByClause object) { + return object.getField().equals("start") + || object.getField().equals("end") + || object.getField().equals("latestExecStatus") + || object.getField().equals("status"); + } + }); + StringBuilder queryString = buildFindAllQuery(type, + resource, + notification, + anyTypeKind, + entityKey, + orderByTaskExecInfo, + queryParameters). + append(toOrderByStatement(getEntityReference(type), orderByClauses, orderByTaskExecInfo)); + + Query query = entityManager().createNativeQuery(queryString.toString()); + + for (int i = 1; i <= queryParameters.size(); i++) { + query.setParameter(i, queryParameters.get(i - 1)); } query.setFirstResult(itemsPerPage * (page <= 0 ? 0 : page - 1)); @@ -212,7 +360,7 @@ public class JPATaskDAO extends AbstractDAO<Task> implements TaskDAO { query.setMaxResults(itemsPerPage); } - return query.getResultList(); + return buildResult(query.getResultList()); } @Override @@ -223,19 +371,18 @@ public class JPATaskDAO extends AbstractDAO<Task> implements TaskDAO { final AnyTypeKind anyTypeKind, final String entityKey) { - StringBuilder queryString = buildFindAllQuery(type, resource, notification, anyTypeKind, entityKey); + List<Object> queryParameters = new ArrayList<>(); - Query query = entityManager().createQuery(StringUtils.replaceOnce( - queryString.toString(), "SELECT t", "SELECT COUNT(t)")); - if (resource != null) { - query.setParameter("resource", resource); - } - if (notification != null) { - query.setParameter("notification", notification); - } - if (anyTypeKind != null && entityKey != null) { - query.setParameter("anyTypeKind", anyTypeKind); - query.setParameter("entityKey", entityKey); + StringBuilder queryString = + buildFindAllQuery(type, resource, notification, anyTypeKind, entityKey, false, queryParameters); + + Query query = entityManager().createNativeQuery(StringUtils.replaceOnce( + queryString.toString(), + "SELECT " + AbstractTask.TABLE + ".id", + "SELECT COUNT(" + AbstractTask.TABLE + ".id)")); + + for (int i = 1; i <= queryParameters.size(); i++) { + query.setParameter(i, queryParameters.get(i - 1)); } return ((Number) query.getSingleResult()).intValue(); @@ -274,4 +421,24 @@ public class JPATaskDAO extends AbstractDAO<Task> implements TaskDAO { } }); } + + private <T extends Task> List<T> buildResult(final List<Object> raw) { + List<T> result = new ArrayList<>(); + + for (Object anyKey : raw) { + String actualKey = anyKey instanceof Object[] + ? (String) ((Object[]) anyKey)[0] + : ((String) anyKey); + + @SuppressWarnings("unchecked") + T any = find(actualKey); + if (any == null) { + LOG.error("Could not find task with id {}, even if returned by native query", actualKey); + } else if (!result.contains(any)) { + result.add(any); + } + } + + return result; + } } http://git-wip-us.apache.org/repos/asf/syncope/blob/bb508d9f/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/TaskTest.java ---------------------------------------------------------------------- diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/TaskTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/TaskTest.java index fc47959..e1e6f1a 100644 --- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/TaskTest.java +++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/TaskTest.java @@ -24,9 +24,11 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashSet; +import java.util.List; import java.util.Set; import org.apache.syncope.common.lib.to.UserTO; import org.apache.syncope.common.lib.types.AnyTypeKind; @@ -59,164 +61,179 @@ import org.apache.syncope.core.provisioning.api.pushpull.PullActions; @Transactional("Master") public class TaskTest extends AbstractTest { - + @Autowired private TaskDAO taskDAO; - + @Autowired private TaskExecDAO taskExecDAO; - + @Autowired private ExternalResourceDAO resourceDAO; - + @Autowired private UserDAO userDAO; - + @Test public void read() { PropagationTask task = taskDAO.find("1e697572-b896-484c-ae7f-0c8f63fcbc6c"); assertNotNull(task); - + assertNotNull(task.getExecs()); assertFalse(task.getExecs().isEmpty()); assertEquals(1, task.getExecs().size()); } - + + @Test + public void readMultipleOrderBy() { + List<OrderByClause> orderByClauses = new ArrayList<>(); + OrderByClause clause1 = new OrderByClause(); + clause1.setField("start"); + OrderByClause clause2 = new OrderByClause(); + clause2.setField("latestExecStatus"); + OrderByClause clause3 = new OrderByClause(); + clause3.setField("connObjectKey"); + orderByClauses.add(clause1); + orderByClauses.add(clause2); + orderByClauses.add(clause3); + assertFalse(taskDAO.findAll(TaskType.PROPAGATION, null, null, null, null, -1, -1, orderByClauses).isEmpty()); + } + @Test public void save() { ExternalResource resource = resourceDAO.find("ws-target-resource-1"); assertNotNull(resource); - + User user = userDAO.findByUsername("verdi"); assertNotNull(user); - + PropagationTask task = entityFactory.newEntity(PropagationTask.class); task.setResource(resource); task.setAnyTypeKind(AnyTypeKind.USER); task.setAnyType(AnyTypeKind.USER.name()); task.setOperation(ResourceOperation.CREATE); task.setConnObjectKey("o...@two.com"); - + Set<Attribute> attributes = new HashSet<>(); attributes.add(AttributeBuilder.build("testAttribute", "testValue1", "testValue2")); attributes.add(AttributeBuilder.buildPassword("password".toCharArray())); task.setAttributes(attributes); - + task = taskDAO.save(task); assertNotNull(task); - + PropagationTask actual = taskDAO.find(task.getKey()); assertEquals(task, actual); - + taskDAO.flush(); - + resource = resourceDAO.find("ws-target-resource-1"); assertTrue(taskDAO.findAll( TaskType.PROPAGATION, resource, null, null, null, -1, -1, Collections.<OrderByClause>emptyList()). contains(task)); } - + @Test public void addPropagationTaskExecution() { PropagationTask task = taskDAO.find("1e697572-b896-484c-ae7f-0c8f63fcbc6c"); assertNotNull(task); - + int executionNumber = task.getExecs().size(); - + TaskExec execution = entityFactory.newEntity(TaskExec.class); execution.setTask(task); execution.setStatus(PropagationTaskExecStatus.CREATED.name()); execution.setStart(new Date()); task.add(execution); - + taskDAO.save(task); taskDAO.flush(); - + task = taskDAO.find("1e697572-b896-484c-ae7f-0c8f63fcbc6c"); assertNotNull(task); - + assertEquals(executionNumber + 1, task.getExecs().size()); } - + @Test public void addPullTaskExecution() { PullTask task = taskDAO.find("c41b9b71-9bfa-4f90-89f2-84787def4c5c"); assertNotNull(task); - + int executionNumber = task.getExecs().size(); - + TaskExec execution = entityFactory.newEntity(TaskExec.class); execution.setStatus("Text-free status"); execution.setTask(task); execution.setStart(new Date()); execution.setMessage("A message"); task.add(execution); - + taskDAO.save(task); taskDAO.flush(); - + task = taskDAO.find("c41b9b71-9bfa-4f90-89f2-84787def4c5c"); assertNotNull(task); - + assertEquals(executionNumber + 1, task.getExecs().size()); } - + @Test public void addPushTaskExecution() { PushTask task = taskDAO.find("af558be4-9d2f-4359-bf85-a554e6e90be1"); assertNotNull(task); - + int executionNumber = task.getExecs().size(); - + TaskExec execution = entityFactory.newEntity(TaskExec.class); execution.setStatus("Text-free status"); execution.setTask(task); execution.setStart(new Date()); execution.setMessage("A message"); task.add(execution); - + taskDAO.save(task); taskDAO.flush(); - + task = taskDAO.find("af558be4-9d2f-4359-bf85-a554e6e90be1"); assertNotNull(task); - + assertEquals(executionNumber + 1, task.getExecs().size()); } - + @Test public void deleteTask() { taskDAO.delete("1e697572-b896-484c-ae7f-0c8f63fcbc6c"); - + taskDAO.flush(); - + assertNull(taskDAO.find("1e697572-b896-484c-ae7f-0c8f63fcbc6c")); assertNull(taskExecDAO.find("e58ca1c7-178a-4012-8a71-8aa14eaf0655")); } - + @Test public void deleteTaskExecution() { TaskExec execution = taskExecDAO.find("e58ca1c7-178a-4012-8a71-8aa14eaf0655"); int executionNumber = execution.getTask().getExecs().size(); - + taskExecDAO.delete("e58ca1c7-178a-4012-8a71-8aa14eaf0655"); - + taskExecDAO.flush(); - + assertNull(taskExecDAO.find("e58ca1c7-178a-4012-8a71-8aa14eaf0655")); - + PropagationTask task = taskDAO.find("1e697572-b896-484c-ae7f-0c8f63fcbc6c"); assertEquals(task.getExecs().size(), executionNumber - 1); } - + @Test public void savePullTask() { ExternalResource resource = resourceDAO.find("ws-target-resource-1"); assertNotNull(resource); - + AnyTemplatePullTask template = entityFactory.newEntity(AnyTemplatePullTask.class); template.set(new UserTO()); - + PullTask task = entityFactory.newEntity(PullTask.class); task.setName("savePullTask"); task.setDescription("PullTask description"); @@ -235,7 +252,7 @@ public class TaskTest extends AbstractTest { exception = e; } assertNotNull(exception); - + task.setCronExpression(null); // this save() fails because a PullTask requires a target resource exception = null; @@ -245,7 +262,7 @@ public class TaskTest extends AbstractTest { exception = e; } assertNotNull(exception); - + task.setResource(resource); task.getActionsClassNames().add(getClass().getName()); @@ -258,24 +275,24 @@ public class TaskTest extends AbstractTest { exception = e; } assertNotNull(exception); - + task.getActionsClassNames().clear(); task.getActionsClassNames().add(PullActions.class.getName()); // this save() finally works task = taskDAO.save(task); assertNotNull(task); - + PullTask actual = taskDAO.find(task.getKey()); assertEquals(task, actual); } - + @Test public void issueSYNCOPE144() { ExternalResource resource = resourceDAO.find("ws-target-resource-1"); assertNotNull(resource); - + PullTask task = entityFactory.newEntity(PullTask.class); - + task.setResource(resource); task.setName("issueSYNCOPE144"); task.setDescription("issueSYNCOPE144 Description"); @@ -284,22 +301,22 @@ public class TaskTest extends AbstractTest { task.getActionsClassNames().add(PullActions.class.getName()); task.setMatchingRule(MatchingRule.UPDATE); task.setUnmatchingRule(UnmatchingRule.PROVISION); - + task = taskDAO.save(task); assertNotNull(task); - + PullTask actual = taskDAO.find(task.getKey()); assertEquals(task, actual); assertEquals("issueSYNCOPE144", actual.getName()); assertEquals("issueSYNCOPE144 Description", actual.getDescription()); - + actual.setName("issueSYNCOPE144_2"); actual.setDescription("issueSYNCOPE144 Description_2"); - + actual = taskDAO.save(actual); assertNotNull(actual); assertEquals("issueSYNCOPE144_2", actual.getName()); assertEquals("issueSYNCOPE144 Description_2", actual.getDescription()); } - + } http://git-wip-us.apache.org/repos/asf/syncope/blob/bb508d9f/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java ---------------------------------------------------------------------- diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java index f583d86..b1e650d 100644 --- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java +++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java @@ -24,12 +24,17 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; import org.apache.commons.collections4.IterableUtils; import org.apache.commons.collections4.Predicate; import org.apache.commons.lang3.SerializationUtils; +import org.apache.syncope.common.lib.patch.AttrPatch; +import org.apache.syncope.common.lib.patch.UserPatch; import org.apache.syncope.common.lib.to.TaskTO; import org.apache.syncope.common.lib.to.AnyObjectTO; +import org.apache.syncope.common.lib.to.AttrTO; import org.apache.syncope.common.lib.to.BulkAction; import org.apache.syncope.common.lib.to.ConnObjectTO; import org.apache.syncope.common.lib.to.PagedResult; @@ -40,6 +45,7 @@ import org.apache.syncope.common.lib.to.ProvisionTO; import org.apache.syncope.common.lib.to.ResourceTO; import org.apache.syncope.common.lib.to.UserTO; import org.apache.syncope.common.lib.types.AnyTypeKind; +import org.apache.syncope.common.lib.types.PatchOperation; import org.apache.syncope.common.lib.types.TaskType; import org.apache.syncope.common.rest.api.beans.ExecuteQuery; import org.apache.syncope.common.rest.api.beans.ExecQuery; @@ -196,4 +202,76 @@ public class PropagationTaskITCase extends AbstractTaskITCase { page(1).size(2).build()); assertTrue(execs.getTotalCount() >= execs.getResult().size()); } + + @Test + public void issueSYNCOPE1288() { + // create a new user + UserTO userTO = UserITCase.getUniqueSampleTO("xxx...@xxx.xxx"); + userTO.getResources().add(RESOURCE_NAME_LDAP); + + userTO = createUser(userTO).getEntity(); + assertNotNull(userTO); + + // generate some PropagationTasks + for (int i = 0; i < 9; i++) { + UserPatch userPatch = new UserPatch(); + userPatch.setKey(userTO.getKey()); + userPatch.getPlainAttrs().add(new AttrPatch.Builder().operation(PatchOperation.ADD_REPLACE). + attrTO(new AttrTO.Builder().schema("userId").value( + "test" + getUUIDString() + i + "@test.com").build()). + build()); + + userService.update(userPatch); + } + + // ASC order + PagedResult<TaskTO> unorderedTasks = taskService.search( + new TaskQuery.Builder(TaskType.PROPAGATION). + resource(RESOURCE_NAME_LDAP). + entityKey(userTO.getKey()). + anyTypeKind(AnyTypeKind.USER). + page(1). + size(10). + build()); + Collections.sort(unorderedTasks.getResult(), new Comparator<TaskTO>() { + + @Override + public int compare(final TaskTO o1, final TaskTO o2) { + return o1.getStart().compareTo(o2.getStart()); + } + }); + assertNotNull(unorderedTasks); + assertFalse(unorderedTasks.getResult().isEmpty()); + assertEquals(10, unorderedTasks.getResult().size()); + + PagedResult<TaskTO> orderedTasks = taskService.search( + new TaskQuery.Builder(TaskType.PROPAGATION). + resource(RESOURCE_NAME_LDAP). + entityKey(userTO.getKey()). + anyTypeKind(AnyTypeKind.USER). + page(1). + size(10). + orderBy("start"). + build()); + assertNotNull(orderedTasks); + assertFalse(orderedTasks.getResult().isEmpty()); + assertEquals(10, orderedTasks.getResult().size()); + + assertTrue(orderedTasks.getResult().equals(unorderedTasks.getResult())); + + // DESC order + Collections.reverse(unorderedTasks.getResult()); + orderedTasks = taskService.search( + new TaskQuery.Builder(TaskType.PROPAGATION). + resource(RESOURCE_NAME_LDAP). + entityKey(userTO.getKey()). + anyTypeKind(AnyTypeKind.USER). + page(1). + size(10). + orderBy("start DESC"). + build()); + + assertTrue(orderedTasks.getResult().equals(unorderedTasks.getResult())); + } + }