This is an automated email from the ASF dual-hosted git repository.

royteeuwen pushed a commit to branch feature/SLING-12582
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-junit-remote.git

commit 4259a14f097b18b0b07beeb09e6a640ba0ec28ae
Author: Roy Teeuwen <[email protected]>
AuthorDate: Wed Dec 18 12:05:12 2024 +0100

    SLING-12582: Create a dynamic test executor for junit5
---
 bnd.bnd                                            |   3 +-
 pom.xml                                            |   8 ++
 .../junit/remote/testrunner/SlingRemoteTest.java   |   8 ++
 .../testrunner/dynamic/ExampleDynamicTest.java     |  52 +++++++++
 .../dynamic/SlingRemoteDynamicTestExecutor.java    | 130 +++++++++++++++++++++
 .../testrunner/dynamic/SlingRemoteTestResult.java  |  44 +++++++
 .../remote/testrunner/dynamic/package-info.java    |  23 ++++
 7 files changed, 267 insertions(+), 1 deletion(-)

diff --git a/bnd.bnd b/bnd.bnd
index ab06448..bc4a998 100644
--- a/bnd.bnd
+++ b/bnd.bnd
@@ -3,6 +3,7 @@ Import-Package:\
     org.apache.sling.testing.tools.http; resolution:=optional,\
     org.apache.sling.testing.tools.sling; resolution:=optional,\
     org.junit.internal.*; resolution:=optional,\
+    org.junit.jupiter.*; resolution:=optional,\
     *
 
 Sling-Test-Regexp:\
@@ -12,4 +13,4 @@ Sling-Test-Regexp:\
     
@org.apache.sling.jcr.contentparser-*.jar!/org/apache/sling/jcr/contentparser/impl/JsonTicksConverter.class
 
 -removeheaders:\
-  Include-Resource
\ No newline at end of file
+  Include-Resource
diff --git a/pom.xml b/pom.xml
index aff70ed..0b05358 100644
--- a/pom.xml
+++ b/pom.xml
@@ -60,11 +60,19 @@
             <version>1.1.6</version>
             <scope>provided</scope>
         </dependency>
+
+        <!-- junit4 for the @Rule and ParentRunner based implementations -->
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <scope>compile</scope>
         </dependency>
+        <!-- junit5 for the DynamicTest based implementations -->
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-api</artifactId>
+            <scope>compile</scope>
+        </dependency>
         <!-- SLF4J is needed at runtime (whenever SlingRemoteTestRunner is 
executed) -->
         <dependency>
             <groupId>org.slf4j</groupId>
diff --git 
a/src/main/java/org/apache/sling/junit/remote/testrunner/SlingRemoteTest.java 
b/src/main/java/org/apache/sling/junit/remote/testrunner/SlingRemoteTest.java
index 060fe3d..c45f5ee 100644
--- 
a/src/main/java/org/apache/sling/junit/remote/testrunner/SlingRemoteTest.java
+++ 
b/src/main/java/org/apache/sling/junit/remote/testrunner/SlingRemoteTest.java
@@ -46,6 +46,14 @@ class SlingRemoteTest {
         }
     }
 
+    public String getDescription() {
+        return description;
+    }
+
+    public String getFailure() {
+        return failure;
+    }
+
     Description describe() {
         return Description.createTestDescription(testClass, description);
     }
diff --git 
a/src/main/java/org/apache/sling/junit/remote/testrunner/dynamic/ExampleDynamicTest.java
 
b/src/main/java/org/apache/sling/junit/remote/testrunner/dynamic/ExampleDynamicTest.java
new file mode 100644
index 0000000..f9b6601
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/junit/remote/testrunner/dynamic/ExampleDynamicTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.junit.remote.testrunner.dynamic;
+
+import java.util.stream.Stream;
+
+import org.apache.sling.junit.remote.testrunner.SlingRemoteTestParameters;
+import org.junit.jupiter.api.DynamicTest;
+import org.junit.jupiter.api.TestFactory;
+
+/**
+ * Test that runs the remote tests defined by the getTestClassesSelector
+ */
+public class ExampleDynamicTest implements SlingRemoteTestParameters {
+
+    @Override
+    public String getJunitServletUrl() {
+        return "http://localhost:8080/system/sling/junit";;
+    }
+
+    @Override
+    public String getTestClassesSelector() {
+        return "my.remote.test.package";
+    }
+
+    @Override
+    public String getTestMethodSelector() {
+        return null;
+    }
+
+    @TestFactory
+    public Stream<DynamicTest> remoteTests() {
+        var executor = new SlingRemoteDynamicTestExecutor(this);
+        return executor.streamRemoteTests();
+    }
+}
diff --git 
a/src/main/java/org/apache/sling/junit/remote/testrunner/dynamic/SlingRemoteDynamicTestExecutor.java
 
b/src/main/java/org/apache/sling/junit/remote/testrunner/dynamic/SlingRemoteDynamicTestExecutor.java
new file mode 100644
index 0000000..ef20368
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/junit/remote/testrunner/dynamic/SlingRemoteDynamicTestExecutor.java
@@ -0,0 +1,130 @@
+/*
+ * 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.junit.remote.testrunner.dynamic;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+
+import java.io.StringReader;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.Stream;
+
+import org.apache.sling.jcr.contentparser.impl.JsonTicksConverter;
+import org.apache.sling.junit.remote.httpclient.RemoteTestHttpClient;
+import org.apache.sling.junit.remote.testrunner.SlingRemoteTestParameters;
+import org.apache.sling.junit.remote.testrunner.SlingTestsCountChecker;
+import org.apache.sling.testing.tools.http.RequestCustomizer;
+import org.apache.sling.testing.tools.http.RequestExecutor;
+import org.apache.sling.testing.tools.sling.SlingTestBase;
+import org.junit.jupiter.api.DynamicTest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** JUnit5 dynamic-tests based executor that talks to a remote
+ *  Sling JUnit test servlet. Using this test
+ *  lets a test class discover tests
+ *  that the JUnit servlet can execute, execute
+ *  them and report results exactly as if the tests
+ *  ran locally.
+ */
+public class SlingRemoteDynamicTestExecutor {
+
+    private static final Logger log = 
LoggerFactory.getLogger(SlingRemoteDynamicTestExecutor.class);
+
+    private final SlingRemoteTestParameters testParameters;
+    private final RemoteTestHttpClient testHttpClient;
+    private final String username;
+    private final String password;
+
+    private final List<SlingRemoteTestResult> children = new LinkedList<>();
+
+    public SlingRemoteDynamicTestExecutor(SlingRemoteTestParameters instance) {
+        // Set configured username using "admin" as default credential
+        final String configuredUsername = 
System.getProperty(SlingTestBase.TEST_SERVER_USERNAME);
+        if (configuredUsername != null && 
!configuredUsername.trim().isEmpty()) {
+            username = configuredUsername;
+        } else {
+            username = SlingTestBase.ADMIN;
+        }
+
+        // Set configured password using "admin" as default credential
+        final String configuredPassword = 
System.getProperty(SlingTestBase.TEST_SERVER_PASSWORD);
+        if (configuredPassword != null && 
!configuredPassword.trim().isEmpty()) {
+            password = configuredPassword;
+        } else {
+            password = SlingTestBase.ADMIN;
+        }
+
+        testParameters = instance;
+        testHttpClient =
+                new RemoteTestHttpClient(testParameters.getJunitServletUrl(), 
this.username, this.password, true);
+    }
+
+    private void executeTests() throws Exception {
+        // Let the parameters class customize the request if desired
+        if (testParameters instanceof RequestCustomizer) {
+            testHttpClient.setRequestCustomizer((RequestCustomizer) 
testParameters);
+        }
+
+        // Run tests remotely and get response
+        final RequestExecutor executor = testHttpClient.runTests(
+                testParameters.getTestClassesSelector(), 
testParameters.getTestMethodSelector(), "json");
+        executor.assertContentType("application/json");
+        final JsonArray json = Json.createReader(
+                        new 
StringReader(JsonTicksConverter.tickToDoubleQuote(executor.getContent())))
+                .readArray();
+
+        // Response contains an array of objects identified by
+        // their INFO_TYPE, extract the tests
+        // based on this vlaue
+        for (int i = 0; i < json.size(); i++) {
+            final JsonObject obj = json.getJsonObject(i);
+            if (obj.containsKey("INFO_TYPE") && 
"test".equals(obj.getString("INFO_TYPE"))) {
+                children.add(new SlingRemoteTestResult(obj));
+            }
+        }
+
+        log.info(
+                "Server-side tests executed as {} at {} with path {}",
+                this.username,
+                testParameters.getJunitServletUrl(),
+                testHttpClient.getTestExecutionPath());
+
+        // Optionally check that number of tests is as expected
+        if (testParameters instanceof SlingTestsCountChecker) {
+            ((SlingTestsCountChecker) 
testParameters).checkNumberOfTests(children.size());
+        }
+    }
+
+    public Stream<DynamicTest> streamRemoteTests() {
+        try {
+            executeTests();
+        } catch (Exception e) {
+            throw new Error(e);
+        }
+        return children.stream()
+                .map(remoteTest -> 
DynamicTest.dynamicTest(remoteTest.getDescription(), () -> {
+                    if (remoteTest.getFailure() != null) {
+                        throw new AssertionError(remoteTest.getFailure());
+                    }
+                }));
+    }
+}
diff --git 
a/src/main/java/org/apache/sling/junit/remote/testrunner/dynamic/SlingRemoteTestResult.java
 
b/src/main/java/org/apache/sling/junit/remote/testrunner/dynamic/SlingRemoteTestResult.java
new file mode 100644
index 0000000..febecb8
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/junit/remote/testrunner/dynamic/SlingRemoteTestResult.java
@@ -0,0 +1,44 @@
+/*
+ * 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.junit.remote.testrunner.dynamic;
+
+import javax.json.JsonException;
+import javax.json.JsonObject;
+
+class SlingRemoteTestResult {
+
+    private final String description;
+    private final String failure;
+
+    public static final String DESCRIPTION = "description";
+    public static final String FAILURE = "failure";
+
+    SlingRemoteTestResult(JsonObject json) throws JsonException {
+        description = json.containsKey(DESCRIPTION) ? 
json.getString(DESCRIPTION) : null;
+        failure = json.containsKey(FAILURE) ? json.getString(FAILURE) : null;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public String getFailure() {
+        return failure;
+    }
+}
diff --git 
a/src/main/java/org/apache/sling/junit/remote/testrunner/dynamic/package-info.java
 
b/src/main/java/org/apache/sling/junit/remote/testrunner/dynamic/package-info.java
new file mode 100644
index 0000000..a5b943b
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/junit/remote/testrunner/dynamic/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+@Version("1.0.0")
+package org.apache.sling.junit.remote.testrunner.dynamic;
+
+import org.osgi.annotation.versioning.Version;

Reply via email to