, CodeSource> locator) {
- super(locator);
+ private static long jarSize(final Path location) {
+ try {
+ return Files.size(location);
+ } catch (final Exception e) {
+ throw new IllegalArgumentException(
+ "Failed to read file size. location: " + location, e);
}
+ }
- String minJavaVersion(final Class> type) {
- final Path path = pathToJar(type);
+ /**
+ * Extract the version number from the path within the Gradle cache.
+ *
+ * Dependencies are in the Gradle cache. This stores jars in a directory structure that
+ * contains the version number. For example {@code
+ * .gradle/caches/modules-2/files-2.1/com.damnhandy/handy-uri-templates/
+ * 2.1.8/170102d8e1d6fcc5e8f9bef45de923285dd3a80f/handy-uri-templates-2.1.8.jar} Where the
+ * version is {@code 2.1.8}.
+ *
+ * @param type a type loaded from the jar file.
+ * @return the version of the jar file.
+ */
+ @SuppressFBWarnings(value = "PATH_TRAVERSAL_IN", justification = "Path provided by JVM")
+ private static String jarVersion(final Class> type, final Path location) {
+ final String textPath = location.toString();
+ final int idx = textPath.indexOf(GRADLE_CACHE_PATH);
+ if (idx < 0) {
+ throw new IllegalArgumentException(
+ "Jar not loaded from the Gradle cache. jar: " + location);
+ }
+ final Path startPath = Paths.get(textPath.substring(0, idx + GRADLE_CACHE_PATH.length()));
+ final Path relative = startPath.relativize(location);
+
+ return Optional.of(relative)
+ .map(Path::getParent)
+ .map(Path::getParent)
+ .map(Path::getFileName)
+ .map(Path::toString)
+ .orElseThrow(
+ () ->
+ new IllegalArgumentException(
+ "Could not decode version from path. jar: " + location));
+ }
- try (JarFile jarFile = new JarFile(path.toFile())) {
- final Enumeration entries = jarFile.entries();
+ private static String minJavaVersion(final Class> type, final Path location) {
+ try (JarFile jarFile = new JarFile(location.toFile())) {
+ final Enumeration entries = jarFile.entries();
- while (entries.hasMoreElements()) {
- final JarEntry entry = entries.nextElement();
+ while (entries.hasMoreElements()) {
+ final JarEntry entry = entries.nextElement();
- if (entry.getName().endsWith(".class")) {
- try (InputStream classInputStream = jarFile.getInputStream(entry)) {
- return minJavaVersion(classInputStream);
- }
+ if (entry.getName().endsWith(".class")) {
+ try (InputStream classInputStream = jarFile.getInputStream(entry)) {
+ return minJavaVersion(classInputStream);
}
}
- } catch (IOException e) {
- throw new IllegalArgumentException(
- "Failed to extract the min Java version the jar supports. Path: " + path,
- e);
}
-
- return "Unknown";
+ } catch (IOException e) {
+ throw new IllegalArgumentException(
+ "Failed to extract the min Java version the jar supports. Path: " + location,
+ e);
}
- public static String minJavaVersion(final InputStream classFile) throws IOException {
- final ClassReader classReader = new ClassReader(classFile);
- final VersionClassVisitor versionClassVisitor = new VersionClassVisitor();
- classReader.accept(versionClassVisitor, 0);
-
- final int majorVersion = versionClassVisitor.majorVersion;
- if (majorVersion < 0) {
- throw new IllegalArgumentException("Failed to determine Java version");
- }
+ return "Unknown";
+ }
- final String javaVersion =
- majorVersion < 49
- ? "1." + (majorVersion - 44)
- : String.valueOf(majorVersion - 44);
+ private static String minJavaVersion(final InputStream classFile) throws IOException {
+ final ClassReader classReader = new ClassReader(classFile);
+ final VersionClassVisitor versionClassVisitor = new VersionClassVisitor();
+ classReader.accept(versionClassVisitor, 0);
- return "Java " + javaVersion;
+ final int majorVersion = versionClassVisitor.majorVersion;
+ if (majorVersion < 0) {
+ throw new IllegalArgumentException("Failed to determine Java version");
}
- private static class VersionClassVisitor extends org.objectweb.asm.ClassVisitor {
+ final String javaVersion =
+ majorVersion < 49 ? "1." + (majorVersion - 44) : String.valueOf(majorVersion - 44);
+
+ return "Java " + javaVersion;
+ }
- private int majorVersion = -1;
+ private static class VersionClassVisitor extends org.objectweb.asm.ClassVisitor {
- VersionClassVisitor() {
- super(org.objectweb.asm.Opcodes.ASM9);
- }
+ private int majorVersion = -1;
- @Override
- public void visit(
- final int version,
- final int access,
- final String name,
- final String signature,
- final String superName,
- final String[] interfaces) {
- if (version > majorVersion) {
- majorVersion = version;
- }
+ VersionClassVisitor() {
+ super(org.objectweb.asm.Opcodes.ASM9);
+ }
+
+ @Override
+ public void visit(
+ final int version,
+ final int access,
+ final String name,
+ final String signature,
+ final String superName,
+ final String[] interfaces) {
+ if (version > majorVersion) {
+ majorVersion = version;
}
}
}
diff --git a/src/test/java/org/creekservice/kafka/test/perf/util/ImplJarFileTest.java b/src/test/java/org/creekservice/kafka/test/perf/util/ImplJarFileTest.java
index a3c7219..cda1c2b 100644
--- a/src/test/java/org/creekservice/kafka/test/perf/util/ImplJarFileTest.java
+++ b/src/test/java/org/creekservice/kafka/test/perf/util/ImplJarFileTest.java
@@ -17,22 +17,20 @@
package org.creekservice.kafka.test.perf.util;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.lessThan;
+import static org.hamcrest.Matchers.matchesPattern;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mock.Strictness.LENIENT;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import java.io.File;
import java.net.URL;
-import java.nio.file.Path;
import java.security.CodeSource;
import java.util.function.Function;
import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
@@ -54,89 +52,74 @@ void setUp() {
.thenReturn(Test.class.getProtectionDomain().getCodeSource().getLocation());
}
- @Nested
- class JarBaseTaskTest {
-
- private ExampleTask task;
-
- @BeforeEach
- void setUp() {
- task = new ExampleTask(sourceAccessor);
- }
-
- @Test
- void shouldPassSuppliedTypeToLocator() {
- // When:
- task.getPath(Test.class);
-
- // Then:
- verify(sourceAccessor).apply(Test.class);
- }
-
- @Test
- void shouldThrowIfSourceCodeNotAvailable() {
- // Given:
- when(sourceAccessor.apply(any())).thenReturn(null);
-
- // When:
- final Exception e =
- assertThrows(IllegalArgumentException.class, () -> task.getPath(Test.class));
-
- // Then:
- assertThat(e.getMessage(), is("Type not loaded from a jar file: " + Test.class));
- }
-
- @Test
- void shouldThrowIfNotLoadedFromFile() throws Exception {
- // Given:
- when(codeSource.getLocation()).thenReturn(new URL("ftp:/localhost/something"));
-
- // When:
- final Exception e =
- assertThrows(IllegalArgumentException.class, () -> task.getPath(Test.class));
-
- // Then:
- assertThat(
- e.getMessage(),
- is(
- "Type not loaded from accessible jar file. location:"
- + " ftp:/localhost/something"));
- }
-
- @Test
- void shouldGetPathOfJar() {
- // When:
- final Path path = task.getPath(Test.class);
-
- // Then:
- assertThat(path.toString(), containsString(".gradle" + File.separator + "caches"));
- }
-
- private final class ExampleTask extends ImplJarFile.JarTaskBase {
-
- ExampleTask(final Function, CodeSource> locator) {
- super(locator);
- }
-
- Path getPath(final Class testClass) {
- return pathToJar(testClass);
- }
- }
+ @Test
+ void shouldPassSuppliedTypeToLocator() {
+ // When:
+ new ImplJarFile(Test.class, sourceAccessor);
+
+ // Then:
+ verify(sourceAccessor).apply(Test.class);
+ }
+
+ @Test
+ void shouldThrowIfSourceCodeNotAvailable() {
+ // Given:
+ when(sourceAccessor.apply(any())).thenReturn(null);
+
+ // When:
+ final Exception e =
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new ImplJarFile(Test.class, sourceAccessor));
+
+ // Then:
+ assertThat(e.getMessage(), is("Type not loaded from a jar file: " + Test.class));
+ }
+
+ @Test
+ void shouldThrowIfNotLoadedFromFile() throws Exception {
+ // Given:
+ when(codeSource.getLocation()).thenReturn(new URL("ftp:/localhost/something"));
+
+ // When:
+ final Exception e =
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new ImplJarFile(Test.class, sourceAccessor));
+
+ // Then:
+ assertThat(
+ e.getMessage(),
+ is(
+ "Type not loaded from accessible jar file. location:"
+ + " ftp:/localhost/something"));
+ }
+
+ @Test
+ void shouldReturnJarSize() {
+ // Given:
+ final ImplJarFile jarFile = new ImplJarFile(Test.class);
+
+ // Then:
+ assertThat(jarFile.jarSize(), is(greaterThan(1_000L)));
+ assertThat(jarFile.jarSize(), is(lessThan(1_000_000L)));
}
- @Nested
- class JarSizeTest {
- @Test
- void shouldReturnJarSize() {
- assertThat(ImplJarFile.jarSizeForClass(Test.class), is(greaterThan(1000L)));
- }
+ @Test
+ void shouldReturnJarVersion() {
+ // Given:
+ final ImplJarFile jarFile = new ImplJarFile(Test.class);
+
+ // Then:
+ assertThat(jarFile.jarVersion(), matchesPattern("\\d+\\.\\d+\\.\\d+"));
}
- @Nested
- class JarMinJavaVersionTest {
- @Test
- void shouldReturnJarMinJavaVersion() {
- assertThat(ImplJarFile.jarMinJavaVersion(Test.class), is("Java 9"));
- }
+ @Test
+ void shouldReturnJarMinJavaVersion() {
+ // Given:
+ final ImplJarFile jarFile = new ImplJarFile(Test.class);
+
+ // Then:
+ assertThat(jarFile.minJavaVersion(), is("Java 9"));
}
}
diff --git a/src/test/java/org/creekservice/kafka/test/perf/util/ImplsJsonFormatterTest.java b/src/test/java/org/creekservice/kafka/test/perf/util/ImplsJsonFormatterTest.java
index c29e0d7..24ea085 100644
--- a/src/test/java/org/creekservice/kafka/test/perf/util/ImplsJsonFormatterTest.java
+++ b/src/test/java/org/creekservice/kafka/test/perf/util/ImplsJsonFormatterTest.java
@@ -132,6 +132,15 @@ void shouldIncludeJarSize() {
assertThat(json, matchesPattern(".*\"jarSize\":\\d+[,}].*"));
}
+ @Test
+ void shouldIncludeJarVersion() {
+ // When:
+ final String json = ImplsJsonFormatter.implDetailsAsJson(List.of(implA));
+
+ // Then:
+ assertThat(json, matchesPattern(".*\"version\":\"\\d+\\.\\d+\\.\\d+\".*"));
+ }
+
@Test
void shouldIncludeMinJavaVersion() {
// When: