deltaspike-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gpetra...@apache.org
Subject git commit: DELTASPIKE-342 test-control module added (first draft)
Date Thu, 05 Dec 2013 10:14:09 GMT
Updated Branches:
  refs/heads/master bcf5eda66 -> 4a57c90ad


DELTASPIKE-342 test-control module added (first draft)


Project: http://git-wip-us.apache.org/repos/asf/deltaspike/repo
Commit: http://git-wip-us.apache.org/repos/asf/deltaspike/commit/4a57c90a
Tree: http://git-wip-us.apache.org/repos/asf/deltaspike/tree/4a57c90a
Diff: http://git-wip-us.apache.org/repos/asf/deltaspike/diff/4a57c90a

Branch: refs/heads/master
Commit: 4a57c90ad28e3acccb7020ae8a3d358acbd71d33
Parents: bcf5eda
Author: gpetracek <gpetracek@apache.org>
Authored: Thu Dec 5 10:54:48 2013 +0100
Committer: gpetracek <gpetracek@apache.org>
Committed: Thu Dec 5 11:11:06 2013 +0100

----------------------------------------------------------------------
 deltaspike/modules/pom.xml                      |   1 +
 deltaspike/modules/test-control/api/pom.xml     |  84 +++
 .../deltaspike/testcontrol/api/TestControl.java |  55 ++
 .../testcontrol/api/junit/CdiTestRunner.java    | 558 +++++++++++++++++++
 .../api/junit/CdiTestSuiteRunner.java           | 160 ++++++
 .../api/literal/TestControlLiteral.java         |  57 ++
 .../junit/TestStatementDecoratorFactory.java    |  32 ++
 deltaspike/modules/test-control/impl/pom.xml    | 134 +++++
 .../TransactionStatementDecoratorFactory.java   | 177 ++++++
 .../shared/ApplicationScopedBean.java           |  60 ++
 .../testcontrol/shared/RequestScopedBean.java   |  55 ++
 .../testcontrol/shared/SessionScopedBean.java   |  39 ++
 .../test/testcontrol/shared/TestUtils.java      |  43 ++
 ...RequestAndSessionScopePerTestMethodTest.java | 102 ++++
 .../uc002/SessionScopePerTestClassTest.java     | 101 ++++
 ...RequestAndSessionScopePerTestMethodTest.java |  73 +++
 .../uc003/SessionScopePerTestClassTest.java     |  67 +++
 .../test/testcontrol/uc003/TestSuite.java       |  50 ++
 .../uc004/ProjectStageTestControlTest.java      |  52 ++
 .../impl/src/test/resources/META-INF/beans.xml  |  23 +
 ...trol.spi.junit.TestStatementDecoratorFactory |  19 +
 deltaspike/modules/test-control/pom.xml         |  40 ++
 deltaspike/parent/pom.xml                       |  14 +
 23 files changed, 1996 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/deltaspike/blob/4a57c90a/deltaspike/modules/pom.xml
----------------------------------------------------------------------
diff --git a/deltaspike/modules/pom.xml b/deltaspike/modules/pom.xml
index 5423910..3049707 100644
--- a/deltaspike/modules/pom.xml
+++ b/deltaspike/modules/pom.xml
@@ -42,5 +42,6 @@
         <module>partial-bean</module>
         <module>bean-validation</module>
         <module>data</module>
+        <module>test-control</module>
     </modules>
 </project>

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/4a57c90a/deltaspike/modules/test-control/api/pom.xml
----------------------------------------------------------------------
diff --git a/deltaspike/modules/test-control/api/pom.xml b/deltaspike/modules/test-control/api/pom.xml
new file mode 100644
index 0000000..1e80638
--- /dev/null
+++ b/deltaspike/modules/test-control/api/pom.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.deltaspike.modules</groupId>
+        <artifactId>test-control-module-project</artifactId>
+        <version>0.6-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.deltaspike.modules</groupId>
+    <artifactId>deltaspike-test-control-module-api</artifactId>
+    <packaging>bundle</packaging>
+
+    <name>Apache DeltaSpike Test-Control-Module API</name>
+
+    <properties>
+        <deltaspike.osgi.export.pkg>
+            org.apache.deltaspike.testcontrol.*
+        </deltaspike.osgi.export.pkg>
+        <deltaspike.osgi.import>
+            javax.enterprise.inject,
+            !org.apache.deltaspike.testcontrol.*,
+            *
+        </deltaspike.osgi.import>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.deltaspike.core</groupId>
+            <artifactId>deltaspike-core-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.deltaspike.cdictrl</groupId>
+            <artifactId>deltaspike-cdictrl-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <inherited>true</inherited>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-source-plugin</artifactId>
+
+                <executions>
+                    <execution>
+                        <id>attach-sources</id>
+                        <goals>
+                            <goal>jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/4a57c90a/deltaspike/modules/test-control/api/src/main/java/org/apache/deltaspike/testcontrol/api/TestControl.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/test-control/api/src/main/java/org/apache/deltaspike/testcontrol/api/TestControl.java b/deltaspike/modules/test-control/api/src/main/java/org/apache/deltaspike/testcontrol/api/TestControl.java
new file mode 100644
index 0000000..d32b2fb
--- /dev/null
+++ b/deltaspike/modules/test-control/api/src/main/java/org/apache/deltaspike/testcontrol/api/TestControl.java
@@ -0,0 +1,55 @@
+/*
+ * 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.deltaspike.testcontrol.api;
+
+import org.apache.deltaspike.core.api.projectstage.ProjectStage;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Handler;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Optional control annotation for unit-tests
+ */
+
+@Target({ TYPE, METHOD })
+@Retention(RUNTIME)
+public @interface TestControl
+{
+    /**
+     * only supports contexts supported by ContextControl#startContext
+     * defaults: session- and request-scope
+     */
+    Class<? extends Annotation>[] startScopes() default { };
+
+    //TODO discuss callbacks
+
+    Class<? extends ProjectStage> projectStage() default ProjectStage.UnitTest.class;
+
+    /**
+     * only supported on test-class-level
+     */
+    Class<? extends Handler> logHandler() default ConsoleHandler.class;
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/4a57c90a/deltaspike/modules/test-control/api/src/main/java/org/apache/deltaspike/testcontrol/api/junit/CdiTestRunner.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/test-control/api/src/main/java/org/apache/deltaspike/testcontrol/api/junit/CdiTestRunner.java b/deltaspike/modules/test-control/api/src/main/java/org/apache/deltaspike/testcontrol/api/junit/CdiTestRunner.java
new file mode 100644
index 0000000..19698d9
--- /dev/null
+++ b/deltaspike/modules/test-control/api/src/main/java/org/apache/deltaspike/testcontrol/api/junit/CdiTestRunner.java
@@ -0,0 +1,558 @@
+/*
+ * 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.deltaspike.testcontrol.api.junit;
+
+import org.apache.deltaspike.cdise.api.CdiContainer;
+import org.apache.deltaspike.cdise.api.CdiContainerLoader;
+import org.apache.deltaspike.cdise.api.ContextControl;
+import org.apache.deltaspike.core.api.projectstage.ProjectStage;
+import org.apache.deltaspike.core.api.provider.BeanManagerProvider;
+import org.apache.deltaspike.core.api.provider.BeanProvider;
+import org.apache.deltaspike.core.util.ExceptionUtils;
+import org.apache.deltaspike.core.util.ProjectStageProducer;
+import org.apache.deltaspike.core.util.ServiceUtils;
+import org.apache.deltaspike.testcontrol.api.TestControl;
+import org.apache.deltaspike.testcontrol.api.literal.TestControlLiteral;
+import org.apache.deltaspike.testcontrol.spi.junit.TestStatementDecoratorFactory;
+import org.junit.Test;
+import org.junit.internal.runners.statements.FailOnTimeout;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.Statement;
+import org.junit.runners.model.TestClass;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.Dependent;
+import javax.enterprise.context.RequestScoped;
+import javax.enterprise.context.SessionScoped;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.inject.Singleton;
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+import java.util.Stack;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class CdiTestRunner extends BlockJUnit4ClassRunner
+{
+    private static final Logger LOGGER = Logger.getLogger(CdiTestRunner.class.getName());
+
+    private static Set<Integer> notifierIdentities = new CopyOnWriteArraySet<Integer>();
+
+    private List<TestStatementDecoratorFactory> statementDecoratorFactories;
+
+    private ContainerAwareTestContext testContext;
+
+    public CdiTestRunner(Class<?> testClass) throws InitializationError
+    {
+        super(testClass);
+
+        TestControl testControl = testClass.getAnnotation(TestControl.class);
+        this.testContext = new ContainerAwareTestContext(testControl, null);
+
+        //benefits from the fallback-handling in ContainerAwareTestContext
+        Class<? extends Handler> logHandlerClass = this.testContext.getLogHandlerClass();
+
+        if (!Handler.class.equals(logHandlerClass))
+        {
+            try
+            {
+                LOGGER.addHandler(logHandlerClass.newInstance());
+            }
+            catch (Exception e)
+            {
+                throw ExceptionUtils.throwAsRuntimeException(e);
+            }
+        }
+
+        this.statementDecoratorFactories = ServiceUtils.loadServiceImplementations(TestStatementDecoratorFactory.class);
+        Collections.sort(this.statementDecoratorFactories, new Comparator<TestStatementDecoratorFactory>()
+        {
+            @Override
+            public int compare(TestStatementDecoratorFactory f1, TestStatementDecoratorFactory f2)
+            {
+                return f1.getOrdinal() > f2.getOrdinal() ? 1 : -1;
+            }
+        });
+    }
+
+    @Override
+    public void run(RunNotifier runNotifier)
+    {
+        if (!CdiTestSuiteRunner.isContainerStarted()) //not called as a part of a test-suite
+        {
+            int identityHashCode = System.identityHashCode(runNotifier);
+            if (!notifierIdentities.contains(identityHashCode))
+            {
+                addLogRunListener(runNotifier, identityHashCode);
+            }
+        }
+
+        super.run(runNotifier);
+    }
+
+    private static synchronized void addLogRunListener(RunNotifier notifier, int identityHashCode)
+    {
+        if (notifierIdentities.contains(identityHashCode))
+        {
+            return;
+        }
+        notifierIdentities.add(identityHashCode);
+        notifier.addListener(new CdiTestSuiteRunner.LogRunListener());
+    }
+
+    @Override
+    protected Statement methodInvoker(FrameworkMethod method, Object test)
+    {
+        return new ContainerAwareMethodInvoker(method, test);
+    }
+
+    @Override
+    protected void runChild(FrameworkMethod method, RunNotifier notifier)
+    {
+        TestControl testControl = method.getAnnotation(TestControl.class);
+
+        ContainerAwareTestContext currentTestContext =
+                new ContainerAwareTestContext(testControl, this.testContext);
+
+        currentTestContext.applyBeforeMethodConfig();
+
+        try
+        {
+            super.runChild(method, notifier);
+        }
+        finally
+        {
+            currentTestContext.applyAfterMethodConfig();
+        }
+    }
+
+    //TODO use Rules instead
+    @Override
+    protected Statement withBefores(FrameworkMethod method, Object target, Statement statement)
+    {
+        Statement result = super.withBefores(method, target, statement);
+        result = wrapBeforeStatement(result, getTestClass(), target);
+        return result;
+    }
+
+    private Statement wrapBeforeStatement(Statement statement, TestClass testClass, Object target)
+    {
+        for (TestStatementDecoratorFactory statementHandler : this.statementDecoratorFactories)
+        {
+            Statement result = statementHandler.createBeforeStatement(statement, testClass, target);
+            if (result != null)
+            {
+                statement = result;
+            }
+        }
+        return statement;
+    }
+
+    //TODO use Rules instead
+    @Override
+    protected Statement withAfters(FrameworkMethod method,
+                                   final Object target,
+                                   final Statement statement)
+    {
+        Statement result = super.withAfters(method, target, statement);
+        result = wrapAfterStatement(result, getTestClass(), target);
+        return result;
+    }
+
+    private Statement wrapAfterStatement(Statement statement, TestClass testClass, Object target)
+    {
+        for (TestStatementDecoratorFactory statementHandler : this.statementDecoratorFactories)
+        {
+            Statement result = statementHandler.createAfterStatement(statement, testClass, target);
+            if (result != null)
+            {
+                statement = result;
+            }
+        }
+        return statement;
+    }
+
+    @Override
+    protected Statement withBeforeClasses(Statement statement)
+    {
+        return new BeforeClassStatement(super.withBeforeClasses(statement), this.testContext);
+    }
+
+    @Override
+    protected Statement withAfterClasses(Statement statement)
+    {
+        Statement result = super.withAfterClasses(statement);
+        if (!CdiTestSuiteRunner.isContainerStarted())
+        {
+            return new AfterClassStatement(result, this.testContext, notifierIdentities);
+        }
+        return result;
+    }
+
+    //TODO use Rules instead
+    @Override
+    protected Statement withPotentialTimeout(FrameworkMethod method, Object test, Statement next)
+    {
+        Statement result = super.withPotentialTimeout(method, test, next);
+
+        if (result instanceof FailOnTimeout)
+        {
+            return new Statement()
+            {
+                @Override
+                public void evaluate() throws Throwable
+                {
+                    throw new RuntimeException("@" + Test.class.getName() + "#timeout isn't supported");
+                }
+            };
+        }
+
+        return result;
+    }
+
+    private class ContainerAwareMethodInvoker extends Statement
+    {
+        private final FrameworkMethod method;
+        private final Object originalTarget;
+
+        public ContainerAwareMethodInvoker(FrameworkMethod method, Object originalTarget)
+        {
+            this.method = method;
+            this.originalTarget = originalTarget;
+        }
+
+        @Override
+        public void evaluate() throws Throwable
+        {
+            BeanManager beanManager = BeanManagerProvider.getInstance().getBeanManager();
+            Class<?> type = this.method.getMethod().getDeclaringClass();
+            Set<Bean<?>> beans = beanManager.getBeans(type);
+
+            if (beans == null || beans.isEmpty())
+            {
+                BeanProvider.injectFields(this.originalTarget); //fallback to simple injection
+                invokeMethod(this.originalTarget);
+            }
+            else
+            {
+                Bean<Object> bean = (Bean<Object>) beanManager.resolve(beans);
+
+                CreationalContext<Object> creationalContext = beanManager.createCreationalContext(bean);
+
+                Object target = beanManager.getReference(bean, type, creationalContext);
+
+                try
+                {
+                    invokeMethod(target);
+                }
+                finally
+                {
+                    if (bean.getScope().equals(Dependent.class))
+                    {
+                        bean.destroy(target, creationalContext);
+                    }
+                }
+            }
+        }
+
+        private void invokeMethod(Object target)
+        {
+            try
+            {
+                this.method.invokeExplosively(target);
+            }
+            catch (Throwable throwable)
+            {
+                throw ExceptionUtils.throwAsRuntimeException(throwable);
+            }
+        }
+    }
+
+    private class BeforeClassStatement extends Statement
+    {
+        private final Statement wrapped;
+        private final ContainerAwareTestContext testContext;
+
+        BeforeClassStatement(Statement statement, ContainerAwareTestContext testContext)
+        {
+            this.wrapped = statement;
+            this.testContext = testContext;
+        }
+
+        @Override
+        public void evaluate() throws Throwable
+        {
+            testContext.applyBeforeClassConfig();
+            wrapped.evaluate();
+        }
+    }
+
+    private class AfterClassStatement extends Statement
+    {
+        private final Statement wrapped;
+        private final ContainerAwareTestContext testContext;
+        private Set<Integer> notifierIdentities;
+
+        public AfterClassStatement(Statement statement,
+                                   ContainerAwareTestContext testContext,
+                                   Set<Integer> notifierIdentities)
+        {
+            this.wrapped = statement;
+            this.testContext = testContext;
+            this.notifierIdentities = notifierIdentities;
+        }
+
+        @Override
+        public void evaluate() throws Throwable
+        {
+            notifierIdentities.clear();
+
+            try
+            {
+                wrapped.evaluate();
+            }
+            finally
+            {
+                testContext.applyAfterClassConfig();
+            }
+        }
+    }
+
+    private static class ContainerAwareTestContext
+    {
+        private ContainerAwareTestContext parent;
+
+        private final ProjectStage projectStage;
+        private final TestControl testControl;
+
+        private ProjectStage previousProjectStage;
+
+        private boolean containerStarted = false; //only true for the layer it was started in
+
+        private Stack<Class<? extends Annotation>> startedScopes = new Stack<Class<? extends Annotation>>();
+
+        ContainerAwareTestContext(TestControl testControl, ContainerAwareTestContext parent)
+        {
+            this.parent = parent;
+
+            Class<? extends ProjectStage> foundProjectStageClass;
+            if (testControl == null)
+            {
+                this.testControl = new TestControlLiteral();
+                if (parent != null)
+                {
+                    foundProjectStageClass = parent.testControl.projectStage();
+                }
+                else
+                {
+                    foundProjectStageClass = this.testControl.projectStage();
+                }
+            }
+            else
+            {
+                this.testControl = testControl;
+                foundProjectStageClass = this.testControl.projectStage();
+            }
+            this.projectStage = ProjectStage.valueOf(foundProjectStageClass.getSimpleName());
+        }
+
+        boolean isContainerStarted()
+        {
+            return this.containerStarted || (this.parent != null && this.parent.isContainerStarted()) ||
+                    CdiTestSuiteRunner.isContainerStarted();
+        }
+
+        Class<? extends Handler> getLogHandlerClass()
+        {
+            return this.testControl.logHandler();
+        }
+
+        void applyBeforeClassConfig()
+        {
+            CdiContainer container = CdiContainerLoader.getCdiContainer();
+
+            if (!isContainerStarted())
+            {
+                container.boot();
+                setContainerStarted();
+            }
+
+            List<Class<? extends Annotation>> restrictedScopes = new ArrayList<Class<? extends Annotation>>();
+
+            //controlled by the container and not supported by weld:
+            restrictedScopes.add(ApplicationScoped.class);
+            restrictedScopes.add(Singleton.class);
+
+            if (this.parent == null && this.testControl.getClass().equals(TestControlLiteral.class))
+            {
+                //skip scope-handling if @TestControl isn't used explicitly on the test-class -> TODO re-visit it
+                restrictedScopes.add(RequestScoped.class);
+                restrictedScopes.add(SessionScoped.class);
+            }
+
+            startContexts(container, restrictedScopes.toArray(new Class[restrictedScopes.size()]));
+        }
+
+        void applyAfterClassConfig()
+        {
+            CdiContainer container = CdiContainerLoader.getCdiContainer();
+
+            stopStartedScopes();
+
+            if (this.containerStarted)
+            {
+                container.shutdown(); //stop the container on the same level which started it
+            }
+        }
+
+        void applyBeforeMethodConfig()
+        {
+            this.previousProjectStage = ProjectStageProducer.getInstance().getProjectStage();
+            ProjectStageProducer.setProjectStage(this.projectStage);
+
+            startContexts(CdiContainerLoader.getCdiContainer());
+        }
+
+        void applyAfterMethodConfig()
+        {
+            try
+            {
+                stopStartedScopes();
+            }
+            finally
+            {
+                ProjectStageProducer.setProjectStage(previousProjectStage);
+                previousProjectStage = null;
+            }
+        }
+
+        void setContainerStarted()
+        {
+            this.containerStarted = true;
+        }
+
+        private void startContexts(CdiContainer container, Class<? extends Annotation>... restrictedScopes)
+        {
+            ContextControl contextControl = container.getContextControl();
+
+            List<Class<? extends Annotation>> scopeClasses = new ArrayList<Class<? extends Annotation>>();
+
+            Collections.addAll(scopeClasses, this.testControl.startScopes());
+
+            if (this.testControl.startScopes().length == 0)
+            {
+                addScopesForDefaultBehavior(scopeClasses);
+            }
+
+            for (Class<? extends Annotation> scopeAnnotation : scopeClasses)
+            {
+                if (this.parent != null && this.parent.isScopeStarted(scopeAnnotation))
+                {
+                    continue;
+                }
+
+                if (isRestrictedScope(scopeAnnotation, restrictedScopes))
+                {
+                    continue;
+                }
+
+                try
+                {
+                    contextControl.stopContext(scopeAnnotation); //force a clean context
+                    contextControl.startContext(scopeAnnotation);
+                    this.startedScopes.add(scopeAnnotation);
+                }
+                catch (RuntimeException e)
+                {
+                    Logger logger = Logger.getLogger(CdiTestRunner.class.getName());
+                    logger.setLevel(Level.SEVERE);
+                    logger.log(Level.SEVERE, "failed to start scope @" + scopeAnnotation.getName(), e);
+                }
+            }
+        }
+
+        private void addScopesForDefaultBehavior(List<Class<? extends Annotation>> scopeClasses)
+        {
+            if (this.parent != null && !this.parent.isScopeStarted(SessionScoped.class))
+            {
+                if (!scopeClasses.contains(SessionScoped.class))
+                {
+                    scopeClasses.add(SessionScoped.class);
+                }
+            }
+            if (this.parent != null && !this.parent.isScopeStarted(RequestScoped.class))
+            {
+                if (!scopeClasses.contains(RequestScoped.class))
+                {
+                    scopeClasses.add(RequestScoped.class);
+                }
+            }
+        }
+
+        private boolean isRestrictedScope(Class<? extends Annotation> scopeAnnotation,
+                                          Class<? extends Annotation>[] restrictedScopes)
+        {
+            for (Class<? extends Annotation> restrictedScope : restrictedScopes)
+            {
+                if (scopeAnnotation.equals(restrictedScope))
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private boolean isScopeStarted(Class<? extends Annotation> scopeAnnotation)
+        {
+            return this.startedScopes.contains(scopeAnnotation);
+        }
+
+        private void stopStartedScopes()
+        {
+            ContextControl contextControl = CdiContainerLoader.getCdiContainer().getContextControl();
+
+            while (!this.startedScopes.empty())
+            {
+                Class<? extends Annotation> scopeAnnotation = this.startedScopes.pop();
+                //TODO check if context was started by parent
+                try
+                {
+                    contextControl.stopContext(scopeAnnotation);
+                }
+                catch (RuntimeException e)
+                {
+                    Logger logger = Logger.getLogger(CdiTestRunner.class.getName());
+                    logger.setLevel(Level.SEVERE);
+                    logger.log(Level.SEVERE, "failed to stop scope @" + scopeAnnotation.getName(), e);
+                }
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/4a57c90a/deltaspike/modules/test-control/api/src/main/java/org/apache/deltaspike/testcontrol/api/junit/CdiTestSuiteRunner.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/test-control/api/src/main/java/org/apache/deltaspike/testcontrol/api/junit/CdiTestSuiteRunner.java b/deltaspike/modules/test-control/api/src/main/java/org/apache/deltaspike/testcontrol/api/junit/CdiTestSuiteRunner.java
new file mode 100644
index 0000000..1d795c5
--- /dev/null
+++ b/deltaspike/modules/test-control/api/src/main/java/org/apache/deltaspike/testcontrol/api/junit/CdiTestSuiteRunner.java
@@ -0,0 +1,160 @@
+/*
+ * 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.deltaspike.testcontrol.api.junit;
+
+import org.apache.deltaspike.cdise.api.CdiContainer;
+import org.apache.deltaspike.cdise.api.CdiContainerLoader;
+import org.junit.runner.Description;
+import org.junit.runner.Runner;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.Suite;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.RunnerBuilder;
+
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+@SuppressWarnings("UnusedDeclaration")
+public class CdiTestSuiteRunner extends Suite
+{
+    private static boolean containerStarted; //TODO
+
+    private final Class<?> testSuiteClass;
+
+    public CdiTestSuiteRunner(Class<?> klass, RunnerBuilder builder) throws InitializationError
+    {
+        super(klass, builder);
+        this.testSuiteClass = klass;
+    }
+
+    protected CdiTestSuiteRunner(Class<?> klass, Class<?>[] suiteClasses) throws InitializationError
+    {
+        super(klass, suiteClasses);
+        this.testSuiteClass = klass;
+    }
+
+    protected CdiTestSuiteRunner(RunnerBuilder builder, Class<?> klass, Class<?>[] suiteClasses)
+        throws InitializationError
+    {
+        super(builder, klass, suiteClasses);
+        this.testSuiteClass = klass;
+    }
+
+    protected CdiTestSuiteRunner(Class<?> klass, List<Runner> runners) throws InitializationError
+    {
+        super(klass, runners);
+        this.testSuiteClass = klass;
+    }
+
+    @Override
+    public void run(RunNotifier notifier)
+    {
+        if (this.testSuiteClass == null)
+        {
+            throw new IllegalStateException("no test-suite class found");
+        }
+
+        CdiContainer container = CdiContainerLoader.getCdiContainer();
+
+        container.boot();
+        containerStarted = true;
+
+        notifier.addListener(new LogRunListener());
+
+        try
+        {
+            super.run(notifier);
+        }
+        finally
+        {
+            container.shutdown();
+            containerStarted = false;
+        }
+    }
+
+    public static boolean isContainerStarted()
+    {
+        return containerStarted;
+    }
+
+    static class LogRunListener extends RunListener
+    {
+        private final Logger logger = Logger.getLogger(LogRunListener.class.getName());
+
+        LogRunListener()
+        {
+        }
+
+        @Override
+        public void testStarted(Description description) throws Exception
+        {
+            Level level = this.logger.getLevel();
+
+            this.logger.setLevel(Level.INFO);
+            this.logger.info("[run] " + description.getClassName() + "#" + description.getMethodName());
+            try
+            {
+                super.testRunStarted(description);
+            }
+            finally
+            {
+                this.logger.setLevel(level);
+            }
+        }
+
+        @Override
+        public void testFinished(Description description) throws Exception
+        {
+            Level level = this.logger.getLevel();
+
+            this.logger.setLevel(Level.INFO);
+            this.logger.info("[finished] " + description.getClassName() + "#" + description.getMethodName());
+            try
+            {
+                super.testFinished(description);
+            }
+            finally
+            {
+                this.logger.setLevel(level);
+            }
+        }
+
+        @Override
+        public void testFailure(Failure failure) throws Exception
+        {
+            Level level = this.logger.getLevel();
+
+            this.logger.setLevel(Level.INFO);
+            Description description = failure.getDescription();
+            this.logger.info("[failed] " + description.getClassName() + "#" + description.getMethodName() +
+                    " message: " + failure.getMessage());
+            try
+            {
+                super.testFailure(failure);
+            }
+            finally
+            {
+                this.logger.setLevel(level);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/4a57c90a/deltaspike/modules/test-control/api/src/main/java/org/apache/deltaspike/testcontrol/api/literal/TestControlLiteral.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/test-control/api/src/main/java/org/apache/deltaspike/testcontrol/api/literal/TestControlLiteral.java b/deltaspike/modules/test-control/api/src/main/java/org/apache/deltaspike/testcontrol/api/literal/TestControlLiteral.java
new file mode 100644
index 0000000..1e72856
--- /dev/null
+++ b/deltaspike/modules/test-control/api/src/main/java/org/apache/deltaspike/testcontrol/api/literal/TestControlLiteral.java
@@ -0,0 +1,57 @@
+/*
+ * 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.deltaspike.testcontrol.api.literal;
+
+import org.apache.deltaspike.core.api.projectstage.ProjectStage;
+import org.apache.deltaspike.core.util.metadata.AnnotationInstanceProvider;
+import org.apache.deltaspike.testcontrol.api.TestControl;
+
+import javax.enterprise.util.AnnotationLiteral;
+import java.lang.annotation.Annotation;
+import java.util.logging.Handler;
+
+public class TestControlLiteral extends AnnotationLiteral<TestControl> implements TestControl
+{
+    private static final long serialVersionUID = 6684011035751678259L;
+
+    private final TestControl defaultInstance;
+
+    public TestControlLiteral()
+    {
+        this.defaultInstance = AnnotationInstanceProvider.of(TestControl.class);
+    }
+
+    @Override
+    public Class<? extends Annotation>[] startScopes()
+    {
+        return defaultInstance.startScopes();
+    }
+
+    @Override
+    public Class<? extends ProjectStage> projectStage()
+    {
+        return defaultInstance.projectStage();
+    }
+
+    @Override
+    public Class<? extends Handler> logHandler()
+    {
+        return defaultInstance.logHandler();
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/4a57c90a/deltaspike/modules/test-control/api/src/main/java/org/apache/deltaspike/testcontrol/spi/junit/TestStatementDecoratorFactory.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/test-control/api/src/main/java/org/apache/deltaspike/testcontrol/spi/junit/TestStatementDecoratorFactory.java b/deltaspike/modules/test-control/api/src/main/java/org/apache/deltaspike/testcontrol/spi/junit/TestStatementDecoratorFactory.java
new file mode 100644
index 0000000..81aadec
--- /dev/null
+++ b/deltaspike/modules/test-control/api/src/main/java/org/apache/deltaspike/testcontrol/spi/junit/TestStatementDecoratorFactory.java
@@ -0,0 +1,32 @@
+/*
+ * 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.deltaspike.testcontrol.spi.junit;
+
+import org.junit.runners.model.Statement;
+import org.junit.runners.model.TestClass;
+
+//TODO find a better name
+public interface TestStatementDecoratorFactory
+{
+    Statement createBeforeStatement(Statement originalStatement, TestClass testClass, Object target);
+
+    Statement createAfterStatement(Statement originalStatement, TestClass testClass, Object target);
+
+    int getOrdinal();
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/4a57c90a/deltaspike/modules/test-control/impl/pom.xml
----------------------------------------------------------------------
diff --git a/deltaspike/modules/test-control/impl/pom.xml b/deltaspike/modules/test-control/impl/pom.xml
new file mode 100644
index 0000000..2b6c0fe
--- /dev/null
+++ b/deltaspike/modules/test-control/impl/pom.xml
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.deltaspike.modules</groupId>
+        <artifactId>test-control-module-project</artifactId>
+        <version>0.6-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.deltaspike.modules</groupId>
+    <artifactId>deltaspike-test-control-module-impl</artifactId>
+    <packaging>bundle</packaging>
+
+    <name>Apache DeltaSpike Test-Control-Module Impl</name>
+
+    <properties>
+        <deltaspike.osgi.export.pkg>
+            org.apache.deltaspike.testcontrol.impl.*
+        </deltaspike.osgi.export.pkg>
+        <deltaspike.osgi.import>
+            !org.apache.deltaspike.testcontrol.impl.*,
+            *
+        </deltaspike.osgi.import>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.deltaspike.modules</groupId>
+            <artifactId>deltaspike-test-control-module-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.deltaspike.cdictrl</groupId>
+            <artifactId>deltaspike-cdictrl-api</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-jpa_2.0_spec</artifactId>
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <inherited>true</inherited>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-source-plugin</artifactId>
+
+                <executions>
+                    <execution>
+                        <id>attach-sources</id>
+                        <goals>
+                            <goal>jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <profiles>
+        <profile>
+            <id>OWB</id>
+            <activation>
+                <activeByDefault>true</activeByDefault>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>org.apache.openwebbeans</groupId>
+                    <artifactId>openwebbeans-impl</artifactId>
+                    <scope>test</scope>
+                </dependency>
+
+                <dependency>
+                    <groupId>org.apache.openwebbeans</groupId>
+                    <artifactId>openwebbeans-spi</artifactId>
+                    <scope>test</scope>
+                </dependency>
+
+                <dependency>
+                    <groupId>org.apache.deltaspike.cdictrl</groupId>
+                    <artifactId>deltaspike-cdictrl-owb</artifactId>
+                    <scope>test</scope>
+                </dependency>
+            </dependencies>
+        </profile>
+        <profile>
+            <id>Weld</id>
+            <dependencies>
+                <dependency>
+                    <groupId>org.apache.deltaspike.cdictrl</groupId>
+                    <artifactId>deltaspike-cdictrl-weld</artifactId>
+                    <scope>test</scope>
+                </dependency>
+
+                <dependency>
+                    <groupId>org.jboss.weld.se</groupId>
+                    <artifactId>weld-se</artifactId>
+                    <version>${weld.version}</version>
+                    <scope>test</scope>
+                </dependency>
+            </dependencies>
+        </profile>
+    </profiles>
+
+</project>

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/4a57c90a/deltaspike/modules/test-control/impl/src/main/java/org/apache/deltaspike/testcontrol/impl/transaction/TransactionStatementDecoratorFactory.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/test-control/impl/src/main/java/org/apache/deltaspike/testcontrol/impl/transaction/TransactionStatementDecoratorFactory.java b/deltaspike/modules/test-control/impl/src/main/java/org/apache/deltaspike/testcontrol/impl/transaction/TransactionStatementDecoratorFactory.java
new file mode 100644
index 0000000..f92a638
--- /dev/null
+++ b/deltaspike/modules/test-control/impl/src/main/java/org/apache/deltaspike/testcontrol/impl/transaction/TransactionStatementDecoratorFactory.java
@@ -0,0 +1,177 @@
+/*
+ * 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.deltaspike.testcontrol.impl.transaction;
+
+import junit.framework.AssertionFailedError;
+import org.apache.deltaspike.core.api.provider.BeanProvider;
+import org.apache.deltaspike.core.util.ExceptionUtils;
+import org.apache.deltaspike.testcontrol.spi.junit.TestStatementDecoratorFactory;
+import org.junit.After;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.MultipleFailureException;
+import org.junit.runners.model.Statement;
+import org.junit.runners.model.TestClass;
+
+import javax.persistence.EntityManager;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Not compatible with too short scopes, because they are closed too early
+ */
+public class TransactionStatementDecoratorFactory implements TestStatementDecoratorFactory
+{
+    private static final Logger LOG = Logger.getLogger(TransactionStatementDecoratorFactory.class.getName());
+
+    static
+    {
+        LOG.setLevel(Level.INFO);
+    }
+
+    @Override
+    public Statement createBeforeStatement(Statement originalStatement, TestClass testClass, Object target)
+    {
+        return originalStatement;
+    }
+
+    @Override
+    public Statement createAfterStatement(Statement originalStatement, TestClass testClass, Object target)
+    {
+        final List<FrameworkMethod> afters = testClass.getAnnotatedMethods(After.class);
+        return new TransactionAwareRunAfters(originalStatement, afters, target);
+    }
+
+    @Override
+    public int getOrdinal()
+    {
+        return 1000; //default in ds
+    }
+
+    //see org.junit.internal.runners.statements.RunAfters
+    private class TransactionAwareRunAfters extends Statement
+    {
+        private final Statement wrapped;
+        private final List<FrameworkMethod> afters;
+        private final Object target;
+
+        public TransactionAwareRunAfters(Statement wrapped, List<FrameworkMethod> afters, Object target)
+        {
+            this.wrapped = wrapped;
+            this.afters = afters;
+            this.target = target;
+        }
+
+        @Override
+        public void evaluate() throws Throwable
+        {
+            List<Throwable> result = new ArrayList<Throwable>();
+
+            try
+            {
+                this.wrapped.evaluate();
+            }
+            catch (Throwable e)
+            {
+                result.add(performConsistencyCheck(e));
+            }
+            finally
+            {
+                Throwable t = performConsistencyCheck(null);
+
+                if (t != null)
+                {
+                    result.add(t);
+                }
+
+                for (FrameworkMethod each : this.afters)
+                {
+                    try
+                    {
+                        each.invokeExplosively(this.target);
+                    }
+                    catch (Throwable e)
+                    {
+                        result.add(e);
+                    }
+                }
+            }
+
+            if (!result.isEmpty())
+            {
+                MultipleFailureException.assertEmpty(result);
+            }
+        }
+
+        private Throwable performConsistencyCheck(Throwable t)
+        {
+            Throwable result = t;
+
+            if (t instanceof InvocationTargetException)
+            {
+                result = t.getCause();
+            }
+
+            List<EntityManager> entityManagerList =
+                    BeanProvider.getContextualReferences(EntityManager.class, true, false);
+
+            for (Field field : this.target.getClass().getDeclaredFields())
+            {
+                if (EntityManager.class.isAssignableFrom(field.getType()))
+                {
+                    field.setAccessible(true);
+                    try
+                    {
+                        entityManagerList.add((EntityManager) field.get(this.target));
+                    }
+                    catch (Exception e)
+                    {
+                        throw ExceptionUtils.throwAsRuntimeException(e);
+                    }
+                }
+            }
+
+            for (EntityManager entityManager : entityManagerList)
+            {
+                if (entityManager.getTransaction().isActive())
+                {
+                    if (t instanceof AssertionFailedError)
+                    {
+                        LOG.severe("assert failed within a transaction");
+                    }
+                    LOG.severe("start manual rollback");
+
+                    //force rollback - otherwise there can be side-effects in other tests or cleanup-code
+                    // (e.g. 'TRUNCATE SCHEMA' would fail)
+                    entityManager.getTransaction().rollback();
+
+                    if (result == null)
+                    {
+                        result = new IllegalStateException("open transaction found");
+                    }
+                }
+            }
+
+            return result;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/4a57c90a/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/shared/ApplicationScopedBean.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/shared/ApplicationScopedBean.java b/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/shared/ApplicationScopedBean.java
new file mode 100644
index 0000000..eabc48d
--- /dev/null
+++ b/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/shared/ApplicationScopedBean.java
@@ -0,0 +1,60 @@
+/*
+ * 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.deltaspike.test.testcontrol.shared;
+
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.ApplicationScoped;
+
+@ApplicationScoped
+public class ApplicationScopedBean
+{
+    private int count = 0;
+    private static int instanceCount = 0;
+
+    @PostConstruct
+    protected void init()
+    {
+        instanceCount++;
+    }
+
+    public int getCount()
+    {
+        return count;
+    }
+
+    public void increaseCount()
+    {
+        this.count++;
+    }
+
+    public void resetCount()
+    {
+        this.count = 0;
+    }
+
+    public static int getInstanceCount()
+    {
+        return instanceCount;
+    }
+
+    public static void resetInstanceCount()
+    {
+        instanceCount = 0;
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/4a57c90a/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/shared/RequestScopedBean.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/shared/RequestScopedBean.java b/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/shared/RequestScopedBean.java
new file mode 100644
index 0000000..6092540
--- /dev/null
+++ b/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/shared/RequestScopedBean.java
@@ -0,0 +1,55 @@
+/*
+ * 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.deltaspike.test.testcontrol.shared;
+
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.RequestScoped;
+
+@RequestScoped
+public class RequestScopedBean
+{
+    private int count = 0;
+    private static int instanceCount = 0;
+
+    @PostConstruct
+    protected void init()
+    {
+        instanceCount++;
+    }
+
+    public int getCount()
+    {
+        return count;
+    }
+
+    public void increaseCount()
+    {
+        this.count++;
+    }
+
+    public static int getInstanceCount()
+    {
+        return instanceCount;
+    }
+
+    public static int resetInstanceCount()
+    {
+        return instanceCount = 0;
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/4a57c90a/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/shared/SessionScopedBean.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/shared/SessionScopedBean.java b/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/shared/SessionScopedBean.java
new file mode 100644
index 0000000..719951b
--- /dev/null
+++ b/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/shared/SessionScopedBean.java
@@ -0,0 +1,39 @@
+/*
+ * 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.deltaspike.test.testcontrol.shared;
+
+import javax.enterprise.context.SessionScoped;
+import java.io.Serializable;
+
+@SessionScoped
+public class SessionScopedBean implements Serializable
+{
+    private static final long serialVersionUID = -6055362670706159152L;
+    private int count = 0;
+
+    public int getCount()
+    {
+        return count;
+    }
+
+    public void increaseCount()
+    {
+        this.count++;
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/4a57c90a/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/shared/TestUtils.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/shared/TestUtils.java b/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/shared/TestUtils.java
new file mode 100644
index 0000000..d3f3f93
--- /dev/null
+++ b/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/shared/TestUtils.java
@@ -0,0 +1,43 @@
+/*
+ * 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.deltaspike.test.testcontrol.shared;
+
+import org.junit.Test;
+
+import java.lang.reflect.Method;
+
+public abstract class TestUtils
+{
+    private TestUtils()
+    {
+    }
+
+    public static int getTestMethodCount(Class testClass)
+    {
+        int result = 0;
+        for (Method method : testClass.getDeclaredMethods())
+        {
+            if (method.isAnnotationPresent(Test.class))
+            {
+                result++;
+            }
+        }
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/4a57c90a/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/uc001/RequestAndSessionScopePerTestMethodTest.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/uc001/RequestAndSessionScopePerTestMethodTest.java b/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/uc001/RequestAndSessionScopePerTestMethodTest.java
new file mode 100644
index 0000000..05b65d8
--- /dev/null
+++ b/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/uc001/RequestAndSessionScopePerTestMethodTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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.deltaspike.test.testcontrol.uc001;
+
+import org.apache.deltaspike.core.api.provider.BeanProvider;
+import org.apache.deltaspike.testcontrol.api.junit.CdiTestRunner;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.apache.deltaspike.test.testcontrol.shared.ApplicationScopedBean;
+import org.apache.deltaspike.test.testcontrol.shared.RequestScopedBean;
+import org.apache.deltaspike.test.testcontrol.shared.SessionScopedBean;
+import org.apache.deltaspike.test.testcontrol.shared.TestUtils;
+
+import javax.inject.Inject;
+
+@RunWith(CdiTestRunner.class) //starts container once and one session + request per test-method
+//implicitly annotated with @TestControl without the default-scope settings
+public class RequestAndSessionScopePerTestMethodTest
+{
+    @Inject
+    private ApplicationScopedBean applicationScopedBean;
+
+    @Inject
+    private SessionScopedBean sessionScopedBean;
+
+    @Inject
+    private RequestScopedBean requestScopedBean;
+
+    @Test
+    //implicitly annotated with @TestControl and its default-values
+    public void firstTest()
+    {
+        applicationScopedBean.increaseCount();
+
+        Assert.assertEquals(0, requestScopedBean.getCount());
+        requestScopedBean.increaseCount();
+        Assert.assertEquals(1, requestScopedBean.getCount());
+
+        Assert.assertEquals(0, sessionScopedBean.getCount());
+        sessionScopedBean.increaseCount();
+        Assert.assertEquals(1, sessionScopedBean.getCount());
+    }
+
+    @Test
+    //implicitly annotated with @TestControl and its default-values
+    public void secondTest()
+    {
+        applicationScopedBean.increaseCount();
+
+        Assert.assertEquals(0, requestScopedBean.getCount());
+        requestScopedBean.increaseCount();
+        Assert.assertEquals(1, requestScopedBean.getCount());
+
+        Assert.assertEquals(0, sessionScopedBean.getCount());
+        sessionScopedBean.increaseCount();
+        Assert.assertEquals(1, sessionScopedBean.getCount());
+    }
+
+    @BeforeClass
+    public static void resetSharedState()
+    {
+        BeanProvider.getContextualReference(ApplicationScopedBean.class).resetCount();
+        RequestScopedBean.resetInstanceCount();
+    }
+
+    @AfterClass
+    public static void finalCheckAndCleanup()
+    {
+        int testCount = TestUtils.getTestMethodCount(RequestAndSessionScopePerTestMethodTest.class);
+
+        if (RequestScopedBean.getInstanceCount() != testCount)
+        {
+            throw new IllegalStateException("unexpected instance count");
+        }
+        RequestScopedBean.resetInstanceCount();
+
+        if (BeanProvider.getContextualReference(ApplicationScopedBean.class).getCount() != testCount)
+        {
+            throw new IllegalStateException("unexpected count");
+        }
+        BeanProvider.getContextualReference(ApplicationScopedBean.class).resetCount();
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/4a57c90a/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/uc002/SessionScopePerTestClassTest.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/uc002/SessionScopePerTestClassTest.java b/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/uc002/SessionScopePerTestClassTest.java
new file mode 100644
index 0000000..f365a54
--- /dev/null
+++ b/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/uc002/SessionScopePerTestClassTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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.deltaspike.test.testcontrol.uc002;
+
+import org.apache.deltaspike.core.api.provider.BeanProvider;
+import org.apache.deltaspike.testcontrol.api.TestControl;
+import org.apache.deltaspike.testcontrol.api.junit.CdiTestRunner;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.apache.deltaspike.test.testcontrol.shared.ApplicationScopedBean;
+import org.apache.deltaspike.test.testcontrol.shared.RequestScopedBean;
+import org.apache.deltaspike.test.testcontrol.shared.SessionScopedBean;
+import org.apache.deltaspike.test.testcontrol.shared.TestUtils;
+
+import javax.enterprise.context.SessionScoped;
+import javax.inject.Inject;
+
+@RunWith(CdiTestRunner.class) //starts container and session once and one request per test-method
+@TestControl(startScopes = SessionScoped.class)
+public class SessionScopePerTestClassTest
+{
+    @Inject
+    private ApplicationScopedBean applicationScopedBean;
+
+    @Inject
+    private SessionScopedBean sessionScopedBean;
+
+    @Inject
+    private RequestScopedBean requestScopedBean;
+
+    @Test
+    public void firstTest()
+    {
+        applicationScopedBean.increaseCount();
+        sessionScopedBean.increaseCount();
+
+        Assert.assertEquals(0, requestScopedBean.getCount());
+        requestScopedBean.increaseCount();
+        Assert.assertEquals(1, requestScopedBean.getCount());
+    }
+
+    @Test
+    public void secondTest()
+    {
+        applicationScopedBean.increaseCount();
+        sessionScopedBean.increaseCount();
+
+        Assert.assertEquals(0, requestScopedBean.getCount());
+        requestScopedBean.increaseCount();
+        Assert.assertEquals(1, requestScopedBean.getCount());
+    }
+
+    @BeforeClass
+    public static void resetSharedState()
+    {
+        BeanProvider.getContextualReference(ApplicationScopedBean.class).resetCount();
+        RequestScopedBean.resetInstanceCount();
+    }
+
+    @AfterClass
+    public static void finalCheckAndCleanup()
+    {
+        int testCount = TestUtils.getTestMethodCount(SessionScopePerTestClassTest.class);
+
+        if (RequestScopedBean.getInstanceCount() != testCount)
+        {
+            throw new IllegalStateException("unexpected instance count");
+        }
+        RequestScopedBean.resetInstanceCount();
+
+        if (BeanProvider.getContextualReference(ApplicationScopedBean.class).getCount() != testCount)
+        {
+            throw new IllegalStateException("unexpected count");
+        }
+
+        if (BeanProvider.getContextualReference(SessionScopedBean.class).getCount() != testCount)
+        {
+            throw new IllegalStateException("unexpected count");
+        }
+        BeanProvider.getContextualReference(ApplicationScopedBean.class).resetCount();
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/4a57c90a/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/uc003/RequestAndSessionScopePerTestMethodTest.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/uc003/RequestAndSessionScopePerTestMethodTest.java b/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/uc003/RequestAndSessionScopePerTestMethodTest.java
new file mode 100644
index 0000000..4623e44
--- /dev/null
+++ b/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/uc003/RequestAndSessionScopePerTestMethodTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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.deltaspike.test.testcontrol.uc003;
+
+import org.apache.deltaspike.testcontrol.api.junit.CdiTestRunner;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.apache.deltaspike.test.testcontrol.shared.ApplicationScopedBean;
+import org.apache.deltaspike.test.testcontrol.shared.RequestScopedBean;
+import org.apache.deltaspike.test.testcontrol.shared.SessionScopedBean;
+
+import javax.inject.Inject;
+
+@RunWith(CdiTestRunner.class) //starts container once and one session + request per test-method
+//implicitly annotated with @TestControl without the default-scope settings
+public class RequestAndSessionScopePerTestMethodTest
+{
+    @Inject
+    private ApplicationScopedBean applicationScopedBean;
+
+    @Inject
+    private SessionScopedBean sessionScopedBean;
+
+    @Inject
+    private RequestScopedBean requestScopedBean;
+
+    @Test
+    //implicitly annotated with @TestControl and its default-values
+    public void firstTest()
+    {
+        applicationScopedBean.increaseCount();
+
+        Assert.assertEquals(0, requestScopedBean.getCount());
+        requestScopedBean.increaseCount();
+        Assert.assertEquals(1, requestScopedBean.getCount());
+
+        Assert.assertEquals(0, sessionScopedBean.getCount());
+        sessionScopedBean.increaseCount();
+        Assert.assertEquals(1, sessionScopedBean.getCount());
+    }
+
+    @Test
+    //implicitly annotated with @TestControl and its default-values
+    public void secondTest()
+    {
+        applicationScopedBean.increaseCount();
+
+        Assert.assertEquals(0, requestScopedBean.getCount());
+        requestScopedBean.increaseCount();
+        Assert.assertEquals(1, requestScopedBean.getCount());
+
+        Assert.assertEquals(0, sessionScopedBean.getCount());
+        sessionScopedBean.increaseCount();
+        Assert.assertEquals(1, sessionScopedBean.getCount());
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/4a57c90a/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/uc003/SessionScopePerTestClassTest.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/uc003/SessionScopePerTestClassTest.java b/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/uc003/SessionScopePerTestClassTest.java
new file mode 100644
index 0000000..f1f9e1e
--- /dev/null
+++ b/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/uc003/SessionScopePerTestClassTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.deltaspike.test.testcontrol.uc003;
+
+import org.apache.deltaspike.testcontrol.api.TestControl;
+import org.apache.deltaspike.testcontrol.api.junit.CdiTestRunner;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.apache.deltaspike.test.testcontrol.shared.ApplicationScopedBean;
+import org.apache.deltaspike.test.testcontrol.shared.RequestScopedBean;
+import org.apache.deltaspike.test.testcontrol.shared.SessionScopedBean;
+
+import javax.enterprise.context.SessionScoped;
+import javax.inject.Inject;
+
+@RunWith(CdiTestRunner.class) //starts container and session once and one request per test-method
+@TestControl(startScopes = SessionScoped.class)
+public class SessionScopePerTestClassTest
+{
+    @Inject
+    private ApplicationScopedBean applicationScopedBean;
+
+    @Inject
+    private SessionScopedBean sessionScopedBean;
+
+    @Inject
+    private RequestScopedBean requestScopedBean;
+
+    @Test
+    public void firstTest()
+    {
+        applicationScopedBean.increaseCount();
+        sessionScopedBean.increaseCount();
+
+        Assert.assertEquals(0, requestScopedBean.getCount());
+        requestScopedBean.increaseCount();
+        Assert.assertEquals(1, requestScopedBean.getCount());
+    }
+
+    @Test
+    public void secondTest()
+    {
+        applicationScopedBean.increaseCount();
+        sessionScopedBean.increaseCount();
+
+        Assert.assertEquals(0, requestScopedBean.getCount());
+        requestScopedBean.increaseCount();
+        Assert.assertEquals(1, requestScopedBean.getCount());
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/4a57c90a/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/uc003/TestSuite.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/uc003/TestSuite.java b/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/uc003/TestSuite.java
new file mode 100644
index 0000000..048d6fb
--- /dev/null
+++ b/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/uc003/TestSuite.java
@@ -0,0 +1,50 @@
+/*
+ * 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.deltaspike.test.testcontrol.uc003;
+
+import org.apache.deltaspike.testcontrol.api.junit.CdiTestSuiteRunner;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.apache.deltaspike.test.testcontrol.shared.ApplicationScopedBean;
+
+@RunWith(CdiTestSuiteRunner.class) //starts container once (for the whole suite)
+@Suite.SuiteClasses({
+        RequestAndSessionScopePerTestMethodTest.class,
+        SessionScopePerTestClassTest.class
+})
+public class TestSuite
+{
+    @BeforeClass
+    public static void resetSharedState()
+    {
+        ApplicationScopedBean.resetInstanceCount();
+    }
+
+    @AfterClass
+    public static void finalCheckAndCleanup()
+    {
+        if (ApplicationScopedBean.getInstanceCount() != 1)
+        {
+            throw new IllegalStateException("unexpected count");
+        }
+        ApplicationScopedBean.resetInstanceCount();
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/4a57c90a/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/uc004/ProjectStageTestControlTest.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/uc004/ProjectStageTestControlTest.java b/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/uc004/ProjectStageTestControlTest.java
new file mode 100644
index 0000000..db1997f
--- /dev/null
+++ b/deltaspike/modules/test-control/impl/src/test/java/org/apache/deltaspike/test/testcontrol/uc004/ProjectStageTestControlTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.deltaspike.test.testcontrol.uc004;
+
+import org.apache.deltaspike.core.api.projectstage.ProjectStage;
+import org.apache.deltaspike.test.testcontrol.uc001.RequestAndSessionScopePerTestMethodTest;
+import org.apache.deltaspike.testcontrol.api.TestControl;
+import org.apache.deltaspike.testcontrol.api.junit.CdiTestRunner;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import javax.enterprise.inject.Typed;
+import javax.inject.Inject;
+
+@RunWith(CdiTestRunner.class)
+@TestControl(projectStage = ProjectStage.Development.class) //can be a custom stage
+@Typed() //needed due to RequestAndSessionScopePerTestMethodTest
+public class ProjectStageTestControlTest extends RequestAndSessionScopePerTestMethodTest //just to inherit the tests - to check that @TestControl#projectStage doesn't influence the default handling
+{
+    @Inject
+    private ProjectStage projectStage;
+
+    @Test
+    public void firstProjectStageTest()
+    {
+        Assert.assertEquals(ProjectStage.Development, this.projectStage);
+    }
+
+    @Test
+    @TestControl(projectStage = ProjectStage.UnitTest.class) //can be a custom stage - e.g. for a special test
+    public void secondProjectStageTest()
+    {
+        Assert.assertEquals(ProjectStage.UnitTest, this.projectStage);
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/4a57c90a/deltaspike/modules/test-control/impl/src/test/resources/META-INF/beans.xml
----------------------------------------------------------------------
diff --git a/deltaspike/modules/test-control/impl/src/test/resources/META-INF/beans.xml b/deltaspike/modules/test-control/impl/src/test/resources/META-INF/beans.xml
new file mode 100644
index 0000000..4070730
--- /dev/null
+++ b/deltaspike/modules/test-control/impl/src/test/resources/META-INF/beans.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<beans xmlns="http://java.sun.com/xml/ns/javaee"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
+</beans>

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/4a57c90a/deltaspike/modules/test-control/impl/src/test/resources/META-INF/services/org.apache.deltaspike.testcontrol.spi.junit.TestStatementDecoratorFactory
----------------------------------------------------------------------
diff --git a/deltaspike/modules/test-control/impl/src/test/resources/META-INF/services/org.apache.deltaspike.testcontrol.spi.junit.TestStatementDecoratorFactory b/deltaspike/modules/test-control/impl/src/test/resources/META-INF/services/org.apache.deltaspike.testcontrol.spi.junit.TestStatementDecoratorFactory
new file mode 100644
index 0000000..f609b5a
--- /dev/null
+++ b/deltaspike/modules/test-control/impl/src/test/resources/META-INF/services/org.apache.deltaspike.testcontrol.spi.junit.TestStatementDecoratorFactory
@@ -0,0 +1,19 @@
+# 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.
+
+#optional - just added to test possible side-effects
+org.apache.deltaspike.testcontrol.impl.transaction.TransactionStatementDecoratorFactory
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/4a57c90a/deltaspike/modules/test-control/pom.xml
----------------------------------------------------------------------
diff --git a/deltaspike/modules/test-control/pom.xml b/deltaspike/modules/test-control/pom.xml
new file mode 100644
index 0000000..69004ed
--- /dev/null
+++ b/deltaspike/modules/test-control/pom.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.deltaspike.modules</groupId>
+        <artifactId>modules-project</artifactId>
+        <version>0.6-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.deltaspike.modules</groupId>
+    <artifactId>test-control-module-project</artifactId>
+    <version>0.6-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <name>Apache DeltaSpike Test-Control-Module</name>
+
+    <modules>
+        <module>api</module>
+        <module>impl</module>
+    </modules>
+</project>

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/4a57c90a/deltaspike/parent/pom.xml
----------------------------------------------------------------------
diff --git a/deltaspike/parent/pom.xml b/deltaspike/parent/pom.xml
index 702b65d..043651d 100644
--- a/deltaspike/parent/pom.xml
+++ b/deltaspike/parent/pom.xml
@@ -548,6 +548,20 @@
             </dependency>
 
             <dependency>
+                <groupId>org.apache.deltaspike.modules</groupId>
+                <artifactId>deltaspike-test-control-module-api</artifactId>
+                <version>${project.version}</version>
+                <scope>compile</scope>
+            </dependency>
+
+            <dependency>
+                <groupId>org.apache.deltaspike.modules</groupId>
+                <artifactId>deltaspike-test-control-module-impl</artifactId>
+                <version>${project.version}</version>
+                <scope>runtime</scope>
+            </dependency>
+
+            <dependency>
                 <groupId>org.apache.geronimo.specs</groupId>
                 <artifactId>geronimo-servlet_2.5_spec</artifactId>
                 <version>${geronimo-servlet-2.5-spec.version}</version>


Mime
View raw message