blob: 66b41175b3724b627a33f8029acda16695757f0d [file] [log] [blame]
/*
* 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.launchpad.base.impl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.InputStream;
import java.util.HashMap;
import org.apache.sling.launchpad.base.shared.Notifiable;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.FrameworkEvent;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.launch.Framework;
import org.osgi.service.packageadmin.PackageAdmin;
import junit.framework.AssertionFailedError;
public class SlingFelixTest {
public static final int N_START_STOP = 100;
public static final long WAIT_FOR_STOP_TIMEOUT_MSEC = 1000;
public static final long STOPPED_CALLED_TIMEOUT_MSEC = 5000L;
private final TestNotifiable notifiable = new TestNotifiable();
private SlingFelix framework;
@Before
public void setup() {
startSling();
}
@After
public void tearDown() {
stopSling();
}
@Test
public void testMultipleStop() {
startSling();
for(int i=0; i < N_START_STOP; i++) {
stopSling();
}
}
@Test
public void testMultipleStartStop() {
stopSling();
for(int i=0; i < N_START_STOP; i++) {
startSling();
stopSling();
}
}
@Test
public void test_start_stop() {
assertNotNull(framework);
assertEquals(Bundle.ACTIVE, framework.getState());
stopSling();
// as the notifiable is notified async we wait
final long start = System.currentTimeMillis();
while ( !this.notifiable.stoppedCalled ) {
// timeout on this wait
if ( System.currentTimeMillis() - start > STOPPED_CALLED_TIMEOUT_MSEC ) {
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException ignore) {
}
}
assertTrue("Expect Notifiable.stopped to be called", this.notifiable.stoppedCalled);
assertFalse("Expect Notifiable.updated to not be called", this.notifiable.updatedCalled);
assertNull("Expect Notifiable.updated to not be called", this.notifiable.updatedCalledFile);
}
@SuppressWarnings("deprecation")
@Test
public void test_Felix_getBundle_Class_from_PackageAdmin() {
/*
* Tests whether the Felix.getBundle(Class) call from PackageAdmin
* is possible. This test should always succeed regardless of the
* SLING-2554 implementation because it uses regular Java call
* methodology.
*/
PackageAdmin pa = getService(framework, PackageAdmin.class);
assertNotNull(pa);
assertNull("Integer class provided by the VM not from a bundle", pa.getBundle(Integer.class));
assertEquals("BundleContext class must come from the framework", framework.getBundle(),
pa.getBundle(BundleContext.class));
}
@Test
public void test_Felix_getBundle_Class_from_UrlStreamHandler() {
/*
* Tests whether the Felix.getBundle(Class) method can be called
* from the URLHandlers class. This call may fail if SLING-2554
* does not work because it uses reflection on the class of the
* framework instance, which happens to be SlingFelix instead of
* Felix
*/
final SlingFelix sf2 = startFramework(new TestNotifiable());
try {
InputStream ins = getClass().getResourceAsStream("/test1.jar");
framework.getBundleContext().installBundle("test1", ins).start();
Runnable r = getService(framework, Runnable.class);
r.run();
} catch (Exception e) {
throw (AssertionFailedError) new AssertionFailedError(e.toString()).initCause(e);
} finally {
stopFramework(sf2);
}
}
private void startSling() {
stopSling();
framework = startFramework(this.notifiable);
}
private static SlingFelix startFramework(final Notifiable notifiable) {
final String baseDir = System.getProperty("basedir");
if (baseDir == null) {
fail("Need the basedir system property to locate the framework folder");
}
File fwDir = new File(baseDir + "/target/felix." + System.nanoTime());
fwDir.mkdirs();
HashMap<String, Object> props = new HashMap<String, Object>();
props.put(Constants.FRAMEWORK_STORAGE, fwDir.getAbsolutePath());
props.put(Constants.FRAMEWORK_STORAGE_CLEAN, Constants.FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT);
props.put(Constants.FRAMEWORK_BEGINNING_STARTLEVEL, "30");
try {
SlingFelix fw = new SlingFelix(notifiable, props);
fw.start();
return fw;
} catch (Exception e) {
fail("Failed to start OSGi Framework: " + e);
return null; // to keep the compiler cool
}
}
private void stopSling() {
stopFramework(framework);
}
private static void stopFramework(Framework f) {
if(f == null) {
return;
}
try {
f.stop();
if (f.waitForStop(WAIT_FOR_STOP_TIMEOUT_MSEC).getType() == FrameworkEvent.WAIT_TIMEDOUT) {
fail("Timed out waiting for framework to stop, after " + WAIT_FOR_STOP_TIMEOUT_MSEC + " msec");
}
} catch (Exception e) {
fail("Cannot stop OSGi Framework: " + e);
}
}
private <T> T getService(final Framework framework, Class<T> type) {
ServiceReference<T> ref = framework.getBundleContext().getServiceReference(type);
if (ref != null) {
return framework.getBundleContext().getService(ref);
}
return null;
}
private static class TestNotifiable implements Notifiable {
volatile boolean stoppedCalled = false;
volatile boolean updatedCalled = false;
volatile File updatedCalledFile = null;
@Override
public void stopped() {
this.stoppedCalled = true;
}
@Override
public void updated(File tmpFile) {
this.updatedCalled = true;
this.updatedCalledFile = tmpFile;
}
}
}