Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.picocontainer.defaults.DefaultPicoContainerLifecycleTestCase Maven / Gradle / Ivy
/*****************************************************************************
* Copyright (c) PicoContainer Organization. All rights reserved. *
* ------------------------------------------------------------------------- *
* The software in this package is published under the terms of the BSD *
* style license a copy of which has been included with this distribution in *
* the license.html file. *
* *
* Idea by Rachel Davies, Original code by Aslak Hellesoy and Paul Hammant *
*****************************************************************************/
package org.picocontainer.defaults;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.picocontainer.tck.MockFactory.mockeryWithCountingNamingScheme;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import junit.framework.Assert;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.integration.junit4.JMock;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.picocontainer.ComponentAdapter;
import org.picocontainer.ComponentMonitor;
import org.picocontainer.DefaultPicoContainer;
import org.picocontainer.LifecycleStrategy;
import org.picocontainer.MutablePicoContainer;
import org.picocontainer.PicoContainer;
import org.picocontainer.PicoLifecycleException;
import org.picocontainer.Startable;
import org.picocontainer.behaviors.Caching;
import org.picocontainer.injectors.AbstractInjector;
import org.picocontainer.injectors.AdaptingInjection;
import org.picocontainer.injectors.ConstructorInjection;
import org.picocontainer.monitors.LifecycleComponentMonitor;
import org.picocontainer.monitors.NullComponentMonitor;
import org.picocontainer.monitors.LifecycleComponentMonitor.LifecycleFailuresException;
import org.picocontainer.testmodel.RecordingLifecycle.FiveTriesToBeMalicious;
import org.picocontainer.testmodel.RecordingLifecycle.Four;
import org.picocontainer.testmodel.RecordingLifecycle.One;
import org.picocontainer.testmodel.RecordingLifecycle.Three;
import org.picocontainer.testmodel.RecordingLifecycle.Two;
/**
* This class tests the lifecycle aspects of DefaultPicoContainer.
*
* @author Aslak Hellesøy
* @author Paul Hammant
* @author Ward Cunningham
* @author Mauro Talevi
*/
@RunWith(JMock.class)
public class DefaultPicoContainerLifecycleTestCase {
private Mockery mockery = mockeryWithCountingNamingScheme();
@Test public void testOrderOfInstantiationShouldBeDependencyOrder() throws Exception {
DefaultPicoContainer pico = new DefaultPicoContainer();
pico.addComponent("recording", StringBuffer.class);
pico.addComponent(Four.class);
pico.addComponent(Two.class);
pico.addComponent(One.class);
pico.addComponent(Three.class);
final List componentInstances = pico.getComponents();
// instantiation - would be difficult to do these in the wrong order!!
assertEquals("Incorrect Order of Instantiation", One.class, componentInstances.get(1).getClass());
assertEquals("Incorrect Order of Instantiation", Two.class, componentInstances.get(2).getClass());
assertEquals("Incorrect Order of Instantiation", Three.class, componentInstances.get(3).getClass());
assertEquals("Incorrect Order of Instantiation", Four.class, componentInstances.get(4).getClass());
}
@Test public void testOrderOfStartShouldBeDependencyOrderAndStopAndDisposeTheOpposite() throws Exception {
DefaultPicoContainer parent = new DefaultPicoContainer(new Caching());
MutablePicoContainer child = parent.makeChildContainer();
parent.addComponent("recording", StringBuffer.class);
child.addComponent(Four.class);
parent.addComponent(Two.class);
parent.addComponent(One.class);
child.addComponent(Three.class);
parent.start();
parent.stop();
parent.dispose();
assertEquals("Three>Two>One>!Four!Three!Two!One",
parent.getComponent("recording").toString());
}
@Test public void testLifecycleIsIgnoredIfAdaptersAreNotLifecycleManagers() {
DefaultPicoContainer parent = new DefaultPicoContainer(new ConstructorInjection());
MutablePicoContainer child = parent.makeChildContainer();
parent.addComponent("recording", StringBuffer.class);
child.addComponent(Four.class);
parent.addComponent(Two.class);
parent.addComponent(One.class);
child.addComponent(Three.class);
parent.start();
parent.stop();
parent.dispose();
assertEquals("",
parent.getComponent("recording").toString());
}
@Test public void testStartStartShouldFail() throws Exception {
DefaultPicoContainer pico = new DefaultPicoContainer();
pico.start();
try {
pico.start();
fail("Should have failed");
} catch (IllegalStateException e) {
// expected;
}
}
@Test public void testStartStopStopShouldFail() throws Exception {
DefaultPicoContainer pico = new DefaultPicoContainer();
pico.start();
pico.stop();
try {
pico.stop();
fail("Should have failed");
} catch (IllegalStateException e) {
// expected;
}
}
@Test public void testStartStopDisposeDisposeShouldFail() throws Exception {
DefaultPicoContainer pico = new DefaultPicoContainer();
pico.start();
pico.stop();
pico.dispose();
try {
pico.dispose();
fail("Should have barfed");
} catch (IllegalStateException e) {
// expected;
}
}
public static class FooRunnable implements Runnable, Startable {
private int runCount;
private Thread thread = new Thread();
private boolean interrupted;
public FooRunnable() {
}
public int runCount() {
return runCount;
}
public boolean isInterrupted() {
return interrupted;
}
public void start() {
thread = new Thread(this);
thread.start();
}
public void stop() {
thread.interrupt();
}
// this would do something a bit more concrete
// than counting in real life !
public void run() {
runCount++;
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
interrupted = true;
}
}
}
@Test public void testStartStopOfDaemonizedThread() throws Exception {
DefaultPicoContainer pico = new DefaultPicoContainer(new Caching());
pico.addComponent(FooRunnable.class);
pico.getComponents();
pico.start();
Thread.sleep(100);
pico.stop();
FooRunnable foo = pico.getComponent(FooRunnable.class);
assertEquals(1, foo.runCount());
pico.start();
Thread.sleep(100);
pico.stop();
assertEquals(2, foo.runCount());
}
@Test public void testGetComponentInstancesOnParentContainerHostedChildContainerDoesntReturnParentAdapter() {
MutablePicoContainer parent = new DefaultPicoContainer();
MutablePicoContainer child = parent.makeChildContainer();
assertEquals(0, child.getComponents().size());
}
@Test public void testComponentsAreStartedBreadthFirstAndStoppedAndDisposedDepthFirst() {
MutablePicoContainer parent = new DefaultPicoContainer(new Caching());
parent.addComponent(Two.class);
parent.addComponent("recording", StringBuffer.class);
parent.addComponent(One.class);
MutablePicoContainer child = parent.makeChildContainer();
child.addComponent(Three.class);
parent.start();
parent.stop();
parent.dispose();
assertEquals("Two>One>!Three!Two!One", parent.getComponent("recording").toString());
}
@Test public void testMaliciousComponentCannotExistInAChildContainerAndSeeAnyElementOfContainerHierarchy() {
MutablePicoContainer parent = new DefaultPicoContainer(new Caching());
parent.addComponent(Two.class);
parent.addComponent("recording", StringBuffer.class);
parent.addComponent(One.class);
parent.addComponent(Three.class);
MutablePicoContainer child = parent.makeChildContainer();
child.addComponent(FiveTriesToBeMalicious.class);
try {
parent.start();
fail("Thrown " + AbstractInjector.UnsatisfiableDependenciesException.class.getName() + " expected");
} catch ( AbstractInjector.UnsatisfiableDependenciesException e) {
// FiveTriesToBeMalicious can't get instantiated as there is no PicoContainer in any component set
}
String recording = parent.getComponent("recording").toString();
assertEquals("!One", pico.getComponent("recording").toString());
}
@Test public void testShouldFailOnStartAfterDispose() {
MutablePicoContainer pico = new DefaultPicoContainer();
pico.dispose();
try {
pico.start();
fail();
} catch (IllegalStateException expected) {
}
}
@Test public void testShouldFailOnStopAfterDispose() {
MutablePicoContainer pico = new DefaultPicoContainer();
pico.dispose();
try {
pico.stop();
fail();
} catch (IllegalStateException expected) {
}
}
@Test public void testShouldStackContainersLast() {
// this is merely a code coverage test - but it doesn't seem to cover the StackContainersAtEndComparator
// fully. oh well.
MutablePicoContainer pico = new DefaultPicoContainer(new Caching());
pico.addComponent(ArrayList.class);
pico.addComponent(DefaultPicoContainer.class);
pico.addComponent(HashMap.class);
pico.start();
DefaultPicoContainer childContainer = pico.getComponent(DefaultPicoContainer.class);
// it should be started too
try {
childContainer.start();
fail();
} catch (IllegalStateException e) {
}
}
@Test public void testCanSpecifyLifeCycleStrategyForInstanceRegistrationWhenSpecifyingComponentFactory()
throws Exception
{
LifecycleStrategy strategy = new LifecycleStrategy() {
public void start(Object component) {
((StringBuffer)component).append("start>");
}
public void stop(Object component) {
((StringBuffer)component).append("stop>");
}
public void dispose(Object component) {
((StringBuffer)component).append("dispose>");
}
public boolean hasLifecycle(Class type) {
return true;
}
};
MutablePicoContainer pico = new DefaultPicoContainer( new AdaptingInjection(), strategy, null );
StringBuffer sb = new StringBuffer();
pico.addComponent(sb);
pico.start();
pico.stop();
pico.dispose();
assertEquals("start>stop>dispose>", sb.toString());
}
@Test public void testLifeCycleStrategyForInstanceRegistrationPassedToChildContainers()
throws Exception
{
LifecycleStrategy strategy = new LifecycleStrategy() {
public void start(Object component) {
((StringBuffer)component).append("start>");
}
public void stop(Object component) {
((StringBuffer)component).append("stop>");
}
public void dispose(Object component) {
((StringBuffer)component).append("dispose>");
}
public boolean hasLifecycle(Class type) {
return true;
}
};
MutablePicoContainer parent = new DefaultPicoContainer(strategy, null);
MutablePicoContainer pico = parent.makeChildContainer();
StringBuffer sb = new StringBuffer();
pico.addComponent(sb);
pico.start();
pico.stop();
pico.dispose();
assertEquals("start>stop>dispose>", sb.toString());
}
@Test public void testLifecycleDoesNotRecoverWithNullComponentMonitor() {
final Startable s1 = mockery.mock(Startable.class, "s1");
Startable s2 = mockery.mock(Startable.class, "s2");
mockery.checking(new Expectations(){{
one(s1).start();
will(throwException(new RuntimeException("I do not want to start myself")));
}});
DefaultPicoContainer dpc = new DefaultPicoContainer();
dpc.addComponent("foo", s1);
dpc.addComponent("bar", s2);
try {
dpc.start();
fail("PicoLifecylceException expected");
} catch (PicoLifecycleException e) {
assertEquals("I do not want to start myself", e.getCause().getMessage());
}
dpc.stop();
}
@Test public void testLifecycleCanRecoverWithCustomComponentMonitor() throws NoSuchMethodException {
final Startable s1 = mockery.mock(Startable.class, "s1");
final Startable s2 = mockery.mock(Startable.class, "s2");
final ComponentMonitor cm = mockery.mock(ComponentMonitor.class);
mockery.checking(new Expectations(){{
one(s1).start();
will(throwException(new RuntimeException("I do not want to start myself")));
one(s1).stop();
one(s2).start();
one(s2).stop();
// s1 expectations
one(cm).invoking(with(aNull(PicoContainer.class)), with(aNull(ComponentAdapter.class)), with(equal(Startable.class.getMethod("start", (Class[])null))), with(same(s1)));
one(cm).lifecycleInvocationFailed(with(aNull(MutablePicoContainer.class)), with(aNull(ComponentAdapter.class)), with(any(Method.class)), with(same(s1)), with(any(RuntimeException.class)));
one(cm).invoking(with(aNull(PicoContainer.class)), with(aNull(ComponentAdapter.class)), with(equal(Startable.class.getMethod("stop", (Class[])null))), with(same(s1)));
one(cm).invoked(with(aNull(PicoContainer.class)), with(aNull(ComponentAdapter.class)), with(equal(Startable.class.getMethod("stop", (Class[])null))), with(same(s1)), with(any(Long.class)));
// s2 expectations
one(cm).invoking(with(aNull(PicoContainer.class)), with(aNull(ComponentAdapter.class)), with(equal(Startable.class.getMethod("start", (Class[])null))), with(same(s2)));
one(cm).invoked(with(aNull(PicoContainer.class)), with(aNull(ComponentAdapter.class)), with(equal(Startable.class.getMethod("start", (Class[])null))), with(same(s2)), with(any(Long.class)));
one(cm).invoking(with(aNull(PicoContainer.class)), with(aNull(ComponentAdapter.class)), with(equal(Startable.class.getMethod("stop", (Class[])null))), with(same(s2)));
one(cm).invoked(with(aNull(PicoContainer.class)), with(aNull(ComponentAdapter.class)), with(equal(Startable.class.getMethod("stop", (Class[])null))), with(same(s2)), with(any(Long.class)));
}});
DefaultPicoContainer dpc = new DefaultPicoContainer(cm);
dpc.addComponent("foo", s1);
dpc.addComponent("bar", s2);
dpc.start();
dpc.stop();
}
@Test public void testLifecycleFailuresCanBePickedUpAfterTheEvent() {
final Startable s1 = mockery.mock(Startable.class, "s1");
final Startable s2 = mockery.mock(Startable.class, "s2");
final Startable s3 = mockery.mock(Startable.class, "s3");
mockery.checking(new Expectations(){{
one(s1).start();
will(throwException(new RuntimeException("I do not want to start myself")));
one(s1).stop();
one(s2).start();
one(s2).stop();
one(s3).start();
will(throwException(new RuntimeException("I also do not want to start myself")));
one(s3).stop();
}});
LifecycleComponentMonitor lifecycleComponentMonitor = new LifecycleComponentMonitor(new NullComponentMonitor());
DefaultPicoContainer dpc = new DefaultPicoContainer(lifecycleComponentMonitor);
dpc.addComponent("one", s1);
dpc.addComponent("two", s2);
dpc.addComponent("three", s3);
dpc.start();
try {
lifecycleComponentMonitor.rethrowLifecycleFailuresException();
fail("LifecycleFailuresException expected");
} catch (LifecycleFailuresException e) {
assertEquals("I do not want to start myself; I also do not want to start myself;", e.getMessage().trim());
dpc.stop();
assertEquals(2, e.getFailures().size());
}
}
@Test public void testStartedComponentsCanBeStoppedIfSomeComponentsFailToStart() {
final Startable s1 = mockery.mock(Startable.class, "s1");
final Startable s2 = mockery.mock(Startable.class, "s2");
mockery.checking(new Expectations(){{
one(s1).start();
one(s1).stop();
one(s2).start();
will(throwException(new RuntimeException("I do not want to start myself")));
// s2 does not expect stop().
}});
DefaultPicoContainer dpc = new DefaultPicoContainer();
dpc.addComponent("foo", s1);
dpc.addComponent("bar", s2);
try {
dpc.start();
fail("PicoLifecylceException expected");
} catch (RuntimeException e) {
dpc.stop();
}
}
@Test public void testStartedComponentsCanBeStoppedIfSomeComponentsFailToStartEvenInAPicoHierarchy() {
final Startable s1 = mockery.mock(Startable.class, "s1");
final Startable s2 = mockery.mock(Startable.class, "s2");
mockery.checking(new Expectations(){{
one(s1).start();
one(s1).stop();
one(s2).start();
will(throwException(new RuntimeException("I do not want to start myself")));
// s2 does not expect stop().
}});
DefaultPicoContainer dpc = new DefaultPicoContainer();
dpc.addComponent("foo", s1);
dpc.addComponent("bar", s2);
dpc.addChildContainer(new DefaultPicoContainer(dpc));
try {
dpc.start();
fail("PicoLifecylceException expected");
} catch (RuntimeException e) {
dpc.stop();
}
}
@Test public void testChildContainerIsStoppedWhenStartedIndependentlyOfParent() throws Exception {
DefaultPicoContainer parent = new DefaultPicoContainer();
parent.start();
MutablePicoContainer child = parent.makeChildContainer();
final Startable s1 = mockery.mock(Startable.class, "s1");
mockery.checking(new Expectations(){{
one(s1).start();
one(s1).stop();
}});
child.addComponent(s1);
child.start();
parent.stop();
}
}