You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by md...@apache.org on 2013/06/19 14:21:21 UTC

svn commit: r1494578 - /jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java

Author: mduerig
Date: Wed Jun 19 12:21:20 2013
New Revision: 1494578

URL: http://svn.apache.org/r1494578
Log:
OAK-144 Implement Observation
simplify observation tests

Modified:
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java

Modified: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java?rev=1494578&r1=1494577&r2=1494578&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java Wed Jun 19 12:21:20 2013
@@ -19,6 +19,13 @@
 package org.apache.jackrabbit.oak.jcr;
 
 import static java.util.Arrays.asList;
+import static javax.jcr.observation.Event.NODE_ADDED;
+import static javax.jcr.observation.Event.NODE_MOVED;
+import static javax.jcr.observation.Event.NODE_REMOVED;
+import static javax.jcr.observation.Event.PERSIST;
+import static javax.jcr.observation.Event.PROPERTY_ADDED;
+import static javax.jcr.observation.Event.PROPERTY_CHANGED;
+import static javax.jcr.observation.Event.PROPERTY_REMOVED;
 import static org.apache.jackrabbit.commons.JcrUtils.getChildNodes;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -32,15 +39,17 @@ import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.Reader;
 import java.math.BigDecimal;
-import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicReference;
@@ -74,7 +83,10 @@ import javax.jcr.observation.EventIterat
 import javax.jcr.observation.EventListener;
 import javax.jcr.observation.ObservationManager;
 
-import com.google.common.collect.Sets;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.SettableFuture;
 import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.commons.cnd.CndImporter;
 import org.apache.jackrabbit.commons.cnd.ParseException;
@@ -1806,228 +1818,96 @@ public class RepositoryTest extends Abst
     }
 
     @Test
-    public void observation() throws RepositoryException, InterruptedException {
-        final Set<String> addNodes = Sets.newHashSet(
-                TEST_PATH + "/1",
-                TEST_PATH + "/2",
-                TEST_PATH + "/3",
-                TEST_PATH + "/{4}");
-
-        final Set<String> removeNodes = Sets.newHashSet(
-                TEST_PATH + "/2");
-
-        final Set<String> addProperties = Sets.newHashSet(
-                TEST_PATH + "/property",
-                TEST_PATH + "/prop0",
-                TEST_PATH + "/1/prop1",
-                TEST_PATH + "/1/prop2",
-                TEST_PATH + "/1/jcr:primaryType",
-                TEST_PATH + "/2/jcr:primaryType",
-                TEST_PATH + "/3/jcr:primaryType",
-                TEST_PATH + "/{4}/jcr:primaryType",
-                TEST_PATH + "/3/prop3");
-
-        final Set<String> setProperties = Sets.newHashSet(
-                TEST_PATH + "/1/prop1");
-
-        final Set<String> removeProperties = Sets.newHashSet(
-                TEST_PATH + "/1/prop2",
-                TEST_PATH + "/2/jcr:primaryType");
-
-        final List<Event> failedEvents = new ArrayList<Event>();
-        final AtomicReference<CountDownLatch> eventCount = new AtomicReference<CountDownLatch>();
+    public void observation() throws RepositoryException, ExecutionException, InterruptedException {
         final Session observingSession = createAnonymousSession();
         try {
             ObservationManager obsMgr = observingSession.getWorkspace().getObservationManager();
-            obsMgr.addEventListener(new EventListener() {
-                @Override
-                public void onEvent(EventIterator events) {
-                    while (events.hasNext()) {
-                        Event event = events.nextEvent();
-                        try {
-                            String path = event.getPath();
-                            if (path.startsWith("/jcr:system")) {
-                                // ignore changes in jcr:system
-                                continue;
-                            }
-                            switch (event.getType()) {
-                                case Event.NODE_ADDED:
-                                    if (!addNodes.remove(path)) {
-                                        failedEvents.add(event);
-                                    }
-                                    if (!observingSession.nodeExists(path)) {
-                                        failedEvents.add(event);
-                                    }
-                                    break;
-                                case Event.NODE_REMOVED:
-                                    if (!removeNodes.remove(path)) {
-                                        failedEvents.add(event);
-                                    }
-                                    if (observingSession.nodeExists(path)) {
-                                        failedEvents.add(event);
-                                    }
-                                    break;
-                                case Event.PROPERTY_ADDED:
-                                    if (!addProperties.remove(path)) {
-                                        failedEvents.add(event);
-                                    }
-                                    if (!observingSession.propertyExists(path)) {
-                                        failedEvents.add(event);
-                                    }
-                                    break;
-                                case Event.PROPERTY_CHANGED:
-                                    if (!setProperties.remove(path)) {
-                                        failedEvents.add(event);
-                                    }
-                                    break;
-                                case Event.PROPERTY_REMOVED:
-                                    if (!removeProperties.remove(path)) {
-                                        failedEvents.add(event);
-                                    }
-                                    if (observingSession.propertyExists(path)) {
-                                        failedEvents.add(event);
-                                    }
-                                    break;
-                                default:
-                                    failedEvents.add(event);
-                            }
-                        } catch (RepositoryException e) {
-                            failedEvents.add(event);
-                        }
-                        eventCount.get().countDown();
-                    }
-                }
-            },
-            Event.NODE_ADDED | Event.NODE_REMOVED | Event.NODE_MOVED | Event.PROPERTY_ADDED |
-                    Event.PROPERTY_REMOVED | Event.PROPERTY_CHANGED | Event.PERSIST, "/", true, null, null, false);
+            ExpectationListener listener = new ExpectationListener();
+            obsMgr.addEventListener(listener, NODE_ADDED | NODE_REMOVED | NODE_MOVED | PROPERTY_ADDED |
+                    PROPERTY_REMOVED | PROPERTY_CHANGED | PERSIST, "/", true, null, null, false);
 
-            eventCount.set(new CountDownLatch(7));
             Node n = getNode(TEST_PATH);
-            n.setProperty("prop0", "val0");
-            Node n1 = n.addNode("1");
-            n1.setProperty("prop1", "val1");
-            n1.setProperty("prop2", "val2");
-            n.addNode("2");
+            listener.expectAdd(n.setProperty("p0", "v0"));
+            Node n1 = listener.expectAdd(n.addNode("n1"));
+            listener.expectAdd(n1.setProperty("p1", "v1"));
+            listener.expectAdd(n1.setProperty("p2", "v2"));
+            listener.expectAdd(n.addNode("n2"));
             getAdminSession().save();
-            assertTrue(eventCount.get().await(2, TimeUnit.SECONDS));
 
-            eventCount.set(new CountDownLatch(10));
-            n.setProperty("property", 42);
-            n.addNode("3").setProperty("prop3", "val3");
-            n1.setProperty("prop1", "val1 new");
-            n1.getProperty("prop2").remove();
-            n.getNode("2").remove();
-            n.addNode("{4}");
+            List<String> missing = listener.getMissing(2, TimeUnit.SECONDS);
+            assertTrue("Missing events: " + missing, missing.isEmpty());
+            List<Event> unexpected = listener.getUnexpected();
+            assertTrue("Unexpected events: " + unexpected, unexpected.isEmpty());
+
+            listener.expectAdd(n.setProperty("property", 42));
+            Node n3 = listener.expectAdd(n.addNode("n3"));
+            listener.expectAdd(n3.setProperty("p3", "v3"));
+            listener.expectChange(n1.setProperty("p1", "v1.1"));
+            listener.expectRemove(n1.getProperty("p2")).remove();
+            listener.expectRemove(n.getNode("n2")).remove();
+            listener.expectAdd(n.addNode("{4}"));
             getAdminSession().save();
-            assertTrue(eventCount.get().await(2, TimeUnit.SECONDS));
 
-            assertTrue("failedEvents not empty: " + failedEvents, failedEvents.isEmpty());
-            assertTrue("addNodes not empty: " + addNodes, addNodes.isEmpty());
-            assertTrue("removeNodes not empty: " + removeNodes, removeNodes.isEmpty());
-            assertTrue("addProperties not empty: " + addProperties, addProperties.isEmpty());
-            assertTrue("removeProperties not empty: " + removeProperties, removeProperties.isEmpty());
-            assertTrue("setProperties not empty: " + setProperties, setProperties.isEmpty());
+            missing = listener.getMissing(2, TimeUnit.SECONDS);
+            assertTrue("Missing events: " + missing, missing.isEmpty());
+            unexpected = listener.getUnexpected();
+            assertTrue("Unexpected events: " + unexpected, unexpected.isEmpty());
         } finally {
             observingSession.logout();
         }
     }
 
     @Test
-    public void observation2() throws RepositoryException, InterruptedException {
-        final Set<String> addNodes = Sets.newHashSet(
-                TEST_PATH + "/1",
-                TEST_PATH + "/2");
-
-        final Set<String> removeNodes = Sets.newHashSet(
-                TEST_PATH + "/1");
-
-        final Set<String> addProperties = Sets.newHashSet(
-                TEST_PATH + "/1/jcr:primaryType",
-                TEST_PATH + "/2/jcr:primaryType");
-
-        final Set<String> removeProperties = Sets.newHashSet(
-                TEST_PATH + "/1/jcr:primaryType");
-
-        final List<Event> failedEvents = new ArrayList<Event>();
-        final AtomicReference<CountDownLatch> eventCount = new AtomicReference<CountDownLatch>();
-
+    public void observation2() throws RepositoryException, InterruptedException, ExecutionException {
         final Session observingSession = createAnonymousSession();
         try {
             ObservationManager obsMgr = observingSession.getWorkspace().getObservationManager();
-            obsMgr.addEventListener(new EventListener() {
-                @Override
-                public void onEvent(EventIterator events) {
-                    while (events.hasNext()) {
-                        Event event = events.nextEvent();
-                        try {
-                            String path = event.getPath();
-                            if (path.startsWith("/jcr:system")) {
-                                // ignore changes in jcr:system
-                                continue;
-                            }
-                            switch (event.getType()) {
-                                case Event.NODE_ADDED:
-                                    if (!addNodes.remove(path)) {
-                                        failedEvents.add(event);
-                                    }
-                                    if (!observingSession.nodeExists(path)) {
-                                        failedEvents.add(event);
-                                    }
-                                    break;
-                                case Event.NODE_REMOVED:
-                                    if (!removeNodes.remove(path)) {
-                                        failedEvents.add(event);
-                                    }
-                                    if (observingSession.nodeExists(path)) {
-                                        failedEvents.add(event);
-                                    }
-                                    break;
-                                case Event.PROPERTY_ADDED:
-                                    if (!addProperties.remove(path)) {
-                                        failedEvents.add(event);
-                                    }
-                                    if (!observingSession.propertyExists(path)) {
-                                        failedEvents.add(event);
-                                    }
-                                    break;
-                                case Event.PROPERTY_REMOVED:
-                                    if (!removeProperties.remove(path)) {
-                                        failedEvents.add(event);
-                                    }
-                                    if (observingSession.propertyExists(path)) {
-                                        failedEvents.add(event);
-                                    }
-                                    break;
-                                default:
-                                    failedEvents.add(event);
-                            }
-                        } catch (RepositoryException e) {
-                            failedEvents.add(event);
-                        }
-                        eventCount.get().countDown();
-                    }
-                }
-            },
-                    Event.NODE_ADDED | Event.NODE_REMOVED | Event.NODE_MOVED | Event.PROPERTY_ADDED |
-                            Event.PROPERTY_REMOVED | Event.PROPERTY_CHANGED | Event.PERSIST, "/", true, null, null, false);
+            ExpectationListener listener = new ExpectationListener();
+            obsMgr.addEventListener(listener, NODE_ADDED | NODE_REMOVED | NODE_MOVED | PROPERTY_ADDED |
+                    PROPERTY_REMOVED | PROPERTY_CHANGED | PERSIST, "/", true, null, null, false);
 
-            eventCount.set(new CountDownLatch(2));
             Node n = getNode(TEST_PATH);
-            n.addNode("1");
+            listener.expectAdd(n.addNode("n1"));
             getAdminSession().save();
-            assertTrue(eventCount.get().await(2, TimeUnit.SECONDS));
 
-            eventCount.set(new CountDownLatch(4));
-            n.addNode("2");
-            n.getNode("1").remove();
+            List<String> missing = listener.getMissing(2, TimeUnit.SECONDS);
+            assertTrue("Missing events: " + missing, missing.isEmpty());
+            List<Event> unexpected = listener.getUnexpected();
+            assertTrue("Unexpected events: " + unexpected, unexpected.isEmpty());
+
+            listener.expectAdd(n.addNode("n2"));
+            listener.expectRemove(n.getNode("n1")).remove();
             getAdminSession().save();
-            assertTrue(eventCount.get().await(2, TimeUnit.SECONDS));
 
-            assertTrue("failedEvents not empty: " + failedEvents, failedEvents.isEmpty());
-            assertTrue("addNodes not empty: " + addNodes, addNodes.isEmpty());
-            assertTrue("removeNodes not empty: " + removeNodes, removeNodes.isEmpty());
-            assertTrue("addProperties not empty: " + addProperties, addProperties.isEmpty());
-            assertTrue("removeProperties not empty: " + removeProperties, removeProperties.isEmpty());
+            missing = listener.getMissing(2, TimeUnit.SECONDS);
+            assertTrue("Missing events: " + missing, missing.isEmpty());
+            unexpected = listener.getUnexpected();
+            assertTrue("Unexpected events: " + unexpected, unexpected.isEmpty());
+        } finally {
+            observingSession.logout();
+        }
+    }
+
+    @Test
+    public void observationOnRootNode() throws Exception {
+        final AtomicReference<CountDownLatch> hasEvents = new AtomicReference<CountDownLatch>(new CountDownLatch(1));
+        Session observingSession = createAdminSession();
+        try {
+            ObservationManager obsMgr = observingSession.getWorkspace().getObservationManager();
+            ExpectationListener listener = new ExpectationListener();
+            obsMgr.addEventListener(listener, PROPERTY_ADDED, "/", true, null, null, false);
+
+            // add property to root node
+            Node root = getNode("/");
+            listener.expectAdd(root.setProperty("prop", "value"));
+            root.getSession().save();
+
+            List<String> missing = listener.getMissing(2, TimeUnit.SECONDS);
+            assertTrue("Missing events: " + missing, missing.isEmpty());
+            List<Event> unexpected = listener.getUnexpected();
+            assertTrue("Unexpected events: " + unexpected, unexpected.isEmpty());
+
+            obsMgr.removeEventListener(listener);
         } finally {
             observingSession.logout();
         }
@@ -2052,8 +1932,8 @@ public class RepositoryTest extends Abst
                 }
             };
 
-            obsMgr.addEventListener(listener, Event.NODE_ADDED | Event.NODE_REMOVED | Event.NODE_MOVED |
-                    Event.PROPERTY_ADDED | Event.PROPERTY_REMOVED | Event.PROPERTY_CHANGED | Event.PERSIST,
+            obsMgr.addEventListener(listener, NODE_ADDED | NODE_REMOVED | NODE_MOVED |
+                    PROPERTY_ADDED | PROPERTY_REMOVED | PROPERTY_CHANGED | PERSIST,
                     "/", true, null, null, false);
 
             // Generate events
@@ -2116,8 +1996,8 @@ public class RepositoryTest extends Abst
                 }
             };
 
-            obsMgr.addEventListener(listener, Event.NODE_ADDED | Event.NODE_REMOVED | Event.NODE_MOVED |
-                    Event.PROPERTY_ADDED | Event.PROPERTY_REMOVED | Event.PROPERTY_CHANGED | Event.PERSIST,
+            obsMgr.addEventListener(listener, NODE_ADDED | NODE_REMOVED | NODE_MOVED |
+                    PROPERTY_ADDED | PROPERTY_REMOVED | PROPERTY_CHANGED | PERSIST,
                     "/", true, null, null, false);
 
             // Ensure the listener is there
@@ -2141,37 +2021,6 @@ public class RepositoryTest extends Abst
     }
 
     @Test
-    public void observationOnRootNode() throws Exception {
-        final AtomicReference<CountDownLatch> hasEvents = new AtomicReference<CountDownLatch>(new CountDownLatch(1));
-        Session observingSession = createAdminSession();
-        try {
-            ObservationManager obsMgr = observingSession.getWorkspace().getObservationManager();
-            EventListener listener = new EventListener() {
-                @Override
-                public void onEvent(EventIterator events) {
-                    while (events.hasNext()) {
-                        events.next();
-                        hasEvents.get().countDown();
-                    }
-                }
-            };
-
-            obsMgr.addEventListener(listener, Event.PROPERTY_ADDED,
-                    "/", true, null, null, false);
-
-            // add property to root node
-            Node root = getNode("/");
-            root.setProperty("prop", "value");
-            root.getSession().save();
-
-            assertTrue(hasEvents.get().await(2, TimeUnit.SECONDS));
-            obsMgr.removeEventListener(listener);
-        } finally {
-            observingSession.logout();
-        }
-    }
-
-    @Test
     public void liveNode() throws RepositoryException {
         Session session = getAdminSession();
 
@@ -2279,6 +2128,8 @@ public class RepositoryTest extends Abst
         }
     }
 
+    //------------------------------------------------------------< NumberStream >---
+
     /**
      * Dummy stream class used by the binary property tests.
      */
@@ -2301,4 +2152,93 @@ public class RepositoryTest extends Abst
 
     }
 
+    //------------------------------------------------------------< ExpectationListener >---
+
+    private static class ExpectationListener implements EventListener {
+        private final Map<String, SettableFuture<Event>> expected = Maps.newHashMap();
+        private final List<Event> unexpected = Lists.newCopyOnWriteArrayList();
+        private volatile Exception failed;
+
+        public Future<Event> expect(String path, int type) {
+            if (failed == null) {
+                SettableFuture<Event> expect = SettableFuture.create();
+                expected.put(key(path, type), expect);
+                return expect;
+            } else {
+                return Futures.immediateFailedFuture(failed);
+            }
+        }
+
+        public Node expectAdd(Node node) throws RepositoryException {
+            expect(node.getPath(), NODE_ADDED);
+            expect(node.getPath() + "/jcr:primaryType", PROPERTY_ADDED);
+            return node;
+        }
+
+        public Node expectRemove(Node node) throws RepositoryException {
+            expect(node.getPath(), NODE_REMOVED);
+            expect(node.getPath() + "/jcr:primaryType", PROPERTY_REMOVED);
+            return node;
+        }
+
+        public Property expectAdd(Property property) throws RepositoryException {
+            expect(property.getPath(), PROPERTY_ADDED);
+            return property;
+        }
+
+        public Property expectRemove(Property property) throws RepositoryException {
+            expect(property.getPath(), PROPERTY_REMOVED);
+            return property;
+        }
+
+        public Property expectChange(Property property) throws RepositoryException {
+            expect(property.getPath(), PROPERTY_CHANGED);
+            return property;
+        }
+
+        public List<String> getMissing(int time, TimeUnit timeUnit)
+                throws ExecutionException, InterruptedException {
+            List<String> missing = Lists.newArrayList();
+            try {
+                Futures.allAsList(expected.values()).get(2, TimeUnit.SECONDS);
+            }
+            catch (TimeoutException e) {
+                for (Entry<String, SettableFuture<Event>> entry : expected.entrySet()) {
+                    if (!entry.getValue().isDone()) {
+                        missing.add(entry.getKey());
+                    }
+                }
+            }
+            return missing;
+        }
+
+        public List<Event> getUnexpected() {
+            return Lists.newArrayList(unexpected);
+        }
+
+        @Override
+        public void onEvent(EventIterator events) {
+            try {
+                while (events.hasNext() && failed == null) {
+                    Event event = events.nextEvent();
+                    SettableFuture<Event> f = expected.get(key(event.getPath(), event.getType()));
+                    if (f != null) {
+                        f.set(event);
+                    } else {
+                        unexpected.add(event);
+                    }
+                }
+            } catch (Exception e) {
+                for (SettableFuture<Event> f : expected.values()) {
+                    f.setException(e);
+                }
+                failed = e;
+            }
+        }
+
+        private static String key(String path, int type) {
+            return path + ':' + type;
+        }
+    }
+
 }