You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ol...@apache.org on 2016/02/20 21:44:01 UTC

svn commit: r1731454 - in /sling/trunk/contrib/launchpad/karaf/org.apache.sling.launchpad.karaf-integration-tests: pom.xml src/test/java/org/apache/sling/launchpad/karaf/tests/bootstrap/AbstractSlingLaunchpadOakTestSupport.java

Author: olli
Date: Sat Feb 20 20:44:01 2016
New Revision: 1731454

URL: http://svn.apache.org/viewvc?rev=1731454&view=rev
Log:
SLING-4411 Provide Oak features

take over tests from org.apache.sling.jcr.repository.it.CommonTests

Modified:
    sling/trunk/contrib/launchpad/karaf/org.apache.sling.launchpad.karaf-integration-tests/pom.xml
    sling/trunk/contrib/launchpad/karaf/org.apache.sling.launchpad.karaf-integration-tests/src/test/java/org/apache/sling/launchpad/karaf/tests/bootstrap/AbstractSlingLaunchpadOakTestSupport.java

Modified: sling/trunk/contrib/launchpad/karaf/org.apache.sling.launchpad.karaf-integration-tests/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/launchpad/karaf/org.apache.sling.launchpad.karaf-integration-tests/pom.xml?rev=1731454&r1=1731453&r2=1731454&view=diff
==============================================================================
--- sling/trunk/contrib/launchpad/karaf/org.apache.sling.launchpad.karaf-integration-tests/pom.xml (original)
+++ sling/trunk/contrib/launchpad/karaf/org.apache.sling.launchpad.karaf-integration-tests/pom.xml Sat Feb 20 20:44:01 2016
@@ -36,6 +36,7 @@
   <description>Integration Tests for Apache Sling Launchpad Karaf</description>
 
   <properties>
+    <org.apache.jackrabbit.version>2.12.0</org.apache.jackrabbit.version>
     <org.apache.karaf.version>4.0.4</org.apache.karaf.version>
     <org.ops4j.pax.exam.version>4.8.0</org.ops4j.pax.exam.version>
   </properties>
@@ -74,6 +75,12 @@
     <!-- Apache Sling -->
     <dependency>
       <groupId>org.apache.sling</groupId>
+      <artifactId>org.apache.sling.api</artifactId>
+      <version>2.11.0</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.sling</groupId>
       <artifactId>org.apache.sling.jcr.api</artifactId>
       <version>2.3.0</version>
       <scope>test</scope>
@@ -92,6 +99,12 @@
       <classifier>features</classifier>
       <scope>test</scope>
     </dependency>
+    <!-- Apache Jackrabbit -->
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>jackrabbit-jcr-commons</artifactId>
+      <version>${org.apache.jackrabbit.version}</version>
+    </dependency>
     <!-- bnd -->
     <dependency>
       <groupId>biz.aQute.bnd</groupId>

Modified: sling/trunk/contrib/launchpad/karaf/org.apache.sling.launchpad.karaf-integration-tests/src/test/java/org/apache/sling/launchpad/karaf/tests/bootstrap/AbstractSlingLaunchpadOakTestSupport.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/launchpad/karaf/org.apache.sling.launchpad.karaf-integration-tests/src/test/java/org/apache/sling/launchpad/karaf/tests/bootstrap/AbstractSlingLaunchpadOakTestSupport.java?rev=1731454&r1=1731453&r2=1731454&view=diff
==============================================================================
--- sling/trunk/contrib/launchpad/karaf/org.apache.sling.launchpad.karaf-integration-tests/src/test/java/org/apache/sling/launchpad/karaf/tests/bootstrap/AbstractSlingLaunchpadOakTestSupport.java (original)
+++ sling/trunk/contrib/launchpad/karaf/org.apache.sling.launchpad.karaf-integration-tests/src/test/java/org/apache/sling/launchpad/karaf/tests/bootstrap/AbstractSlingLaunchpadOakTestSupport.java Sat Feb 20 20:44:01 2016
@@ -18,17 +18,51 @@
  */
 package org.apache.sling.launchpad.karaf.tests.bootstrap;
 
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
 import javax.inject.Inject;
+import javax.jcr.Credentials;
+import javax.jcr.Item;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
 import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.observation.EventIterator;
+import javax.jcr.observation.EventListener;
+import javax.jcr.observation.ObservationManager;
+import javax.jcr.query.Query;
 
+import org.apache.jackrabbit.commons.cnd.CndImporter;
+import org.apache.sling.api.SlingConstants;
+import org.apache.sling.api.resource.ResourceResolverFactory;
 import org.apache.sling.jcr.api.SlingRepository;
 import org.apache.sling.launchpad.karaf.testing.KarafTestSupport;
+import org.junit.After;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.ops4j.pax.exam.util.Filter;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventConstants;
+import org.osgi.service.event.EventHandler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 public abstract class AbstractSlingLaunchpadOakTestSupport extends KarafTestSupport {
 
@@ -36,6 +70,10 @@ public abstract class AbstractSlingLaunc
     @Filter(timeout = 300000)
     public SlingRepository slingRepository;
 
+    @Inject
+    @Filter(timeout = 300000)
+    public ResourceResolverFactory resourceResolverFactory;
+
     private final Logger logger = LoggerFactory.getLogger(getClass());
 
     public AbstractSlingLaunchpadOakTestSupport() {
@@ -53,4 +91,444 @@ public abstract class AbstractSlingLaunc
         session.logout();
     }
 
+    // see org.apache.sling.jcr.repository.it.CommonTests
+
+    private final List<String> toDelete = new LinkedList<String>();
+    private final AtomicInteger uniqueNameCounter = new AtomicInteger();
+    protected static final Integer TEST_SCALE = Integer.getInteger("test.scale", 1);
+
+    public static final String I18N_MESSAGE_CND =
+        "<sling = 'http://sling.apache.org/jcr/sling/1.0'>\n"
+            + "[mix:language]\n"
+            + "mixin\n"
+            + "- jcr:language (string)\n"
+            + "\n"
+            + "[sling:Message]\n"
+            + "mixin\n"
+            + "- sling:key (string)\n"
+            + "- sling:message (undefined)\n"
+            + "\n"
+            + "[sling:MessageEntry] > nt:hierarchyNode, sling:Message\n"
+        ;
+
+    protected class JcrEventsCounter implements EventListener {
+        private final Session s;
+        private int jcrEventsCounter;
+
+        public JcrEventsCounter() throws RepositoryException {
+            s = slingRepository.loginAdministrative(null);
+            final ObservationManager om = s.getWorkspace().getObservationManager();
+            final int eventTypes = 255; // not sure if that's a recommended value, but common
+            final boolean deep = true;
+            final String [] uuid = null;
+            final String [] nodeTypeNames = new String [] { "mix:language", "sling:Message" };
+            final boolean noLocal = true;
+            final String root = "/";
+            om.addEventListener(this, eventTypes, root, deep, uuid, nodeTypeNames, noLocal);
+        }
+
+        void close() {
+            s.logout();
+        }
+
+        @Override
+        public void onEvent(EventIterator it) {
+            while(it.hasNext()) {
+                it.nextEvent();
+                jcrEventsCounter++;
+            }
+        }
+
+        int get() {
+            return jcrEventsCounter;
+        }
+    }
+
+    /** Simple Retry loop for tests */
+    public abstract class Retry {
+
+        public Retry(int timeoutMsec) {
+            final long timeout = System.currentTimeMillis() + timeoutMsec;
+            Throwable lastT = null;
+            while(System.currentTimeMillis() < timeout) {
+                try {
+                    lastT = null;
+                    exec();
+                    break;
+                } catch(Throwable t) {
+                    lastT = t;
+                }
+            }
+
+            if(lastT != null) {
+                fail("Failed after " + timeoutMsec + " msec: " + lastT);
+            }
+        }
+
+        protected abstract void exec() throws Exception;
+    }
+
+    private <ItemType extends Item> ItemType deleteAfterTests(ItemType it) throws RepositoryException {
+        toDelete.add(it.getPath());
+        return it;
+    }
+
+    /** Verify that admin can create and retrieve a node of the specified type.
+     * @return the path of the test node that was created.
+     */
+    private String assertCreateRetrieveNode(String nodeType) throws RepositoryException {
+        Session s = slingRepository.loginAdministrative(null);
+        try {
+            final Node root = s.getRootNode();
+            final String name = uniqueName("assertCreateRetrieveNode");
+            final String propName = "PN_" + name;
+            final String propValue = "PV_" + name;
+            final Node child = nodeType == null ? root.addNode(name) : root.addNode(name, nodeType);
+            child.setProperty(propName, propValue);
+            child.setProperty("foo", child.getPath());
+            s.save();
+            s.logout();
+            s = slingRepository.loginAdministrative(null);
+            final Node n = s.getNode("/" + name);
+            assertNotNull(n);
+            assertEquals(propValue, n.getProperty(propName).getString());
+            return n.getPath();
+        } finally {
+            s.logout();
+        }
+    }
+
+    protected String uniqueName(String hint) {
+        return hint + "_" + uniqueNameCounter.incrementAndGet() + "_" + System.currentTimeMillis();
+    }
+
+    @After
+    public void deleteTestItems() throws RepositoryException {
+        if(toDelete.isEmpty()) {
+            return;
+
+        }
+
+        final Session s = slingRepository.loginAdministrative(null);
+        try {
+            for(String path : toDelete) {
+                if(s.itemExists(path)) {
+                    s.getItem(path).remove();
+                }
+            }
+            s.save();
+            toDelete.clear();
+        } finally {
+            s.logout();
+        }
+    }
+
+    @Test
+    public void testRepositoryPresent() {
+        assertNotNull(slingRepository);
+    }
+
+    @Test
+    public void testLoginAdministrative() throws RepositoryException {
+        final Session s = slingRepository.loginAdministrative(null);
+        assertNotNull(s);
+        s.logout();
+    }
+
+    @Test
+    public void testExplicitAdminLogin() throws RepositoryException {
+        final Credentials creds = new SimpleCredentials("admin", "admin".toCharArray());
+        slingRepository.login(creds).logout();
+    }
+
+    @Test(expected=RepositoryException.class)
+    public void testWrongLogin() throws RepositoryException {
+        final Credentials creds = new SimpleCredentials("badName", "badPAssword".toCharArray());
+        slingRepository.login(creds);
+    }
+
+    @Test
+    public void testAnonymousLoginA() throws RepositoryException {
+        final Session s = slingRepository.login();
+        assertNotNull(s);
+        s.logout();
+    }
+
+    @Test
+    public void testAnonymousLoginB() throws RepositoryException {
+        final Session s = slingRepository.login(null, null);
+        assertNotNull(s);
+        s.logout();
+    }
+
+    @Test
+    public void testCreateRetrieveNode() throws RepositoryException {
+        assertCreateRetrieveNode(null);
+    }
+
+    @Test
+    public void testCreateRetrieveSlingFolder() throws RepositoryException {
+        assertCreateRetrieveNode("sling:Folder");
+    }
+
+    @Test
+    public void testAnonymousHasReadAccess() throws RepositoryException {
+        final String path = assertCreateRetrieveNode(null);
+        final Session s = slingRepository.login();
+        try {
+            assertTrue("Expecting anonymous to see " + path, s.itemExists(path));
+            final Node n = s.getNode(path);
+            assertEquals("Expecting anonymous to see the foo property", path, n.getProperty("foo").getString());
+        } finally {
+            s.logout();
+        }
+    }
+
+    @Test
+    public void testSqlQuery() throws RepositoryException {
+        final Session s = slingRepository.loginAdministrative(null);
+        final String id = "ID_" + System.currentTimeMillis();
+        final String propName = "PROP_" + id;
+        final String value = "VALUE_" + id;
+        try {
+            final int N_NODES = 100;
+            for(int i=0 ; i < N_NODES; i++) {
+                final Node root = s.getRootNode();
+                root.addNode(id + i).setProperty(propName, value);
+            }
+            s.save();
+
+            final String stmt = "SELECT * FROM nt:base WHERE " + propName + " IS NOT NULL";
+
+            @SuppressWarnings("deprecation")
+            final Query q = s.getWorkspace().getQueryManager().createQuery(stmt, Query.SQL);
+
+            final NodeIterator it = q.execute().getNodes();
+            int count = 0;
+            while(it.hasNext()) {
+                it.next();
+                count++;
+            }
+            assertEquals("Expected " + N_NODES + " result for query " + stmt, N_NODES, count);
+        } finally {
+            s.logout();
+        }
+    }
+
+    @Test
+    public void testXpathQueryWithMixin() throws RepositoryException {
+        Session s = slingRepository.loginAdministrative(null);
+        try {
+            final String path = "XPATH_QUERY_" + System.currentTimeMillis();
+            final String absPath = "/" + path;
+            final Node n = deleteAfterTests(s.getRootNode().addNode(path));
+            n.addMixin("mix:title");
+            s.save();
+
+            final String statement = "/jcr:root//element(*, mix:title)";
+            @SuppressWarnings("deprecation")
+            final Query q = s.getWorkspace().getQueryManager().createQuery(statement, Query.XPATH);
+            final NodeIterator it = q.execute().getNodes();
+            assertTrue("Expecting a non-empty result", it.hasNext());
+            boolean found = false;
+            while(it.hasNext()) {
+                if(it.nextNode().getPath().equals(absPath)) {
+                    found = true;
+                    break;
+                }
+            }
+            assertTrue("Expecting test node " + absPath + " to be found", found);
+        } finally {
+            s.logout();
+        }
+    }
+
+    // TODO: see SLING-4841 why the template method pattern was removed
+    //@Test
+    //public final void checkRepositoryDescriptors() {
+    //    doCheckRepositoryDescriptors();
+    //}
+
+    @Test
+    public void testSingleValueInputStream() throws RepositoryException {
+        Session s = slingRepository.loginAdministrative(null);
+        try {
+            final String path = getClass().getSimpleName() + System.currentTimeMillis();
+            final Node child = deleteAfterTests(s.getRootNode().addNode(path));
+            final Property p = child.setProperty("foo", "bar");
+            s.save();
+            assertNotNull(p.getBinary().getStream());
+        } finally {
+            s.logout();
+        }
+
+    }
+
+    @Test
+    public void testMultiValueInputStream() throws RepositoryException {
+        final Session s = slingRepository.loginAdministrative(null);
+        try {
+            final String path = getClass().getSimpleName() + System.currentTimeMillis();
+            final Node child = deleteAfterTests(s.getRootNode().addNode(path));
+            final Property p = child.setProperty("foo", new String[] { "bar", "wii " });
+            s.save();
+            try {
+                p.getBinary().getStream();
+                fail("Expecting getStream() to fail on a multi-value Property");
+            } catch(RepositoryException asExpected) {
+            }
+        } finally {
+            s.logout();
+        }
+    }
+
+    @Test
+    @Ignore // TODO failure: OSGi add resource events are missing for 2500/2500 paths after 5000 msec: 2500 paths missing
+    public void testOsgiResourceEvents() throws RepositoryException {
+        final ResourceEventListener listener = new ResourceEventListener();
+        final ServiceRegistration reg = listener.register(bundleContext, SlingConstants.TOPIC_RESOURCE_ADDED);
+        final Session s = slingRepository.loginAdministrative(null);
+        final int nPaths = 2500 * TEST_SCALE;
+        final int timeoutMsec = 2 * nPaths;
+        final String prefix = uniqueName("testOsgiResourceEvents");
+
+        // Create N nodes with a unique name under /
+        // and verify that ResourceEventListener gets an event
+        // for each of them
+        try {
+            for(int i=0; i  < nPaths; i++) {
+                s.getRootNode().addNode(prefix + i);
+            }
+            s.save();
+
+            logger.info("Added {} nodes, checking what ResourceEventListener got...", nPaths);
+            final long timeout = System.currentTimeMillis() + timeoutMsec;
+            final Set<String> missing = new HashSet<String>();
+            while(System.currentTimeMillis() < timeout) {
+                missing.clear();
+                final Set<String> paths = listener.getPaths();
+                for(int i=0; i  < nPaths; i++) {
+                    final String path = "/" + prefix + i;
+                    if(!paths.contains(path)) {
+                        missing.add(path);
+                    }
+                }
+
+                if(missing.isEmpty()) {
+                    break;
+                }
+            }
+
+            if(!missing.isEmpty()) {
+                final String missingStr = missing.size() > 10 ? missing.size() + " paths missing" : missing.toString();
+                fail("OSGi add resource events are missing for "
+                    + missing.size() + "/" + nPaths + " paths after "
+                    + timeoutMsec + " msec: " + missingStr);
+            }
+        } finally {
+            reg.unregister();
+            s.logout();
+        }
+
+        logger.info("Successfuly detected OSGi observation events for " + nPaths + " paths");
+    }
+
+    @Test
+    public void testNodetypeObservation() throws Exception {
+        Session s = slingRepository.loginAdministrative(null);
+        final Reader cnd = new StringReader(I18N_MESSAGE_CND);
+        JcrEventsCounter counter = null;
+        final String path = "/" + uniqueName("observation");
+
+        // Add a sling:MessageEntry and verify that we get JCR events
+        try {
+            CndImporter.registerNodeTypes(cnd, s);
+            counter = new JcrEventsCounter();
+
+            final Node n = s.getRootNode().addNode(path.substring(1), "sling:MessageEntry");
+            toDelete.add(n.getPath());
+            n.setProperty("sling:key", "foo");
+            n.setProperty("sling:message", "bar");
+            s.save();
+
+            final JcrEventsCounter c = counter;
+            new Retry(5000) {
+                @Override
+                protected void exec() throws Exception {
+                    assertTrue("Expecting JCR events after adding " + path, c.get() > 0);
+                }
+            };
+
+        } finally {
+            s.logout();
+            cnd.close();
+            if(counter != null) {
+                counter.close();
+            }
+        }
+
+        // In a separate session, modify node and verify that we get events
+        counter = new JcrEventsCounter();
+        s = slingRepository.loginAdministrative(null);
+        try {
+
+            final Node n = s.getNode(path);
+            n.setProperty("sling:message", "CHANGED now");
+            s.save();
+
+            final JcrEventsCounter c = counter;
+            new Retry(5000) {
+                @Override
+                protected void exec() throws Exception {
+                    assertTrue("Expecting JCR events after modifying " + path, c.get() > 0);
+                }
+            };
+
+        } finally {
+            s.logout();
+            cnd.close();
+            counter.close();
+        }
+
+    }
+
+    /** Keep track of OSGi events received on a given topic */
+    public class ResourceEventListener implements EventHandler {
+
+        private final Logger log = LoggerFactory.getLogger(getClass());
+        private final Set<String> paths = new HashSet<String>();
+
+        ServiceRegistration register(BundleContext ctx, String osgiEventTopic) {
+            final Hashtable<String, Object> props = new Hashtable<String, Object>();
+            props.put(EventConstants.EVENT_TOPIC, osgiEventTopic);
+            return ctx.registerService(EventHandler.class.getName(), this, props);
+        }
+
+        @Override
+        public void handleEvent(Event event) {
+            final String path = (String) event.getProperty("path");
+            if(path != null) {
+                final int n = paths.size();
+                synchronized (paths) {
+                    if(n % 1000 == 0) {
+                        log.info("Got events for {} paths so far, last path={}", n, path);
+                    }
+                    paths.add(path);
+                }
+            }
+        }
+
+        void clear() {
+            synchronized (paths) {
+                paths.clear();
+            }
+        }
+
+        Set<String> getPaths() {
+            synchronized (paths) {
+                return Collections.unmodifiableSet(paths);
+            }
+        }
+    }
+
 }