You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2019/06/06 15:10:09 UTC

[sling-whiteboard] 11/16: Converted IntegrationTest to a proper IT

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

rombert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git

commit 9a46cacd3b36be0f692af79601c6a04e5f9eb1d5
Author: Robert Munteanu <ro...@apache.org>
AuthorDate: Wed Jun 5 17:00:17 2019 +0200

    Converted IntegrationTest to a proper IT
    
    - load the java agent from the compiled jar
    - switch to using a surefire test
---
 url-connection-agent/pom.xml                       |  12 ++
 .../java/org/apache/sling/uca/impl/AgentIT.java    | 163 +++++++++++++++++++++
 .../org/apache/sling/uca/impl/IntegrationTest.java | 107 --------------
 3 files changed, 175 insertions(+), 107 deletions(-)

diff --git a/url-connection-agent/pom.xml b/url-connection-agent/pom.xml
index bc5a25f..1e96414 100644
--- a/url-connection-agent/pom.xml
+++ b/url-connection-agent/pom.xml
@@ -57,6 +57,18 @@
                     </execution>
                 </executions>
             </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-failsafe-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>integration-test</goal>
+                            <goal>verify</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
         </plugins>
     </build>
 
diff --git a/url-connection-agent/src/test/java/org/apache/sling/uca/impl/AgentIT.java b/url-connection-agent/src/test/java/org/apache/sling/uca/impl/AgentIT.java
new file mode 100644
index 0000000..b67a650
--- /dev/null
+++ b/url-connection-agent/src/test/java/org/apache/sling/uca/impl/AgentIT.java
@@ -0,0 +1,163 @@
+/*
+ * 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.uca.impl;
+
+import static java.time.Duration.ofSeconds;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTimeout;
+
+import java.io.IOException;
+import java.lang.ProcessBuilder.Redirect;
+import java.net.SocketTimeoutException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Validates that accessing URLs that exhibit connection problems results in a timeouts being fired when the agent is used
+ * 
+ * <p>This test validates that the agent works when statically loaded, i.e. with a <tt>-javaagent:</tt> flag
+ * passed to the JVM. As such it requires launching a new JVM instance each time, otherwise the results are
+ * not valid.</p>
+ * 
+ * <p>It does so by reusing the same JVM as the one running the test. Validation is done by looking for a
+ * Throwable information in the stderr and recording the exception class name and the message.</p>
+ *
+ */
+@ExtendWith(MisbehavingServerExtension.class)
+public class AgentIT {
+    
+    private static final Path STDERR = Paths.get("target", "stderr.txt");
+    private static final Path STDOUT = Paths.get("target", "stdout.txt");
+    private static final Logger LOG = LoggerFactory.getLogger(AgentIT.class);
+
+    /**
+     * Validates that connecting to a unaccessible port on an existing port fails with a connect 
+     * timeout exception
+     * 
+     * <p>It is surprisingly hard to simulate a connnection timeout. The most reliable way seems to
+     * be to get a firewall to drop packets, but this is very hard to do portably and safely
+     * in a unit test. The least bad possible solution is to access an URL that we know will timeout
+     * and that is able to sustain additional traffic. Maven Central is a good candidate for that.</p>
+     * 
+     * @throws IOException various I/O problems 
+     */
+    @Test
+    public void connectTimeout() throws IOException {
+
+        RecordedThrowable error = assertTimeout(ofSeconds(5),  () -> runTest("http://repo1.maven.org:81"));
+        assertEquals(SocketTimeoutException.class.getName(), error.className);
+        assertEquals("connect timed out", error.message);
+    }
+
+    /**
+     * Validates that connecting to a host that delays the response fails with a read timeout
+     * 
+     * @throws IOException various I/O problems
+     */
+    @Test
+    public void readTimeout(MisbehavingServerControl server) throws IOException {
+        
+        RecordedThrowable error = assertTimeout(ofSeconds(5),  () -> runTest("http://localhost:" + server.getLocalPort()));
+        assertEquals(SocketTimeoutException.class.getName(), error.className);
+        assertEquals("Read timed out", error.message);
+    }
+    
+
+    private RecordedThrowable runTest(String urlSpec) throws IOException, InterruptedException {
+
+        Process process = runForkedCommandWithAgent(new URL(urlSpec), 3, 3);
+        int exitCode = process.waitFor();
+        
+        LOG.info("Exited with code {}", exitCode);
+        LOG.info("Dump of stdout: ");
+        Files
+            .lines(STDOUT)
+            .forEach(LOG::info);
+
+        LOG.info("Dump of stderr: ");
+        Files
+            .lines(STDERR)
+            .forEach(LOG::info);
+
+        if ( exitCode != 0 ) {
+            return Files.lines(STDERR)
+                .filter( l -> l.startsWith("Exception in thread \"main\""))
+                .map( l -> newRecordedThrowable(l) )
+                .findFirst()
+                .orElseThrow(() -> new RuntimeException("Exit code was zero but did not find any exception information in stderr.txt"));
+        }
+        
+        return null;
+    }
+    
+    private Process runForkedCommandWithAgent(URL url, int connectTimeoutSeconds, int readTimeoutSeconds) throws IOException {
+        
+        Path jar = Files.list(Paths.get("target"))
+            .filter( p -> p.getFileName().toString().endsWith("-jar-with-dependencies.jar"))
+            .findFirst()
+            .orElseThrow( () -> new IllegalStateException("Did not find the agent jar. Did you run mvn package first?"));
+
+        String javaHome = System.getProperty("java.home");
+        Path javaExe = Paths.get(javaHome, "bin", "java");
+        ProcessBuilder pb = new ProcessBuilder(
+            javaExe.toString(),
+            "-showversion",
+            "-javaagent:" + jar +"=" + TimeUnit.SECONDS.toMillis(connectTimeoutSeconds) +"," + TimeUnit.SECONDS.toMillis(readTimeoutSeconds),
+            "-cp",
+            jar.toString(),
+            "org.apache.sling.uca.impl.Main",
+            url.toString()
+        );
+        
+        pb.redirectInput(Redirect.INHERIT);
+        pb.redirectOutput(STDOUT.toFile());
+        pb.redirectError(STDERR.toFile());
+        
+        return pb.start();
+    }
+    
+    private RecordedThrowable newRecordedThrowable(String string) {
+     
+        string = string.replace("Exception in thread \"main\"", "");
+        String[] parts = string.split(":");
+
+        return new RecordedThrowable(parts[0].trim(), parts[1].trim());
+    }
+    
+    /**
+     * Basic information about a {@link Throwable} that was recorded in a file
+     */
+    static class RecordedThrowable {
+        String className;
+        String message;
+
+        public RecordedThrowable(String className, String message) {
+            this.className = className;
+            this.message = message;
+        }
+        
+        
+    }
+}
diff --git a/url-connection-agent/src/test/java/org/apache/sling/uca/impl/IntegrationTest.java b/url-connection-agent/src/test/java/org/apache/sling/uca/impl/IntegrationTest.java
deleted file mode 100644
index 9e42394..0000000
--- a/url-connection-agent/src/test/java/org/apache/sling/uca/impl/IntegrationTest.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * 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.uca.impl;
-
-import static java.time.Duration.ofSeconds;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTimeout;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.SocketTimeoutException;
-import java.net.URL;
-import java.net.URLConnection;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.concurrent.TimeUnit;
-
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@ExtendWith(MisbehavingServerExtension.class)
-public class IntegrationTest {
-    
-    private static final Logger LOG = LoggerFactory.getLogger(IntegrationTest.class);
-
-    /**
-     * Validates that connecting to a unaccessible port on an existing port fails with a connect 
-     * timeout exception
-     * 
-     * <p>It is surprisingly hard to simulate a connnection timeout. The most reliable way seems to
-     * be to get a firewall to drop packets, but this is very hard to do portably and safely
-     * in a unit test. The least bad possible solution is to access an URL that we know will timeout
-     * and that is able to sustain additional traffic. Maven Central is a good candidate for that.</p>
-     * 
-     * @throws IOException various I/O problems 
-     */
-    @Test
-    public void connectTimeout() throws IOException {
-
-        SocketTimeoutException exception = assertThrows(SocketTimeoutException.class, 
-            () -> assertTimeout(ofSeconds(5),  () -> runTest("http://repo1.maven.org:81"))
-        );
-        assertEquals("connect timed out", exception.getMessage());
-    }
-
-    /**
-     * Validates that connecting to a host that delays the response fails with a read timeout
-     * 
-     * @throws IOException various I/O problems
-     */
-    @Test
-    public void readTimeout(MisbehavingServerControl server) throws IOException {
-        
-        SocketTimeoutException exception = assertThrows(SocketTimeoutException.class, 
-            () -> assertTimeout(ofSeconds(10),  () -> runTest("http://localhost:" + server.getLocalPort()))
-        );
-        assertEquals("Read timed out", exception.getMessage());
-    }
-    
-
-    private void runTest(String urlSpec) throws MalformedURLException, IOException, InterruptedException {
-        
-        String javaHome = System.getProperty("java.home");
-        Path javaExe = Paths.get(javaHome, "bin", "java");
-        ProcessBuilder pb = new ProcessBuilder(javaExe.toString(), "-version");
-        pb.inheritIO();
-        Process process = pb.start();
-        
-        process.getInputStream();
-        
-        int exitCode = process.waitFor();
-        
-        LOG.info("Exited with code {}", exitCode);
-        
-        URL url = new URL(urlSpec);
-        LOG.info("connecting to {}", url);
-        URLConnection connection = url.openConnection();
-        // TODO - remove when running through the harness
-        connection.setConnectTimeout((int) TimeUnit.SECONDS.toMillis(3));
-        connection.setReadTimeout((int) TimeUnit.SECONDS.toMillis(3));
-        connection.connect();
-        LOG.info("connected");
-        try ( InputStream is = connection.getInputStream()) {
-            while ( is.read() != -1)
-                ;
-        }
-        LOG.info("read");
-    }
-}