Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix demo-spec webapp failures #10178

Merged
merged 2 commits into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ public void onStartup(Set<Class<?>> classes, ServletContext context)
if (context.getAttribute("org.example.Foo") != null)
throw new IllegalStateException("FooInitializer on Startup already called");

context.setAttribute("org.example.Foo", new ArrayList<Class>(classes));
ServletRegistration.Dynamic reg = context.addServlet("AnnotationTest", "org.example.AnnotationTest");
context.setAttribute("org.example.Foo", new ArrayList<>(classes));
ServletRegistration.Dynamic reg = context.addServlet("AnnotationTest", "org.example.test.AnnotationTest");
Comment on lines -86 to +87
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the bug that caused all of the varying failures.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should refer to the class, rather than the name of the class?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The AnnotationTest class is in the jetty-ee10-demo-spec-webapp project.
The above line in FooInitializer is in the jetty-ee10-demo-container-initializer project (It cannot see the AnnotationTest class)

context.setAttribute("org.example.AnnotationTest.complete", (reg == null));
context.addListener(new FooListener());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,20 +207,30 @@
<groupId>org.eclipse.jetty.ee10.demos</groupId>
<artifactId>jetty-ee10-demo-container-initializer</artifactId>
</dependency>

<!-- deliberately old version to test classloading -->
<!-- TODO uncomment and update the following once 9.4.19 is released with a fix for #3726
<dependency>
<groupId>org.eclipse.jetty.ee10</groupId>
<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>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>9.4.19.vXXXXXXXX</version>
<exclusions>
<exclusion>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
</exclusion>
</exclusions>
<artifactId>jetty-slf4j-impl</artifactId>
<scope>test</scope>
</dependency>
-->
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
//
// ========================================================================
// 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.Iterator;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.stream.Stream;

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.IO;
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.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("/");
copyContents(depPath.resolve("target/classes"), root);
copyContents(depPath.resolve("src/main/resources"), root);
}
}

public void copyContents(Path srcPath, Path destPath) throws IOException
{
try (Stream<Path> srcStream = Files.walk(srcPath))
{
Iterator<Path> iter = srcStream
.filter(Files::isRegularFile)
.iterator();
while (iter.hasNext())
{
Path path = iter.next();
URI relativeSrc = srcPath.toUri().relativize(path.toUri());
Path destFile = destPath.resolve(relativeSrc.toASCIIString());
System.err.printf("Copy %s (%s) -> %s%n", path, relativeSrc, destFile);
if (!Files.exists(destFile.getParent()))
Files.createDirectories(destFile.getParent());
Files.copy(path, destFile, 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<")));
}
}
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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