001package io.ebean.test;
002
003import io.ebean.DB;
004import io.ebean.Transaction;
005import io.ebeaninternal.api.HelpScopeTrans;
006
007/**
008 * Helper methods for testing.
009 */
010public class ForTests {
011
012  /**
013   * Enable or disable <code>@Transactional</code> methods.
014   * <p>
015   * This is intended for testing purposes such that tests
016   * on code with {@code @Transactional} methods don't actually
017   * start or complete transactions.
018   * </p>
019   *
020   * @param enable Set false to disable {@code @Transactional} methods
021   */
022  public static void enableTransactional(boolean enable) {
023    HelpScopeTrans.setEnabled(enable);
024  }
025
026  /**
027   * Run the closure with <code>@Transactional</code> methods
028   * effectively disabled (they won't create/commit transactions).
029   */
030  public static void noTransactional(Runnable run) {
031    try {
032      enableTransactional(false);
033      run.run();
034    } finally {
035      enableTransactional(true);
036    }
037  }
038
039  /**
040   * All transactions started in the closure are effectively rolled back.
041   * <p>
042   * This creates a wrapping transaction that uses {@link Transaction#setNestedUseSavepoint()}.
043   * All nested transactions are created as savepoints. On completion the wrapping
044   * transaction is rolled back.
045   * </p>
046   *
047   * @param run Closure that runs such that all the transactions are rolled back.
048   */
049  public static void rollbackAll(Runnable run) {
050
051    try (Transaction transaction = DB.beginTransaction()) {
052      transaction.setNestedUseSavepoint();
053      run.run();
054
055      transaction.rollback();
056    }
057  }
058
059  /**
060   * Create and return a RollbackAll which should be closed at the end of the test(s).
061   * <p>
062   * In tests for <code>@Before</code> we create the rollbackAll and on
063   * <code>@After</code> we <code>close()</code> it effectively rolling
064   * back all changes made during test execution.
065   * </p>
066   *
067   * <pre>{@code
068   *
069   *   private ForTests.RollbackAll rollbackAll;
070   *
071   *   @Before
072   *   public void before() {
073   *     rollbackAll = ForTests.createRollbackAll();
074   *   }
075   *
076   *   @After
077   *   public void after() {
078   *     rollbackAll.close();
079   *   }
080   *
081   *   ... tests execute and everything is rolled back
082   *
083   *
084   * }</pre>
085   */
086  public static RollbackAll createRollbackAll() {
087
088    final Transaction transaction = DB.beginTransaction();
089    transaction.setNestedUseSavepoint();
090    return new RollbackAll(transaction);
091  }
092
093  /**
094   * A wrapping transaction used in test code to rollback all changes.
095   * <p>
096   * We must ensure that <code>close()</code> is called.
097   * </p>
098   */
099  public static class RollbackAll implements AutoCloseable {
100
101    private final Transaction transaction;
102
103    private RollbackAll(Transaction transaction) {
104      this.transaction = transaction;
105    }
106
107    /**
108     * Rollback the wrapping transaction.
109     */
110    @Override
111    public void close() {
112      transaction.rollback();
113    }
114  }
115}