Bazel: Add EE8 servlet test targets
Add EE8 variants of the HTTP and LFS servlet test suites and run them
against the generated EE8 servlet bridge artifacts.
Generate EE8 test sources from the canonical Jakarta-based tests by
rewriting servlet API references and Jetty EE10 test helper imports to
their EE8 equivalents. Export canonical test source filegroups so the
generated tests remain synchronized with the primary test suites.
Introduce EE8 Jetty test dependencies, generated junit-http helpers,
and JUnit suite generation for the transformed sources. Restore
AppServer from the servlet-4 branch because its API usage cannot be
converted mechanically.
Extend generated-source verification to cover test sources and ensure
that no Jakarta or Jetty EE10 servlet references remain in generated
EE8 outputs.
Test Plan:
bazelisk test \
//tools/jgit-ee8:generated_srcs_test \
//org.eclipse.jgit.http.test.ee8/... \
//org.eclipse.jgit.lfs.server.test.ee8/...
Change-Id: Id3d9312f0a93d443d83054a81b9d868611e18b27
diff --git a/MODULE.bazel b/MODULE.bazel
index e95290a..ab705cb 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -76,6 +76,9 @@
"org.eclipse.jetty:jetty-session:" + JETTY_VERSION,
"org.eclipse.jetty:jetty-util-ajax:" + JETTY_VERSION,
"org.eclipse.jetty:jetty-util:" + JETTY_VERSION,
+ "org.eclipse.jetty.ee8:jetty-ee8-nested:" + JETTY_VERSION,
+ "org.eclipse.jetty.ee8:jetty-ee8-security:" + JETTY_VERSION,
+ "org.eclipse.jetty.ee8:jetty-ee8-servlet:" + JETTY_VERSION,
"org.eclipse.jetty.ee10:jetty-ee10-servlet:" + JETTY_VERSION,
"org.hamcrest:hamcrest:3.0",
"org.mockito:mockito-core:5.21.0",
diff --git a/lib/BUILD b/lib/BUILD
index 2bd9209..4ce0c1a 100644
--- a/lib/BUILD
+++ b/lib/BUILD
@@ -69,6 +69,7 @@
visibility = [
"//org.eclipse.jgit.http.apache:__pkg__",
"//org.eclipse.jgit.lfs.server.test:__pkg__",
+ "//org.eclipse.jgit.lfs.server.test.ee8:__pkg__",
"//org.eclipse.jgit.pgm:__pkg__",
],
exports = ["@external_deps//:org_apache_httpcomponents_httpclient"],
@@ -79,9 +80,11 @@
visibility = [
"//org.eclipse.jgit.http.apache:__pkg__",
"//org.eclipse.jgit.http.test:__pkg__",
+ "//org.eclipse.jgit.http.test.ee8:__pkg__",
"//org.eclipse.jgit.lfs.server:__pkg__",
"//org.eclipse.jgit.lfs.server.ee8:__pkg__",
"//org.eclipse.jgit.lfs.server.test:__pkg__",
+ "//org.eclipse.jgit.lfs.server.test.ee8:__pkg__",
"//org.eclipse.jgit.pgm:__pkg__",
],
exports = ["@external_deps//:org_apache_httpcomponents_httpcore"],
@@ -179,6 +182,35 @@
)
java_library(
+ name = "jetty-ee8-nested",
+ testonly = 1,
+ visibility = ["//org.eclipse.jgit.junit.http.ee8:__pkg__"],
+ exports = ["@external_deps//:org_eclipse_jetty_ee8_jetty_ee8_nested"],
+)
+
+java_library(
+ name = "jetty-security-ee8",
+ testonly = 1,
+ visibility = [
+ "//org.eclipse.jgit.http.test.ee8:__pkg__",
+ "//org.eclipse.jgit.junit.http.ee8:__pkg__",
+ "//org.eclipse.jgit.lfs.server.test.ee8:__pkg__",
+ ],
+ exports = ["@external_deps//:org_eclipse_jetty_ee8_jetty_ee8_security"],
+)
+
+java_library(
+ name = "jetty-servlet-ee8",
+ testonly = 1,
+ visibility = [
+ "//org.eclipse.jgit.http.test.ee8:__pkg__",
+ "//org.eclipse.jgit.junit.http.ee8:__pkg__",
+ "//org.eclipse.jgit.lfs.server.test.ee8:__pkg__",
+ ],
+ exports = ["@external_deps//:org_eclipse_jetty_ee8_jetty_ee8_servlet"],
+)
+
+java_library(
name = "jetty-util",
# TODO: This should be testonly but org.eclipse.jgit.pgm depends on it.
visibility = ["//visibility:public"],
@@ -303,6 +335,7 @@
"//org.eclipse.jgit.http.server:__pkg__",
"//org.eclipse.jgit.http.test:__pkg__",
"//org.eclipse.jgit.junit.http:__pkg__",
+ "//org.eclipse.jgit.junit.http.ee8:__pkg__",
"//org.eclipse.jgit.lfs.server:__pkg__",
"//org.eclipse.jgit.lfs.server.test:__pkg__",
"//org.eclipse.jgit.pgm:__pkg__",
@@ -314,7 +347,10 @@
name = "javax-servlet-api",
visibility = [
"//org.eclipse.jgit.http.server.ee8:__pkg__",
+ "//org.eclipse.jgit.http.test.ee8:__pkg__",
+ "//org.eclipse.jgit.junit.http.ee8:__pkg__",
"//org.eclipse.jgit.lfs.server.ee8:__pkg__",
+ "//org.eclipse.jgit.lfs.server.test.ee8:__pkg__",
],
exports = ["@external_deps//:javax_servlet_javax_servlet_api"],
)
diff --git a/org.eclipse.jgit.http.test.ee8/BUILD b/org.eclipse.jgit.http.test.ee8/BUILD
new file mode 100644
index 0000000..a6a5506
--- /dev/null
+++ b/org.eclipse.jgit.http.test.ee8/BUILD
@@ -0,0 +1,84 @@
+load("@rules_java//java:defs.bzl", "java_library")
+load("@com_googlesource_gerrit_bazlets//tools:junit.bzl", "junit_tests")
+load("@com_googlesource_gerrit_bazlets//tools:servlet_transform.bzl", "transform_srcjar")
+
+transform_srcjar(
+ name = "helpers-srcs",
+ testonly = 1,
+ direction = "to_javax",
+ sources = ["//org.eclipse.jgit.http.test:helper-srcs"],
+ src_prefix = "org.eclipse.jgit.http.test/src/",
+ visibility = ["//tools/jgit-ee8:__pkg__"],
+)
+
+transform_srcjar(
+ name = "test-srcs",
+ testonly = 1,
+ direction = "to_javax",
+ sources = ["//org.eclipse.jgit.http.test:test-srcs"],
+ src_prefix = "org.eclipse.jgit.http.test/tst/",
+ visibility = ["//tools/jgit-ee8:__pkg__"],
+)
+
+transform_srcjar(
+ name = "server-unit-test-srcs",
+ testonly = 1,
+ direction = "to_javax",
+ sources = ["//org.eclipse.jgit.http.test:http-server-unit-test-srcs"],
+ src_prefix = "org.eclipse.jgit.http.test/tst/",
+)
+
+# Fast slice for the server utility tests; the default EE8 suite runs the full
+# HTTP test target, which already includes these classes.
+junit_tests(
+ name = "server_unit",
+ suite_srcs = ["//org.eclipse.jgit.http.test:http-server-unit-test-srcs"],
+ tags = ["http"],
+ srcs = [":server-unit-test-srcs"],
+ deps = [
+ "//lib:junit",
+ "//org.eclipse.jgit.http.server.ee8:jgit-servlet-ee8",
+ "//org.eclipse.jgit:jgit",
+ "//org.eclipse.jgit.junit:junit",
+ ],
+)
+
+junit_tests(
+ name = "http",
+ suite_srcs = ["//org.eclipse.jgit.http.test:test-srcs"],
+ tags = ["http"],
+ srcs = [":test-srcs"],
+ deps = [
+ ":helpers",
+ "//lib:commons-logging",
+ "//lib:httpcore",
+ "//lib:javax-servlet-api",
+ "//lib:jetty-http",
+ "//lib:jetty-io",
+ "//lib:jetty-security",
+ "//lib:jetty-security-ee8",
+ "//lib:jetty-server",
+ "//lib:jetty-servlet-ee8",
+ "//lib:jetty-util",
+ "//lib:junit",
+ "//lib:slf4j-api",
+ "//lib:slf4j-simple",
+ "//org.eclipse.jgit.http.apache:http-apache",
+ "//org.eclipse.jgit.http.server.ee8:jgit-servlet-ee8",
+ "//org.eclipse.jgit:jgit",
+ "//org.eclipse.jgit.junit.http.ee8:junit-http-ee8",
+ "//org.eclipse.jgit.junit:junit",
+ ],
+)
+
+java_library(
+ name = "helpers",
+ testonly = 1,
+ srcs = [":helpers-srcs"],
+ deps = [
+ "//lib:javax-servlet-api",
+ "//lib:junit",
+ "//org.eclipse.jgit:jgit",
+ "//org.eclipse.jgit.junit:junit",
+ ],
+)
diff --git a/org.eclipse.jgit.http.test/BUILD b/org.eclipse.jgit.http.test/BUILD
index bc04d22..cb6a738 100644
--- a/org.eclipse.jgit.http.test/BUILD
+++ b/org.eclipse.jgit.http.test/BUILD
@@ -4,9 +4,46 @@
)
load("@rules_java//java:defs.bzl", "java_library")
+HTTP_HELPER_SRCS = glob(["src/**/*.java"])
+
+HTTP_TEST_SRCS = glob(["tst/**/*.java"])
+
+HTTP_SERVER_UNIT_TEST_SRCS = [
+ "tst/org/eclipse/jgit/http/server/ClientVersionUtilTest.java",
+ "tst/org/eclipse/jgit/http/server/RootLocaleTest.java",
+ "tst/org/eclipse/jgit/http/server/ServletUtilsTest.java",
+]
+
+filegroup(
+ name = "helper-srcs",
+ testonly = 1,
+ srcs = HTTP_HELPER_SRCS,
+ visibility = [
+ "//org.eclipse.jgit.http.test.ee8:__pkg__",
+ "//tools/jgit-ee8:__pkg__",
+ ],
+)
+
+filegroup(
+ name = "test-srcs",
+ testonly = 1,
+ srcs = HTTP_TEST_SRCS,
+ visibility = [
+ "//org.eclipse.jgit.http.test.ee8:__pkg__",
+ "//tools/jgit-ee8:__pkg__",
+ ],
+)
+
+filegroup(
+ name = "http-server-unit-test-srcs",
+ testonly = 1,
+ srcs = HTTP_SERVER_UNIT_TEST_SRCS,
+ visibility = ["//org.eclipse.jgit.http.test.ee8:__pkg__"],
+)
+
junit_tests(
name = "http",
- srcs = glob(["tst/**/*.java"]),
+ srcs = HTTP_TEST_SRCS,
tags = ["http"],
deps = [
":helpers",
@@ -33,7 +70,7 @@
java_library(
name = "helpers",
testonly = 1,
- srcs = glob(["src/**/*.java"]),
+ srcs = HTTP_HELPER_SRCS,
deps = [
"//lib:jakarta-servlet-api",
"//lib:junit",
diff --git a/org.eclipse.jgit.junit.http.ee8/BUILD b/org.eclipse.jgit.junit.http.ee8/BUILD
new file mode 100644
index 0000000..c7f6fb5
--- /dev/null
+++ b/org.eclipse.jgit.junit.http.ee8/BUILD
@@ -0,0 +1,43 @@
+load("@rules_java//java:defs.bzl", "java_library")
+
+package(default_visibility = ["//visibility:public"])
+
+java_library(
+ name = "junit-http-ee8",
+ testonly = 1,
+ srcs = [
+ "//org.eclipse.jgit.junit.http:junit-http-ee8-srcs",
+ # AppServer diverges from the canonical Jakarta version and is copied
+ # from the servlet-4 branch as a hand-maintained EE8 overlay.
+ "src/org/eclipse/jgit/junit/http/AppServer.java",
+ ],
+ resources = glob(
+ ["resources/**"],
+ allow_empty = True,
+ ),
+ deps = [
+ "//lib:javax-servlet-api",
+ "//lib:jetty-ee8-nested",
+ "//lib:jetty-http",
+ "//lib:jetty-io",
+ "//lib:jetty-security",
+ "//lib:jetty-security-ee8",
+ "//lib:jetty-server",
+ "//lib:jetty-servlet-ee8",
+ "//lib:jetty-session",
+ "//lib:jetty-util",
+ "//lib:junit",
+ "//lib:slf4j-api",
+ "//org.eclipse.jgit.http.server.ee8:jgit-servlet-ee8",
+ "//org.eclipse.jgit:jgit",
+ "//org.eclipse.jgit.junit:junit",
+ ],
+)
+
+test_suite(
+ name = "tests",
+ tests = [
+ "//org.eclipse.jgit.http.test.ee8:http",
+ "//org.eclipse.jgit.lfs.server.test.ee8:lfs_server",
+ ],
+)
diff --git a/org.eclipse.jgit.junit.http.ee8/src/org/eclipse/jgit/junit/http/AppServer.java b/org.eclipse.jgit.junit.http.ee8/src/org/eclipse/jgit/junit/http/AppServer.java
new file mode 100644
index 0000000..1e4c796
--- /dev/null
+++ b/org.eclipse.jgit.junit.http.ee8/src/org/eclipse/jgit/junit/http/AppServer.java
@@ -0,0 +1,461 @@
+/*
+ * Copyright (C) 2010, 2017 Google Inc. and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.junit.http;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.UnknownHostException;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.eclipse.jetty.ee8.nested.ServletConstraint;
+import org.eclipse.jetty.ee8.security.Authenticator;
+import org.eclipse.jetty.ee8.security.ConstraintMapping;
+import org.eclipse.jetty.ee8.security.ConstraintSecurityHandler;
+import org.eclipse.jetty.ee8.security.authentication.BasicAuthenticator;
+import org.eclipse.jetty.ee8.servlet.ServletContextHandler;
+import org.eclipse.jetty.security.AbstractLoginService;
+import org.eclipse.jetty.security.RolePrincipal;
+import org.eclipse.jetty.security.UserPrincipal;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.SecureRequestCustomizer;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.SslConnectionFactory;
+import org.eclipse.jetty.server.handler.ContextHandlerCollection;
+import org.eclipse.jetty.util.security.Password;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.eclipse.jgit.transport.URIish;
+
+/**
+ * Tiny web application server for unit testing.
+ * <p>
+ * Tests should start the server in their {@code setUp()} method and stop the
+ * server in their {@code tearDown()} method. Only while started the server's
+ * URL and/or port number can be obtained.
+ */
+public class AppServer {
+ /** Realm name for the secure access areas. */
+ public static final String realm = "Secure Area";
+
+ /** Username for secured access areas. */
+ public static final String username = "agitter";
+
+ /** Password for {@link #username} in secured access areas. */
+ public static final String password = "letmein";
+
+ /** SSL keystore password; must have at least 6 characters. */
+ private static final String keyPassword = "mykeys";
+
+ /** Role for authentication. */
+ private static final String authRole = "can-access";
+
+ static {
+ // Install a logger that throws warning messages.
+ //
+ final String prop = "org.eclipse.jetty.util.log.class";
+ System.setProperty(prop, RecordingLogger.class.getName());
+ }
+
+ private final Server server;
+
+ private final HttpConfiguration config;
+
+ private final ServerConnector connector;
+
+ private final HttpConfiguration secureConfig;
+
+ private final ServerConnector secureConnector;
+
+ private final ContextHandlerCollection contexts;
+
+ private final TestRequestLog log;
+
+ private List<File> filesToDelete = new ArrayList<>();
+
+ /**
+ * Constructor for <code>AppServer</code>.
+ */
+ public AppServer() {
+ this(0, -1);
+ }
+
+ /**
+ * Constructor for <code>AppServer</code>.
+ *
+ * @param port
+ * the http port number; may be zero to allocate a port
+ * dynamically
+ * @since 4.2
+ */
+ public AppServer(int port) {
+ this(port, -1);
+ }
+
+ /**
+ * Constructor for <code>AppServer</code>.
+ *
+ * @param port
+ * for http, may be zero to allocate a port dynamically
+ * @param sslPort
+ * for https,may be zero to allocate a port dynamically. If
+ * negative, the server will be set up without https support.
+ * @since 4.9
+ */
+ public AppServer(int port, int sslPort) {
+ server = new Server();
+
+ config = new HttpConfiguration();
+ config.setSecureScheme("https");
+ config.setSecurePort(0);
+ config.setOutputBufferSize(32768);
+
+ connector = new ServerConnector(server,
+ new HttpConnectionFactory(config));
+ connector.setPort(port);
+ String ip;
+ String hostName;
+ try {
+ final InetAddress me = InetAddress.getByName("localhost");
+ ip = me.getHostAddress();
+ connector.setHost(ip);
+ hostName = InetAddress.getLocalHost().getCanonicalHostName();
+ } catch (UnknownHostException e) {
+ throw new RuntimeException("Cannot find localhost", e);
+ }
+
+ if (sslPort >= 0) {
+ SslContextFactory.Server sslContextFactory = createTestSslContextFactory(
+ hostName, ip);
+ secureConfig = new HttpConfiguration(config);
+ secureConfig.addCustomizer(new SecureRequestCustomizer());
+ HttpConnectionFactory http11 = new HttpConnectionFactory(
+ secureConfig);
+ SslConnectionFactory tls = new SslConnectionFactory(
+ sslContextFactory, http11.getProtocol());
+ secureConnector = new ServerConnector(server, tls, http11);
+ secureConnector.setPort(sslPort);
+ secureConnector.setHost(ip);
+ } else {
+ secureConfig = null;
+ secureConnector = null;
+ }
+
+ contexts = new ContextHandlerCollection();
+
+ log = new TestRequestLog();
+ log.setHandler(contexts);
+
+ if (secureConnector == null) {
+ server.setConnectors(new Connector[] { connector });
+ } else {
+ server.setConnectors(
+ new Connector[] { connector, secureConnector });
+ }
+ server.setHandler(log);
+ }
+
+ private SslContextFactory.Server createTestSslContextFactory(
+ String hostName, String ip) {
+ SslContextFactory.Server factory = new SslContextFactory.Server();
+
+ String dName = "CN=localhost,OU=JGit,O=Eclipse,ST=Ontario,L=Toronto,C=CA";
+
+ try {
+ File tmpDir = Files.createTempDirectory("jks").toFile();
+ tmpDir.deleteOnExit();
+ makePrivate(tmpDir);
+ File keyStore = new File(tmpDir, "keystore.jks");
+ File keytool = new File(
+ new File(new File(System.getProperty("java.home")), "bin"),
+ "keytool");
+ Runtime.getRuntime().exec(
+ new String[] {
+ keytool.getAbsolutePath(), //
+ "-keystore", keyStore.getAbsolutePath(), //
+ "-storepass", keyPassword,
+ "-alias", hostName, //
+ "-ext", "bc=ca:true", //
+ "-ext",
+ String.format(
+ "san=ip:%s,ip:127.0.0.1,ip:[::1],DNS:%s",
+ ip, hostName), //
+ "-genkeypair", //
+ "-keyalg", "RSA", //
+ "-keypass", keyPassword, //
+ "-dname", dName, //
+ "-validity", "2" //
+ }).waitFor();
+ keyStore.deleteOnExit();
+ makePrivate(keyStore);
+ filesToDelete.add(keyStore);
+ filesToDelete.add(tmpDir);
+ factory.setKeyStorePath(keyStore.getAbsolutePath());
+ factory.setKeyStorePassword(keyPassword);
+ factory.setKeyManagerPassword(keyPassword);
+ factory.setTrustStorePath(keyStore.getAbsolutePath());
+ factory.setTrustStorePassword(keyPassword);
+ } catch (InterruptedException | IOException e) {
+ throw new RuntimeException("Cannot create ssl key/certificate", e);
+ }
+ return factory;
+ }
+
+ private void makePrivate(File file) {
+ file.setReadable(false);
+ file.setWritable(false);
+ file.setExecutable(false);
+ file.setReadable(true, true);
+ file.setWritable(true, true);
+ if (file.isDirectory()) {
+ file.setExecutable(true, true);
+ }
+ }
+
+ /**
+ * Create a new servlet context within the server.
+ * <p>
+ * This method should be invoked before the server is started, once for each
+ * context the caller wants to register.
+ *
+ * @param path
+ * path of the context; use "/" for the root context if binding
+ * to the root is desired.
+ * @return the context to add servlets into.
+ * @since 7.0
+ */
+ public ServletContextHandler addContext(String path) {
+ assertNotYetSetUp();
+ if ("".equals(path))
+ path = "/";
+
+ ServletContextHandler ctx = new ServletContextHandler();
+ ctx.setContextPath(path);
+ contexts.addHandler(ctx);
+
+ return ctx;
+ }
+
+ /**
+ * Configure basic authentication.
+ *
+ * @param ctx
+ * servlet context handler
+ * @param methods
+ * the methods
+ * @return servlet context handler
+ * @since 7.0
+ */
+ public ServletContextHandler authBasic(ServletContextHandler ctx,
+ String... methods) {
+ assertNotYetSetUp();
+ auth(ctx, new BasicAuthenticator(), methods);
+ return ctx;
+ }
+
+ static class TestMappedLoginService extends AbstractLoginService {
+ private RolePrincipal role;
+
+ protected final Map<String, UserPrincipal> users = new ConcurrentHashMap<>();
+
+ TestMappedLoginService(String role) {
+ this.role = new RolePrincipal(role);
+ }
+
+ @Override
+ protected void doStart() throws Exception {
+ UserPrincipal p = new UserPrincipal(username,
+ new Password(password));
+ users.put(username, p);
+ super.doStart();
+ }
+
+ @Override
+ protected UserPrincipal loadUserInfo(String user) {
+ return users.get(user);
+ }
+
+ @Override
+ protected List<RolePrincipal> loadRoleInfo(UserPrincipal user) {
+ if (users.get(user.getName()) == null) {
+ return null;
+ }
+ return Collections.singletonList(role);
+ }
+ }
+
+ private ConstraintMapping createConstraintMapping() {
+ ConstraintMapping cm = new ConstraintMapping();
+ cm.setConstraint(new ServletConstraint());
+ cm.getConstraint().setAuthenticate(true);
+ cm.getConstraint().setDataConstraint(ServletConstraint.DC_NONE);
+ cm.getConstraint().setRoles(new String[] { authRole });
+ return cm;
+ }
+
+ private void auth(ServletContextHandler ctx, Authenticator authType,
+ String... methods) {
+ AbstractLoginService users = new TestMappedLoginService(authRole);
+ List<ConstraintMapping> mappings = new ArrayList<>();
+ if (methods == null || methods.length == 0) {
+ ConstraintMapping cm = createConstraintMapping();
+ cm.setPathSpec("/*");
+ mappings.add(cm);
+ } else {
+ for (String method : methods) {
+ ConstraintMapping cm = createConstraintMapping();
+ cm.setMethod(method.toUpperCase(Locale.ROOT));
+ cm.setPathSpec("/*");
+ mappings.add(cm);
+ }
+ }
+
+ ConstraintSecurityHandler sec = new ConstraintSecurityHandler();
+ sec.setRealmName(realm);
+ sec.setAuthenticator(authType);
+ sec.setLoginService(users);
+ sec.setConstraintMappings(mappings.toArray(new ConstraintMapping[0]));
+ ctx.setSecurityHandler(sec);
+ }
+
+ /**
+ * Start the server on a random local port.
+ *
+ * @throws Exception
+ * the server cannot be started, testing is not possible.
+ */
+ public void setUp() throws Exception {
+ RecordingLogger.clear();
+ log.clear();
+ server.start();
+ config.setSecurePort(getSecurePort());
+ if (secureConfig != null) {
+ secureConfig.setSecurePort(getSecurePort());
+ }
+ }
+
+ /**
+ * Shutdown the server.
+ *
+ * @throws Exception
+ * the server refuses to halt, or wasn't running.
+ */
+ public void tearDown() throws Exception {
+ RecordingLogger.clear();
+ log.clear();
+ server.stop();
+ for (File f : filesToDelete) {
+ f.delete();
+ }
+ filesToDelete.clear();
+ }
+
+ /**
+ * Get the URI to reference this server.
+ * <p>
+ * The returned URI includes the proper host name and port number, but does
+ * not contain a path.
+ *
+ * @return URI to reference this server's root context.
+ */
+ public URI getURI() {
+ assertAlreadySetUp();
+ String host = connector.getHost();
+ if (host.contains(":") && !host.startsWith("["))
+ host = "[" + host + "]";
+ final String uri = "http://" + host + ":" + getPort();
+ try {
+ return new URI(uri);
+ } catch (URISyntaxException e) {
+ throw new RuntimeException("Unexpected URI error on " + uri, e);
+ }
+ }
+
+ /**
+ * Get port.
+ *
+ * @return the local port number the server is listening on.
+ */
+ public int getPort() {
+ assertAlreadySetUp();
+ return connector.getLocalPort();
+ }
+
+ /**
+ * Get secure port.
+ *
+ * @return the HTTPS port or -1 if not configured.
+ */
+ public int getSecurePort() {
+ assertAlreadySetUp();
+ return secureConnector != null ? secureConnector.getLocalPort() : -1;
+ }
+
+ /**
+ * Get requests.
+ *
+ * @return all requests since the server was started.
+ */
+ public List<AccessEvent> getRequests() {
+ return new ArrayList<>(log.getEvents());
+ }
+
+ /**
+ * Get requests.
+ *
+ * @param base
+ * base URI used to access the server.
+ * @param path
+ * the path to locate requests for, relative to {@code base}.
+ * @return all requests which match the given path.
+ */
+ public List<AccessEvent> getRequests(URIish base, String path) {
+ return getRequests(HttpTestCase.join(base, path));
+ }
+
+ /**
+ * Get requests.
+ *
+ * @param path
+ * the path to locate requests for.
+ * @return all requests which match the given path.
+ */
+ public List<AccessEvent> getRequests(String path) {
+ ArrayList<AccessEvent> r = new ArrayList<>();
+ for (AccessEvent event : log.getEvents()) {
+ if (event.getPath().equals(path)) {
+ r.add(event);
+ }
+ }
+ return r;
+ }
+
+ private void assertNotYetSetUp() {
+ assertFalse("server is not running", server.isRunning());
+ }
+
+ private void assertAlreadySetUp() {
+ assertTrue("server is running", server.isRunning());
+ }
+}
diff --git a/org.eclipse.jgit.junit.http/BUILD b/org.eclipse.jgit.junit.http/BUILD
index 17a7570..8ab98ac 100644
--- a/org.eclipse.jgit.junit.http/BUILD
+++ b/org.eclipse.jgit.junit.http/BUILD
@@ -1,11 +1,36 @@
load("@rules_java//java:defs.bzl", "java_library")
+load("@com_googlesource_gerrit_bazlets//tools:servlet_transform.bzl", "transform_srcjar")
package(default_visibility = ["//visibility:public"])
+JUNIT_HTTP_SRCS = glob(["src/**/*.java"])
+
+JUNIT_HTTP_EE8_TRANSFORM_SRCS = glob(
+ ["src/**/*.java"],
+ exclude = ["src/org/eclipse/jgit/junit/http/AppServer.java"],
+)
+
+filegroup(
+ name = "srcs",
+ testonly = 1,
+ srcs = JUNIT_HTTP_SRCS,
+ visibility = [
+ "//org.eclipse.jgit.junit.http.ee8:__pkg__",
+ "//tools/jgit-ee8:__pkg__",
+ ],
+)
+
+filegroup(
+ name = "ee8-transform-srcs",
+ testonly = 1,
+ srcs = JUNIT_HTTP_EE8_TRANSFORM_SRCS,
+ visibility = ["//tools/jgit-ee8:__pkg__"],
+)
+
java_library(
name = "junit-http",
testonly = 1,
- srcs = glob(["src/**/*.java"]),
+ srcs = JUNIT_HTTP_SRCS,
resources = glob(
["resources/**"],
allow_empty = True,
@@ -27,3 +52,14 @@
"//org.eclipse.jgit.junit:junit",
],
)
+
+transform_srcjar(
+ name = "junit-http-ee8-srcs",
+ direction = "to_javax",
+ sources = JUNIT_HTTP_EE8_TRANSFORM_SRCS,
+ src_prefix = "org.eclipse.jgit.junit.http/src/",
+ visibility = [
+ "//org.eclipse.jgit.junit.http.ee8:__pkg__",
+ "//tools/jgit-ee8:__pkg__",
+ ],
+)
diff --git a/org.eclipse.jgit.lfs.server.test.ee8/BUILD b/org.eclipse.jgit.lfs.server.test.ee8/BUILD
new file mode 100644
index 0000000..bb93b79
--- /dev/null
+++ b/org.eclipse.jgit.lfs.server.test.ee8/BUILD
@@ -0,0 +1,65 @@
+load("@rules_java//java:defs.bzl", "java_library")
+load("@com_googlesource_gerrit_bazlets//tools:junit.bzl", "junit_tests")
+load("@com_googlesource_gerrit_bazlets//tools:servlet_transform.bzl", "transform_srcjar")
+
+transform_srcjar(
+ name = "test-srcs",
+ testonly = 1,
+ direction = "to_javax",
+ sources = ["//org.eclipse.jgit.lfs.server.test:test-srcs"],
+ src_prefix = "org.eclipse.jgit.lfs.server.test/tst/",
+ visibility = ["//tools/jgit-ee8:__pkg__"],
+)
+
+transform_srcjar(
+ name = "base-test-srcs",
+ testonly = 1,
+ direction = "to_javax",
+ sources = ["//org.eclipse.jgit.lfs.server.test:base-test-srcs"],
+ src_prefix = "org.eclipse.jgit.lfs.server.test/tst/",
+)
+
+# Keep the helper/base class separate: the canonical LfsServerTest is compiled
+# into the helper jar, while the remaining tests are executed from the EE8
+# suite target.
+DEPS = [
+ "//org.eclipse.jgit.lfs.test:helpers",
+ "//org.eclipse.jgit:jgit",
+ "//org.eclipse.jgit.junit:junit",
+ "//org.eclipse.jgit.junit.http.ee8:junit-http-ee8",
+ "//org.eclipse.jgit.lfs:jgit-lfs",
+ "//org.eclipse.jgit.lfs.server.ee8:jgit-lfs-server-ee8",
+ "//lib:commons-logging",
+ "//lib:httpcore",
+ "//lib:httpclient",
+ "//lib:junit",
+ "//lib:jetty-http",
+ "//lib:jetty-io",
+ "//lib:jetty-server",
+ "//lib:jetty-servlet-ee8",
+ "//lib:jetty-security",
+ "//lib:jetty-security-ee8",
+ "//lib:jetty-util",
+ "//lib:javax-servlet-api",
+]
+
+junit_tests(
+ name = "lfs_server",
+ jvm_flags = [
+ "-Xmx512m",
+ "-Dfile.encoding=UTF-8",
+ ],
+ suite_srcs = ["//org.eclipse.jgit.lfs.server.test:nonbase-test-srcs"],
+ tags = ["lfs-server"],
+ srcs = [":test-srcs"],
+ deps = DEPS + [
+ ":helpers",
+ ],
+)
+
+java_library(
+ name = "helpers",
+ testonly = 1,
+ srcs = [":base-test-srcs"],
+ deps = DEPS,
+)
diff --git a/org.eclipse.jgit.lfs.server.test/BUILD b/org.eclipse.jgit.lfs.server.test/BUILD
index adc2df6..4b69804 100644
--- a/org.eclipse.jgit.lfs.server.test/BUILD
+++ b/org.eclipse.jgit.lfs.server.test/BUILD
@@ -6,6 +6,35 @@
TEST_BASE = ["tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java"]
+TEST_SRCS = glob(["tst/**/*.java"])
+
+filegroup(
+ name = "test-srcs",
+ testonly = 1,
+ srcs = TEST_SRCS,
+ visibility = [
+ "//org.eclipse.jgit.lfs.server.test.ee8:__pkg__",
+ "//tools/jgit-ee8:__pkg__",
+ ],
+)
+
+filegroup(
+ name = "base-test-srcs",
+ testonly = 1,
+ srcs = TEST_BASE,
+ visibility = ["//org.eclipse.jgit.lfs.server.test.ee8:__pkg__"],
+)
+
+filegroup(
+ name = "nonbase-test-srcs",
+ testonly = 1,
+ srcs = glob(
+ ["tst/**/*.java"],
+ exclude = TEST_BASE,
+ ),
+ visibility = ["//org.eclipse.jgit.lfs.server.test.ee8:__pkg__"],
+)
+
DEPS = [
"//org.eclipse.jgit.lfs.test:helpers",
"//org.eclipse.jgit:jgit",
diff --git a/tools/jgit-ee8/BUILD b/tools/jgit-ee8/BUILD
index df5c27c..f6681cc 100644
--- a/tools/jgit-ee8/BUILD
+++ b/tools/jgit-ee8/BUILD
@@ -7,8 +7,11 @@
"--forbid",
"jakarta\\.servlet",
"--forbid",
+ "org\\.eclipse\\.jetty\\.ee10\\.servlet",
+ "--forbid",
"org\\.eclipse\\.jgit\\..*\\.ee8",
- "--require",
+ "--require-if-source",
+ "jakarta\\.servlet",
"javax\\.servlet",
"--module",
"org.eclipse.jgit.http.server/src/",
@@ -18,11 +21,35 @@
"org.eclipse.jgit.lfs.server/src/",
"$(location //org.eclipse.jgit.lfs.server.ee8:jgit-lfs-server-ee8-srcs)",
"$(locations //org.eclipse.jgit.lfs.server:srcs)",
+ "--module",
+ "org.eclipse.jgit.junit.http/src/",
+ "$(location //org.eclipse.jgit.junit.http:junit-http-ee8-srcs)",
+ "$(locations //org.eclipse.jgit.junit.http:ee8-transform-srcs)",
+ "--module",
+ "org.eclipse.jgit.http.test/src/",
+ "$(location //org.eclipse.jgit.http.test.ee8:helpers-srcs)",
+ "$(locations //org.eclipse.jgit.http.test:helper-srcs)",
+ "--module",
+ "org.eclipse.jgit.http.test/tst/",
+ "$(location //org.eclipse.jgit.http.test.ee8:test-srcs)",
+ "$(locations //org.eclipse.jgit.http.test:test-srcs)",
+ "--module",
+ "org.eclipse.jgit.lfs.server.test/tst/",
+ "$(location //org.eclipse.jgit.lfs.server.test.ee8:test-srcs)",
+ "$(locations //org.eclipse.jgit.lfs.server.test:test-srcs)",
],
data = [
"//org.eclipse.jgit.http.server.ee8:jgit-http-server-ee8-srcs",
"//org.eclipse.jgit.http.server:srcs",
+ "//org.eclipse.jgit.http.test.ee8:helpers-srcs",
+ "//org.eclipse.jgit.http.test.ee8:test-srcs",
+ "//org.eclipse.jgit.http.test:helper-srcs",
+ "//org.eclipse.jgit.http.test:test-srcs",
+ "//org.eclipse.jgit.junit.http:ee8-transform-srcs",
+ "//org.eclipse.jgit.junit.http:junit-http-ee8-srcs",
"//org.eclipse.jgit.lfs.server.ee8:jgit-lfs-server-ee8-srcs",
"//org.eclipse.jgit.lfs.server:srcs",
+ "//org.eclipse.jgit.lfs.server.test.ee8:test-srcs",
+ "//org.eclipse.jgit.lfs.server.test:test-srcs",
],
)
diff --git a/tools/jgit-ee8/README.md b/tools/jgit-ee8/README.md
index 5578d65..7bb2f47 100644
--- a/tools/jgit-ee8/README.md
+++ b/tools/jgit-ee8/README.md
@@ -22,17 +22,18 @@
Do not put one of these generated jars and its canonical Jakarta counterpart on
the same classpath. They contain the same JGit classes.
-This is intentionally limited to Bazel source consumers. It does not add Maven,
-Tycho, p2, or Maven Central publication machinery. Those should be added only if
-a non-Bazel consumer needs published EE8 artifacts.
+This is intentionally limited to source generation, build, and test. It does
+not add Tycho, p2, or Maven Central publication machinery yet.
Run:
```sh
-bazelisk test //tools/jgit-ee8:generated_srcs_test
+bazelisk test \
+ //tools/jgit-ee8:generated_srcs_test \
+ //org.eclipse.jgit.junit.http.ee8:tests
```
-The test checks:
+`//tools/jgit-ee8:generated_srcs_test` checks:
* generated sources are derived from the canonical source filegroups
* generated srcjar entries use Java package paths
@@ -40,10 +41,28 @@
* generated sources contain `javax.servlet`, not `jakarta.servlet`
* generated sources do not move JGit classes to an `.ee8` package
+The dedicated `org.eclipse.jgit.*.ee8` targets follow the Jetty 12 EE8 testing
+model in a smaller form. Jetty generates EE8 main and test sources from the
+canonical newer-EE modules and then runs the EE8 tests in the EE8 module graph.
+JGit does the same for the servlet-facing tests: the HTTP/LFS test sources and
+shared `junit-http` helpers are transformed to `javax.servlet`, wired to Jetty
+EE8 test dependencies, and run against the generated EE8 JGit jars.
+
+`//org.eclipse.jgit.http.test.ee8:server_unit` is a fast, focused target for the
+three HTTP server utility tests. It is not part of the default EE8 suite because
+those classes already run under `//org.eclipse.jgit.http.test.ee8:http`.
+
+The test rewrite rules also map Jetty test helper imports from
+`org.eclipse.jetty.ee10.servlet` to the Jetty EE8 packages needed by the tests.
+They are intentionally test-only and separate from the production
+`jakarta.servlet` to `javax.servlet` rules.
+
Next steps:
* Keep this source-consumer bridge while Gerrit runs on Jetty 12 EE8.
* Reuse these targets for other Bazel source consumers that need EE8 output.
+* Move the generated-test JUnit helper to bazlets only if more generated-test
+ users need the same split between suite source labels and compiled sources.
* Add Maven/Tycho/p2 generation only when a non-Bazel consumer needs published
EE8 artifacts.
* Keep the canonical `srcs` filegroups aligned with each servlet-facing