Compare commits

..

No commits in common. "2177fcb57c5110e5542caa1d7f9a333c49f9dcc4" and "af6130709e97ab2f12ca1fa2633c9e34b671fb77" have entirely different histories.

8 changed files with 186 additions and 538 deletions

View file

@ -243,24 +243,15 @@ public class DependencyResolver {
*/
public RepositoryArtifact transferIntoDirectory(File directory)
throws DependencyTransferException {
DependencyTransferException transient_failure = null;
for (var artifact : getTransferArtifacts()) {
try {
if (retriever_.transferIntoDirectory(artifact, directory)) {
return artifact;
}
} catch (IOException e) {
// a transient issue with this repository, try the next one
// before giving up
transient_failure = rememberFailure(transient_failure, new DependencyTransferException(dependency_, artifact.location(), directory, e));
throw new DependencyTransferException(dependency_, artifact.location(), directory, e);
}
}
// transient failures never degrade into a null not-found result,
// an artifact that couldn't be transferred might still exist
if (transient_failure != null) {
throw transient_failure;
}
return null;
}
@ -379,58 +370,46 @@ public class DependencyResolver {
}
private MavenMetadata parseMavenMetadata(List<RepositoryArtifact> artifacts) {
var retrieved = retrieveFirstAvailable(artifacts, "metadata locations");
var xml = new Xml2MavenMetadata();
if (!xml.processXml(retrieved.content())) {
throw new DependencyXmlParsingErrorException(dependency_, retrieved.artifact().location(), xml.getErrors());
}
return xml;
}
private record RetrievedArtifact(RepositoryArtifact artifact, String content) {
}
private RetrievedArtifact retrieveFirstAvailable(List<RepositoryArtifact> artifacts, String locationsDescription) {
ArtifactRetrievalErrorException transient_failure = null;
RepositoryArtifact retrieved_artifact = null;
String metadata = null;
for (var artifact : artifacts) {
try {
return new RetrievedArtifact(artifact, retriever_.readString(artifact));
var content = retriever_.readString(artifact);
if (content == null) {
throw new ArtifactNotFoundException(dependency_, artifact.location());
}
retrieved_artifact = artifact;
metadata = content;
break;
} catch (FileUtilsErrorException e) {
if (e.getCause() instanceof FileNotFoundException) {
continue;
}
// a transient issue with this repository, try the next one
// before giving up
transient_failure = rememberFailure(transient_failure, new ArtifactRetrievalErrorException(dependency_, artifact.location(), e));
throw new ArtifactRetrievalErrorException(dependency_, artifact.location(), e);
}
}
// transient failures never degrade into not-found, an artifact
// that couldn't be retrieved might still exist
if (transient_failure != null) {
throw transient_failure;
if (metadata == null) {
var location = artifacts.stream().map(RepositoryArtifact::location).collect(Collectors.joining(", "));
if (location.isEmpty()) {
if (repositories_.isEmpty()) {
location = "[no repositories defined]";
}
else {
location = "[no metadata locations defined]";
}
}
throw new ArtifactNotFoundException(dependency_, location);
}
var location = artifacts.stream().map(RepositoryArtifact::location).collect(Collectors.joining(", "));
if (location.isEmpty()) {
if (repositories_.isEmpty()) {
location = "[no repositories defined]";
}
else {
location = "[no " + locationsDescription + " defined]";
}
var xml = new Xml2MavenMetadata();
if (!xml.processXml(metadata)) {
throw new DependencyXmlParsingErrorException(dependency_, retrieved_artifact.location(), xml.getErrors());
}
throw new ArtifactNotFoundException(dependency_, location);
}
private static <T extends Throwable> T rememberFailure(T remembered, T failure) {
if (remembered == null) {
return failure;
}
remembered.addSuppressed(failure);
return remembered;
return xml;
}
private List<RepositoryArtifact> getPomLocations() {
@ -447,16 +426,50 @@ public class DependencyResolver {
}
Xml2MavenPom getMavenPom(Dependency parent) {
var retrieved = retrieveFirstAvailable(getPomLocations(), "pom locations");
RepositoryArtifact retrieved_artifact = null;
String pom = null;
var artifacts = getPomLocations();
for (var artifact : artifacts) {
try {
var content = retriever_.readString(artifact);
if (content == null) {
throw new ArtifactNotFoundException(dependency_, artifact.location());
}
retrieved_artifact = artifact;
pom = content;
break;
} catch (FileUtilsErrorException e) {
if (e.getCause() instanceof FileNotFoundException) {
continue;
}
throw new ArtifactRetrievalErrorException(dependency_, artifact.location(), e);
}
}
if (pom == null) {
var location = artifacts.stream().map(RepositoryArtifact::location).collect(Collectors.joining(", "));
if (location.isEmpty()) {
if (repositories_.isEmpty()) {
location = "[no repositories defined]";
}
else {
location = "[no pom locations defined]";
}
}
throw new ArtifactNotFoundException(dependency_, location);
}
var xml = new Xml2MavenPom(parent, resolution_, retriever_, repositories_);
// first pass only extracts the properties from the pom
if (!xml.processXml(retrieved.content())) {
throw new DependencyXmlParsingErrorException(dependency_, retrieved.artifact().location(), xml.getErrors());
if (!xml.processXml(pom)) {
throw new DependencyXmlParsingErrorException(dependency_, retrieved_artifact.location(), xml.getErrors());
}
// second pass parses all the rest so that the properties are available anywhere
if (!xml.processXml(retrieved.content())) {
throw new DependencyXmlParsingErrorException(dependency_, retrieved.artifact().location(), xml.getErrors());
if (!xml.processXml(pom)) {
throw new DependencyXmlParsingErrorException(dependency_, retrieved_artifact.location(), xml.getErrors());
}
return xml;

View file

@ -629,32 +629,29 @@ public class Wrapper {
private void downloadDistribution(File file, String downloadUrl)
throws IOException {
retryOnTransientIoIssues(() -> {
try {
System.out.print("Downloading: " + downloadUrl + " ... ");
System.out.flush();
var url = new URL(downloadUrl);
var readableByteChannel = Channels.newChannel(url.openStream());
try (var fileOutputStream = new FileOutputStream(file)) {
var fileChannel = fileOutputStream.getChannel();
fileChannel.transferFrom(readableByteChannel, 0, Long.MAX_VALUE);
try {
System.out.print("Downloading: " + downloadUrl + " ... ");
System.out.flush();
var url = new URL(downloadUrl);
var readableByteChannel = Channels.newChannel(url.openStream());
try (var fileOutputStream = new FileOutputStream(file)) {
var fileChannel = fileOutputStream.getChannel();
fileChannel.transferFrom(readableByteChannel, 0, Long.MAX_VALUE);
System.out.print("done");
}
} catch (FileNotFoundException e) {
System.err.println("not found");
System.err.println("Failed to download file " + file + ".");
throw e;
} catch (IOException e) {
System.err.println("error");
System.err.println("Failed to download file " + file + " due to I/O issue.");
Files.deleteIfExists(file.toPath());
throw e;
} finally {
System.out.println();
System.out.print("done");
}
return null;
});
} catch (FileNotFoundException e) {
System.err.println("not found");
System.err.println("Failed to download file " + file + ".");
throw e;
} catch (IOException e) {
System.err.println("error");
System.err.println("Failed to download file " + file + " due to I/O issue.");
Files.deleteIfExists(file.toPath());
throw e;
} finally {
System.out.println();
}
}
private void resolveExtensions() {
@ -838,48 +835,11 @@ public class Wrapper {
private String readString(String version, URL url)
throws IOException {
return retryOnTransientIoIssues(() -> {
var connection = url.openConnection();
connection.setUseCaches(false);
connection.setRequestProperty(HttpUtils.HEADER_USER_AGENT, Product.BLD.toUserAgent(version));
try (var in = connection.getInputStream()) {
return new String(in.readAllBytes(), StandardCharsets.UTF_8);
}
});
}
static final int DOWNLOAD_ATTEMPTS = 3;
static final long DOWNLOAD_RETRY_DELAY_MS = 2000L;
interface IoAction<T> {
T execute() throws IOException;
}
private static <T> T retryOnTransientIoIssues(IoAction<T> action)
throws IOException {
return retryOnTransientIoIssues(action, DOWNLOAD_ATTEMPTS, DOWNLOAD_RETRY_DELAY_MS);
}
static <T> T retryOnTransientIoIssues(IoAction<T> action, int attempts, long delayMs)
throws IOException {
for (var attempt = 1; ; ++attempt) {
try {
return action.execute();
} catch (FileNotFoundException e) {
// a resource that doesn't exist will not appear by retrying
throw e;
} catch (IOException e) {
if (attempt >= attempts) {
throw e;
}
System.err.println("Download issue (" + e.getMessage() + "), retrying ...");
try {
Thread.sleep(delayMs * attempt);
} catch (InterruptedException interrupted) {
Thread.currentThread().interrupt();
throw e;
}
}
var connection = url.openConnection();
connection.setUseCaches(false);
connection.setRequestProperty(HttpUtils.HEADER_USER_AGENT, Product.BLD.toUserAgent(version));
try (var in = connection.getInputStream()) {
return new String(in.readAllBytes(), StandardCharsets.UTF_8);
}
}

View file

@ -6,7 +6,6 @@ package rife.bld.dependencies;
import com.sun.net.httpserver.HttpServer;
import org.junit.jupiter.api.Test;
import rife.bld.testing.RetryTest;
import rife.ioc.HierarchicalProperties;
import rife.tools.FileUtils;
import rife.tools.StringUtils;
@ -42,38 +41,38 @@ public class TestDependencyResolver {
assertEquals(new Dependency("com.uwyn.rife2", "rife2", new VersionNumber(1, 4, 0)), resolver.dependency());
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testNotFound() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("com.org.unknown", "voidthing"));
assertFalse(resolver.exists());
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testCheckExistence() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("com.uwyn.rife2", "rife2"));
assertTrue(resolver.exists());
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testCheckExistenceVersion() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("com.uwyn.rife2", "rife2", new VersionNumber(1, 4, 0)));
assertTrue(resolver.exists());
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testCheckExistenceMissingVersion() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("com.uwyn.rife2", "rife2", new VersionNumber(1, 3, 9)));
assertFalse(resolver.exists());
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testCheckVersionOverride() {
var resolver = new DependencyResolver(new VersionResolution(new HierarchicalProperties().put(PROPERTY_OVERRIDE_PREFIX, "com.uwyn.rife2:rife2:1.8.0")),
ArtifactRetriever.instance(), getNextRepositories(), new Dependency("com.uwyn.rife2", "rife2", new VersionNumber(1, 3, 9)));
assertEquals(new VersionNumber(1, 8, 0), resolver.resolveVersion());
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testListVersions() {
var resolver1 = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("com.uwyn.rife2", "rife2"));
var versions1 = resolver1.listVersions();
@ -92,7 +91,7 @@ public class TestDependencyResolver {
assertTrue(versions2.contains(new VersionNumber(11, 0, 14)));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetLatestVersion() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(3), new Dependency("com.uwyn.rife2", "rife2"));
var version = resolver.latestVersion();
@ -100,7 +99,7 @@ public class TestDependencyResolver {
assertTrue(version.compareTo(new VersionNumber(1, 4)) >= 0);
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetReleaseVersion() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(4), new Dependency("com.uwyn.rife2", "rife2"));
var version = resolver.releaseVersion();
@ -108,7 +107,7 @@ public class TestDependencyResolver {
assertTrue(version.compareTo(new VersionNumber(1, 4)) >= 0);
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testMetadata() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(5), new Dependency("com.uwyn.rife2", "rife2", new VersionNumber(1, 4, 0)));
var metadata = resolver.getMavenMetadata();
@ -117,7 +116,7 @@ public class TestDependencyResolver {
assertNull(resolver.getSnapshotMavenMetadata());
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testSnapshotMetadata() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), List.of(getNextRepository(), RIFE2_SNAPSHOTS), new Dependency("com.uwyn.rife2", "rife2", new VersionNumber(1, 9, 1, "SNAPSHOT")));
var metadata = resolver.getSnapshotMavenMetadata();
@ -126,7 +125,7 @@ public class TestDependencyResolver {
assertEquals(4, metadata.getSnapshotBuildNumber());
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileDependenciesRIFE2() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("com.uwyn.rife2", "rife2"));
var dependencies = resolver.getDirectDependencies(compile);
@ -134,7 +133,7 @@ public class TestDependencyResolver {
assertEquals(0, dependencies.size());
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileDependenciesRIFE2Snapshot() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), List.of(getNextRepository(), RIFE2_SNAPSHOTS), new Dependency("com.uwyn.rife2", "rife2", new VersionNumber(1, 9, 1, "SNAPSHOT")));
var dependencies = resolver.getDirectDependencies(compile);
@ -142,7 +141,7 @@ public class TestDependencyResolver {
assertEquals(0, dependencies.size());
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileDependenciesGoogleApi() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("com.google.apis", "google-api-services-youtube", new VersionGeneric("v3-rev20240514-2.0.0")));
var dependencies = resolver.getDirectDependencies(compile);
@ -152,7 +151,7 @@ public class TestDependencyResolver {
com.google.api-client:google-api-client:2.5.0""", StringUtils.join(dependencies, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileDependenciesJetty() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("org.eclipse.jetty", "jetty-server", new VersionNumber(11, 0, 14)));
var dependencies = resolver.getDirectDependencies(compile);
@ -165,7 +164,7 @@ public class TestDependencyResolver {
org.slf4j:slf4j-api:2.0.5""", StringUtils.join(dependencies, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileDependenciesAssertJ() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("org.assertj", "assertj-joda-time", new VersionNumber(2, 2, 0)));
var dependencies = resolver.getDirectDependencies(compile);
@ -175,7 +174,7 @@ public class TestDependencyResolver {
org.assertj:assertj-core""", StringUtils.join(dependencies, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileDependenciesSwagger() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("io.swagger.core.v3", "swagger-core", new VersionNumber(2,2,27)));
var dependencies = resolver.getDirectDependencies(compile);
@ -195,7 +194,7 @@ public class TestDependencyResolver {
jakarta.validation:jakarta.validation-api:2.0.2""", StringUtils.join(dependencies, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileDependenciesJettyOverride1() {
var resolver = new DependencyResolver(new VersionResolution(new HierarchicalProperties().put(PROPERTY_OVERRIDE_PREFIX, "org.slf4j:slf4j-api:2.0.16")),
ArtifactRetriever.instance(), getNextRepositories(), new Dependency("org.eclipse.jetty", "jetty-server", new VersionNumber(11, 0, 14)));
@ -209,7 +208,7 @@ public class TestDependencyResolver {
org.slf4j:slf4j-api:2.0.16""", StringUtils.join(dependencies, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileDependenciesJettyOverride2() {
var resolver = new DependencyResolver(new VersionResolution(new HierarchicalProperties().put(PROPERTY_OVERRIDE_PREFIX, "org.slf4j:slf4j-api:2.0.11,org.eclipse.jetty:jetty-io:11.0.13,org.eclipse.jetty:jetty-server:11.0.15")),
ArtifactRetriever.instance(), getNextRepositories(), new Dependency("org.eclipse.jetty", "jetty-server", new VersionNumber(11, 0, 14)));
@ -223,7 +222,7 @@ public class TestDependencyResolver {
org.slf4j:slf4j-api:2.0.11""", StringUtils.join(dependencies, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileRuntimeDependenciesJunit() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("org.junit.jupiter", "junit-jupiter", new VersionNumber(5, 9, 2)));
var dependencies_compile = resolver.getDirectDependencies(compile, runtime);
@ -235,7 +234,7 @@ public class TestDependencyResolver {
org.junit.jupiter:junit-jupiter-engine:5.9.2""", StringUtils.join(dependencies_compile, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileDependenciesSpringBoot() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("org.springframework.boot", "spring-boot-starter", new VersionNumber(3, 0, 4)));
var dependencies = resolver.getDirectDependencies(compile);
@ -250,7 +249,7 @@ public class TestDependencyResolver {
org.yaml:snakeyaml:1.33""", StringUtils.join(dependencies, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileDependenciesMaven() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("org.apache.maven", "maven-core", new VersionNumber(3, 9, 0)));
var dependencies = resolver.getDirectDependencies(compile);
@ -285,7 +284,7 @@ public class TestDependencyResolver {
org.slf4j:slf4j-api:1.7.36""", StringUtils.join(dependencies, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileDependenciesPlay() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("com.typesafe.play", "play_2.13", new VersionNumber(2, 8, 19)));
var dependencies = resolver.getDirectDependencies(compile);
@ -319,7 +318,7 @@ public class TestDependencyResolver {
org.scala-lang.modules:scala-parser-combinators_2.13:1.1.2""", StringUtils.join(dependencies, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileDependenciesVaadin() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("com.vaadin", "vaadin", new VersionNumber(23, 3, 7)));
var dependencies = resolver.getDirectDependencies(compile);
@ -337,7 +336,7 @@ public class TestDependencyResolver {
com.vaadin:collaboration-engine:5.3.0""", StringUtils.join(dependencies, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileRuntimeDependenciesBitly() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("net.thauvin.erik", "bitly-shorten", new VersionNumber(2, 0, 0)));
var dependencies = resolver.getDirectDependencies(compile, runtime);
@ -352,7 +351,7 @@ public class TestDependencyResolver {
org.json:json:20250107""", StringUtils.join(dependencies, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileTransitiveDependenciesRIFE2() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("com.uwyn.rife2", "rife2"));
var dependencies = resolver.getAllDependencies(compile);
@ -362,7 +361,7 @@ public class TestDependencyResolver {
com.uwyn.rife2:rife2""", StringUtils.join(dependencies, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileTransitiveDependenciesRIFE2Snapshot() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), List.of(getNextRepository(), RIFE2_SNAPSHOTS), new Dependency("com.uwyn.rife2", "rife2", new VersionNumber(1, 9, 1, "SNAPSHOT")));
var dependencies = resolver.getAllDependencies(compile);
@ -372,7 +371,7 @@ public class TestDependencyResolver {
com.uwyn.rife2:rife2:1.9.1-SNAPSHOT""", StringUtils.join(dependencies, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileTransitiveDependenciesJetty() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("org.eclipse.jetty", "jetty-server", new VersionNumber(11, 0, 14)));
var dependencies = resolver.getAllDependencies(compile);
@ -387,7 +386,7 @@ public class TestDependencyResolver {
org.eclipse.jetty:jetty-util:11.0.14""", StringUtils.join(dependencies, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileTransitiveDependenciesJettyExclusion() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(),
new Dependency("org.eclipse.jetty", "jetty-server", new VersionNumber(11, 0, 14))
@ -403,7 +402,7 @@ public class TestDependencyResolver {
org.eclipse.jetty:jetty-util:11.0.14""", StringUtils.join(dependencies, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileTransitiveDependenciesJettyFullGroupExclusion() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(),
new Dependency("org.eclipse.jetty", "jetty-server", new VersionNumber(11, 0, 14))
@ -417,7 +416,7 @@ public class TestDependencyResolver {
org.slf4j:slf4j-api:2.0.5""", StringUtils.join(dependencies, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileTransitiveDependenciesJettyFullArtifactExclusion() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(),
new Dependency("org.eclipse.jetty", "jetty-server", new VersionNumber(11, 0, 14))
@ -433,7 +432,7 @@ public class TestDependencyResolver {
org.eclipse.jetty:jetty-util:11.0.14""", StringUtils.join(dependencies, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileTransitiveDependenciesJettyFullExclusion() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(),
new Dependency("org.eclipse.jetty", "jetty-server", new VersionNumber(11, 0, 14))
@ -445,7 +444,7 @@ public class TestDependencyResolver {
org.eclipse.jetty:jetty-server:11.0.14""", StringUtils.join(dependencies, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileTransitiveDependenciesJettyAndSlfj() {
var dependencies = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("org.eclipse.jetty", "jetty-server", new VersionNumber(11, 0, 14))).getAllDependencies(compile);
var dependencies2 = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("org.slf4j", "slf4j-simple", new VersionNumber(2, 0, 6))).getAllDependencies(compile, runtime);
@ -465,7 +464,7 @@ public class TestDependencyResolver {
org.slf4j:slf4j-api:2.0.6""", StringUtils.join(dependencies, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileRuntimeTransitiveDependenciesJunit() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("org.junit.jupiter", "junit-jupiter", new VersionNumber(5, 9, 2)));
var dependencies_compile = resolver.getAllDependencies(compile, runtime);
@ -488,7 +487,7 @@ public class TestDependencyResolver {
org.junit.jupiter:junit-jupiter-engine:5.9.2""", StringUtils.join(dependencies_runtime, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileTransitiveDependenciesSpringBoot() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("org.springframework.boot", "spring-boot-starter", new VersionNumber(3, 0, 4)));
var dependencies = resolver.getAllDependencies(compile);
@ -515,7 +514,7 @@ public class TestDependencyResolver {
org.apache.logging.log4j:log4j-api:2.19.0""", StringUtils.join(dependencies, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileTransitiveDependenciesMaven() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("org.apache.maven", "maven-core", new VersionNumber(3, 9, 0)));
var dependencies = resolver.getAllDependencies(compile);
@ -556,7 +555,7 @@ public class TestDependencyResolver {
org.codehaus.plexus:plexus-cipher:2.0""", StringUtils.join(dependencies, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileTransitiveDependenciesPlay() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("com.typesafe.play", "play_2.13", new VersionNumber(2, 8, 19)));
var dependencies = resolver.getAllDependencies(compile);
@ -613,7 +612,7 @@ public class TestDependencyResolver {
com.thoughtworks.paranamer:paranamer:2.8""", StringUtils.join(dependencies, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileTransitiveDependenciesVaadin() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("com.vaadin", "vaadin", new VersionNumber(23, 3, 7)));
var dependencies = resolver.getAllDependencies(compile);
@ -710,7 +709,7 @@ public class TestDependencyResolver {
com.google.code.findbugs:jsr305:3.0.2""", StringUtils.join(dependencies, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileRuntimeTransitiveDependenciesBitly() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("net.thauvin.erik", "bitly-shorten", new VersionNumber(2, 0, 0)));
var dependencies = resolver.getAllDependencies(compile, runtime);
@ -730,7 +729,7 @@ public class TestDependencyResolver {
com.squareup.okio:okio-jvm:3.6.0""", StringUtils.join(dependencies, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetCompileRuntimeTransitiveDependenciesMariaDb() {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("org.mariadb.jdbc", "mariadb-java-client", new VersionNumber(3, 1, 3)));
var dependencies_compile = resolver.getAllDependencies(compile, runtime);
@ -753,7 +752,7 @@ public class TestDependencyResolver {
org.mariadb.jdbc:mariadb-java-client:3.1.3""", StringUtils.join(dependencies_runtime, "\n"));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependency()
throws Exception {
var repos = getNextRepositories();
@ -777,7 +776,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencySources()
throws Exception {
var repos = getNextRepositories();
@ -802,7 +801,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencySourcesJavadoc()
throws Exception {
var repos = getNextRepositories();
@ -828,7 +827,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencySnapshot()
throws Exception {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), List.of(getNextRepository(), RIFE2_SNAPSHOTS), new Dependency("com.uwyn.rife2", "rife2", new VersionNumber(1, 9, 1, "SNAPSHOT")));
@ -850,7 +849,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencySnapshotSources()
throws Exception {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), List.of(getNextRepository(), RIFE2_SNAPSHOTS), new Dependency("com.uwyn.rife2", "rife2", new VersionNumber(1, 9, 1, "SNAPSHOT")));
@ -874,7 +873,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencySnapshotSourcesJavadoc()
throws Exception {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), List.of(getNextRepository(), RIFE2_SNAPSHOTS), new Dependency("com.uwyn.rife2", "rife2", new VersionNumber(1, 9, 1, "SNAPSHOT")));
@ -900,7 +899,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencySourcesModule()
throws Exception {
var repos = getNextRepositories();
@ -925,7 +924,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencySourcesJavadocModule()
throws Exception {
var repos = getNextRepositories();
@ -951,7 +950,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencySnapshotModule()
throws Exception {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), List.of(getNextRepository(), RIFE2_SNAPSHOTS), new Module("com.uwyn.rife2", "rife2", new VersionNumber(1, 9, 1, "SNAPSHOT")));
@ -973,7 +972,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencySnapshotSourcesModule()
throws Exception {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), List.of(getNextRepository(), RIFE2_SNAPSHOTS), new Module("com.uwyn.rife2", "rife2", new VersionNumber(1, 9, 1, "SNAPSHOT")));
@ -997,7 +996,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencySnapshotSourcesJavadocModule()
throws Exception {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), List.of(SONATYPE_SNAPSHOTS, RIFE2_SNAPSHOTS), new Module("com.uwyn.rife2", "rife2", new VersionNumber(1, 9, 1, "SNAPSHOT")));
@ -1023,7 +1022,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencyJetty()
throws Exception {
var repos = getNextRepositories();
@ -1060,7 +1059,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencyJettyModule()
throws Exception {
var repos = getNextRepositories();
@ -1097,7 +1096,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencySwagger()
throws Exception {
var repos = getNextRepositories();
@ -1150,7 +1149,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencyGoogleApi()
throws Exception {
var repos = getNextRepositories();
@ -1223,7 +1222,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencyGoogleApiModule()
throws Exception {
var repos = getNextRepositories();
@ -1296,7 +1295,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencyJettyOverriddenVersions()
throws Exception {
var repos = getNextRepositories();
@ -1337,7 +1336,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencyJettyOverriddenVersionsModule()
throws Exception {
var repos = getNextRepositories();
@ -1378,7 +1377,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencyJettySources()
throws Exception {
var repos = getNextRepositories();
@ -1427,7 +1426,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencyJettySourcesModule()
throws Exception {
var repos = getNextRepositories();
@ -1476,7 +1475,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencyJettySourcesJavadoc()
throws Exception {
var repos = getNextRepositories();
@ -1537,7 +1536,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencyJettySourcesJavadocModule()
throws Exception {
var repos = getNextRepositories();
@ -1598,7 +1597,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependenciesJunit()
throws Exception {
var repos = getNextRepositories();
@ -1639,7 +1638,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencySpringBoot()
throws Exception {
var repos = getNextRepositories();
@ -1700,7 +1699,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencyMaven()
throws Exception {
var repos = getNextRepositories();
@ -1789,7 +1788,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencyPlay()
throws Exception {
var repos = getNextRepositories();
@ -1910,7 +1909,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencyPlayOverriddenVersions()
throws Exception {
var repos = getNextRepositories();
@ -2032,7 +2031,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferDependencyVaadin()
throws Exception {
var repos = getNextRepositories();
@ -2232,7 +2231,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferCheckExisting()
throws Exception {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Dependency("org.eclipse.jetty", "jetty-server", new VersionNumber(11, 0, 14)));
@ -2290,7 +2289,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testTransferCheckExistingModule()
throws Exception {
var resolver = new DependencyResolver(VersionResolution.dummy(), ArtifactRetriever.instance(), getNextRepositories(), new Module("org.eclipse.jetty", "jetty-server", new VersionNumber(11, 0, 14)));
@ -2348,7 +2347,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetAllDependenciesParallelPomPrefetching() throws Exception {
var max_concurrent_retrievals = new AtomicInteger();
var server = createPomServer(max_concurrent_retrievals);
@ -2374,7 +2373,7 @@ public class TestDependencyResolver {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testGetAllDependenciesSequentialWithoutCachingRetriever() throws Exception {
var max_concurrent_retrievals = new AtomicInteger();
var server = createPomServer(max_concurrent_retrievals);
@ -2406,23 +2405,19 @@ public class TestDependencyResolver {
try {
// delay the response so that parallel retrievals overlap
Thread.sleep(100);
// serve the POM of the artifact in the request path
var segments = exchange.getRequestURI().getPath().split("/");
var artifact = segments[segments.length - 3];
var body = buildPom(artifact, graph.getOrDefault(artifact, List.of())).getBytes();
exchange.sendResponseHeaders(200, body.length);
exchange.getResponseBody().write(body);
exchange.close();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
active_retrievals.decrementAndGet();
}
// serve the POM of the artifact in the request path
var segments = exchange.getRequestURI().getPath().split("/");
var artifact = segments[segments.length - 3];
var body = buildPom(artifact, graph.getOrDefault(artifact, List.of())).getBytes();
// stop counting before the response is released, a sequential
// client sends its next request the moment the response
// arrives, even while this handler is still finishing up
active_retrievals.decrementAndGet();
exchange.sendResponseHeaders(200, body.length);
exchange.getResponseBody().write(body);
exchange.close();
});
server.setExecutor(Executors.newCachedThreadPool());
return server;

View file

@ -1,248 +0,0 @@
/*
* Copyright 2001-2026 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.dependencies;
import com.sun.net.httpserver.HttpServer;
import org.junit.jupiter.api.Test;
import rife.bld.dependencies.exceptions.ArtifactNotFoundException;
import rife.bld.dependencies.exceptions.ArtifactRetrievalErrorException;
import rife.bld.dependencies.exceptions.DependencyTransferException;
import rife.ioc.HierarchicalProperties;
import rife.tools.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.file.Files;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import static org.junit.jupiter.api.Assertions.*;
import static rife.bld.dependencies.Scope.*;
/**
* A repository that fails with a transient issue is skipped in favor of
* the next one, and transient failures never degrade into not-found.
*/
public class TestRepositoryFallthrough {
private DependencyResolver resolver(List<Repository> repositories, Dependency dependency) {
return new DependencyResolver(new VersionResolution(new HierarchicalProperties()), ArtifactRetriever.instance(), repositories, dependency);
}
@Test
void testMetadataFallsThroughTransientFailure() throws Exception {
var failing = createFailingServer();
var serving = createArtifactServer(Map.of("tool:1.0.0", pom("tool", "1.0.0", "")),
Map.of("tool", metadata("tool", "1.0.0")));
failing.start();
serving.start();
try {
var resolver = resolver(List.of(serverRepository(failing), serverRepository(serving)),
new Dependency("com.example", "tool"));
assertEquals(Version.parse("1.0.0"), resolver.latestVersion());
} finally {
failing.stop(0);
serving.stop(0);
}
}
@Test
void testMetadataAllTransientFailures() throws Exception {
var failing1 = createFailingServer();
var failing2 = createFailingServer();
failing1.start();
failing2.start();
try {
var resolver = resolver(List.of(serverRepository(failing1), serverRepository(failing2)),
new Dependency("com.example", "tool"));
var exception = assertThrows(ArtifactRetrievalErrorException.class, resolver::latestVersion);
// the failure of the second repository is preserved as suppressed
assertEquals(1, exception.getSuppressed().length);
} finally {
failing1.stop(0);
failing2.stop(0);
}
}
@Test
void testMetadataNotFoundStaysNotFound() throws Exception {
var empty1 = createArtifactServer(Map.of(), Map.of());
var empty2 = createArtifactServer(Map.of(), Map.of());
empty1.start();
empty2.start();
try {
var resolver = resolver(List.of(serverRepository(empty1), serverRepository(empty2)),
new Dependency("com.example", "tool"));
assertThrows(ArtifactNotFoundException.class, resolver::latestVersion);
} finally {
empty1.stop(0);
empty2.stop(0);
}
}
@Test
void testPomFallsThroughTransientFailure() throws Exception {
var failing = createFailingServer();
var serving = createArtifactServer(Map.of(
"tool:1.0.0", pom("tool", "1.0.0", dependency("liba", "1.1.0")),
"liba:1.1.0", pom("liba", "1.1.0", "")), Map.of());
failing.start();
serving.start();
try {
var resolver = resolver(List.of(serverRepository(failing), serverRepository(serving)),
new Dependency("com.example", "tool", new VersionNumber(1, 0, 0)));
var dependencies = resolver.getAllDependencies(compile);
assertEquals(2, dependencies.size());
} finally {
failing.stop(0);
serving.stop(0);
}
}
@Test
void testPomAllTransientFailures() throws Exception {
var failing = createFailingServer();
failing.start();
try {
var resolver = resolver(List.of(serverRepository(failing)),
new Dependency("com.example", "tool", new VersionNumber(1, 0, 0)));
assertThrows(ArtifactRetrievalErrorException.class, () -> resolver.getAllDependencies(compile));
} finally {
failing.stop(0);
}
}
@Test
void testTransferFallsThroughTransientFailure() throws Exception {
var failing = createFailingServer();
var serving = createArtifactServer(Map.of("tool:1.0.0", pom("tool", "1.0.0", "")), Map.of());
failing.start();
serving.start();
var tmp = Files.createTempDirectory("fallthrough").toFile();
try {
var resolver = resolver(List.of(serverRepository(failing), serverRepository(serving)),
new Dependency("com.example", "tool", new VersionNumber(1, 0, 0)));
var artifact = resolver.transferIntoDirectory(tmp);
assertNotNull(artifact);
assertTrue(new File(tmp, "tool-1.0.0.jar").exists());
} finally {
failing.stop(0);
serving.stop(0);
FileUtils.deleteDirectory(tmp);
}
}
@Test
void testTransferAllTransientFailures() throws Exception {
var failing = createFailingServer();
failing.start();
var tmp = Files.createTempDirectory("fallthrough").toFile();
try {
var resolver = resolver(List.of(serverRepository(failing)),
new Dependency("com.example", "tool", new VersionNumber(1, 0, 0)));
// a transient failure surfaces as an exception, not as the
// null result that signals not-found
assertThrows(DependencyTransferException.class, () -> resolver.transferIntoDirectory(tmp));
} finally {
failing.stop(0);
FileUtils.deleteDirectory(tmp);
}
}
@Test
void testTransferNotFoundReturnsNull() throws Exception {
var empty = createArtifactServer(Map.of(), Map.of());
empty.start();
var tmp = Files.createTempDirectory("fallthrough").toFile();
try {
var resolver = resolver(List.of(serverRepository(empty)),
new Dependency("com.example", "tool", new VersionNumber(1, 0, 0)));
assertNull(resolver.transferIntoDirectory(tmp));
} finally {
empty.stop(0);
FileUtils.deleteDirectory(tmp);
}
}
private static Repository serverRepository(HttpServer server) {
return new Repository("http://localhost:" + server.getAddress().getPort() + "/");
}
private static HttpServer createFailingServer()
throws IOException {
var server = HttpServer.create(new InetSocketAddress("localhost", 0), 0);
server.createContext("/", exchange -> {
exchange.sendResponseHeaders(500, -1);
exchange.close();
});
server.setExecutor(Executors.newCachedThreadPool());
return server;
}
private static HttpServer createArtifactServer(Map<String, String> poms, Map<String, String> metadata)
throws IOException {
var server = HttpServer.create(new InetSocketAddress("localhost", 0), 0);
server.createContext("/", exchange -> {
var segments = exchange.getRequestURI().getPath().split("/");
var filename = segments[segments.length - 1];
byte[] body = null;
if (filename.endsWith(".pom") && segments.length >= 3) {
var content = poms.get(segments[segments.length - 3] + ":" + segments[segments.length - 2]);
if (content != null) {
body = content.getBytes();
}
} else if (filename.endsWith(".jar") && segments.length >= 3) {
if (poms.containsKey(segments[segments.length - 3] + ":" + segments[segments.length - 2])) {
body = "jar".getBytes();
}
} else if (filename.equals("maven-metadata.xml") && segments.length >= 2) {
var content = metadata.get(segments[segments.length - 2]);
if (content != null) {
body = content.getBytes();
}
}
if (body == null) {
exchange.sendResponseHeaders(404, -1);
} else {
exchange.sendResponseHeaders(200, body.length);
exchange.getResponseBody().write(body);
}
exchange.close();
});
server.setExecutor(Executors.newCachedThreadPool());
return server;
}
private static String dependency(String artifact, String version) {
return "<dependency><groupId>com.example</groupId><artifactId>" + artifact + "</artifactId><version>" + version + "</version></dependency>";
}
private static String pom(String artifact, String version, String dependencies) {
return """
<?xml version="1.0" encoding="UTF-8"?>
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>%s</artifactId>
<version>%s</version>
<dependencies>%s</dependencies>
</project>""".formatted(artifact, version, dependencies);
}
private static String metadata(String artifact, String version) {
return """
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<groupId>com.example</groupId>
<artifactId>%s</artifactId>
<versioning>
<latest>%s</latest>
<release>%s</release>
<versions><version>%s</version></versions>
</versioning>
</metadata>""".formatted(artifact, version, version, version);
}
}

View file

@ -5,7 +5,6 @@
package rife.bld.operations;
import org.junit.jupiter.api.Test;
import rife.bld.testing.RetryTest;
import rife.bld.BldVersion;
import rife.bld.WebProject;
import rife.bld.dependencies.*;
@ -15,7 +14,6 @@ import rife.tools.FileUtils;
import rife.tools.StringUtils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
@ -66,7 +64,7 @@ public class TestDependencyTreeOperation {
assertTrue(operation3.repositories().contains(repository2));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testExecution()
throws Exception {
var tmp = Files.createTempDirectory("test").toFile();
@ -139,7 +137,7 @@ public class TestDependencyTreeOperation {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testExecutionProvidedTest()
throws Exception {
var tmp = Files.createTempDirectory("test").toFile();
@ -217,7 +215,7 @@ public class TestDependencyTreeOperation {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testFromProject()
throws Exception {
var tmp = Files.createTempDirectory("test").toFile();
@ -294,7 +292,7 @@ public class TestDependencyTreeOperation {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testFromProjectProvidedTest()
throws Exception {
var tmp = Files.createTempDirectory("test").toFile();
@ -369,7 +367,7 @@ public class TestDependencyTreeOperation {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testFromProjectExtensions()
throws Exception {
var tmp = Files.createTempDirectory("test").toFile();

View file

@ -5,14 +5,12 @@
package rife.bld.operations;
import org.junit.jupiter.api.Test;
import rife.bld.testing.RetryTest;
import rife.bld.WebProject;
import rife.bld.dependencies.*;
import rife.bld.dependencies.Module;
import rife.tools.FileUtils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
@ -122,7 +120,7 @@ public class TestDownloadOperation {
assertTrue(operation3.repositories().contains(repository2));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testExecution()
throws Exception {
var tmp = Files.createTempDirectory("test").toFile();
@ -210,7 +208,7 @@ public class TestDownloadOperation {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testExecutionAdditionalSourcesJavadoc()
throws Exception {
var tmp = Files.createTempDirectory("test").toFile();
@ -354,7 +352,7 @@ public class TestDownloadOperation {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testFromProject()
throws Exception {
var tmp = Files.createTempDirectory("test").toFile();
@ -462,7 +460,7 @@ public class TestDownloadOperation {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testFromProject2()
throws Exception {
var tmp = Files.createTempDirectory("test").toFile();

View file

@ -5,14 +5,12 @@
package rife.bld.operations;
import org.junit.jupiter.api.Test;
import rife.bld.testing.RetryTest;
import rife.bld.WebProject;
import rife.bld.dependencies.*;
import rife.bld.dependencies.Module;
import rife.tools.FileUtils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
@ -117,7 +115,7 @@ public class TestPurgeOperation {
assertTrue(operation3.repositories().contains(repository2));
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testExecution()
throws Exception {
var tmp = Files.createTempDirectory("test").toFile();
@ -327,7 +325,7 @@ public class TestPurgeOperation {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testExecutionAdditionalSourcesJavadoc()
throws Exception {
var tmp = Files.createTempDirectory("test").toFile();
@ -800,7 +798,7 @@ public class TestPurgeOperation {
}
}
@RetryTest(value = 3, delay = 2, withExceptions = IOException.class)
@Test
void testFromProject()
throws Exception {
var tmp = Files.createTempDirectory("test").toFile();

View file

@ -1,66 +0,0 @@
/*
* Copyright 2001-2026 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.wrapper;
import org.junit.jupiter.api.Test;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.jupiter.api.Assertions.*;
public class TestWrapperRetry {
@Test
void testSucceedsWithoutRetry() throws Exception {
var attempts = new AtomicInteger();
var result = Wrapper.retryOnTransientIoIssues(() -> {
attempts.incrementAndGet();
return "ok";
}, 3, 1);
assertEquals("ok", result);
assertEquals(1, attempts.get());
}
@Test
void testRetriesTransientIoIssues() throws Exception {
// the first two attempts fail with a transient issue, the third
// succeeds
var attempts = new AtomicInteger();
var result = Wrapper.retryOnTransientIoIssues(() -> {
if (attempts.incrementAndGet() < 3) {
throw new IOException("Connection timed out");
}
return "ok";
}, 3, 1);
assertEquals("ok", result);
assertEquals(3, attempts.get());
}
@Test
void testThrowsAfterExhaustedAttempts() {
var attempts = new AtomicInteger();
var exception = assertThrows(IOException.class, () ->
Wrapper.retryOnTransientIoIssues(() -> {
attempts.incrementAndGet();
throw new IOException("Connection timed out");
}, 3, 1));
assertEquals("Connection timed out", exception.getMessage());
assertEquals(3, attempts.get());
}
@Test
void testDoesntRetryMissingResources() {
// a 404 is not transient, retrying it would only slow down the
// fallback paths that rely on a quick failure
var attempts = new AtomicInteger();
assertThrows(FileNotFoundException.class, () ->
Wrapper.retryOnTransientIoIssues(() -> {
attempts.incrementAndGet();
throw new FileNotFoundException("http://localhost/absent");
}, 3, 1));
assertEquals(1, attempts.get());
}
}