1 package com.atlassian.sal.core.rdbms;
2
3 import io.atlassian.fugue.Option;
4 import com.atlassian.sal.api.rdbms.ConnectionCallback;
5 import com.atlassian.sal.api.rdbms.RdbmsException;
6 import com.atlassian.sal.spi.HostConnectionAccessor;
7 import org.junit.Before;
8 import org.junit.Rule;
9 import org.junit.Test;
10 import org.junit.rules.ExpectedException;
11 import org.mockito.Mock;
12 import org.mockito.Mockito;
13 import org.mockito.MockitoAnnotations;
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.ArgumentMatchers.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 public class TestDefaultTransactionalExecutor {
28 @Rule
29 public ExpectedException expectedException = ExpectedException.none();
30
31 private DefaultTransactionalExecutor transactionalExecutor;
32
33 @Mock
34 private HostConnectionAccessor hostConnectionAccessor;
35 @Mock
36 private Connection connection;
37 @Mock
38 private ConnectionCallback<Object> callback;
39 @Mock
40 private Object result;
41
42 private WrappedConnection wrappedConnection;
43
44 private Throwable callbackThrows;
45
46 @Before
47 public void setUp() {
48 MockitoAnnotations.initMocks(this);
49
50 transactionalExecutor = new DefaultTransactionalExecutor(hostConnectionAccessor, false, false);
51
52 callbackThrows = null;
53
54 when(hostConnectionAccessor.execute(Mockito.anyBoolean(), Mockito.anyBoolean(), any())).thenAnswer(i -> {
55 ConnectionCallback callback = (ConnectionCallback) i.getArguments()[2];
56 return callback.execute(connection);
57 });
58
59
60 when(callback.execute(any(WrappedConnection.class))).thenAnswer(i -> {
61 wrappedConnection = (WrappedConnection) i.getArguments()[0];
62 if (callbackThrows != null) {
63 throw callbackThrows;
64 } else {
65 return result;
66 }
67 });
68 }
69
70 @Test
71 public void testGetSchemaName() {
72 when(hostConnectionAccessor.getSchemaName()).thenReturn(Option.option("schema"));
73
74 assertThat(transactionalExecutor.getSchemaName().get(), is("schema"));
75 }
76
77 @Test
78 public void testChangeProperties() {
79 transactionalExecutor.readOnly();
80 assertThat(transactionalExecutor.readOnly, is(true));
81
82 transactionalExecutor.readWrite();
83 assertThat(transactionalExecutor.readOnly, is(false));
84
85 transactionalExecutor.newTransaction();
86 assertThat(transactionalExecutor.newTransaction, is(true));
87
88 transactionalExecutor.existingTransaction();
89 assertThat(transactionalExecutor.newTransaction, is(false));
90 }
91
92 @Test
93 public void testExecute() throws SQLException {
94 assertThat(transactionalExecutor.execute(callback), is(result));
95 assertThat(wrappedConnection.connection, nullValue());
96
97 verify(callback).execute(any(WrappedConnection.class));
98 verify(connection, never()).commit();
99 verify(connection, never()).rollback();
100 }
101
102 @Test
103 public void testExecuteFailsOnAutoCommit() throws SQLException {
104 when(connection.getAutoCommit()).thenReturn(true);
105
106 expectedException.expect(IllegalStateException.class);
107
108 transactionalExecutor.execute(callback);
109 }
110
111 @Test
112 public void testExecuteAutoCommitFails() throws SQLException {
113 SQLException exception = new SQLException("horrible getAutoCommit error");
114 doThrow(exception).when(connection).getAutoCommit();
115
116 expectedException.expect(RdbmsException.class);
117 expectedException.expectCause(is(exception));
118
119 transactionalExecutor.execute(callback);
120 verify(callback, never()).execute(any(WrappedConnection.class));
121 }
122
123 @Test
124 public void testExecuteFailsOnAutoCommitGetFail() throws SQLException {
125 when(connection.getAutoCommit()).thenThrow(new SQLException("horrible getAutoCommit exception"));
126
127 expectedException.expect(RdbmsException.class);
128
129 transactionalExecutor.execute(callback);
130 }
131 }