Merge pull request #10178 from eclipse/fix/12.0.x/spec-webapp-testing

Fix demo-spec webapp failures
This commit is contained in:
Joakim Erdfelt 2023-07-31 13:03:24 -05:00 committed by GitHub
commit 4fe2b041c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 247 additions and 14 deletions

View File

@ -27,16 +27,21 @@ import java.io.PrintWriter;
import java.io.Reader; import java.io.Reader;
import java.io.StringWriter; import java.io.StringWriter;
import java.io.Writer; import java.io.Writer;
import java.net.URI;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.GatheringByteChannel; import java.nio.channels.GatheringByteChannel;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.file.CopyOption;
import java.nio.file.FileVisitResult; import java.nio.file.FileVisitResult;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor; import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import java.util.Iterator;
import java.util.Objects;
import java.util.concurrent.CompletionException; import java.util.concurrent.CompletionException;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.stream.Stream;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -218,6 +223,37 @@ public class IO
} }
} }
/**
* Copy the contents of a directory from one directory to another.
*
* @param srcDir the source directory
* @param destDir the destination directory
* @throws IOException if unable to copy the file
*/
public static void copyDir(Path srcDir, Path destDir, CopyOption... copyOptions) throws IOException
{
if (!Files.isDirectory(Objects.requireNonNull(srcDir)))
throw new IllegalArgumentException("Source is not a directory: " + srcDir);
if (!Files.isDirectory(Objects.requireNonNull(destDir)))
throw new IllegalArgumentException("Dest is not a directory: " + destDir);
try (Stream<Path> sourceStream = Files.walk(srcDir, 20))
{
Iterator<Path> iterFiles = sourceStream
.filter(Files::isRegularFile)
.iterator();
while (iterFiles.hasNext())
{
Path sourceFile = iterFiles.next();
URI relativeSrc = srcDir.toUri().relativize(sourceFile.toUri());
Path destFile = destDir.resolve(relativeSrc.toASCIIString());
if (!Files.exists(destFile.getParent()))
Files.createDirectories(destFile.getParent());
Files.copy(sourceFile, destFile, copyOptions);
}
}
}
public static void copyFile(File from, File to) throws IOException public static void copyFile(File from, File to) throws IOException
{ {
try (InputStream in = new FileInputStream(from); try (InputStream in = new FileInputStream(from);

View File

@ -83,8 +83,8 @@ public class FooInitializer implements ServletContainerInitializer
if (context.getAttribute("org.example.Foo") != null) if (context.getAttribute("org.example.Foo") != null)
throw new IllegalStateException("FooInitializer on Startup already called"); throw new IllegalStateException("FooInitializer on Startup already called");
context.setAttribute("org.example.Foo", new ArrayList<Class>(classes)); context.setAttribute("org.example.Foo", new ArrayList<>(classes));
ServletRegistration.Dynamic reg = context.addServlet("AnnotationTest", "org.example.AnnotationTest"); ServletRegistration.Dynamic reg = context.addServlet("AnnotationTest", "org.example.test.AnnotationTest");
context.setAttribute("org.example.AnnotationTest.complete", (reg == null)); context.setAttribute("org.example.AnnotationTest.complete", (reg == null));
context.addListener(new FooListener()); context.addListener(new FooListener());

View File

@ -207,20 +207,30 @@
<groupId>org.eclipse.jetty.ee10.demos</groupId> <groupId>org.eclipse.jetty.ee10.demos</groupId>
<artifactId>jetty-ee10-demo-container-initializer</artifactId> <artifactId>jetty-ee10-demo-container-initializer</artifactId>
</dependency> </dependency>
<dependency>
<!-- deliberately old version to test classloading --> <groupId>org.eclipse.jetty.ee10</groupId>
<!-- TODO uncomment and update the following once 9.4.19 is released with a fix for #3726 <artifactId>jetty-ee10-webapp</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.ee10</groupId>
<artifactId>jetty-ee10-annotations</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.ee10.demos</groupId>
<artifactId>jetty-ee10-demo-mock-resources</artifactId>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId> <artifactId>jetty-client</artifactId>
<version>9.4.19.vXXXXXXXX</version> <scope>test</scope>
<exclusions> </dependency>
<exclusion> <dependency>
<groupId>jakarta.servlet</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jakarta.servlet-api</artifactId> <artifactId>jetty-slf4j-impl</artifactId>
</exclusion> <scope>test</scope>
</exclusions>
</dependency> </dependency>
-->
</dependencies> </dependencies>
</project> </project>

View File

@ -0,0 +1,155 @@
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.ee10.demos;
import java.io.IOException;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.ee10.webapp.WebAppContext;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.MavenPaths;
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.example.MockDataSource;
import org.example.MockUserTransaction;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.jupiter.api.Assertions.fail;
@ExtendWith(WorkDirExtension.class)
public class SpecWebAppTest
{
private Server server;
private HttpClient client;
@BeforeEach
public void setup(WorkDir workDir) throws Exception
{
server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(0);
server.addConnector(connector);
Path webappDir = prepareWebAppDir(workDir);
WebAppContext webapp = new WebAppContext();
ResourceFactory resourceFactory = ResourceFactory.of(webapp);
webapp.setContextPath("/");
webapp.setWarResource(resourceFactory.newResource(webappDir));
webapp.setAttribute(
"org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
".*/jakarta.servlet-api-[^/]*\\.jar$|.*/[^/]*taglibs.*\\.jar$");
HashLoginService hashLoginService = new HashLoginService();
hashLoginService.setName("Test Realm");
Path realmFile = MavenPaths.findTestResourceFile("ee10-demo-realm.properties");
Resource realmResource = ResourceFactory.of(server).newResource(realmFile);
hashLoginService.setConfig(realmResource);
SecurityHandler securityHandler = webapp.getSecurityHandler();
securityHandler.setLoginService(hashLoginService);
new org.eclipse.jetty.ee10.plus.jndi.Resource(webapp, "jdbc/mydatasource", new MockDataSource());
new org.eclipse.jetty.ee10.plus.jndi.Transaction("ee10", new MockUserTransaction());
server.setHandler(webapp);
server.start();
client = new HttpClient();
client.start();
}
private Path prepareWebAppDir(WorkDir workDir) throws IOException
{
Path webappDir = workDir.getEmptyPathDir();
Path srcWebapp = MavenPaths.projectBase().resolve("src/main/webapp");
IO.copyDir(srcWebapp, webappDir);
Path webappClassesDir = webappDir.resolve("WEB-INF/classes");
FS.ensureDirExists(webappClassesDir);
Path classesDir = MavenPaths.projectBase().resolve("target/classes");
IO.copyDir(classesDir, webappClassesDir);
Path libDir = webappDir.resolve("WEB-INF/lib");
FS.ensureDirExists(libDir);
copyDependency("jetty-ee10-demo-container-initializer", libDir);
copyDependency("jetty-ee10-demo-web-fragment", libDir);
return webappDir;
}
private void copyDependency(String depName, Path libDir) throws IOException
{
Path depPath = MavenPaths.projectBase().resolve("../" + depName).normalize();
if (!Files.isDirectory(depPath))
fail("Dependency not found: " + depPath);
Path outputJar = libDir.resolve(depName + ".jar");
Map<String, String> env = new HashMap<>();
env.put("create", "true");
URI uri = URI.create("jar:" + outputJar.toUri().toASCIIString());
try (FileSystem fs = FileSystems.newFileSystem(uri, env))
{
Path root = fs.getPath("/");
IO.copyDir(depPath.resolve("target/classes"), root);
IO.copyDir(depPath.resolve("src/main/resources"), root, StandardCopyOption.REPLACE_EXISTING);
}
}
@AfterEach
public void teardown()
{
LifeCycle.stop(client);
LifeCycle.stop(server);
}
@Test
public void testNoFailures() throws InterruptedException, ExecutionException, TimeoutException
{
ContentResponse response = client.newRequest(server.getURI().resolve("/test/"))
.followRedirects(false)
.send();
assertThat("response status", response.getStatus(), is(HttpStatus.OK_200));
// Look for 0 entries that fail.
assertThat("response", response.getContentAsString(), not(containsString(">FAIL<")));
}
}

View File

@ -0,0 +1,21 @@
#
# This file defines users passwords and roles for a HashUserRealm
#
# The format is
# <username>: <password>[,<rolename> ...]
#
# Passwords may be clear text, obfuscated or checksummed. The class
# org.eclipse.util.Password should be used to generate obfuscated
# passwords or password checksums
#
# If DIGEST Authentication is used, the password must be in a recoverable
# format, either plain text or OBF:.
#
jetty: MD5:164c88b302622e17050af52c89945d44,user
admin: CRYPT:adpexzg3FUZAk,server-administrator,content-administrator,admin,user
other: OBF:1xmk1w261u9r1w1c1xmq,user
plain: plain,user
user: password,user
# This entry is for digest auth. The credential is a MD5 hash of username:realmname:password
digest: MD5:6e120743ad67abfbc385bc2bb754e297,user

View File

@ -0,0 +1,11 @@
## Jetty Logging using jetty-slf4j-impl
org.eclipse.jetty.LEVEL=INFO
#org.eclipse.jetty.STACKS=true
#org.eclipse.jetty.ee10.annotations.LEVEL=DEBUG
#org.eclipse.jetty.STACKS=false
#org.eclipse.jetty.io.LEVEL=DEBUG
#org.eclipse.jetty.io.ssl.LEVEL=DEBUG
#org.eclipse.jetty.server.LEVEL=DEBUG
#org.eclipse.jetty.ee10.servlets.LEVEL=DEBUG
#org.eclipse.jetty.alpn.LEVEL=DEBUG
#org.eclipse.jetty.jmx.LEVEL=DEBUG