| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 org.apache.sling.maven.slingstart; |
| |
| import static org.junit.Assert.assertArrayEquals; |
| import static org.junit.Assert.assertEquals; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.StringReader; |
| import java.lang.reflect.Field; |
| import java.net.URL; |
| import java.nio.file.Files; |
| import java.nio.file.Path; |
| import java.util.HashSet; |
| import java.util.Set; |
| import java.util.jar.Attributes; |
| import java.util.jar.JarEntry; |
| import java.util.jar.JarFile; |
| import java.util.jar.JarInputStream; |
| import java.util.jar.Manifest; |
| import java.util.zip.ZipEntry; |
| |
| import org.apache.commons.io.FileUtils; |
| import org.apache.commons.io.IOUtils; |
| import org.apache.maven.artifact.DefaultArtifact; |
| import org.apache.maven.artifact.handler.ArtifactHandler; |
| import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager; |
| import org.apache.maven.artifact.resolver.ArtifactResolver; |
| import org.apache.maven.execution.MavenSession; |
| import org.apache.maven.model.Build; |
| import org.apache.maven.project.MavenProject; |
| import org.apache.sling.provisioning.model.Model; |
| import org.apache.sling.provisioning.model.io.ModelReader; |
| import org.codehaus.plexus.archiver.UnArchiver; |
| import org.codehaus.plexus.archiver.manager.ArchiverManager; |
| import org.junit.Test; |
| import org.mockito.Mockito; |
| |
| public class PreparePackageMojoTest { |
| @Test |
| public void testBSNRenaming() throws Exception { |
| // Provide the system with some artifacts that are known to be in the local .m2 repo |
| // These are explicitly included in the test section of the pom.xml |
| PreparePackageMojo ppm = getMojoUnderTest( |
| "org.apache.sling/org.apache.sling.commons.classloader/1.3.2", |
| "org.apache.sling/org.apache.sling.commons.classloader/1.3.2/app", |
| "org.apache.sling/org.apache.sling.commons.johnzon/1.0.0"); |
| try { |
| String modelTxt = "[feature name=:launchpad]\n" + |
| "[artifacts]\n" + |
| " org.apache.sling/org.apache.sling.commons.classloader/1.3.2\n" + |
| "" + |
| "[feature name=rename_test]\n" + |
| " org.apache.sling/org.apache.sling.commons.johnzon/1.0.0 [bundle:rename-bsn=r-foo.bar.renamed.sling.commons.johnzon]\n"; |
| |
| Model model = ModelReader.read(new StringReader(modelTxt), null); |
| ppm.execute(model); |
| |
| File orgJar = getMavenArtifactFile(getMavenRepoRoot(), "org.apache.sling", "org.apache.sling.commons.johnzon", "1.0.0"); |
| File generatedJar = new File(ppm.getTmpDir(), "r-foo.bar.renamed.sling.commons.johnzon-1.0.0.jar"); |
| |
| compareJarContents(orgJar, generatedJar); |
| |
| try (JarFile jfOrg = new JarFile(orgJar); |
| JarFile jfNew = new JarFile(generatedJar)) { |
| Manifest mfOrg = jfOrg.getManifest(); |
| Manifest mfNew = jfNew.getManifest(); |
| |
| Attributes orgAttrs = mfOrg.getMainAttributes(); |
| Attributes newAttrs = mfNew.getMainAttributes(); |
| for (Object key : orgAttrs.keySet()) { |
| String orgVal = orgAttrs.getValue(key.toString()); |
| String newVal = newAttrs.getValue(key.toString()); |
| |
| if ("Bundle-SymbolicName".equals(key.toString())) { |
| assertEquals("Should have recorded the original Bundle-SymbolicName", |
| orgVal, newAttrs.getValue("X-Original-Bundle-SymbolicName")); |
| |
| assertEquals("r-foo.bar.renamed.sling.commons.johnzon", newVal); |
| } else { |
| assertEquals("Different keys: " + key, orgVal, newVal); |
| } |
| } |
| } |
| } finally { |
| FileUtils.deleteDirectory(new File(ppm.project.getBuild().getDirectory())); |
| } |
| } |
| |
| private static void compareJarContents(File orgJar, File actualJar) throws IOException { |
| try (JarInputStream jis1 = new JarInputStream(new FileInputStream(orgJar)); |
| JarInputStream jis2 = new JarInputStream(new FileInputStream(actualJar))) { |
| JarEntry je1 = null; |
| while ((je1 = jis1.getNextJarEntry()) != null) { |
| if (je1.isDirectory()) |
| continue; |
| |
| JarEntry je2 = null; |
| while((je2 = jis2.getNextJarEntry()) != null) { |
| if (!je2.isDirectory()) |
| break; |
| } |
| |
| assertEquals(je1.getName(), je2.getName()); |
| assertEquals(je1.getSize(), je2.getSize()); |
| |
| try { |
| byte[] buf1 = IOUtils.toByteArray(jis1); |
| byte[] buf2 = IOUtils.toByteArray(jis2); |
| |
| assertArrayEquals("Contents not equal: " + je1.getName(), buf1, buf2); |
| } finally { |
| jis1.closeEntry(); |
| jis2.closeEntry(); |
| } |
| } |
| } |
| } |
| |
| @Test |
| public void testSubsystemBaseGeneration() throws Exception { |
| // Provide the system with some artifacts that are known to be in the local .m2 repo |
| // These are explicitly included in the test section of the pom.xml |
| PreparePackageMojo ppm = getMojoUnderTest( |
| "org.apache.sling/org.apache.sling.commons.classloader/1.3.2", |
| "org.apache.sling/org.apache.sling.commons.classloader/1.3.2/app", |
| "org.apache.sling/org.apache.sling.commons.contentdetection/1.0.2", |
| "org.apache.sling/org.apache.sling.commons.johnzon/1.0.0", |
| "org.apache.sling/org.apache.sling.commons.mime/2.1.8", |
| "org.apache.sling/org.apache.sling.commons.threads/3.2.0"); |
| |
| try { |
| // The launchpad feature is a prerequisite for the model |
| String modelTxt = |
| "[feature name=:launchpad]\n" + |
| "[artifacts]\n" + |
| " org.apache.sling/org.apache.sling.commons.classloader/1.3.2\n" + |
| "" + |
| "[feature name=test1 type=osgi.subsystem.composite]\n" + |
| "" + |
| "[:subsystem-manifest startLevel=123]\n" + |
| " Subsystem-Description: Extra subsystem headers can go here including very long ones that would span multiple lines in a manifest\n" + |
| " Subsystem-Copyright: (c) 2015 yeah!\n" + |
| "" + |
| "[artifacts startLevel=10]\n" + |
| " org.apache.sling/org.apache.sling.commons.johnzon/1.0.0\n" + |
| " org.apache.sling/org.apache.sling.commons.mime/2.1.8\n" + |
| "" + |
| "[artifacts startLevel=20 runModes=foo,bar,:blah]\n" + |
| " org.apache.sling/org.apache.sling.commons.threads/3.2.0\n" + |
| "" + |
| "[artifacts startLevel=100 runModes=bar]\n" + |
| " org.apache.sling/org.apache.sling.commons.contentdetection/1.0.2\n"; |
| Model model = ModelReader.read(new StringReader(modelTxt), null); |
| ppm.execute(model); |
| |
| File generatedFile = new File(ppm.getTmpDir(), "test1.subsystem-base"); |
| try (JarFile jf = new JarFile(generatedFile)) { |
| // Test META-INF/MANIFEST.MF |
| Manifest mf = jf.getManifest(); |
| Attributes attrs = mf.getMainAttributes(); |
| String expected = "Potential_Bundles/10/org.apache.sling.commons.johnzon-1.0.0.jar|" |
| + "Potential_Bundles/10/org.apache.sling.commons.mime-2.1.8.jar"; |
| assertEquals(expected, attrs.getValue("_all_")); |
| assertEquals("Potential_Bundles/20/org.apache.sling.commons.threads-3.2.0.jar", attrs.getValue("foo")); |
| assertEquals("Potential_Bundles/20/org.apache.sling.commons.threads-3.2.0.jar|" |
| + "Potential_Bundles/100/org.apache.sling.commons.contentdetection-1.0.2.jar", attrs.getValue("bar")); |
| |
| // Test SUBSYSTEM-MANIFEST-BASE.MF |
| ZipEntry smbZE = jf.getEntry("SUBSYSTEM-MANIFEST-BASE.MF"); |
| try (InputStream smbIS = jf.getInputStream(smbZE)) { |
| Manifest smbMF = new Manifest(smbIS); |
| Attributes smbAttrs = smbMF.getMainAttributes(); |
| assertEquals("test1", smbAttrs.getValue("Subsystem-SymbolicName")); |
| assertEquals("osgi.subsystem.composite", smbAttrs.getValue("Subsystem-Type")); |
| assertEquals("(c) 2015 yeah!", smbAttrs.getValue("Subsystem-Copyright")); |
| assertEquals("Extra subsystem headers can go here including very long ones " |
| + "that would span multiple lines in a manifest", |
| smbAttrs.getValue("Subsystem-Description")); |
| } |
| |
| // Test embedded bundles |
| File mrr = getMavenRepoRoot(); |
| |
| File sjj = getMavenArtifactFile(mrr, "org.apache.sling", "org.apache.sling.commons.johnzon", "1.0.0"); |
| ZipEntry sjZE = jf.getEntry("Potential_Bundles/10/org.apache.sling.commons.johnzon-1.0.0.jar"); |
| try (InputStream is = jf.getInputStream(sjZE)) { |
| assertArtifactsEqual(sjj, is); |
| } |
| |
| File smj = getMavenArtifactFile(mrr, "org.apache.sling", "org.apache.sling.commons.mime", "2.1.8"); |
| ZipEntry smjZE = jf.getEntry("Potential_Bundles/10/org.apache.sling.commons.mime-2.1.8.jar"); |
| try (InputStream is = jf.getInputStream(smjZE)) { |
| assertArtifactsEqual(smj, is); |
| } |
| |
| File stj = getMavenArtifactFile(mrr, "org.apache.sling", "org.apache.sling.commons.threads", "3.2.0"); |
| ZipEntry stjZE = jf.getEntry("Potential_Bundles/20/org.apache.sling.commons.threads-3.2.0.jar"); |
| try (InputStream is = jf.getInputStream(stjZE)) { |
| assertArtifactsEqual(stj, is); |
| } |
| |
| File ctj = getMavenArtifactFile(mrr, "org.apache.sling", "org.apache.sling.commons.contentdetection", "1.0.2"); |
| ZipEntry ctjZE = jf.getEntry("Potential_Bundles/100/org.apache.sling.commons.contentdetection-1.0.2.jar"); |
| try (InputStream is = jf.getInputStream(ctjZE)) { |
| assertArtifactsEqual(ctj, is); |
| } |
| } |
| } finally { |
| FileUtils.deleteDirectory(new File(ppm.project.getBuild().getDirectory())); |
| } |
| } |
| |
| private void assertArtifactsEqual(File f, InputStream is) throws IOException { |
| byte[] bytes1 = Files.readAllBytes(f.toPath()); |
| byte[] bytes2 = IOUtils.toByteArray(is); |
| assertArrayEquals("Bytes not equal on file " + f.getName(), bytes1, bytes2); |
| } |
| |
| private PreparePackageMojo getMojoUnderTest(String ... knownArtifacts) throws Exception { |
| File mrr = getMavenRepoRoot(); |
| |
| ArtifactHandler ah = Mockito.mock(ArtifactHandler.class); |
| ArtifactHandlerManager ahm = Mockito.mock(ArtifactHandlerManager.class); |
| Mockito.when(ahm.getArtifactHandler(Mockito.anyString())).thenReturn(ah); |
| |
| Set<org.apache.maven.artifact.Artifact> artifacts = new HashSet<>(); |
| for (String s : knownArtifacts) { |
| String[] parts = s.split("[/]"); |
| switch (parts.length) { |
| case 3: |
| artifacts.add(getMavenArtifact(mrr, ah, parts[0], parts[1], parts[2])); |
| break; |
| case 4: |
| artifacts.add(getMavenArtifact(mrr, ah, parts[0], parts[1], parts[2], parts[3])); |
| break; |
| default: throw new IllegalStateException(s); |
| } |
| } |
| |
| MavenProject mavenPrj = new MavenProject(); |
| Build build = new Build(); |
| Path tempDir = Files.createTempDirectory(getClass().getSimpleName()); |
| build.setOutputDirectory(tempDir.toString()); |
| build.setDirectory(tempDir.toString()); |
| mavenPrj.setBuild(build); |
| mavenPrj.setDependencyArtifacts(artifacts); |
| |
| PreparePackageMojo ppm = new PreparePackageMojo(); |
| ppm.mavenSession = Mockito.mock(MavenSession.class); |
| ppm.project = mavenPrj; |
| ArchiverManager am = Mockito.mock(ArchiverManager.class); |
| UnArchiver ua = Mockito.mock(UnArchiver.class); |
| Mockito.when(am.getUnArchiver(Mockito.isA(File.class))).thenReturn(ua); |
| setPrivateField(ppm, "archiverManager", am); |
| setPrivateField(ppm, "artifactHandlerManager", ahm); |
| setPrivateField(ppm, "resolver", Mockito.mock(ArtifactResolver.class)); |
| return ppm; |
| } |
| |
| private org.apache.maven.artifact.Artifact getMavenArtifact(File repoRoot, ArtifactHandler ah, String gid, String aid, String ver) { |
| return getMavenArtifact(repoRoot, ah, gid, aid, ver, null); |
| } |
| |
| private org.apache.maven.artifact.Artifact getMavenArtifact(File repoRoot, ArtifactHandler ah, String gid, String aid, String ver, String classifier) { |
| DefaultArtifact art = new DefaultArtifact(gid, aid, ver, "compile", "jar", classifier, ah); |
| art.setFile(getMavenArtifactFile(repoRoot, gid, aid, ver)); |
| return art; |
| } |
| |
| private File getMavenArtifactFile(File repoRoot, String gid, String aid, String ver) { |
| return new File(repoRoot, gid.replace('.', File.separatorChar) + File.separatorChar + aid + File.separatorChar |
| + ver + File.separatorChar + aid + '-' + ver + ".jar"); |
| } |
| |
| private File getMavenRepoRoot() throws IOException { |
| URL res = getClass().getClassLoader().getResource( |
| Test.class.getName().replace('.', '/') + ".class"); |
| |
| String u = res.toExternalForm(); |
| if (u.startsWith("jar:")) |
| u = u.substring(4); |
| |
| int idx = u.indexOf("junit"); |
| if (idx < 0) |
| throw new IllegalStateException("Cannot infer maven repo root: " + res); |
| |
| return new File(new URL(u.substring(0, idx)).getFile()); |
| } |
| |
| private void setPrivateField(Object obj, String name, Object val) throws Exception { |
| Field f = obj.getClass().getDeclaredField(name); |
| f.setAccessible(true); |
| f.set(obj, val); |
| } |
| } |