This is an automated email from the ASF dual-hosted git repository.
kwin pushed a commit to branch master
in repository
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-jcr-resource.git
The following commit(s) were added to refs/heads/master by this push:
new 7660582 SLING-12246 Add tests for move and orderBefore operations
(#41)
7660582 is described below
commit 7660582019bc8b4b0fdda73bdddbde77262159e6
Author: Konrad Windszus <[email protected]>
AuthorDate: Fri Mar 1 12:17:55 2024 +0100
SLING-12246 Add tests for move and orderBefore operations (#41)
The move operations are tested with observers on different levels
---
.../resource/internal/JcrResourceListenerTest.java | 153 ++++++++++++++++++++-
1 file changed, 147 insertions(+), 6 deletions(-)
diff --git
a/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerTest.java
b/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerTest.java
index 9389a69..e487b10 100644
---
a/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerTest.java
+++
b/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerTest.java
@@ -18,6 +18,7 @@ package org.apache.sling.jcr.resource.internal;
import static java.util.Collections.synchronizedList;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -29,12 +30,17 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import javax.jcr.AccessDeniedException;
import javax.jcr.Credentials;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;
+import javax.jcr.lock.LockException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.version.VersionException;
+import org.apache.jackrabbit.commons.JcrUtils;
import org.apache.sling.api.resource.observation.ResourceChange;
import org.apache.sling.api.resource.observation.ResourceChange.ChangeType;
import org.apache.sling.api.resource.path.PathSet;
@@ -61,6 +67,8 @@ public class JcrResourceListenerTest {
private final String createdPath = "/test" + System.currentTimeMillis() +
"-create";
+ private final String movedPath = "/test" + System.currentTimeMillis() +
"-moved";
+
private final String pathToDelete = "/test" + System.currentTimeMillis() +
"-delete";
private final String pathToModify = "/test" + System.currentTimeMillis() +
"-modify";
@@ -74,7 +82,13 @@ public class JcrResourceListenerTest {
public void setUp() throws Exception {
repository = SlingRepositoryProvider.getRepository();
this.adminSession = repository.loginAdministrative(null);
- ObservationReporter observationReporter = getObservationReporter();
+ registerListener("/");
+ }
+
+ private void registerListener(String paths) throws RepositoryException {
+ unregisterListener();
+ events.clear();
+ ObservationReporter observationReporter =
getObservationReporter(paths);
this.config = new JcrListenerBaseConfig(observationReporter,
new SlingRepository() {
@@ -140,7 +154,6 @@ public class JcrResourceListenerTest {
@Override
public String getDefaultWorkspace() {
- // TODO Auto-generated method stub
return repository.getDefaultWorkspace();
}
});
@@ -149,11 +162,22 @@ public class JcrResourceListenerTest {
}
@After
- public void tearDown() {
+ public void tearDown() throws AccessDeniedException, VersionException,
LockException, ConstraintViolationException, RepositoryException {
+ unregisterListener();
+ if (adminSession.itemExists("/apps")) {
+ adminSession.removeItem("/apps");
+ }
+ if (adminSession.itemExists("/apps2")) {
+ adminSession.removeItem("/apps2");
+ }
if (adminSession != null) {
+ adminSession.save();
adminSession.logout();
adminSession = null;
}
+ }
+
+ private void unregisterListener() {
if (listener != null) {
listener.close();
listener = null;
@@ -200,6 +224,115 @@ public class JcrResourceListenerTest {
assertTrue("Removed set should contain " + pathToDelete,
removePaths.contains(pathToDelete));
}
+ @Test
+ public void testMoveOperationsInsideObservedPathOnLeafNode() throws
RepositoryException, InterruptedException {
+ createNode(adminSession, createdPath);
+ adminSession.move(createdPath, movedPath);
+ adminSession.save();
+ Thread.sleep(3500);
+
+ assertTrue("Events must contain \"added\" for path \"" + movedPath +
"\"",
+ events.stream().anyMatch(e -> e.getPath().equals(movedPath) &&
e.getType() == ChangeType.ADDED));
+ assertTrue("Events must contain \"removed\" for path \"" + createdPath
+ "\"",
+ events.stream().anyMatch(e -> e.getPath().equals(createdPath)
&& e.getType() == ChangeType.REMOVED));
+ }
+
+ @Test
+ public void testMoveOperationsInsideObservedPath() throws
RepositoryException, InterruptedException {
+ createNode(adminSession, "/apps/test" + createdPath);
+ // clear events for node creation
+ Thread.sleep(2000);
+ registerListener("/");
+ adminSession.move("/apps", "/apps2");
+ adminSession.save();
+ Thread.sleep(3500);
+
+ // 1 added + 1 removed event for roots
+ assertEquals("Events must only contain 2 events but has " +
events.toString(), 2, events.size());
+ assertTrue("Events must contain \"added\" for path \"/apps2\"",
+ events.stream().anyMatch(e -> e.getPath().equals("/apps2") &&
e.getType() == ChangeType.ADDED));
+ assertTrue("Events must contain \"removed\" for path \"/apps\"",
+ events.stream().anyMatch(e -> e.getPath().equals("/apps") &&
e.getType() == ChangeType.REMOVED));
+ }
+
+ @Test
+ public void testMoveOperationsIntoObservedPath() throws
RepositoryException, InterruptedException {
+ registerListener("/apps");
+ createNode(adminSession, "/apps2/test" + createdPath);
+ adminSession.move("/apps2", "/apps");
+ adminSession.save();
+ Thread.sleep(3500);
+ String expectedAddedPath = "/apps/test" + createdPath;
+ assertTrue("Events must contain \"added\" for path \"" +
expectedAddedPath + "\"",
+ events.stream().anyMatch(e ->
e.getPath().equals(expectedAddedPath) && e.getType() == ChangeType.ADDED));
+ assertFalse("Events must not contain any \"removed\" events",
+ events.stream().anyMatch(e -> e.getType() ==
ChangeType.REMOVED));
+ }
+
+ @Test
+ public void testMoveOperationsOutOfObservedPath() throws
RepositoryException, InterruptedException {
+ createNode(adminSession, "/apps/test" + createdPath);
+ Thread.sleep(2000);
+ registerListener("/apps");
+ adminSession.move("/apps", "/apps2");
+ adminSession.save();
+ Thread.sleep(3500);
+ String expectedPath = "/apps";
+ // 1 removed events for the moved root only
+ assertEquals("Events must only contain 1 events but has " +
events.toString(), 1, events.size());
+ assertTrue("Events must contain \"removed\" for path \"" +
expectedPath + "\"",
+ events.stream().anyMatch(e -> e.getPath().equals(expectedPath)
&& e.getType() == ChangeType.REMOVED));
+ }
+
+ @Test
+ public void testMoveOperationsIntoObservedPathWithGlobs() throws
RepositoryException, InterruptedException {
+ registerListener("glob:/*/test/**");
+ createNode(adminSession, "/apps/test2" + createdPath);
+ adminSession.move("/apps/test2", "/apps/test"); // move happens above
observed path
+ adminSession.save();
+ Thread.sleep(3500);
+
+ // only an added event for the root is received
+ assertEquals("Events must only contain 1 event but has " +
events.toString(), 1, events.size());
+ assertTrue("Events must contain \"added\" for root path
\"/apps/test\"",
+ events.stream().anyMatch(e -> e.getPath().equals("/apps/test")
&& e.getType() == ChangeType.ADDED));
+ }
+
+ @Test
+ public void testMoveOperationsOutOfObservedPathWithGlobs() throws
RepositoryException, InterruptedException {
+ createNode(adminSession, "/apps/test" + createdPath);
+ Thread.sleep(2000);
+ registerListener("glob:/*/test/**");
+ adminSession.save();
+ adminSession.move("/apps/test", "/apps/test2"); // move happens above
observed path
+ adminSession.save();
+ Thread.sleep(3500);
+
+ // 2 removed events for the whole subgraph below the observed path is
received
+ assertEquals("Events must only contain 2 events but has " +
events.toString(), 2, events.size());
+ assertTrue("Events must contain \"added\" for root path
\"/apps/test\"",
+ events.stream().anyMatch(e -> e.getPath().equals("/apps/test"
+ createdPath) && e.getType() == ChangeType.REMOVED));
+ }
+
+ @Test
+ public void testOrderBeforeOperations() throws RepositoryException,
InterruptedException {
+ Node node = createNode(adminSession, createdPath);
+ node.addNode("child1");
+ node.addNode("child2");
+
+ adminSession.save();
+ Thread.sleep(2000);
+ events.clear();
+ // reorder child1 to appear after child2
+ node.orderBefore("child1", null);
+
+ adminSession.save();
+ Thread.sleep(2000);
+
+ // TODO: send events here
+ assertEquals("Received: " + events, 0, events.size());
+ }
+
@Test
public void testMultiplePaths() throws Exception {
ObserverConfiguration observerConfig = new ObserverConfiguration() {
@@ -304,7 +437,7 @@ public class JcrResourceListenerTest {
}
private static Node createNode(final Session session, final String path)
throws RepositoryException {
- final Node n = session.getRootNode().addNode(path.substring(1),
"nt:unstructured");
+ Node n = JcrUtils.getOrCreateByPath(path, "nt:unstructured", session);
session.save();
return n;
}
@@ -332,11 +465,19 @@ public class JcrResourceListenerTest {
}
protected ObservationReporter getObservationReporter() {
- return new SimpleObservationReporter();
+ return new SimpleObservationReporter("/");
+ }
+
+ protected ObservationReporter getObservationReporter(String... paths) {
+ return new SimpleObservationReporter(paths);
}
private class SimpleObservationReporter implements ObservationReporter {
+ private final String[] paths;
+ public SimpleObservationReporter(String... paths) {
+ this.paths = paths;
+ }
@Override
public void reportChanges(Iterable<ResourceChange> changes, boolean
distribute) {
for (ResourceChange c : changes) {
@@ -355,7 +496,7 @@ public class JcrResourceListenerTest {
@Override
public PathSet getPaths() {
- return PathSet.fromStrings("/");
+ return PathSet.fromStrings(paths);
}
@Override