001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.test.context.transaction; 018 019import org.springframework.test.context.TestExecutionListeners; 020import org.springframework.transaction.TransactionStatus; 021import org.springframework.util.Assert; 022 023/** 024 * {@code TestTransaction} provides a collection of static utility methods for 025 * programmatic interaction with <em>test-managed transactions</em> within 026 * <em>test</em> methods, <em>before</em> methods, and <em>after</em> methods. 027 * 028 * <p>Consult the javadocs for {@link TransactionalTestExecutionListener} 029 * for a detailed explanation of <em>test-managed transactions</em>. 030 * 031 * <p>Support for {@code TestTransaction} is automatically available whenever 032 * the {@code TransactionalTestExecutionListener} is enabled. Note that the 033 * {@code TransactionalTestExecutionListener} is typically enabled by default, 034 * but it can also be manually enabled via the 035 * {@link TestExecutionListeners @TestExecutionListeners} annotation. 036 * 037 * @author Sam Brannen 038 * @since 4.1 039 * @see TransactionalTestExecutionListener 040 */ 041public class TestTransaction { 042 043 /** 044 * Determine whether a test-managed transaction is currently <em>active</em>. 045 * @return {@code true} if a test-managed transaction is currently active 046 * @see #start() 047 * @see #end() 048 */ 049 public static boolean isActive() { 050 TransactionContext transactionContext = TransactionContextHolder.getCurrentTransactionContext(); 051 if (transactionContext != null) { 052 TransactionStatus transactionStatus = transactionContext.getTransactionStatus(); 053 return (transactionStatus != null && !transactionStatus.isCompleted()); 054 } 055 return false; 056 } 057 058 /** 059 * Determine whether the current test-managed transaction has been 060 * {@linkplain #flagForRollback() flagged for rollback} or 061 * {@linkplain #flagForCommit() flagged for commit}. 062 * @return {@code true} if the current test-managed transaction is flagged 063 * to be rolled back; {@code false} if the current test-managed transaction 064 * is flagged to be committed 065 * @throws IllegalStateException if a transaction is not active for the 066 * current test 067 * @see #isActive() 068 * @see #flagForRollback() 069 * @see #flagForCommit() 070 */ 071 public static boolean isFlaggedForRollback() { 072 return requireCurrentTransactionContext().isFlaggedForRollback(); 073 } 074 075 /** 076 * Flag the current test-managed transaction for <em>rollback</em>. 077 * <p>Invoking this method will <em>not</em> end the current transaction. 078 * Rather, the value of this flag will be used to determine whether or not 079 * the current test-managed transaction should be rolled back or committed 080 * once it is {@linkplain #end ended}. 081 * @throws IllegalStateException if no transaction is active for the current test 082 * @see #isActive() 083 * @see #isFlaggedForRollback() 084 * @see #start() 085 * @see #end() 086 */ 087 public static void flagForRollback() { 088 setFlaggedForRollback(true); 089 } 090 091 /** 092 * Flag the current test-managed transaction for <em>commit</em>. 093 * <p>Invoking this method will <em>not</em> end the current transaction. 094 * Rather, the value of this flag will be used to determine whether or not 095 * the current test-managed transaction should be rolled back or committed 096 * once it is {@linkplain #end ended}. 097 * @throws IllegalStateException if no transaction is active for the current test 098 * @see #isActive() 099 * @see #isFlaggedForRollback() 100 * @see #start() 101 * @see #end() 102 */ 103 public static void flagForCommit() { 104 setFlaggedForRollback(false); 105 } 106 107 /** 108 * Start a new test-managed transaction. 109 * <p>Only call this method if {@link #end} has been called or if no 110 * transaction has been previously started. 111 * @throws IllegalStateException if the transaction context could not be 112 * retrieved or if a transaction is already active for the current test 113 * @see #isActive() 114 * @see #end() 115 */ 116 public static void start() { 117 requireCurrentTransactionContext().startTransaction(); 118 } 119 120 /** 121 * Immediately force a <em>commit</em> or <em>rollback</em> of the 122 * current test-managed transaction, according to the 123 * {@linkplain #isFlaggedForRollback rollback flag}. 124 * @throws IllegalStateException if the transaction context could not be 125 * retrieved or if a transaction is not active for the current test 126 * @see #isActive() 127 * @see #start() 128 */ 129 public static void end() { 130 requireCurrentTransactionContext().endTransaction(); 131 } 132 133 134 private static TransactionContext requireCurrentTransactionContext() { 135 TransactionContext txContext = TransactionContextHolder.getCurrentTransactionContext(); 136 Assert.state(txContext != null, "TransactionContext is not active"); 137 return txContext; 138 } 139 140 private static void setFlaggedForRollback(boolean flag) { 141 requireCurrentTransactionContext().setFlaggedForRollback(flag); 142 } 143 144}