/* * 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.installer.factories.subsystems.base.impl; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.util.Arrays; import java.util.Dictionary; import java.util.HashSet; import java.util.Set; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.jar.Manifest; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import org.apache.sling.installer.api.tasks.RegisteredResource; import org.apache.sling.installer.api.tasks.TransformationResult; import org.apache.sling.installer.factories.subsystems.base.impl.SubsystemBaseTransformer.DeleteOnCloseFileInputStream; import org.apache.sling.settings.SlingSettingsService; import org.junit.Test; import org.mockito.Mockito; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; public class SubsystemBaseTransformerTest { @Test public void testTransformNoRunMode() throws Exception { SlingSettingsService slingSettings = Mockito.mock(SlingSettingsService.class); SubsystemBaseTransformer sbt = new SubsystemBaseTransformer(slingSettings); URL testArchive = getClass().getResource("/test1.subsystem-base"); RegisteredResource resource = new TestRegisteredResource(testArchive); TransformationResult[] tra = sbt.transform(resource); assertEquals(1, tra.length); TransformationResult tr = tra[0]; assertEquals("esa", tr.getResourceType()); assertEquals("test1", tr.getId()); DeleteOnCloseFileInputStream dcis = (DeleteOnCloseFileInputStream) tr.getInputStream(); assertTrue("The file backing the stream should exist", dcis.file.exists()); Set<String> foundBundles = new HashSet<>(); try (ZipInputStream zis = new ZipInputStream(dcis); JarFile jf = new JarFile(testArchive.getFile())) { ZipEntry ze = null; while((ze = zis.getNextEntry()) != null) { foundBundles.add(ze.getName()); switch(ze.getName()) { case "OSGI-INF/SUBSYSTEM.MF": Manifest mf = new Manifest(zis); Attributes attrs = mf.getMainAttributes(); assertEquals("test1", attrs.getValue("Subsystem-SymbolicName")); assertEquals("osgi.subsystem.composite", attrs.getValue("Subsystem-Type")); assertEquals("(c) 2015 yeah!", attrs.getValue("Subsystem-Copyright")); assertEquals("Extra subsystem headers can go here including very long ones " + "that would span multiple lines in a manifest", attrs.getValue("Subsystem-Description")); assertEquals("org.apache.sling.commons.osgi;version=2.3.0;type=osgi.bundle;start-order:=0," + "org.apache.sling.commons.json;version=2.0.12;type=osgi.bundle;start-order:=10," + "org.apache.sling.commons.mime;version=2.1.8;type=osgi.bundle;start-order:=10", attrs.getValue("Subsystem-Content")); break; case "org.apache.sling.commons.osgi-2.3.0.jar": ZipEntry oze = jf.getEntry("Potential_Bundles/0/org.apache.sling.commons.osgi-2.3.0.jar"); assertArtifactsEqual(oze.getName(), jf.getInputStream(oze), zis); break; case "org.apache.sling.commons.json-2.0.12.jar": ZipEntry jze = jf.getEntry("Potential_Bundles/10/org.apache.sling.commons.json-2.0.12.jar"); assertArtifactsEqual(jze.getName(), jf.getInputStream(jze), zis); break; case "org.apache.sling.commons.mime-2.1.8.jar": ZipEntry mze = jf.getEntry("Potential_Bundles/10/org.apache.sling.commons.mime-2.1.8.jar"); assertArtifactsEqual(mze.getName(), jf.getInputStream(mze), zis); break; } } } assertEquals(new HashSet<>(Arrays.asList("OSGI-INF/SUBSYSTEM.MF", "org.apache.sling.commons.osgi-2.3.0.jar", "org.apache.sling.commons.json-2.0.12.jar", "org.apache.sling.commons.mime-2.1.8.jar")), foundBundles); assertFalse("After closing the stream the temp file should have been deleted.", dcis.file.exists()); } @Test public void testOtherRunMode() throws Exception { SlingSettingsService slingSettings = Mockito.mock(SlingSettingsService.class); Mockito.when(slingSettings.getRunModes()).thenReturn(new HashSet<String>(Arrays.asList("bar", "tar"))); SubsystemBaseTransformer sbt = new SubsystemBaseTransformer(slingSettings); URL testArchive = getClass().getResource("/test1.subsystem-base"); RegisteredResource resource = new TestRegisteredResource(testArchive); TransformationResult[] tra = sbt.transform(resource); assertEquals(1, tra.length); TransformationResult tr = tra[0]; assertEquals("esa", tr.getResourceType()); assertEquals("test1", tr.getId()); DeleteOnCloseFileInputStream dcis = (DeleteOnCloseFileInputStream) tr.getInputStream(); assertTrue("The file backing the stream should exist", dcis.file.exists()); Set<String> foundBundles = new HashSet<>(); try (ZipInputStream zis = new ZipInputStream(dcis); JarFile jf = new JarFile(testArchive.getFile())) { ZipEntry ze = null; while((ze = zis.getNextEntry()) != null) { foundBundles.add(ze.getName()); switch(ze.getName()) { case "OSGI-INF/SUBSYSTEM.MF": Manifest mf = new Manifest(zis); Attributes attrs = mf.getMainAttributes(); assertEquals("test1", attrs.getValue("Subsystem-SymbolicName")); assertEquals("osgi.subsystem.composite", attrs.getValue("Subsystem-Type")); assertEquals("(c) 2015 yeah!", attrs.getValue("Subsystem-Copyright")); assertEquals("Extra subsystem headers can go here including very long ones " + "that would span multiple lines in a manifest", attrs.getValue("Subsystem-Description")); assertEquals("org.apache.sling.commons.osgi;version=2.3.0;type=osgi.bundle;start-order:=0," + "org.apache.sling.commons.json;version=2.0.12;type=osgi.bundle;start-order:=10," + "org.apache.sling.commons.mime;version=2.1.8;type=osgi.bundle;start-order:=10," + "org.apache.sling.commons.threads;version=3.2.0;type=osgi.bundle;start-order:=20," + "org.apache.sling.commons.contentdetection;version=1.0.2;type=osgi.bundle;start-order:=100", attrs.getValue("Subsystem-Content")); break; case "org.apache.sling.commons.osgi-2.3.0.jar": ZipEntry oze = jf.getEntry("Potential_Bundles/0/org.apache.sling.commons.osgi-2.3.0.jar"); assertArtifactsEqual(oze.getName(), jf.getInputStream(oze), zis); break; case "org.apache.sling.commons.json-2.0.12.jar": ZipEntry jze = jf.getEntry("Potential_Bundles/10/org.apache.sling.commons.json-2.0.12.jar"); assertArtifactsEqual(jze.getName(), jf.getInputStream(jze), zis); break; case "org.apache.sling.commons.mime-2.1.8.jar": ZipEntry mze = jf.getEntry("Potential_Bundles/10/org.apache.sling.commons.mime-2.1.8.jar"); assertArtifactsEqual(mze.getName(), jf.getInputStream(mze), zis); break; case "org.apache.sling.commons.threads-3.2.0.jar": ZipEntry tze = jf.getEntry("Potential_Bundles/20/org.apache.sling.commons.threads-3.2.0.jar"); assertArtifactsEqual(tze.getName(), jf.getInputStream(tze), zis); break; case "org.apache.sling.commons.contentdetection-1.0.2.jar": ZipEntry cze = jf.getEntry("Potential_Bundles/100/org.apache.sling.commons.contentdetection-1.0.2.jar"); assertArtifactsEqual(cze.getName(), jf.getInputStream(cze), zis); break; } } } assertEquals(new HashSet<>(Arrays.asList("OSGI-INF/SUBSYSTEM.MF", "org.apache.sling.commons.osgi-2.3.0.jar", "org.apache.sling.commons.json-2.0.12.jar", "org.apache.sling.commons.mime-2.1.8.jar", "org.apache.sling.commons.threads-3.2.0.jar", "org.apache.sling.commons.contentdetection-1.0.2.jar")), foundBundles); assertFalse("After closing the stream the temp file should have been deleted.", dcis.file.exists()); } private void assertArtifactsEqual(String name, InputStream is1, InputStream is2) throws IOException { byte[] bytes1 = suckStreams(is1); byte[] bytes2 = suckStreams(is2); assertArrayEquals(name, bytes1, bytes2); } public static void pumpStreams(InputStream is, OutputStream os) throws IOException { byte[] bytes = new byte[16384]; int length = 0; int offset = 0; while ((length = is.read(bytes, offset, bytes.length - offset)) != -1) { offset += length; if (offset == bytes.length) { os.write(bytes, 0, bytes.length); offset = 0; } } if (offset != 0) { os.write(bytes, 0, offset); } } public static byte [] suckStreams(InputStream is) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); pumpStreams(is, baos); return baos.toByteArray(); } private static class TestRegisteredResource implements RegisteredResource { private final URL resourceURL; TestRegisteredResource(URL url) { resourceURL = url; } @Override public String getScheme() { return resourceURL.getProtocol(); } @Override public String getURL() { return resourceURL.toExternalForm(); } @Override public String getType() { return "file"; } @Override public InputStream getInputStream() throws IOException { return resourceURL.openStream(); } @Override public Dictionary<String, Object> getDictionary() { return null; } @Override public String getDigest() { return null; } @Override public int getPriority() { return 0; } @Override public String getEntityId() { return null; } } }