1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.dbcp2.managed;
19
20 import static org.junit.jupiter.api.Assertions.assertEquals;
21 import static org.junit.jupiter.api.Assertions.assertThrows;
22 import static org.junit.jupiter.api.Assertions.assertTrue;
23
24 import java.sql.Connection;
25 import java.sql.PreparedStatement;
26 import java.sql.ResultSet;
27 import java.sql.SQLException;
28 import java.sql.Timestamp;
29 import java.time.Duration;
30
31 import javax.transaction.RollbackException;
32 import javax.transaction.Status;
33
34 import org.apache.commons.dbcp2.Utils;
35 import org.junit.jupiter.api.AfterEach;
36 import org.junit.jupiter.api.Assertions;
37 import org.junit.jupiter.api.BeforeEach;
38 import org.junit.jupiter.api.Test;
39
40 import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple;
41 import com.arjuna.ats.jta.common.jtaPropertyManager;
42
43
44
45
46 public class TestConnectionWithNarayana {
47 private static final String CREATE_STMT = "CREATE TABLE TEST_DATA (KEY1 VARCHAR(100), ID BIGINT, VALUE1 DOUBLE PRECISION, INFO TEXT, TS TIMESTAMP)";
48 private static final String INSERT_STMT = "INSERT INTO TEST_DATA (KEY1, ID, VALUE1, INFO, TS) VALUES (?,?,?,?,?)";
49 private static final String SELECT_STMT = "SELECT KEY1, ID, VALUE1, INFO, TS FROM TEST_DATA LIMIT 1";
50 private static final String PAYLOAD;
51 private static final String DROP_STMT = "DROP TABLE TEST_DATA";
52
53 static {
54 final StringBuilder sb = new StringBuilder();
55 sb.append("Start");
56 sb.append("payload");
57 for (int i = 0; i < 10000; i++) {
58 sb.append("...");
59 sb.append(i);
60 }
61 sb.append("End");
62 sb.append("payload");
63
64 PAYLOAD = sb.toString();
65 }
66
67 private BasicManagedDataSource mds;
68
69 @BeforeEach
70 public void setUp() throws Exception {
71 jtaPropertyManager.getJTAEnvironmentBean()
72 .setLastResourceOptimisationInterfaceClassName("org.apache.commons.dbcp2.managed.LocalXAConnectionFactory$LocalXAResource");
73 mds = new BasicManagedDataSource();
74 mds.setTransactionManager(new TransactionManagerImple());
75 mds.setDriverClassName("org.h2.Driver");
76 mds.setUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1");
77
78 mds.setMaxTotal(80);
79 mds.setMinIdle(0);
80 mds.setMaxIdle(80);
81 mds.setMinEvictableIdle(Duration.ofSeconds(10));
82 mds.setDurationBetweenEvictionRuns(Duration.ofSeconds(10));
83 mds.setLogAbandoned(true);
84 mds.setMaxWait(Duration.ofSeconds(2));
85 mds.setRemoveAbandonedOnMaintenance(true);
86 mds.setRemoveAbandonedOnBorrow(true);
87
88 mds.setRemoveAbandonedTimeout(Duration.ofSeconds(10));
89 mds.setLogExpiredConnections(true);
90 mds.setLifo(false);
91
92 try (final Connection conn = mds.getConnection()) {
93 try (final PreparedStatement ps = conn.prepareStatement(CREATE_STMT)) {
94 ps.execute();
95 }
96 }
97 }
98
99 @AfterEach
100 public void tearDown() throws Exception {
101 try (final Connection conn = mds.getConnection()) {
102 try (final PreparedStatement ps = conn.prepareStatement(DROP_STMT)) {
103 ps.execute();
104 }
105 }
106 Utils.closeQuietly(mds);
107 }
108
109 @Test
110 void testConnectionCommitAfterTimeout() throws Exception {
111 mds.getTransactionManager().setTransactionTimeout(1);
112 mds.getTransactionManager().begin();
113 try (Connection conn = mds.getConnection()) {
114 do {
115 Thread.sleep(1000);
116 } while (mds.getTransactionManager().getTransaction().getStatus() != Status.STATUS_ROLLEDBACK);
117
118 Thread.sleep(1000);
119 final SQLException e = assertThrows(SQLException.class, conn::commit);
120 assertEquals("Commit cannot be set while enrolled in a transaction", e.getMessage(), "Should not work after timeout");
121 mds.getTransactionManager().rollback();
122 }
123 assertEquals(0, mds.getNumActive());
124 }
125
126 @Test
127 void testConnectionInTimeout() throws Exception {
128 Connection conn = null;
129 PreparedStatement ps = null;
130 for (int i = 0; i < 5; i++) {
131 try {
132 mds.getTransactionManager().setTransactionTimeout(1);
133 mds.getTransactionManager().begin();
134
135 conn = mds.getConnection();
136 ps = conn.prepareStatement(INSERT_STMT);
137 ps.setString(1, Thread.currentThread().getName());
138 ps.setLong(2, i);
139 ps.setDouble(3, new java.util.Random().nextDouble());
140 ps.setString(4, PAYLOAD);
141 ps.setTimestamp(5, new Timestamp(System.currentTimeMillis()));
142 ps.execute();
143
144 int n = 0;
145 do {
146 if (mds.getTransactionManager().getTransaction().getStatus() != Status.STATUS_ACTIVE) {
147 n++;
148 }
149 try (Connection c = mds.getConnection(); PreparedStatement ps2 = c.prepareStatement(SELECT_STMT); ResultSet rs = ps2.executeQuery()) {
150
151 }
152 } while (n < 2);
153
154 ps.close();
155 ps = null;
156 conn.close();
157 conn = null;
158
159 assertThrows(RollbackException.class, () -> mds.getTransactionManager().commit());
160
161 if (mds.getTransactionManager().getTransaction() != null) {
162
163
164 mds.getTransactionManager().rollback();
165 }
166 } catch (final Exception e) {
167 if (mds.getTransactionManager().getTransaction() != null) {
168
169
170 mds.getTransactionManager().rollback();
171 }
172 } finally {
173 if (ps != null) {
174 ps.close();
175 }
176 if (conn != null) {
177 conn.close();
178 }
179 }
180 Assertions.assertEquals(0, mds.getNumActive());
181 }
182 }
183
184 @Test
185 void testRepeatedGetConnectionInTimeout() throws Exception {
186 mds.getTransactionManager().setTransactionTimeout(1);
187 mds.getTransactionManager().begin();
188 try {
189 do {
190 Thread.sleep(1000);
191 } while (mds.getTransactionManager().getTransaction().getStatus() != Status.STATUS_ROLLEDBACK);
192
193 Thread.sleep(1000);
194 final SQLException e = assertThrows(SQLException.class, mds::getConnection);
195 assertTrue(e.getCause().getClass().equals(IllegalStateException.class));
196 final SQLException e2 = assertThrows(SQLException.class, mds::getConnection);
197 assertTrue(e2.getCause().getClass().equals(IllegalStateException.class));
198 } finally {
199 mds.getTransactionManager().rollback();
200 }
201 Assertions.assertEquals(0, mds.getNumActive());
202 }
203 }