1 package com.atlassian.sal.core.rdbms;
2
3 import com.atlassian.sal.api.rdbms.ConnectionCallback;
4 import com.atlassian.sal.spi.HostConnectionAccessor;
5 import org.junit.Before;
6 import org.junit.Rule;
7 import org.junit.Test;
8 import org.junit.rules.ExpectedException;
9 import org.junit.runner.RunWith;
10 import org.mockito.Mock;
11 import org.mockito.invocation.InvocationOnMock;
12 import org.mockito.runners.MockitoJUnitRunner;
13 import org.mockito.stubbing.Answer;
14
15 import java.sql.Connection;
16 import java.sql.SQLException;
17
18 import static org.hamcrest.Matchers.nullValue;
19 import static org.hamcrest.core.Is.is;
20 import static org.junit.Assert.assertThat;
21 import static org.mockito.Matchers.any;
22 import static org.mockito.Mockito.doThrow;
23 import static org.mockito.Mockito.never;
24 import static org.mockito.Mockito.verify;
25 import static org.mockito.Mockito.when;
26
27 @RunWith (MockitoJUnitRunner.class)
28 public class TestDefaultTransactionalExecutor
29 {
30 @Rule
31 public ExpectedException expectedException = ExpectedException.none();
32
33 private DefaultTransactionalExecutor defaultTransactionalExecutor;
34
35 @Mock
36 private HostConnectionAccessor hostConnectionAccessor;
37 @Mock
38 private Connection connection;
39 @Mock
40 private ConnectionCallback<Object> callback;
41 @Mock
42 private Object result;
43
44 private WrappedConnection wrappedConnection;
45
46 private boolean callbackThrows;
47
48 @Before
49 public void before()
50 {
51 defaultTransactionalExecutor = new DefaultTransactionalExecutor(hostConnectionAccessor, false, false);
52
53 callbackThrows = false;
54
55
56 when(callback.execute(any(WrappedConnection.class))).thenAnswer(new Answer<Object>()
57 {
58 @Override
59 public Object answer(final InvocationOnMock invocation) throws Throwable
60 {
61 wrappedConnection = (WrappedConnection) invocation.getArguments()[0];
62 if (callbackThrows)
63 {
64 throw new RuntimeException("epic fail");
65 }
66 else
67 {
68 return result;
69 }
70 }
71 });
72 }
73
74 @Test
75 public void changeProperties()
76 {
77 defaultTransactionalExecutor.readOnly();
78 assertThat(defaultTransactionalExecutor.readOnly, is(true));
79
80 defaultTransactionalExecutor.readWrite();
81 assertThat(defaultTransactionalExecutor.readOnly, is(false));
82
83 defaultTransactionalExecutor.newTransaction();
84 assertThat(defaultTransactionalExecutor.newTransaction, is(true));
85
86 defaultTransactionalExecutor.existingTransaction();
87 assertThat(defaultTransactionalExecutor.newTransaction, is(false));
88 }
89
90 @Test
91 public void executeCommitSucceeds() throws SQLException
92 {
93 callbackThrows = false;
94
95 assertThat(defaultTransactionalExecutor.executeInternal(connection, callback), is(result));
96 assertThat(wrappedConnection.connection, nullValue());
97
98 verify(callback).execute(any(WrappedConnection.class));
99 verify(connection).commit();
100 verify(connection, never()).rollback();
101 }
102
103 @Test
104 public void executeCommitFails() throws SQLException
105 {
106 callbackThrows = false;
107
108 doThrow(new SQLException("horrible commit exception")).when(connection).commit();
109
110 expectedException.expect(RuntimeException.class);
111 expectedException.expectCause(is(SQLException.class));
112
113 defaultTransactionalExecutor.executeInternal(connection, callback);
114 assertThat(wrappedConnection.connection, nullValue());
115
116 verify(callback).execute(any(WrappedConnection.class));
117 verify(connection).commit();
118 verify(connection, never()).rollback();
119 }
120
121 @Test
122 public void executeRollbackSucceeds() throws SQLException
123 {
124 callbackThrows = true;
125
126 expectedException.expect(RuntimeException.class);
127 expectedException.expectMessage("epic fail");
128
129 defaultTransactionalExecutor.executeInternal(connection, callback);
130 assertThat(wrappedConnection.connection, nullValue());
131
132 verify(callback).execute(any(WrappedConnection.class));
133 verify(connection, never()).commit();
134 verify(connection).rollback();
135 }
136
137 @Test
138 public void executeRollbackFails() throws SQLException
139 {
140 callbackThrows = true;
141
142 doThrow(new SQLException("horrible rollback exception")).when(connection).rollback();
143
144 expectedException.expect(RuntimeException.class);
145 expectedException.expectMessage("epic fail");
146
147 defaultTransactionalExecutor.executeInternal(connection, callback);
148 assertThat(wrappedConnection.connection, nullValue());
149
150 verify(callback).execute(any(WrappedConnection.class));
151 verify(connection, never()).commit();
152 verify(connection).rollback();
153 }
154
155 @Test
156 public void executeFailsOnAutoCommit() throws SQLException
157 {
158 when(connection.getAutoCommit()).thenReturn(true);
159
160 expectedException.expect(IllegalStateException.class);
161
162 defaultTransactionalExecutor.executeInternal(connection, callback);
163 }
164
165 @Test
166 public void executeFailsOnAutoCommitGetFail() throws SQLException
167 {
168 when(connection.getAutoCommit()).thenThrow(new SQLException("horrible getAutoCommit exception"));
169
170 expectedException.expect(RuntimeException.class);
171
172 defaultTransactionalExecutor.executeInternal(connection, callback);
173 }
174 }