/* 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.aries.quiesce.manager.itest; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.List; | |
import java.util.concurrent.Future; | |
import java.util.concurrent.TimeUnit; | |
import java.util.concurrent.TimeoutException; | |
import org.apache.aries.itest.AbstractIntegrationTest; | |
import org.apache.aries.quiesce.manager.QuiesceManager; | |
import org.apache.aries.quiesce.participant.QuiesceParticipant; | |
import org.junit.After; | |
import org.junit.Before; | |
import org.junit.Test; | |
import org.junit.runner.RunWith; | |
import org.ops4j.pax.exam.Configuration; | |
import org.ops4j.pax.exam.Option; | |
import org.ops4j.pax.exam.junit.PaxExam; | |
import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; | |
import org.ops4j.pax.exam.spi.reactors.PerClass; | |
import org.ops4j.pax.exam.spi.reactors.PerMethod; | |
import org.osgi.framework.Bundle; | |
import static org.junit.Assert.assertEquals; | |
import static org.junit.Assert.assertTrue; | |
import static org.junit.Assert.fail; | |
import static org.ops4j.pax.exam.CoreOptions.composite; | |
import static org.ops4j.pax.exam.CoreOptions.junitBundles; | |
import static org.ops4j.pax.exam.CoreOptions.mavenBundle; | |
import static org.ops4j.pax.exam.CoreOptions.systemProperty; | |
import static org.ops4j.pax.exam.CoreOptions.vmOption; | |
import static org.ops4j.pax.exam.CoreOptions.when; | |
@RunWith(PaxExam.class) | |
@ExamReactorStrategy(PerMethod.class) | |
public class QuiesceManagerTest extends AbstractIntegrationTest { | |
private QuiesceManager manager; | |
private Bundle b1; | |
private Bundle b2; | |
private Bundle b3; | |
private long timeoutTime; | |
private List<Bundle> bundleList; | |
private MockQuiesceParticipant participant1; | |
private MockQuiesceParticipant participant2; | |
private MockQuiesceParticipant participant3; | |
@Before | |
public void setup() { | |
manager = context().getService(QuiesceManager.class); | |
b1 = bundleContext.getBundle(5); | |
b2 = bundleContext.getBundle(6); | |
b3 = bundleContext.getBundle(10); | |
participant1 = new MockQuiesceParticipant(MockQuiesceParticipant.RETURNIMMEDIATELY); | |
participant2 = new MockQuiesceParticipant(MockQuiesceParticipant.NEVERRETURN); | |
participant3 = new MockQuiesceParticipant(MockQuiesceParticipant.WAIT); | |
} | |
@After | |
public void after() { | |
participant1.reset(); | |
participant2.reset(); | |
participant3.reset(); | |
} | |
@Test | |
public void testNullSafe() throws Exception { | |
//Check we're null safe | |
manager.quiesce(null); | |
} | |
@Test | |
public void testNoParticipants() throws Exception { | |
bundleList = new ArrayList<Bundle>(); | |
bundleList.add(b1); | |
assertEquals("Bundle "+b1.getSymbolicName()+" should be in active state", Bundle.ACTIVE, b1.getState()); | |
//Try quiescing one bundle with no participants | |
manager.quiesceWithFuture(2000, bundleList).get(5000, TimeUnit.MILLISECONDS); | |
assertTrue("Bundle "+b1.getSymbolicName()+" should not be in active state", b1.getState() != Bundle.ACTIVE); | |
} | |
@Test | |
public void testImmediateReturn() throws Exception { | |
bundleList = new ArrayList<Bundle>(); | |
bundleList.add(b1); | |
//Register a mock participant which will report back quiesced immediately | |
bundleContext.registerService(QuiesceParticipant.class.getName(), participant1, null); | |
//Try quiescing the bundle with immediate return | |
assertEquals("Bundle "+b1.getSymbolicName()+" should be in active state", Bundle.ACTIVE, b1.getState()); | |
manager.quiesceWithFuture(1000,bundleList).get(5000, TimeUnit.MILLISECONDS); | |
assertEquals("Participant should have finished once", 1, participant1.getFinishedCount()); | |
assertTrue("Bundle "+b1.getSymbolicName()+" should not be in active state", b1.getState() != Bundle.ACTIVE); | |
} | |
@Test | |
public void testNoReturn() throws Exception { | |
//Register a mock participant which won't respond | |
bundleContext.registerService(QuiesceParticipant.class.getName(), participant2, null); | |
//recreate the list as it may have been emptied? | |
bundleList = new ArrayList<Bundle>(); | |
bundleList.add(b1); | |
//Try quiescing the bundle with no return | |
assertEquals("Bundle "+b1.getSymbolicName()+" should be in active state", Bundle.ACTIVE, b1.getState()); | |
manager.quiesce(1000,bundleList); | |
timeoutTime = System.currentTimeMillis()+5000; | |
while (System.currentTimeMillis() < timeoutTime && b1.getState() == Bundle.ACTIVE){ | |
Thread.sleep(500); | |
} | |
assertEquals("Participant should have started once", 1, participant2.getStartedCount()); | |
assertEquals("Participant should not have finished", 0, participant2.getFinishedCount()); | |
assertTrue("Bundle "+b1.getSymbolicName()+" should not be in active state", b1.getState() != Bundle.ACTIVE); | |
} | |
@Test | |
public void testWaitAShortTime() throws Exception { | |
//Try quiescing where participant takes 5s to do the work. We should get InterruptedException | |
bundleContext.registerService(QuiesceParticipant.class.getName(), participant3, null); | |
//recreate the list as it may have been emptied? | |
bundleList = new ArrayList<Bundle>(); | |
bundleList.add(b1); | |
assertEquals("Bundle "+b1.getSymbolicName()+" should be in active state", Bundle.ACTIVE, b1.getState()); | |
// we should be finishing in about 5000 millis not 10000 | |
manager.quiesceWithFuture(10000,bundleList).get(7000, TimeUnit.MILLISECONDS); | |
assertEquals("Participant should have started once", 1, participant3.getStartedCount()); | |
assertEquals("Participant should finished once", 1, participant3.getFinishedCount()); | |
assertTrue("Bundle "+b1.getSymbolicName()+" should not be in active state", b1.getState() != Bundle.ACTIVE); | |
} | |
@Test | |
public void testThreeParticipants() throws Exception { | |
//Register three participants. One returns immediately, one waits 5s then returns, one never returns | |
bundleContext.registerService(QuiesceParticipant.class.getName(), participant1, null); | |
bundleContext.registerService(QuiesceParticipant.class.getName(), participant2, null); | |
bundleContext.registerService(QuiesceParticipant.class.getName(), participant3, null); | |
//recreate the list as it may have been emptied | |
bundleList = new ArrayList<Bundle>(); | |
bundleList.add(b1); | |
assertEquals("Bundle "+b1.getSymbolicName()+" should be in active state", Bundle.ACTIVE, b1.getState()); | |
manager.quiesceWithFuture(10000,bundleList).get(15000, TimeUnit.MILLISECONDS); | |
assertEquals("Participant 1 should have started once", 1, participant1.getStartedCount()); | |
assertEquals("Participant 1 should finished once", 1, participant1.getFinishedCount()); | |
assertEquals("Participant 2 should have started once", 1, participant2.getStartedCount()); | |
assertEquals("Participant 2 should not have finished", 0, participant2.getFinishedCount()); | |
assertEquals("Participant 3 should have started once", 1, participant3.getStartedCount()); | |
assertEquals("Participant 3 should finished once", 1, participant3.getFinishedCount()); | |
assertTrue("Bundle "+b1.getSymbolicName()+" should not be in active state", b1.getState() != Bundle.ACTIVE); | |
} | |
@Test | |
public void testFuture() throws Exception { | |
bundleContext.registerService(QuiesceParticipant.class.getName(), participant2, null); | |
bundleContext.registerService(QuiesceParticipant.class.getName(), participant3, null); | |
bundleList = new ArrayList<Bundle>(); | |
bundleList.add(b1); | |
assertEquals("Bundle "+b1.getSymbolicName()+" should be in active state", Bundle.ACTIVE, b1.getState()); | |
Future<?> future = manager.quiesceWithFuture(2000, Arrays.asList(b1)); | |
// causes us to wait | |
future.get(); | |
assertEquals("Participant 2 has started", 1, participant2.getStartedCount()); | |
assertEquals("Participant 2 has finished", 0, participant2.getFinishedCount()); | |
assertEquals("Participant 3 has started", 1, participant3.getStartedCount()); | |
assertEquals("Participant 3 has finished", 1, participant3.getFinishedCount()); | |
} | |
@Test | |
public void testFutureWithWait() throws Exception { | |
bundleContext.registerService(QuiesceParticipant.class.getName(), participant2, null); | |
bundleContext.registerService(QuiesceParticipant.class.getName(), participant3, null); | |
bundleList = new ArrayList<Bundle>(); | |
bundleList.add(b1); | |
assertEquals("Bundle "+b1.getSymbolicName()+" should be in active state", Bundle.ACTIVE, b1.getState()); | |
Future<?> future = manager.quiesceWithFuture(2000, Arrays.asList(b1)); | |
try { | |
// causes us to wait, but too short | |
future.get(500, TimeUnit.MILLISECONDS); | |
fail("Too short wait, should have thrown TimeoutException"); | |
} catch (TimeoutException te) { | |
// expected | |
} | |
assertEquals("Participant 2 has started", 1, participant2.getStartedCount()); | |
assertEquals("Participant 2 has finished", 0, participant2.getFinishedCount()); | |
assertEquals("Participant 3 has started", 1, participant3.getStartedCount()); | |
assertEquals("Participant 3 has finished", 0, participant3.getFinishedCount()); | |
assertEquals("Bundle "+b1.getSymbolicName()+" should still be active, because we did not wait long enough", Bundle.ACTIVE, b1.getState()); | |
} | |
@Test | |
public void testTwoBundles() throws Exception { | |
//Register three participants. One returns immediately, one waits 5s then returns, one never returns | |
bundleContext.registerService(QuiesceParticipant.class.getName(), participant1, null); | |
bundleContext.registerService(QuiesceParticipant.class.getName(), participant2, null); | |
bundleContext.registerService(QuiesceParticipant.class.getName(), participant3, null); | |
//recreate the list as it may have been emptied | |
bundleList = new ArrayList<Bundle>(); | |
bundleList.add(b1); | |
bundleList.add(b2); | |
assertEquals("Bundle "+b1.getSymbolicName()+" should be in active state", Bundle.ACTIVE, b1.getState()); | |
assertEquals("Bundle "+b2.getSymbolicName()+" should be in active state", Bundle.ACTIVE, b2.getState()); | |
manager.quiesceWithFuture(10000,bundleList).get(15000, TimeUnit.MILLISECONDS); | |
assertEquals("Participant 1 should have started once", 1, participant1.getStartedCount()); | |
assertEquals("Participant 1 should finished once", 1, participant1.getFinishedCount()); | |
assertEquals("Participant 2 should have started once", 1, participant2.getStartedCount()); | |
assertEquals("Participant 2 should not have finished", 0, participant2.getFinishedCount()); | |
assertEquals("Participant 3 should have started once", 1, participant3.getStartedCount()); | |
assertEquals("Participant 3 should finished once", 1, participant3.getFinishedCount()); | |
assertTrue("Bundle "+b1.getSymbolicName()+" should not be in active state", b1.getState() != Bundle.ACTIVE); | |
assertTrue("Bundle "+b2.getSymbolicName()+" should not be in active state", b2.getState() != Bundle.ACTIVE); | |
} | |
@Test | |
public void testOverlappedQuiesces() throws Exception { | |
//Register three participants. One returns immediately, one waits 5s then returns, one never returns | |
bundleContext.registerService(QuiesceParticipant.class.getName(), participant1, null); | |
bundleContext.registerService(QuiesceParticipant.class.getName(), participant2, null); | |
bundleContext.registerService(QuiesceParticipant.class.getName(), participant3, null); | |
//recreate the list as it may have been emptied | |
bundleList = new ArrayList<Bundle>(); | |
bundleList.add(b1); | |
bundleList.add(b2); | |
assertEquals("Bundle "+b1.getSymbolicName()+" should be in active state", Bundle.ACTIVE, b1.getState()); | |
assertEquals("Bundle "+b2.getSymbolicName()+" should be in active state", Bundle.ACTIVE, b2.getState()); | |
assertEquals("Bundle "+b3.getSymbolicName()+" should be in active state", Bundle.ACTIVE, b3.getState()); | |
manager.quiesce(2000,bundleList); | |
bundleList = new ArrayList<Bundle>(); | |
bundleList.add(b2); | |
bundleList.add(b3); | |
manager.quiesce(2000,bundleList); | |
timeoutTime = System.currentTimeMillis()+10000; | |
while (System.currentTimeMillis() < timeoutTime && (b1.getState() == Bundle.ACTIVE || b2.getState() == Bundle.ACTIVE || b3.getState() == Bundle.ACTIVE)) { | |
Thread.sleep(500); | |
} | |
assertEquals("Participant 1 should have started twice as it has been asked to quiesce twice", 2, participant1.getStartedCount()); | |
assertEquals("Participant 1 should finished twice as it should have returned from two quiesce requests immediately", 2, participant1.getFinishedCount()); | |
assertEquals("Participant 2 should have started twice as it has been asked to quiesce twice", 2, participant2.getStartedCount()); | |
assertEquals("Participant 2 should not have finished as it should never return from it's two quiesce requests", 0, participant2.getFinishedCount()); | |
assertEquals("Participant 3 should have started twice as it has been asked to quiesce twice", 2, participant3.getStartedCount()); | |
assertEquals("Participant 3 should finished twice as it should have waited a short time before returning from it's two quiesce requests", 2, participant3.getFinishedCount()); | |
assertTrue("Bundle "+b1.getSymbolicName()+" should not be in active state", b1.getState() != Bundle.ACTIVE); | |
assertTrue("Bundle "+b2.getSymbolicName()+" should not be in active state", b2.getState() != Bundle.ACTIVE); | |
assertTrue("Bundle "+b3.getSymbolicName()+" should not be in active state", b3.getState() != Bundle.ACTIVE); | |
} | |
public Option baseOptions() { | |
String localRepo = getLocalRepo(); | |
return composite( | |
junitBundles(), | |
// this is how you set the default log level when using pax | |
// logging (logProfile) | |
systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("INFO"), | |
when(localRepo != null).useOptions(vmOption("-Dorg.ops4j.pax.url.mvn.localRepository=" + localRepo)) | |
); | |
} | |
@Configuration | |
public Option[] configuration() { | |
return new Option[]{ | |
baseOptions(), | |
// Bundles | |
mavenBundle("org.osgi", "org.osgi.compendium").versionAsInProject(), | |
mavenBundle("org.apache.aries", "org.apache.aries.util").versionAsInProject(), | |
mavenBundle("commons-lang", "commons-lang").versionAsInProject(), | |
mavenBundle("commons-collections", "commons-collections").versionAsInProject(), | |
mavenBundle("commons-pool", "commons-pool").versionAsInProject(), | |
mavenBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.serp").versionAsInProject(), | |
mavenBundle("org.apache.aries.quiesce", "org.apache.aries.quiesce.api").versionAsInProject(), | |
mavenBundle("org.apache.aries.quiesce", "org.apache.aries.quiesce.manager").versionAsInProject(), | |
mavenBundle("org.apache.aries.testsupport", "org.apache.aries.testsupport.unit").versionAsInProject(), | |
//new VMOption( "-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000" ), | |
//new TimeoutOption( 0 ), | |
}; | |
} | |
} |