You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2015/09/16 19:16:28 UTC

svn commit: r1703437 - in /sling/whiteboard/bdelacretaz/test-rules: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/sling/ src/main/java/org/apache/sling/testing/ src/main/java/org/apache/sling/tes...

Author: bdelacretaz
Date: Wed Sep 16 17:16:26 2015
New Revision: 1703437

URL: http://svn.apache.org/r1703437
Log:
Rough prototype - JUnit rule to simplify writing server-side tests

Added:
    sling/whiteboard/bdelacretaz/test-rules/   (with props)
    sling/whiteboard/bdelacretaz/test-rules/pom.xml
    sling/whiteboard/bdelacretaz/test-rules/src/
    sling/whiteboard/bdelacretaz/test-rules/src/main/
    sling/whiteboard/bdelacretaz/test-rules/src/main/java/
    sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/
    sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/apache/
    sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/apache/sling/
    sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/apache/sling/testing/
    sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/apache/sling/testing/rules/
    sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/apache/sling/testing/rules/ClientSideSupport.java
    sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/apache/sling/testing/rules/DefaultClientSideSupport.java
    sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/apache/sling/testing/rules/MultipartAdapter.java
    sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/apache/sling/testing/rules/ServerSideTest.java
    sling/whiteboard/bdelacretaz/test-rules/src/test/
    sling/whiteboard/bdelacretaz/test-rules/src/test/java/
    sling/whiteboard/bdelacretaz/test-rules/src/test/java/org/
    sling/whiteboard/bdelacretaz/test-rules/src/test/java/org/apache/
    sling/whiteboard/bdelacretaz/test-rules/src/test/java/org/apache/sling/
    sling/whiteboard/bdelacretaz/test-rules/src/test/java/org/apache/sling/testing/
    sling/whiteboard/bdelacretaz/test-rules/src/test/java/org/apache/sling/testing/rules/
    sling/whiteboard/bdelacretaz/test-rules/src/test/java/org/apache/sling/testing/rules/DummyTest.java

Propchange: sling/whiteboard/bdelacretaz/test-rules/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Wed Sep 16 17:16:26 2015
@@ -0,0 +1,19 @@
+target
+sling
+bin
+logs
+jackrabbit-repository
+derby.log
+*.iml
+*.ipr
+*.iws
+.settings
+.project
+.classpath
+.externalToolBuilders
+maven-eclipse.xml
+jackrabbit
+
+
+
+

Added: sling/whiteboard/bdelacretaz/test-rules/pom.xml
URL: http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/test-rules/pom.xml?rev=1703437&view=auto
==============================================================================
--- sling/whiteboard/bdelacretaz/test-rules/pom.xml (added)
+++ sling/whiteboard/bdelacretaz/test-rules/pom.xml Wed Sep 16 17:16:26 2015
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.sling</groupId>
+    <artifactId>sling</artifactId>
+    <version>23</version>
+    <relativePath/>
+  </parent>
+
+  <artifactId>org.apache.sling.testing.rules</artifactId>
+  <version>0.1.1-SNAPSHOT</version>
+  <packaging>jar</packaging>
+  <name>Apache Sling Testing Rules</name>
+  <description>JUnit Rules for Sling testing</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.ops4j.pax.tinybundles</groupId>
+      <artifactId>tinybundles</artifactId>
+      <version>2.0.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-simple</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+</project>

Added: sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/apache/sling/testing/rules/ClientSideSupport.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/apache/sling/testing/rules/ClientSideSupport.java?rev=1703437&view=auto
==============================================================================
--- sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/apache/sling/testing/rules/ClientSideSupport.java (added)
+++ sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/apache/sling/testing/rules/ClientSideSupport.java Wed Sep 16 17:16:26 2015
@@ -0,0 +1,28 @@
+/*
+ * 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.sling.testing.rules;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+
+interface ClientSideSupport {
+    InputStream buildTestBundle(Class<?> c, String bundleSymbolicName);
+    void installBundle(InputStream bundle, String bundleSymbolicName) throws MalformedURLException, IOException;
+    void uninstallBundle(String bundleSymbolicName) throws MalformedURLException, IOException;
+    void runTests(Class<?> c) throws MalformedURLException, IOException;
+}

Added: sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/apache/sling/testing/rules/DefaultClientSideSupport.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/apache/sling/testing/rules/DefaultClientSideSupport.java?rev=1703437&view=auto
==============================================================================
--- sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/apache/sling/testing/rules/DefaultClientSideSupport.java (added)
+++ sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/apache/sling/testing/rules/DefaultClientSideSupport.java Wed Sep 16 17:16:26 2015
@@ -0,0 +1,109 @@
+/*
+ * 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.sling.testing.rules;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+
+import javax.xml.bind.DatatypeConverter;
+
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
+
+class DefaultClientSideSupport implements ClientSideSupport {
+    
+    private final String CHARSET = "UTF-8";
+    
+    // TODO dynamic/configurable!!
+    private final String baseUrl = "http://localhost:8080";
+    private final String credentials = "admin:admin";
+    
+    /** Build a test bundle that contains c as a Sling server-side test.
+     *  Need to include the ServerSideTest class as c refers to it.
+     */
+    public InputStream buildTestBundle(Class<?> c, String bundleSymbolicName) {
+        return TinyBundles.bundle()
+                .set(Constants.BUNDLE_SYMBOLICNAME, bundleSymbolicName)
+                .set("Sling-Test-Regexp", c.getName() + ".*")
+                .add(c)
+                .add(ServerSideTest.class)
+                .build(TinyBundles.withBnd());
+    }
+    
+    public void setCredentials(URLConnection c) {
+        final String basicAuth = "Basic " + new String(DatatypeConverter.printBase64Binary(credentials.getBytes()));
+        c.setRequestProperty ("Authorization", basicAuth);
+
+    }
+
+    @Override
+    public void installBundle(InputStream bundle, String bundleSymbolicName) throws MalformedURLException, IOException {
+        // Equivalent of
+        // curl -u admin:admin -F action=install -Fbundlestart=1 -Fbundlefile=@somefile.jar http://localhost:8080/system/console/bundles
+        final String url = baseUrl + "/system/console/bundles";
+        final String contentType = "application/octet-stream";
+        final HttpURLConnection c = (HttpURLConnection)new URL(url).openConnection();
+        setCredentials(c);
+        new MultipartAdapter(c, CHARSET)
+        .parameter("action", "install")
+        .parameter("bundlestart", "1")
+        .file("bundlefile", bundleSymbolicName + ".jar", contentType, bundle)
+        .close();
+        final int status = c.getResponseCode();
+        if(status != 302) {
+            throw new IOException("Got status code " + status + " for " + url);
+        }
+    }
+
+    @Override
+    public void uninstallBundle(String bundleSymbolicName) throws MalformedURLException, IOException {
+        // equivalent of
+        // curl -u admin:admin -F action=uninstall http://localhost:8080/system/console/bundles/$N
+        final String url = baseUrl + "/system/console/bundles/" + bundleSymbolicName;
+        final HttpURLConnection c = (HttpURLConnection)new URL(url).openConnection();
+        setCredentials(c);
+        new MultipartAdapter(c, CHARSET)
+        .parameter("action", "uninstall")
+        .close();
+        final int status = c.getResponseCode();
+        if(status != 200) {
+            throw new IOException("Got status code " + status + " for " + url);
+        }
+    }
+
+    @Override
+    public void runTests(Class<?> clazz) throws MalformedURLException, IOException {
+        final String testUrl = baseUrl + "/system/sling/junit/" + clazz.getName() + ".json";
+        final HttpURLConnection c = (HttpURLConnection)new URL(testUrl).openConnection();
+        // TODO wait for non-404 response, signals that test bundle is ready
+        c.setRequestMethod("POST");
+        c.setUseCaches(false);
+        c.setDoOutput(true);
+        c.setDoInput(true);
+        c.setInstanceFollowRedirects(false);
+        final int status = c.getResponseCode();
+        if(status != 200) {
+            throw new IOException("Got status code " + status + " for " + testUrl);
+        }
+        // TODO read test results etc
+    }
+}

Added: sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/apache/sling/testing/rules/MultipartAdapter.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/apache/sling/testing/rules/MultipartAdapter.java?rev=1703437&view=auto
==============================================================================
--- sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/apache/sling/testing/rules/MultipartAdapter.java (added)
+++ sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/apache/sling/testing/rules/MultipartAdapter.java Wed Sep 16 17:16:26 2015
@@ -0,0 +1,79 @@
+/*
+ * 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.sling.testing.rules;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.net.HttpURLConnection;
+
+/** Minimal HTTP client functionality for multipart POST requests */
+class MultipartAdapter {
+    final OutputStream out;
+    final PrintWriter pw;
+    final String boundary = "______________" + Double.toHexString(Math.random()) + "______________";
+    final String eol = "\r\n";
+    final String dashes = "--";
+    final String charset;
+    int counter = 0;
+    
+    MultipartAdapter(HttpURLConnection c, String charset) throws IOException {
+        this.charset = charset;
+        c.setUseCaches(false);
+        c.setDoOutput(true);
+        c.setInstanceFollowRedirects(false);
+        c.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
+        out = c.getOutputStream();
+        pw = new PrintWriter(new OutputStreamWriter(out, charset), true); 
+    }
+    
+    void close() throws IOException {
+        pw.append(dashes).append(boundary).append(dashes).append(eol).flush();
+        out.close();
+    }
+    
+    MultipartAdapter parameter(String name, String value) {
+        pw.append(dashes).append(boundary).append(eol);
+        pw.append("Content-Disposition: form-data; name=\"" + name + "\"").append(eol);
+        pw.append("Content-Type: text/plain; charset=").append(charset).append(eol);
+        pw.append(eol).append(value).append(eol).flush();
+        return this;
+    }
+    
+    MultipartAdapter file(String fieldName, String filename, String contentType, InputStream data) throws IOException {
+        pw.append(dashes).append(boundary).append(eol);
+        pw.append("Content-Disposition: form-data; name=\"").append(fieldName).append("\"");
+        pw.append("; filename=\"").append(filename).append("\"").append(eol);
+        pw.append("Content-Type: ").append(contentType).append(eol);
+        pw.append("Content-Transfer-Encoding: binary").append(eol);
+        pw.append(eol).flush();
+        copy(data, out);
+        pw.append(eol).flush();
+        return this;
+    }
+    
+    private void copy(InputStream is, OutputStream os) throws IOException {
+        final byte[] buffer = new byte[16384];
+        int n=0;
+        while((n = is.read(buffer, 0, buffer.length)) > 0) {
+            os.write(buffer, 0, n);
+        }
+        os.flush();
+    }
+}

Added: sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/apache/sling/testing/rules/ServerSideTest.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/apache/sling/testing/rules/ServerSideTest.java?rev=1703437&view=auto
==============================================================================
--- sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/apache/sling/testing/rules/ServerSideTest.java (added)
+++ sling/whiteboard/bdelacretaz/test-rules/src/main/java/org/apache/sling/testing/rules/ServerSideTest.java Wed Sep 16 17:16:26 2015
@@ -0,0 +1,79 @@
+/*
+ * 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.sling.testing.rules;
+
+import java.io.InputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.UUID;
+
+import org.junit.rules.ExternalResource;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/** JUnit Rule that executes the current test in a Sling instance, by
+ *  packaging it in a temporary OSGi bundle, installing that bundle on
+ *  the Sling instance and executing the test via the Sling JUnit servlet. 
+ */
+public class ServerSideTest extends ExternalResource {
+    
+    private final Class<?> classUnderTest;
+    private final String bundleSymbolicName;
+    private final ClientSideSupport css;
+    
+    /** Build a server-side test rule that uses the default test server */
+    ServerSideTest(Class<?> underTest) {
+        this(underTest, null);
+    }
+    
+    /** Build a server-side test rule that can use a specific test server */
+    ServerSideTest(Class<?> underTest, String serverSelector) {
+        this.classUnderTest = underTest;
+        
+        // Unique and somewhat identifiable name for our test bundle 
+        final SimpleDateFormat fmt = new SimpleDateFormat("HH-mm-ss-");
+        bundleSymbolicName = getClass().getSimpleName() + "." + fmt.format(new Date()) + "." + UUID.randomUUID();
+        
+        // Try to load our default bundle builder - we don't have it on the server side (see that class for details)
+        ClientSideSupport s = null;
+        try {
+            s = (ClientSideSupport)getClass().getClassLoader().loadClass("org.apache.sling.testing.rules.DefaultClientSideSupport").newInstance();
+        } catch(Exception ignoreWeAreProbablyOnTheServerSide) {
+        }
+        css = s;
+    }
+    
+    @Override
+    public Statement apply(final Statement base, Description description) {
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                if(css != null) {
+                    final InputStream bundle = css.buildTestBundle(classUnderTest, bundleSymbolicName);
+                    css.installBundle(bundle, bundleSymbolicName);
+                    try {
+                        css.runTests(classUnderTest);
+                    } finally {
+                        css.uninstallBundle(bundleSymbolicName);
+                    }
+                } else {
+                    base.evaluate();
+                }
+            }
+        };
+    }
+}

Added: sling/whiteboard/bdelacretaz/test-rules/src/test/java/org/apache/sling/testing/rules/DummyTest.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/bdelacretaz/test-rules/src/test/java/org/apache/sling/testing/rules/DummyTest.java?rev=1703437&view=auto
==============================================================================
--- sling/whiteboard/bdelacretaz/test-rules/src/test/java/org/apache/sling/testing/rules/DummyTest.java (added)
+++ sling/whiteboard/bdelacretaz/test-rules/src/test/java/org/apache/sling/testing/rules/DummyTest.java Wed Sep 16 17:16:26 2015
@@ -0,0 +1,38 @@
+/*
+ * 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.sling.testing.rules;
+
+import static org.junit.Assert.assertTrue;
+
+import org.junit.ClassRule;
+import org.junit.Test;
+
+public class DummyTest {
+
+    @ClassRule
+    public static final ServerSideTest t = new ServerSideTest(DummyTest.class);
+    
+    @Test
+    public void semiRandomFailure() {
+        assertTrue("Semi-randomly failing, by design", Math.random() < 0.5);
+    }
+    
+    @Test
+    public void alwaysPasses() {
+    }
+    
+}