/*
* JBoss, Home of Professional Open Source
* Copyright 2011 Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the @authors tag. All rights reserved.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* 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.jboss.arquillian.container.test.impl.client.deployment;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jboss.arquillian.config.descriptor.impl.ContainerDefImpl;
import org.jboss.arquillian.container.impl.LocalContainerRegistry;
import org.jboss.arquillian.container.spi.Container;
import org.jboss.arquillian.container.spi.ContainerRegistry;
import org.jboss.arquillian.container.spi.client.container.DeployableContainer;
import org.jboss.arquillian.container.spi.client.deployment.DeploymentScenario;
import org.jboss.arquillian.container.spi.client.protocol.ProtocolDescription;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.OverProtocol;
import org.jboss.arquillian.container.test.api.TargetsContainer;
import org.jboss.arquillian.container.test.impl.client.deployment.event.GenerateDeployment;
import org.jboss.arquillian.container.test.impl.domain.ProtocolDefinition;
import org.jboss.arquillian.container.test.impl.domain.ProtocolRegistry;
import org.jboss.arquillian.container.test.spi.TestDeployment;
import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor;
import org.jboss.arquillian.container.test.spi.client.deployment.AuxiliaryArchiveAppender;
import org.jboss.arquillian.container.test.spi.client.deployment.AuxiliaryArchiveProcessor;
import org.jboss.arquillian.container.test.spi.client.deployment.DeploymentPackager;
import org.jboss.arquillian.container.test.spi.client.deployment.DeploymentScenarioGenerator;
import org.jboss.arquillian.container.test.spi.client.protocol.Protocol;
import org.jboss.arquillian.container.test.test.AbstractContainerTestTestBase;
import org.jboss.arquillian.core.api.Injector;
import org.jboss.arquillian.core.api.Instance;
import org.jboss.arquillian.core.api.annotation.ApplicationScoped;
import org.jboss.arquillian.core.api.annotation.Inject;
import org.jboss.arquillian.core.spi.ServiceLoader;
import org.jboss.arquillian.test.spi.TestClass;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* DeploymentGeneratorTestCase
*
* @author <a href="mailto:aslak@redhat.com">Aslak Knutsen</a>
* @version $Revision: $
*/
@RunWith(MockitoJUnitRunner.class)
public class DeploymentGeneratorTestCase extends AbstractContainerTestTestBase {
public static final String PROTOCOL_NAME_1 = "TEST_DEFAULT_1";
public static final String PROTOCOL_NAME_2 = "TEST_DEFAULT_2";
public static final String CONTAINER_NAME_1 = "CONTAINER_NAME_1";
public static final String CONTAINER_NAME_2 = "CONTAINER_NAME_2";
@Inject
private Instance<Injector> injectorInst;
@Mock
private ServiceLoader serviceLoader;
private ContainerRegistry containerRegistry;
private ProtocolRegistry protocolRegistry;
@Mock
@SuppressWarnings("rawtypes")
private DeployableContainer deployableContainer;
@Mock
private DeploymentPackager packager;
@Override
protected void addExtensions(List<Class<?>> extensions) {
extensions.add(DeploymentGenerator.class);
}
@Before
public void prepare() {
Injector injector = injectorInst.get();
when(serviceLoader.onlyOne(DeploymentScenarioGenerator.class, AnnotationDeploymentScenarioGenerator.class))
.thenReturn(new AnnotationDeploymentScenarioGenerator());
when(serviceLoader.onlyOne(eq(DeployableContainer.class))).thenReturn(deployableContainer);
when(deployableContainer.getDefaultProtocol()).thenReturn(new ProtocolDescription(PROTOCOL_NAME_1));
when(serviceLoader.all(eq(AuxiliaryArchiveAppender.class)))
.thenReturn(create(AuxiliaryArchiveAppender.class, injector.inject(new TestAuxiliaryArchiveAppender())));
when(serviceLoader.all(eq(AuxiliaryArchiveProcessor.class)))
.thenReturn(create(AuxiliaryArchiveProcessor.class, injector.inject(new TestAuxiliaryArchiveProcessor())));
when(serviceLoader.all(eq(ApplicationArchiveProcessor.class)))
.thenReturn(create(ApplicationArchiveProcessor.class, injector.inject(new TestApplicationArchiveAppender())));
containerRegistry = new LocalContainerRegistry(injector);
protocolRegistry = new ProtocolRegistry();
bind(ApplicationScoped.class, ServiceLoader.class, serviceLoader);
bind(ApplicationScoped.class, ContainerRegistry.class, containerRegistry);
bind(ApplicationScoped.class, ProtocolRegistry.class, protocolRegistry);
bind(ApplicationScoped.class, CallMap.class, new CallMap());
}
@Test
public void shouldUseDefaultDefinedProtocolIfFound() {
addContainer("test-contianer").getContainerConfiguration().setMode("suite");
addProtocol(PROTOCOL_NAME_1, true);
fire(createEvent(DeploymentWithDefaults.class));
verify(deployableContainer, times(0)).getDefaultProtocol();
}
@Test
public void shouldUseContainerDefaultProtocolIfNonDefaultDefined() {
addContainer("test-contianer").getContainerConfiguration().setMode("suite");
addProtocol(PROTOCOL_NAME_1, false);
addProtocol(PROTOCOL_NAME_2, false);
fire(createEvent(DeploymentWithDefaults.class));
verify(deployableContainer, times(1)).getDefaultProtocol();
verifyScenario("_DEFAULT_");
}
@Test
public void shouldCallPackagingSPIsOnTestableArchive() throws Exception {
addContainer("test-contianer").getContainerConfiguration().setMode("suite");
addProtocol(PROTOCOL_NAME_1, true);
fire(createEvent(DeploymentWithDefaults.class));
CallMap spi = getManager().resolve(CallMap.class);
Assert.assertTrue(spi.wasCalled(ApplicationArchiveProcessor.class));
Assert.assertTrue(spi.wasCalled(AuxiliaryArchiveAppender.class));
Assert.assertTrue(spi.wasCalled(AuxiliaryArchiveProcessor.class));
verifyScenario("_DEFAULT_");
}
@Test
public void shouldNotCallPackagingSPIsOnNonTestableArchive() throws Exception {
addContainer("test-contianer").getContainerConfiguration().setMode("suite");
addProtocol(PROTOCOL_NAME_1, true);
fire(createEvent(DeploymentNonTestableWithDefaults.class));
CallMap spi = getManager().resolve(CallMap.class);
Assert.assertFalse(spi.wasCalled(ApplicationArchiveProcessor.class));
Assert.assertFalse(spi.wasCalled(AuxiliaryArchiveAppender.class));
Assert.assertFalse(spi.wasCalled(AuxiliaryArchiveProcessor.class));
verifyScenario("_DEFAULT_");
}
@Test
public void shouldAllowNonManagedDeploymentOnCustomContainer() throws Exception {
addContainer(CONTAINER_NAME_1).getContainerConfiguration().setMode("custom");
fire(createEvent(DeploymentNonManagedWithCustomContainerReference.class));
verifyScenario("DeploymentNonManagedWithCustomContainerReference");
}
@Test
public void shouldAllowMultipleSameNamedArchiveDeploymentWithDifferentTargets() throws Exception {
addContainer(CONTAINER_NAME_1).getContainerConfiguration().setMode("suite");
addContainer(CONTAINER_NAME_2).getContainerConfiguration().setMode("suite");
addProtocol(PROTOCOL_NAME_1, true);
fire(createEvent(DeploymentMultipleSameNameArchiveDifferentTarget.class));
verifyScenario("X", "Y");
}
@Test // ARQ-971
@SuppressWarnings("unchecked")
public void shouldFilterNullAuxiliaryArchiveAppenderResulsts() throws Exception {
when(serviceLoader.all(eq(AuxiliaryArchiveAppender.class)))
.thenReturn(
create(AuxiliaryArchiveAppender.class, injectorInst.get().inject(new NullAuxiliaryArchiveAppender())));
addContainer(CONTAINER_NAME_1);
addProtocol(PROTOCOL_NAME_1, true);
fire(createEvent(DeploymentWithDefaults.class));
CallMap spi = getManager().resolve(CallMap.class);
Assert.assertTrue(spi.wasCalled(AuxiliaryArchiveAppender.class));
DeploymentScenario scenario = getManager().resolve(DeploymentScenario.class);
Assert.assertEquals(1, scenario.deployments().size());
ArgumentCaptor<TestDeployment> captor = ArgumentCaptor.forClass(TestDeployment.class);
verify(packager).generateDeployment(captor.capture(), Mockito.any(Collection.class));
Assert.assertEquals(0, captor.getValue().getAuxiliaryArchives().size());
}
@Test(expected = ValidationException.class)
public void shouldThrowExceptionOnMissingContainerReference() throws Exception {
try {
fire(createEvent(DeploymentWithContainerReference.class));
} catch (Exception e) {
Assert.assertTrue("Validate correct error message",
e.getMessage().contains("Please include at least 1 Deployable Container on your Classpath"));
throw e;
}
}
@Test(expected = ValidationException.class)
public void shouldThrowExceptionOnWrongContainerReference() throws Exception {
addContainer("test-contianer").getContainerConfiguration().setMode("suite");
try {
fire(createEvent(DeploymentWithContainerReference.class));
} catch (Exception e) {
Assert.assertTrue("Validate correct error message",
e.getMessage().contains("does not match any found/configured Containers"));
throw e;
}
}
@Test(expected = ValidationException.class)
public void shouldThrowExceptionOnMissingProtocolReference() throws Exception {
addContainer("test-contianer").getContainerConfiguration().setMode("suite");
try {
fire(createEvent(DeploymentWithProtocolReference.class));
} catch (Exception e) {
Assert.assertTrue("Validate correct error message",
e.getMessage().contains("not maching any defined Protocol"));
throw e;
}
}
@Test(expected = IllegalArgumentException.class)
public void shouldThrowExceptionOnMultipleNoNamedDeployments() throws Exception {
addContainer("test-contianer").getContainerConfiguration().setMode("suite");
try {
fire(createEvent(DeploymentMultipleNoNamed.class));
} catch (Exception e) {
throw e;
}
}
@Test(expected = IllegalArgumentException.class)
public void shouldThrowExceptionOnMultipleSameNamedArchiveDeployments() throws Exception {
addContainer("test-contianer").getContainerConfiguration().setMode("suite");
try {
fire(createEvent(DeploymentMultipleSameNameArchive.class));
} catch (Exception e) {
throw e;
}
}
@Test(expected = ValidationException.class)
public void shouldThrowExceptionOnManagedDeploymentOnCustomContainer() throws Exception {
addContainer(CONTAINER_NAME_1).getContainerConfiguration().setMode("custom");
try {
fire(createEvent(DeploymentManagedWithCustomContainerReference.class));
} catch (Exception e) {
Assert.assertTrue("Validate correct error message",
e.getMessage().contains("This container is set to mode custom "));
throw e;
}
}
private void verifyScenario(String... names) {
DeploymentScenario scenario = getManager().resolve(DeploymentScenario.class);
Assert.assertEquals(names.length, scenario.deployments().size());
for (int i = 0; i < names.length; i++) {
contains(scenario.deployments(), names[i]);
}
}
private void contains(Collection<org.jboss.arquillian.container.spi.client.deployment.Deployment> deployments,
String name) {
if (deployments == null || deployments.size() == 0) {
Assert.fail("No deployment by name " + name + " found in scenario. Scenario is empty");
}
for (org.jboss.arquillian.container.spi.client.deployment.Deployment deployment : deployments) {
if (name.equals(deployment.getDescription().getName())) {
return;
}
}
Assert.fail("No deployment by name " + name + " found in scenario. " + deployments);
}
private Container addContainer(String name) {
return containerRegistry.create(
new ContainerDefImpl("arquillian.xml")
.container(name),
serviceLoader);
}
private ProtocolDefinition addProtocol(String name, boolean shouldBeDefault) {
Protocol<?> protocol = mock(Protocol.class);
when(protocol.getPackager()).thenReturn(packager);
when(protocol.getDescription()).thenReturn(new ProtocolDescription(name));
Map<String, String> config = Collections.emptyMap();
return protocolRegistry.addProtocol(new ProtocolDefinition(protocol, config, shouldBeDefault))
.getProtocol(new ProtocolDescription(name));
}
private <T> Collection<T> create(Class<T> type, T... instances) {
List<T> list = new ArrayList<T>();
Collections.addAll(list, instances);
return list;
}
private GenerateDeployment createEvent(Class<?> testClass) {
return new GenerateDeployment(new TestClass(testClass));
}
private static class DeploymentWithDefaults {
@SuppressWarnings("unused")
@Deployment
public static JavaArchive deploy() {
return ShrinkWrap.create(JavaArchive.class);
}
}
private static class DeploymentMultipleNoNamed {
@SuppressWarnings("unused")
@Deployment
public static JavaArchive deploy() {
return ShrinkWrap.create(JavaArchive.class);
}
@SuppressWarnings("unused")
@Deployment
public static JavaArchive deploy2() {
return ShrinkWrap.create(JavaArchive.class);
}
}
private static class DeploymentMultipleSameNameArchive {
@SuppressWarnings("unused")
@Deployment(name = "Y")
public static JavaArchive deploy() {
return ShrinkWrap.create(JavaArchive.class, "test.jar");
}
@SuppressWarnings("unused")
@Deployment(name = "X")
public static JavaArchive deploy2() {
return ShrinkWrap.create(JavaArchive.class, "test.jar");
}
}
private static class DeploymentMultipleSameNameArchiveDifferentTarget {
@SuppressWarnings("unused")
@Deployment(name = "Y")
@TargetsContainer(CONTAINER_NAME_1)
public static JavaArchive deploy() {
return ShrinkWrap.create(JavaArchive.class, "test.jar");
}
@SuppressWarnings("unused")
@Deployment(name = "X")
@TargetsContainer(CONTAINER_NAME_2)
public static JavaArchive deploy2() {
return ShrinkWrap.create(JavaArchive.class, "test.jar");
}
}
private static class DeploymentNonTestableWithDefaults {
@SuppressWarnings("unused")
@Deployment(testable = false)
public static JavaArchive deploy() {
return ShrinkWrap.create(JavaArchive.class);
}
}
private static class DeploymentWithContainerReference {
@SuppressWarnings("unused")
@Deployment
@TargetsContainer("DOES_NOT_EXIST")
public static JavaArchive deploy() {
return ShrinkWrap.create(JavaArchive.class);
}
}
private static class DeploymentWithProtocolReference {
@SuppressWarnings("unused")
@Deployment
@OverProtocol("DOES_NOT_EXIST")
public static JavaArchive deploy() {
return ShrinkWrap.create(JavaArchive.class);
}
}
private static class DeploymentManagedWithCustomContainerReference {
@SuppressWarnings("unused")
@Deployment(managed = true, testable = false)
@TargetsContainer(CONTAINER_NAME_1)
public static JavaArchive deploy() {
return ShrinkWrap.create(JavaArchive.class);
}
}
private static class DeploymentNonManagedWithCustomContainerReference {
@SuppressWarnings("unused")
@Deployment(name = "DeploymentNonManagedWithCustomContainerReference", managed = false, testable = false)
@TargetsContainer(CONTAINER_NAME_1)
public static JavaArchive deploy() {
return ShrinkWrap.create(JavaArchive.class);
}
}
private static class CallMap {
private Set<Class<?>> calls = new HashSet<Class<?>>();
public void add(Class<?> called) {
calls.add(called);
}
public boolean wasCalled(Class<?> called) {
return calls.contains(called);
}
}
private static class TestMaker {
@Inject
private Instance<CallMap> callmap;
protected void called() {
callmap.get().add(super.getClass().getInterfaces()[0]);
}
}
private static class TestAuxiliaryArchiveAppender extends TestMaker implements AuxiliaryArchiveAppender {
@Override
public Archive<?> createAuxiliaryArchive() {
called();
return ShrinkWrap.create(JavaArchive.class, this.getClass().getSimpleName() + ".jar");
}
}
private static class NullAuxiliaryArchiveAppender extends TestMaker implements AuxiliaryArchiveAppender {
@Override
public Archive<?> createAuxiliaryArchive() {
called();
return null;
}
}
private static class TestAuxiliaryArchiveProcessor extends TestMaker implements AuxiliaryArchiveProcessor {
@Override
public void process(Archive<?> auxiliaryArchive) {
called();
}
}
private static class TestApplicationArchiveAppender extends TestMaker implements ApplicationArchiveProcessor {
@Override
public void process(Archive<?> applicationArchive, TestClass testClass) {
called();
}
}
}