Skip to content
Permalink
Browse files
FELIX-518 - add unit test for signed DPs:
- created utility to create signed deployment packages for use in itests;
- verify that signed DPs are correctly installed;
- some small cleanups and typos fixed.



git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1724647 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
Jan Willem Janssen committed Jan 14, 2016
1 parent 71e5d7e commit 2acb8de55574074c1855f42f0eae5710f69ff2bd
Show file tree
Hide file tree
Showing 13 changed files with 727 additions and 248 deletions.
@@ -511,6 +511,6 @@ protected AbstractInfo getAbstractInfoByPath(String path) {
*/
protected boolean isMetaInfFile(String name) {
name = name.toUpperCase(Locale.US);
return name.startsWith("META-INF/") && (name.endsWith("/INDEX.LIST") || name.endsWith(".SF") || name.endsWith(".DSA") || name.endsWith(".RS"));
return name.startsWith("META-INF/") && (name.endsWith("/INDEX.LIST") || name.endsWith(".SF") || name.endsWith(".DSA") || name.endsWith(".RSA") || name.endsWith(".EC"));
}
}
@@ -18,7 +18,8 @@
*/
package org.apache.felix.deploymentadmin;

import java.io.Closeable;
import static org.apache.felix.deploymentadmin.Utils.closeSilently;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
@@ -53,7 +54,7 @@ class ContentCopyingJarInputStream extends JarInputStream {
private OutputStream m_entryOS;

public ContentCopyingJarInputStream(InputStream in, File indexFile, File contentDir) throws IOException {
super(in);
super(in, true /* verify */);

m_contentDir = contentDir;

@@ -122,17 +123,6 @@ private void closeIndex() {
m_indexFileWriter = null;
}

private void closeSilently(Closeable resource) {
try {
if (resource != null) {
resource.close();
}
}
catch (IOException e) {
// Ignore, not much we can do about this...
}
}

/**
* Creates a verbatim copy of the manifest, when it is read from the original JAR.
*/
@@ -181,6 +181,8 @@ public DeploymentPackage installDeploymentPackage(InputStream sourceInput) throw
jarInput = new ContentCopyingJarInputStream(sourceInput, tempIndex, tempContents);

if (jarInput.getManifest() == null) {
Utils.closeSilently(jarInput);

m_log.log(LogService.LOG_ERROR, "Stream does not contain a valid deployment package: missing manifest!");
throw new DeploymentException(CODE_MISSING_HEADER, "No manifest present in deployment package!");
}
@@ -33,10 +33,8 @@
* deployment package manifest and can interpret the various manifest entries and headers the OSGi specification defines.
*/
public class DeploymentPackageManifest implements Constants {

private final Manifest m_manifest;
private final Version m_version;

private final List m_bundleInfos = new ArrayList();
private final List m_resourceInfos = new ArrayList();
private final String m_symbolicName;
@@ -28,75 +28,68 @@
*
*/
public class NonCloseableStream extends InputStream {

private final InputStream m_input;
private boolean m_closed;
private volatile boolean m_closed;

public NonCloseableStream(InputStream m_input) {
this.m_input = m_input;
public NonCloseableStream(InputStream input) {
m_input = input;
}

// stream should not be actually closed, subsequent calls to read methods will throw an exception though
public int available() throws IOException {
return m_input.available();
}

public void close() throws IOException {
if (m_closed) {
throw new IOException("Unable to read, stream is closed.");
}
// stream should not be actually closed, subsequent calls to read methods will throw an exception though
assertOpen();
m_closed = true;
}

public int read() throws IOException {
return m_input.read();
public boolean equals(Object obj) {
return m_input.equals(obj);
}

public int read(byte[] b, int off, int len) throws IOException {
if (m_closed) {
throw new IOException("Unable to read, stream is closed.");
}
return m_input.read(b, off, len);
public int hashCode() {
return m_input.hashCode();
}

public int read(byte[] b) throws IOException {
if (m_closed) {
throw new IOException("Unable to read, stream is closed.");
}
return m_input.read(b);
public void mark(int readlimit) {
// do nothing
}

// No mark & reset support

public boolean markSupported() {
return false;
}

public void mark(int readlimit) {
// do nothing
public int read() throws IOException {
return m_input.read();
}

public void reset() throws IOException {
throw new IOException("Mark and reset are not available on this type of stream.");
public int read(byte[] b) throws IOException {
assertOpen();
return m_input.read(b);
}

// Unaffected methods

public int available() throws IOException {
return m_input.available();
public int read(byte[] b, int off, int len) throws IOException {
assertOpen();
return m_input.read(b, off, len);
}

public int hashCode() {
return m_input.hashCode();
public void reset() throws IOException {
throw new IOException("Mark and reset are not available on this type of stream.");
}

public long skip(long n) throws IOException {
return m_input.skip(n);
}

public boolean equals(Object obj) {
return m_input.equals(obj);
}

public String toString() {
return m_input.toString();
}

private void assertOpen() throws IOException {
if (m_closed) {
throw new IOException("Unable to read, stream is closed.");
}
}
}
@@ -116,6 +116,18 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.54</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.54</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
@@ -144,14 +156,6 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<target>1.6</target>
<source>1.6</source>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
@@ -25,6 +25,7 @@
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.Security;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -38,6 +39,7 @@
import junit.framework.TestCase;

import org.apache.felix.deploymentadmin.itest.util.DeploymentPackageBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.After;
import org.junit.Before;
import org.ops4j.pax.exam.Configuration;
@@ -74,24 +76,23 @@ public abstract class BaseIntegrationTest extends TestCase {
protected volatile AtomicInteger m_gate = new AtomicInteger(0);
protected volatile String m_testBundleBasePath;
protected volatile Map<String, List<Version>> m_initialBundles;
private int cnt = 0;

private int cnt = 0;

@Configuration
public Option[] config() throws Exception {
return options(
bootDelegationPackage("sun.*"),
systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("ERROR"),
return options(bootDelegationPackage("sun.*"), systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("ERROR"),

mavenBundle("org.apache.felix", "org.apache.felix.metatype").versionAsInProject(),
mavenBundle("org.apache.felix", "org.apache.felix.metatype").versionAsInProject(),
mavenBundle("org.apache.felix", "org.apache.felix.dependencymanager").versionAsInProject(),
mavenBundle("org.apache.felix", "org.apache.felix.deploymentadmin").versionAsInProject(),
mavenBundle("org.apache.felix", "org.apache.felix.deploymentadmin").versionAsInProject(),
mavenBundle("org.apache.felix", "org.apache.felix.eventadmin").versionAsInProject(),
mavenBundle("org.apache.felix", "org.apache.felix.configadmin").versionAsInProject(),
mavenBundle("commons-codec", "commons-codec").versionAsInProject(),

junitBundles()
);
mavenBundle("org.bouncycastle", "bcprov-jdk15on").versionAsInProject(),
mavenBundle("org.bouncycastle", "bcpkix-jdk15on").versionAsInProject(),

junitBundles());
}

@Before
@@ -110,9 +111,9 @@ public void frameworkEvent(FrameworkEvent event) {
}
}
});

m_initialBundles = new HashMap<String, List<Version>>();

for (Bundle bundle : m_context.getBundles()) {
List<Version> versions = m_initialBundles.get(bundle.getSymbolicName());
if (versions == null) {
@@ -121,12 +122,16 @@ public void frameworkEvent(FrameworkEvent event) {
}
versions.add(bundle.getVersion());
}

Security.addProvider(new BouncyCastleProvider());
}

@After
public void tearDown() throws Exception {
System.setProperty("rp1", "");
System.setProperty("bundle3", "");

Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
}

protected void assertBundleExists(String symbolicName, String version) {
@@ -168,42 +173,44 @@ protected <T> T awaitService(String serviceName) throws Exception {
}
return result;
}

protected final DeploymentPackage installDeploymentPackage(DeploymentPackageBuilder dpBuilder) throws Exception {
return installDeploymentPackage(dpBuilder.generate());
}

protected final DeploymentPackage installDeploymentPackage(InputStream is) throws Exception {
try {
return m_deploymentAdmin.installDeploymentPackage(is);
} finally {
}
finally {
try {
is.close();
} catch (IOException e) {
}
catch (IOException e) {
// Nothing we can do about this, but log it...
e.printStackTrace();
}
}
}

protected final int countDeploymentPackages() {
return m_deploymentAdmin.listDeploymentPackages().length;
}

protected DeploymentPackageBuilder createNewDeploymentPackageBuilder(String version) {
return createDeploymentPackageBuilder(String.format("itest%d", ++cnt), version);
}

protected DeploymentPackageBuilder createDeploymentPackageBuilder(String symName, String version) {
return DeploymentPackageBuilder.create(symName, version);
}

protected Map<String, List<Version>> getCurrentBundles() {
Map<String, List<Version>> bundles = new HashMap<String, List<Version>>();
for (Bundle bundle : m_context.getBundles()) {
String symbolicName = bundle.getSymbolicName();
Version version = bundle.getVersion();

// Is is not part of any of the initially provisioned bundles?
List<Version> versions = m_initialBundles.get(symbolicName);
if ((versions == null) || !versions.contains(version)) {
@@ -217,7 +224,7 @@ protected Map<String, List<Version>> getCurrentBundles() {
}
return bundles;
}

protected String getSymbolicName(String baseName) {
return "testbundles.".concat(baseName);
}
@@ -241,10 +248,11 @@ protected Bundle getBundle(String bsn) {
}

protected URL getTestBundleURL(String baseName) throws MalformedURLException {
return getTestBundleURL(baseName, "1.0.0");
return getTestBundleURL(baseName, "1.0.0");
}

protected URL getTestBundleURL(String baseName, String version) throws MalformedURLException {
return getTestBundleURL(baseName, baseName, version);
return getTestBundleURL(baseName, baseName, version);
}

protected URL getTestBundleURL(String artifactName, String baseName, String version) throws MalformedURLException {
@@ -253,7 +261,7 @@ protected URL getTestBundleURL(String artifactName, String baseName, String vers
assertTrue("No such bundle: " + f, f.exists() && f.isFile());
return f.toURI().toURL();
}

protected boolean isBundleActive(Bundle bundle) {
return isBundleInState(bundle, Bundle.ACTIVE);
}
@@ -280,7 +288,7 @@ protected boolean isBundleInState(Bundle bundle, int state) {
protected boolean isBundleRemoved(String symbolicName, String version) {
return isBundleRemoved(symbolicName, new Version(version));
}

protected boolean isBundleRemoved(String symbolicName, Version version) {
Map<String, List<Version>> bundles = getCurrentBundles();

@@ -297,13 +305,13 @@ protected boolean resolveBundles(Bundle... bundles) throws Exception {

FrameworkWiring frameworkWiring = systemBundle.adapt(FrameworkWiring.class);
frameworkWiring.resolveBundles(Arrays.asList(bundles));

for (Bundle bundle : bundles) {
if ((bundle.getState() & Bundle.RESOLVED) == 0) {
return false;
}
}

return true;
}
}

0 comments on commit 2acb8de

Please sign in to comment.