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 final class TestTransaction { 042 043 044 private TestTransaction() { 045 } 046 047 048 /** 049 * Determine whether a test-managed transaction is currently <em>active</em>. 050 * @return {@code true} if a test-managed transaction is currently active 051 * @see #start() 052 * @see #end() 053 */ 054 public static boolean isActive() { 055 TransactionContext transactionContext = TransactionContextHolder.getCurrentTransactionContext(); 056 if (transactionContext != null) { 057 TransactionStatus transactionStatus = transactionContext.getTransactionStatus(); 058 return (transactionStatus != null && !transactionStatus.isCompleted()); 059 } 060 return false; 061 } 062 063 /** 064 * Determine whether the current test-managed transaction has been 065 * {@linkplain #flagForRollback() flagged for rollback} or 066 * {@linkplain #flagForCommit() flagged for commit}. 067 * @return {@code true} if the current test-managed transaction is flagged 068 * to be rolled back; {@code false} if the current test-managed transaction 069 * is flagged to be committed 070 * @throws IllegalStateException if a transaction is not active for the 071 * current test 072 * @see #isActive() 073 * @see #flagForRollback() 074 * @see #flagForCommit() 075 */ 076 public static boolean isFlaggedForRollback() { 077 return requireCurrentTransactionContext().isFlaggedForRollback(); 078 } 079 080 /** 081 * Flag the current test-managed transaction for <em>rollback</em>. 082 * <p>Invoking this method will <em>not</em> end the current transaction. 083 * Rather, the value of this flag will be used to determine whether or not 084 * the current test-managed transaction should be rolled back or committed 085 * once it is {@linkplain #end ended}. 086 * @throws IllegalStateException if no transaction is active for the current test 087 * @see #isActive() 088 * @see #isFlaggedForRollback() 089 * @see #start() 090 * @see #end() 091 */ 092 public static void flagForRollback() { 093 setFlaggedForRollback(true); 094 } 095 096 /** 097 * Flag the current test-managed transaction for <em>commit</em>. 098 * <p>Invoking this method will <em>not</em> end the current transaction. 099 * Rather, the value of this flag will be used to determine whether or not 100 * the current test-managed transaction should be rolled back or committed 101 * once it is {@linkplain #end ended}. 102 * @throws IllegalStateException if no transaction is active for the current test 103 * @see #isActive() 104 * @see #isFlaggedForRollback() 105 * @see #start() 106 * @see #end() 107 */ 108 public static void flagForCommit() { 109 setFlaggedForRollback(false); 110 } 111 112 /** 113 * Start a new test-managed transaction. 114 * <p>Only call this method if {@link #end} has been called or if no 115 * transaction has been previously started. 116 * @throws IllegalStateException if the transaction context could not be 117 * retrieved or if a transaction is already active for the current test 118 * @see #isActive() 119 * @see #end() 120 */ 121 public static void start() { 122 requireCurrentTransactionContext().startTransaction(); 123 } 124 125 /** 126 * Immediately force a <em>commit</em> or <em>rollback</em> of the 127 * current test-managed transaction, according to the 128 * {@linkplain #isFlaggedForRollback rollback flag}. 129 * @throws IllegalStateException if the transaction context could not be 130 * retrieved or if a transaction is not active for the current test 131 * @see #isActive() 132 * @see #start() 133 */ 134 public static void end() { 135 requireCurrentTransactionContext().endTransaction(); 136 } 137 138 139 private static TransactionContext requireCurrentTransactionContext() { 140 TransactionContext txContext = TransactionContextHolder.getCurrentTransactionContext(); 141 Assert.state(txContext != null, "TransactionContext is not active"); 142 return txContext; 143 } 144 145 private static void setFlaggedForRollback(boolean flag) { 146 requireCurrentTransactionContext().setFlaggedForRollback(flag); 147 } 148 149}