Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.microprofile.context.tck.cdi;
import org.eclipse.microprofile.context.ManagedExecutor;
import org.eclipse.microprofile.context.ThreadContext;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.testng.Arquillian;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.testng.Assert;
import org.testng.ITestResult;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Ignore;
import org.testng.annotations.Test;
import javax.enterprise.inject.spi.CDI;
import javax.inject.Inject;
import javax.transaction.NotSupportedException;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.TransactionManager;
import javax.transaction.Transactional;
import javax.transaction.UserTransaction;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
/*
* Tests for propagating transaction contexts
*/
public class JTACDITest extends Arquillian {
public static final int UNSUPPORTED = -1000;
@Inject
private TransactionalService transactionalService;
@AfterMethod
public void afterMethod(Method m, ITestResult result) {
System.out.printf("<<< END %s.%s%n", m.getName(), (result.isSuccess() ? " SUCCESS" : " FAILED"));
Throwable failure = result.getThrowable();
if (failure != null) {
failure.printStackTrace(System.out);
}
}
@BeforeMethod
public void beforeMethod(Method m) {
System.out.printf(">>> BEGIN %s.%s%n", m.getClass().getSimpleName(), m.getName());
}
@Deployment
public static WebArchive createDeployment() {
return ShrinkWrap.create(WebArchive.class, JTACDITest.class.getSimpleName() + ".war")
.addClasses(TransactionalBean.class, TransactionalBeanImpl.class, TransactionalService.class)
.addClass(JTACDITest.class);
}
/*
* use a CDI injected transaction manager to:
* - start a transaction and then,
* - run single asynchronous stage and then
* - verify that a transaction scoped bean is updated correctly and finally
* - finish the transaction
*/
@Test
public void testTransaction() throws Exception {
// create an executor that propagates the transaction context
ManagedExecutor executor = createExecutor("testTransaction");
UserTransaction ut = getUserTransaction("testTransaction");
if (executor == null || ut == null) {
return; // the implementation does not support transaction propagation
}
try {
// enter transaction scope by starting a transaction
ut.begin();
int initialValue = transactionalService.getValue(); // transaction scoped beans will be available
// call a transactional bean on another thread to validate that the transaction context propagates
CompletableFuture stage;
try {
stage = executor.runAsync(() -> transactionalService.mandatory());
}
catch (IllegalStateException x) {
System.out.println("Propagation of active transactions is not supported. Skipping test.");
return;
}
try {
stage.join();
}
catch (CompletionException x) {
if (x.getCause() instanceof IllegalStateException) {
System.out.println("Propagation of active transactions to multiple threads in parallel is not supported. Skipping test.");
return;
}
else {
throw x;
}
}
// we are still in transaction context so transaction scoped beans will still be available
Assert.assertEquals(initialValue + 1, transactionalService.getValue());
}
finally {
// Must end the transaction in the same thread it was started from.
// If it is ended by an executor thread then the transaction context provider
// will re-associate the terminated transaction with the initiating thread when
// the executor fiishes.
try {
ut.rollback();
try {
// transaction scoped beans should no longer be available since the
// transaction will have been disassociated
transactionalService.getValue();
Assert.fail("TransactionScoped bean should only be available from transaction scope");
}
catch (Exception ignore) {
// expected since we are no longer in the scope of a transactions
}
}
finally {
verifyNoTransaction();
}
}
}
/*
* same as testTransaction but using @Transactional for transaction demarcation
*/
@Test
public void testAsyncTransaction() {
// create an executor that propagates the transaction context
ManagedExecutor executor = createExecutor("testAsyncTransaction");
if (executor == null) {
return; // the implementation does not support transaction propagation
}
try {
// delegate this test to transactionalService which manages transactional
// boundaries using the @Transactional annotation
int result = transactionalService.testAsync(executor);
if (result != UNSUPPORTED) {
Assert.assertEquals(1, result,
"testAsyncTransaction failed%n");
}
verifyNoTransaction();
}
finally {
executor.shutdownNow();
}
}
/*
* run asynchronous stages, one after the other, where each stage tests
* one of the Transactional.TxType element attributes
* (MANDATORY, NEVER, NOT_SUPPORTED, REQUIRED, REQUIRES_NEW, SUPPORTS).
* Validate that a transaction scoped bean is updated in accordance
* with the semantics of this element.
*/
@Test
public void testTransactionPropagation() throws Exception {
// create an executor that propagates the transaction context
ManagedExecutor executor = createExecutor("testTransactionPropagation");
UserTransaction ut = getUserTransaction("testTransactionPropagation");
if (executor == null || ut == null) {
return;
}
try {
try {
ut.begin();
int currentValue = transactionalService.getValue(); // the bean should be in scope
CompletableFuture stage0;
try {
// run various transactional updates on the executor
stage0 = executor.runAsync(() -> {
transactionalService.required(); // invoke a method that requires a transaction
// the service call should have updated the bean in this transaction scope
Assert.assertEquals(currentValue + 1, transactionalService.getValue());
});
}
catch (IllegalStateException x) {
System.out.println("Propagation of active transactions is not supported. Skipping test.");
return;
}
CompletableFuture stage1= stage0.thenRunAsync(() -> {
transactionalService.requiresNew();
// the service call should have updated a different bean in a different transaction scope
Assert.assertEquals(currentValue + 1, transactionalService.getValue());
}).thenRunAsync(() -> {
// the service call should have updated the bean in this transaction scope
transactionalService.supports();
Assert.assertEquals(currentValue + 2, transactionalService.getValue());
}).thenRunAsync(() -> {
// updating a transaction scoped bean outside of a transacction should fail
if (callServiceExpectFailure(Transactional.TxType.NEVER.name(),
TransactionalService::never, transactionalService)) {
// true means the feature is supported
Assert.assertEquals(currentValue + 2, transactionalService.getValue());
}
}).thenRunAsync(() -> {
// updating a transaction scoped bean outside of a transacction should fail
if (callServiceExpectFailure(Transactional.TxType.NOT_SUPPORTED.name(),
TransactionalService::notSupported, transactionalService)) {
// true means the feature is supported
Assert.assertEquals(currentValue + 2, transactionalService.getValue());
}
}).thenRunAsync(() -> {
transactionalService.mandatory();
// the service call should have updated the bean in this transaction scope
Assert.assertEquals(currentValue + 3, transactionalService.getValue());
});
try {
stage1.join();
}
catch (CompletionException x) {
if (x.getCause() instanceof IllegalStateException) {
System.out.println("Propagation of active transactions to multiple threads in parallel is not supported. Skipping test.");
return;
}
else {
throw x;
}
}
Assert.assertEquals(currentValue + 3, transactionalService.getValue());
}
finally {
ut.rollback();
}
}
finally {
executor.shutdownNow();
}
}
/*
* Start two concurrent asynchronous stages and verify that
* a transaction scoped bean is updated twice.
*/
@Test
@Ignore
public void testConcurrentTransactionPropagation() {
// create an executor that propagates the transaction context
ManagedExecutor executor = createExecutor("testConcurrentTransactionPropagation");
UserTransaction ut = getUserTransaction("testConcurrentTransactionPropagation");
if (executor == null || ut == null) {
return; // the implementation does not support transaction propagation
}
try {
int result = transactionalService.testConcurrentTransactionPropagation(executor);
if (result != UNSUPPORTED) {
Assert.assertEquals(2, result, "testTransactionPropagation failed%n");
}
verifyNoTransaction();
}
finally {
executor.shutdownNow();
}
}
/*
* run under the transaction that is activate on the thread at the time when a task runs
*/
@Test
public void testRunWithTxnOfExecutingThread() throws SystemException, NotSupportedException {
ThreadContext threadContext = ThreadContext.builder()
.propagated()
.unchanged(ThreadContext.TRANSACTION)
.cleared(ThreadContext.ALL_REMAINING)
.build();
UserTransaction ut = getUserTransaction("testRunWithTxnOfExecutingThread");
if (threadContext == null || ut == null) {
return; // the implementation does not support transaction propagation
}
Callable isInTransaction =
threadContext.contextualCallable(() -> ut.getStatus() == Status.STATUS_ACTIVE);
ut.begin();
try {
Assert.assertTrue(isInTransaction.call());
}
catch (Exception e) {
Assert.fail("testRunWithTxnOfExecutingThread: a transaction should have been active");
}
finally {
ut.rollback();
}
}
@Test
public void testTransactionWithUT() throws Exception {
// create an executor that propagates the transaction context
ManagedExecutor executor = createExecutor("testTransactionWithUT");
UserTransaction ut = getUserTransaction("testConcurrentTransactionPropagation");
if (executor == null || ut == null) {
return; // the implementation does not support transaction propagation
}
TransactionalService service = CDI.current().select(TransactionalService.class).get();
ut.begin();
Assert.assertEquals(0, service.getValue());
CompletableFuture stage;
try {
stage = executor.runAsync(service::mandatory);
}
catch (IllegalStateException x) {
System.out.println("Propagation of active transactions is not supported. Skipping test.");
return;
}
try {
stage.join();
}
catch (CompletionException x) {
if (x.getCause() instanceof IllegalStateException) {
System.out.println("Propagation of active transactions to multiple threads in parallel is not supported. Skipping test.");
return;
}
else {
throw x;
}
}
try {
ut.rollback();
Assert.assertEquals(ut.getStatus(), Status.STATUS_NO_TRANSACTION,
"transaction still active");
}
catch (SystemException e) {
e.printStackTrace();
}
}
@FunctionalInterface
interface TransactionalServiceCall {
void apply(TransactionalService ts);
}
// utility mehtod to avoid having to duplicate code
private boolean callServiceExpectFailure(String txType,
TransactionalServiceCall op,
TransactionalService ts) {
try {
ThreadContext.builder()
.propagated()
.cleared(ThreadContext.TRANSACTION)
.unchanged(ThreadContext.ALL_REMAINING)
.build().contextualRunnable(() -> callServiceWithoutContextExpectFailure(op, ts)).run();
return true;
}
catch (IllegalStateException e) {
System.out.printf("Skipping testTransactionPropagation for %s. Transaction context propagation is not supported.%n",
txType);
return false;
}
}
private void callServiceWithoutContextExpectFailure(TransactionalServiceCall op,
TransactionalService ts) {
try {
op.apply(ts);
Assert.fail("TransactionScoped bean should only be available from transaction scope");
}
catch (Exception ignore) {
// expected
}
}
// verify that there the is no transaction associated with the calling thread
private void verifyNoTransaction() {
try {
TransactionManager transactionManager = CDI.current().select(TransactionManager.class).get();
try {
if (transactionManager.getTransaction() != null) {
Assert.fail("transaction still active");
}
}
catch (SystemException e) {
Assert.fail("Could verify that no transaction is associated", e);
}
}
catch (Exception ignore) {
// the implementation does not expose a JTA TM as a CDI bean
}
}
/*
* Locate a UserTransaction bean
*/
private UserTransaction getUserTransaction(String testName) {
try {
return CDI.current().select(UserTransaction.class).get();
}
catch (IllegalStateException x) {
System.out.printf("Skipping test %s. UserTransaction is not available.%n", testName);
return null;
}
}
/*
* Create a manager executor that propagates transaction context
*/
private ManagedExecutor createExecutor(String testName) {
try {
return ManagedExecutor.builder()
.maxAsync(2)
.propagated(ThreadContext.TRANSACTION)
.cleared(ThreadContext.ALL_REMAINING)
.build();
}
catch (IllegalStateException x) {
System.out.printf("Skipping test %s. Transaction context propagation is not supported.%n",
testName);
return null;
}
}
}