diff --git a/crd-generator/collector/src/main/java/io/fabric8/crd/generator/collector/CustomResourceClassLoader.java b/crd-generator/collector/src/main/java/io/fabric8/crd/generator/collector/CustomResourceClassLoader.java index 10e4bb8d4d3..9a82f1e8034 100644 --- a/crd-generator/collector/src/main/java/io/fabric8/crd/generator/collector/CustomResourceClassLoader.java +++ b/crd-generator/collector/src/main/java/io/fabric8/crd/generator/collector/CustomResourceClassLoader.java @@ -84,7 +84,7 @@ private ClassLoader getClassLoader() { try { return new File(s).toURI().toURL(); } catch (MalformedURLException e) { - throw new RuntimeException(e); + throw new CustomResourceCollectorException("Could not transform file to URL: " + s, e); } }).toArray(URL[]::new); diff --git a/crd-generator/collector/src/main/java/io/fabric8/crd/generator/collector/JandexIndexer.java b/crd-generator/collector/src/main/java/io/fabric8/crd/generator/collector/JandexIndexer.java index 891bea2b108..18d88bbf963 100644 --- a/crd-generator/collector/src/main/java/io/fabric8/crd/generator/collector/JandexIndexer.java +++ b/crd-generator/collector/src/main/java/io/fabric8/crd/generator/collector/JandexIndexer.java @@ -79,14 +79,14 @@ public JandexIndexer withMaxJarEntries(int maxJarEntries) { public JandexIndexer withMaxClassFileSize(int maxClassFileSize) { if (maxClassFileSize < 10) - throw new IllegalArgumentException("maxClassFileSize must be greater than 10 B (1 KB)"); + throw new IllegalArgumentException("maxClassFileSize must be greater than 10"); this.maxClassFileSize = maxClassFileSize; return this; } public JandexIndexer withMaxBytesReadFromJar(long maxBytesReadFromJar) { if (maxBytesReadFromJar < 10) - throw new IllegalArgumentException("maxBytesReadFromJar must be greater than 10 B (1 KB)"); + throw new IllegalArgumentException("maxBytesReadFromJar must be greater than 10"); this.maxBytesReadFromJar = maxBytesReadFromJar; return this; } @@ -204,7 +204,7 @@ public long getBytesRead() { @Override public int read() throws IOException { if (bytesRead >= maxBytes) { - throw new IOException("Read limit of " + maxBytes + " bytes reached"); + throw new IOException("Read limit of " + maxBytes + " bytes exceeded"); } int result = inputStream.read(); if (result != -1) { @@ -213,6 +213,33 @@ public int read() throws IOException { return result; } + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (bytesRead >= maxBytes) { + throw new IOException("Read limit of " + maxBytes + " bytes exceeded"); + } + long bytesRemaining = maxBytes - bytesRead; + if (len > bytesRemaining) { + len = (int) bytesRemaining; // Reduce len to the maximum allowable bytes + } + int count = inputStream.read(b, off, len); + if (count > 0) { + bytesRead += count; + } + return count; + } + + @Override + public int available() throws IOException { + long available = inputStream.available(); + long bytesRemaining = maxBytes - bytesRead; + if (available > bytesRemaining) { + return (int) bytesRemaining; + } else { + return (int) available; + } + } + @Override public void close() throws IOException { inputStream.close(); diff --git a/crd-generator/collector/src/test/java/io/fabric8/crd/generator/collector/CustomResourceClassLoaderTest.java b/crd-generator/collector/src/test/java/io/fabric8/crd/generator/collector/CustomResourceClassLoaderTest.java index 651d276aca1..8277c207047 100644 --- a/crd-generator/collector/src/test/java/io/fabric8/crd/generator/collector/CustomResourceClassLoaderTest.java +++ b/crd-generator/collector/src/test/java/io/fabric8/crd/generator/collector/CustomResourceClassLoaderTest.java @@ -26,7 +26,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; -public class CustomResourceClassLoaderTest { +class CustomResourceClassLoaderTest { @Test void checkNullsafe() { @@ -35,7 +35,7 @@ void checkNullsafe() { loader.withClasspathElement((String) null); loader.withClasspathElements(null); loader.withParentClassLoader(null); - loader.loadCustomResourceClass(MyCustomResource.class.getName()); + assertNotNull(loader.loadCustomResourceClass(MyCustomResource.class.getName())); } @Test @@ -49,8 +49,9 @@ void loadNotExisting_thenError() { @Test void loadNotCustomResource_thenError() { CustomResourceClassLoader loader = new CustomResourceClassLoader(); - CustomResourceCollectorException e = assertThrows(CustomResourceCollectorException.class, - () -> loader.loadCustomResourceClass(String.class.getName())); + String notACustomResourceClassName = String.class.getName(); + assertThrows(CustomResourceCollectorException.class, + () -> loader.loadCustomResourceClass(notACustomResourceClassName)); } @Test diff --git a/crd-generator/maven-plugin/pom.xml b/crd-generator/maven-plugin/pom.xml index 151b0ba049e..3aab70b4919 100644 --- a/crd-generator/maven-plugin/pom.xml +++ b/crd-generator/maven-plugin/pom.xml @@ -51,6 +51,24 @@ crd-generator-collector ${project.version} + + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.mockito + mockito-core + ${mockito.version} + test + diff --git a/crd-generator/maven-plugin/src/main/java/io/fabric8/crd/generator/maven/plugin/ClasspathType.java b/crd-generator/maven-plugin/src/main/java/io/fabric8/crd/generator/maven/plugin/ClasspathType.java index b6fd07e442b..8f39849c70e 100644 --- a/crd-generator/maven-plugin/src/main/java/io/fabric8/crd/generator/maven/plugin/ClasspathType.java +++ b/crd-generator/maven-plugin/src/main/java/io/fabric8/crd/generator/maven/plugin/ClasspathType.java @@ -18,9 +18,8 @@ import org.apache.maven.artifact.DependencyResolutionRequiredException; import org.apache.maven.project.MavenProject; -import java.util.Collection; -import java.util.Collections; import java.util.HashSet; +import java.util.Set; public enum ClasspathType { /** @@ -44,34 +43,30 @@ public enum ClasspathType { */ WITH_ALL_DEPENDENCIES_AND_TESTS; - public Collection getClasspathElements(MavenProject project) { - Collection classpathElements; + public Set getClasspathElements(MavenProject project) { + Set classpathElements = new HashSet<>(); try { switch (this) { case PROJECT_ONLY: - classpathElements = Collections.singleton(project.getBuild().getOutputDirectory()); + classpathElements.add(project.getBuild().getOutputDirectory()); break; case WITH_COMPILE_DEPENDENCIES: - classpathElements = project.getCompileClasspathElements(); + classpathElements.addAll(project.getCompileClasspathElements()); break; case WITH_RUNTIME_DEPENDENCIES: - classpathElements = project.getRuntimeClasspathElements(); + classpathElements.addAll(project.getRuntimeClasspathElements()); break; case WITH_ALL_DEPENDENCIES: // to remove duplicates - classpathElements = new HashSet<>(); classpathElements.addAll(project.getRuntimeClasspathElements()); classpathElements.addAll(project.getCompileClasspathElements()); break; case WITH_ALL_DEPENDENCIES_AND_TESTS: // to remove duplicates - classpathElements = new HashSet<>(); classpathElements.addAll(project.getRuntimeClasspathElements()); classpathElements.addAll(project.getCompileClasspathElements()); classpathElements.addAll(project.getTestClasspathElements()); break; - default: - throw new IllegalArgumentException("ClasspathType " + this + " not supported"); } } catch (DependencyResolutionRequiredException e) { throw new IllegalStateException("Failed to resolve classpathType elements", e); diff --git a/crd-generator/maven-plugin/src/main/java/io/fabric8/crd/generator/maven/plugin/CrdGeneratorMojo.java b/crd-generator/maven-plugin/src/main/java/io/fabric8/crd/generator/maven/plugin/CrdGeneratorMojo.java index a65122ac6a3..b541afed10e 100644 --- a/crd-generator/maven-plugin/src/main/java/io/fabric8/crd/generator/maven/plugin/CrdGeneratorMojo.java +++ b/crd-generator/maven-plugin/src/main/java/io/fabric8/crd/generator/maven/plugin/CrdGeneratorMojo.java @@ -41,13 +41,13 @@ public class CrdGeneratorMojo extends AbstractMojo { @Parameter(defaultValue = "${project}", required = true, readonly = true) - private MavenProject mavenProject; + MavenProject mavenProject; /** * The input directory to be used to scan for Custom Resource classes */ @Parameter(property = "fabric8.crd-generator.classesToIndex", defaultValue = "${project.build.outputDirectory}", readonly = true) - private File classesToIndex; + File classesToIndex; /** * Custom Resource classes, which should be considered to generate the CRDs. @@ -60,7 +60,7 @@ public class CrdGeneratorMojo extends AbstractMojo { * Dependencies which should be scanned for Custom Resources. */ @Parameter(property = "fabric8.crd-generator.dependenciesToIndex") - private List dependenciesToIndex = new LinkedList<>(); + List dependenciesToIndex = new LinkedList<>(); /** * Inclusions, used to filter Custom Resource classes after scanning. @@ -88,13 +88,13 @@ public class CrdGeneratorMojo extends AbstractMojo { * */ @Parameter(property = "fabric8.crd-generator.classpath", defaultValue = "WITH_RUNTIME_DEPENDENCIES") - private ClasspathType classpath; + ClasspathType classpath; /** * The output directory where the CRDs are emitted. */ @Parameter(property = "fabric8.crd-generator.outputDirectory", defaultValue = "${project.build.outputDirectory}/META-INF/fabric8/") - private File outputDirectory; + File outputDirectory; /** * If true, a Jandex index will be created even if the directory or JAR file contains an existing index. @@ -114,12 +114,6 @@ public class CrdGeneratorMojo extends AbstractMojo { @Parameter(property = "fabric8.crd-generator.implicitPreserveUnknownFields", defaultValue = "false") private boolean implicitPreserveUnknownFields; - /** - * Print verbose output (debug output without needing to enable -X for the whole build). - */ - @Parameter(property = "fabric8.crd-generator.verbose", defaultValue = "false") - private boolean verbose; - /** * Skip execution if set. */ @@ -174,10 +168,6 @@ public void execute() throws MojoExecutionException { }); } - private boolean isVerbose() { - return verbose || getLog().isDebugEnabled(); - } - /** * Returns a list of archive files derived from the given dependencies. * diff --git a/crd-generator/maven-plugin/src/test/java/io/fabric8/crd/generator/maven/plugin/ClasspathTypeTest.java b/crd-generator/maven-plugin/src/test/java/io/fabric8/crd/generator/maven/plugin/ClasspathTypeTest.java new file mode 100644 index 00000000000..cb8e709ddfb --- /dev/null +++ b/crd-generator/maven-plugin/src/test/java/io/fabric8/crd/generator/maven/plugin/ClasspathTypeTest.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.fabric8.crd.generator.maven.plugin; + +import org.apache.maven.artifact.DependencyResolutionRequiredException; +import org.apache.maven.model.Build; +import org.apache.maven.project.MavenProject; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.util.Collections; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.when; + +public class ClasspathTypeTest { + + private static final String RUNTIME_PATH = "/runtime"; + private static final String COMPILE_PATH = "/compile"; + private static final String TEST_PATH = "/test"; + private static final String PROJECT_PATH = "/project"; + + private MavenProject project; + + @BeforeEach + public void setUp() throws DependencyResolutionRequiredException { + this.project = Mockito.mock(MavenProject.class); + when(this.project.getRuntimeClasspathElements()) + .thenReturn(Collections.singletonList(RUNTIME_PATH)); + when(this.project.getCompileClasspathElements()) + .thenReturn(Collections.singletonList(COMPILE_PATH)); + when(this.project.getTestClasspathElements()) + .thenReturn(Collections.singletonList(TEST_PATH)); + + Build build = new Build(); + build.setOutputDirectory(PROJECT_PATH); + when(this.project.getBuild()).thenReturn(build); + } + + @Test + public void testGetUrlsCompile() { + Set urls = ClasspathType.WITH_COMPILE_DEPENDENCIES.getClasspathElements(this.project); + assertEquals(1, urls.size()); + assertTrue(urls.contains(COMPILE_PATH)); + } + + @Test + public void testGetUrlsRuntime() { + Set urls = ClasspathType.WITH_RUNTIME_DEPENDENCIES.getClasspathElements(this.project); + assertEquals(1, urls.size()); + assertTrue(urls.contains(RUNTIME_PATH)); + } + + @Test + public void testGetUrlsAll() { + Set urls = ClasspathType.WITH_ALL_DEPENDENCIES.getClasspathElements(this.project); + assertEquals(2, urls.size()); + assertTrue(urls.contains(RUNTIME_PATH)); + assertTrue(urls.contains(COMPILE_PATH)); + } + + @Test + public void testGetUrlsAllAndTests() { + Set urls = ClasspathType.WITH_ALL_DEPENDENCIES_AND_TESTS.getClasspathElements(this.project); + assertEquals(3, urls.size()); + assertTrue(urls.contains(RUNTIME_PATH)); + assertTrue(urls.contains(COMPILE_PATH)); + assertTrue(urls.contains(TEST_PATH)); + } + + @Test + public void testGetUrlsProject() { + Set urls = ClasspathType.PROJECT_ONLY.getClasspathElements(this.project); + assertEquals(1, urls.size()); + assertTrue(urls.contains(PROJECT_PATH)); + } + +} diff --git a/crd-generator/maven-plugin/src/test/java/io/fabric8/crd/generator/maven/plugin/CrdGeneratorMojoTest.java b/crd-generator/maven-plugin/src/test/java/io/fabric8/crd/generator/maven/plugin/CrdGeneratorMojoTest.java new file mode 100644 index 00000000000..3f7b95add96 --- /dev/null +++ b/crd-generator/maven-plugin/src/test/java/io/fabric8/crd/generator/maven/plugin/CrdGeneratorMojoTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.fabric8.crd.generator.maven.plugin; + +import io.fabric8.crd.generator.collector.CustomResourceCollector; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.project.MavenProject; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.ArgumentCaptor; +import org.mockito.MockedConstruction; +import org.mockito.Mockito; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.when; + +public class CrdGeneratorMojoTest { + + @Test + void checkFindingJarArchiveForDependency(@TempDir File tempDir) throws MojoExecutionException, IOException { + CrdGeneratorMojo crdGeneratorMojo = new CrdGeneratorMojo(); + crdGeneratorMojo.mavenProject = Mockito.mock(MavenProject.class); + crdGeneratorMojo.classpath = Mockito.mock(ClasspathType.class); + + crdGeneratorMojo.classesToIndex = tempDir; + crdGeneratorMojo.outputDirectory = tempDir; + + File dummyJar = new File(tempDir, "test.jar"); + Files.write(dummyJar.toPath(), "dummy".getBytes()); + + Artifact artifact1 = Mockito.mock(Artifact.class); + when(artifact1.getGroupId()).thenReturn("othergroup"); + when(artifact1.getArtifactId()).thenReturn("otherartifact"); + when(artifact1.getFile()).thenReturn(new File("/not-existing")); + + Artifact artifact2 = Mockito.mock(Artifact.class); + when(artifact2.getGroupId()).thenReturn("mygroup"); + when(artifact2.getArtifactId()).thenReturn("otherartifact"); + when(artifact2.getFile()).thenReturn(new File("/not-existing")); + + Artifact artifact3 = Mockito.mock(Artifact.class); + when(artifact3.getGroupId()).thenReturn("mygroup"); + when(artifact3.getArtifactId()).thenReturn("myartifact"); + when(artifact3.getFile()).thenReturn(dummyJar); + when(crdGeneratorMojo.mavenProject.getArtifacts()) + .thenReturn(Stream.of(artifact1, artifact2, artifact3).collect(Collectors.toSet())); + + Dependency dependency = new Dependency(); + dependency.setGroupId("mygroup"); + dependency.setArtifactId("myartifact"); + crdGeneratorMojo.dependenciesToIndex = Collections.singletonList(dependency); + + @SuppressWarnings("unchecked") + ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class); + + try (MockedConstruction mockedConstruction = Mockito + .mockConstruction(CustomResourceCollector.class, (mock, context) -> { + given(mock.withParentClassLoader(any())).willReturn(mock); + given(mock.withClasspathElements(any())).willReturn(mock); + given(mock.withFilesToIndex(captor.capture())).willReturn(mock); + given(mock.withForceIndex(anyBoolean())).willReturn(mock); + given(mock.withCustomResourceClasses(any())).willReturn(mock); + given(mock.withIncludePackages(any())).willReturn(mock); + given(mock.withIncludeGroups(any())).willReturn(mock); + given(mock.withIncludeVersions(any())).willReturn(mock); + given(mock.withExcludePackages(any())).willReturn(mock); + given(mock.withExcludeGroups(any())).willReturn(mock); + given(mock.withExcludeVersions(any())).willReturn(mock); + })) { + crdGeneratorMojo.execute(); + assertTrue(captor.getValue().contains(dummyJar)); + } + } +}