/*
* Copyright 2012 Harald Wellmann.
*
* Licensed 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.ops4j.pax.exam.spi.reactors;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.ops4j.pax.exam.TestAddress;
import org.ops4j.pax.exam.TestContainer;
import org.ops4j.pax.exam.TestContainerException;
import org.ops4j.pax.exam.TestProbeBuilder;
import org.ops4j.pax.exam.spi.StagedExamReactor;
import org.ops4j.pax.exam.spi.intern.DefaultTestAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A singleton reactor which starts the container and installs the probes just once. The teardown
* logic is postponed to a JVM shutdown hook.
*
* @author Harald Wellmann
* @since 3.0.0
*/
public class SingletonStagedReactor implements StagedExamReactor {
private static final Logger LOG = LoggerFactory.getLogger(SingletonStagedReactor.class);
private static SingletonStagedReactor instance;
private List<TestContainer> testContainers;
private List<TestProbeBuilder> probes;
private Map<TestAddress, TestContainer> testToContainerMap;
private SingletonStagedReactor(List<TestContainer> containers, List<TestProbeBuilder> mProbes) {
testToContainerMap = new LinkedHashMap<TestAddress, TestContainer>();
testContainers = containers;
probes = mProbes;
}
private void buildTestMap(List<TestContainer> containers, List<TestProbeBuilder> mProbes) {
int index = 0;
for (TestContainer container : containers) {
String caption = buildCaption(containers, container, index);
for (TestProbeBuilder builder : mProbes) {
// each probe has addresses.
for (TestAddress a : builder.getTests()) {
// we need to create a new, because "a" exists for each test container
// this new address makes the test (reachable via getTargets() ) reachable
// directly.
testToContainerMap.put(new DefaultTestAddress(a, caption), container);
}
}
index++;
}
}
private String buildCaption(List<TestContainer> containers, TestContainer container, int index) {
if (containers.size() == 1) {
return container.toString();
}
else {
return String.format("%s[%d]", container.toString(), index);
}
}
/**
* @param containers
* to be used
* @param mProbes
* to be installed on all probes
* @return staged reactor
*/
public static synchronized StagedExamReactor getInstance(List<TestContainer> containers,
List<TestProbeBuilder> mProbes) {
if (instance == null) {
instance = new SingletonStagedReactor(containers, mProbes);
}
else {
if ( /* ! instance.testContainers.equals( containers ) || */
!instance.probes.equals(mProbes)) {
throw new TestContainerException(
"using the PerSuite reactor strategy, all test classes must share the same probes");
}
}
return instance;
}
public void invoke(TestAddress address) throws Exception {
assert (address != null) : "TestAddress must not be null.";
TestContainer testContainer = testToContainerMap.get(address);
if (testContainer == null) {
throw new IllegalArgumentException("TestAddress " + address
+ " not from this reactor? Got it from getTargets() really?");
}
testContainer.call(address);
}
public Set<TestAddress> getTargets() {
buildTestMap(testContainers, probes);
return testToContainerMap.keySet();
}
public void tearDown() {
}
@Override
public void beforeSuite() {
for (TestContainer container : testContainers) {
container.start();
for (TestProbeBuilder builder : probes) {
LOG.debug("installing probe " + builder);
try {
container.installProbe(builder.build().getStream());
}
catch (IOException e) {
throw new TestContainerException("Unable to build the probe.", e);
}
}
}
}
public void afterSuite() {
for (TestContainer container : testContainers) {
container.stop();
}
}
@Override
public void beforeClass() {
}
@Override
public void afterClass() {
}
}