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.assertFalse;
22 import static org.junit.jupiter.api.Assertions.assertNull;
23 import static org.junit.jupiter.api.Assertions.assertThrows;
24 import static org.junit.jupiter.api.Assertions.assertTrue;
25
26 import java.sql.Array;
27 import java.sql.Blob;
28 import java.sql.CallableStatement;
29 import java.sql.Clob;
30 import java.sql.Connection;
31 import java.sql.DatabaseMetaData;
32 import java.sql.NClob;
33 import java.sql.PreparedStatement;
34 import java.sql.SQLClientInfoException;
35 import java.sql.SQLException;
36 import java.sql.SQLWarning;
37 import java.sql.SQLXML;
38 import java.sql.Savepoint;
39 import java.sql.Statement;
40 import java.sql.Struct;
41 import java.util.Map;
42 import java.util.Properties;
43 import java.util.concurrent.Executor;
44
45 import javax.transaction.xa.XAException;
46 import javax.transaction.xa.XAResource;
47 import javax.transaction.xa.Xid;
48
49 import org.junit.jupiter.api.BeforeEach;
50 import org.junit.jupiter.api.Test;
51
52
53
54
55 public class TestLocalXaResource {
56
57 private static final class TestConnection implements Connection {
58
59 public boolean throwWhenGetAutoCommit;
60 public boolean throwWhenSetAutoCommit;
61 boolean autoCommit;
62 boolean readOnly;
63 public boolean committed;
64 public boolean rolledback;
65 public boolean closed;
66
67 @Override
68 public void abort(final Executor executor) throws SQLException {
69 }
70
71 @Override
72 public void clearWarnings() throws SQLException {
73 }
74
75 @Override
76 public void close() throws SQLException {
77 closed = true;
78 }
79
80 @Override
81 public void commit() throws SQLException {
82 committed = true;
83 }
84
85 @Override
86 public Array createArrayOf(final String typeName, final Object[] elements) throws SQLException {
87 return null;
88 }
89
90 @Override
91 public Blob createBlob() throws SQLException {
92 return null;
93 }
94
95 @Override
96 public Clob createClob() throws SQLException {
97 return null;
98 }
99
100 @Override
101 public NClob createNClob() throws SQLException {
102 return null;
103 }
104
105 @Override
106 public SQLXML createSQLXML() throws SQLException {
107 return null;
108 }
109
110 @Override
111 public Statement createStatement() throws SQLException {
112 return null;
113 }
114
115 @Override
116 public Statement createStatement(final int resultSetType, final int resultSetConcurrency) throws SQLException {
117 return null;
118 }
119
120 @Override
121 public Statement createStatement(final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability)
122 throws SQLException {
123 return null;
124 }
125
126 @Override
127 public Struct createStruct(final String typeName, final Object[] attributes) throws SQLException {
128 return null;
129 }
130
131 @Override
132 public boolean getAutoCommit() throws SQLException {
133 if (throwWhenGetAutoCommit) {
134 throw new SQLException();
135 }
136 return autoCommit;
137 }
138
139 @Override
140 public String getCatalog() throws SQLException {
141 return null;
142 }
143
144 @Override
145 public Properties getClientInfo() throws SQLException {
146 return null;
147 }
148
149 @Override
150 public String getClientInfo(final String name) throws SQLException {
151 return null;
152 }
153
154 @Override
155 public int getHoldability() throws SQLException {
156 return 0;
157 }
158
159 @Override
160 public DatabaseMetaData getMetaData() throws SQLException {
161 return null;
162 }
163
164 @Override
165 public int getNetworkTimeout() throws SQLException {
166 return 0;
167 }
168
169 @Override
170 public String getSchema() throws SQLException {
171 return null;
172 }
173
174 @Override
175 public int getTransactionIsolation() throws SQLException {
176 return 0;
177 }
178
179 @Override
180 public Map<String, Class<?>> getTypeMap() throws SQLException {
181 return null;
182 }
183
184 @Override
185 public SQLWarning getWarnings() throws SQLException {
186 return null;
187 }
188
189 @Override
190 public boolean isClosed() throws SQLException {
191 return closed;
192 }
193
194 @Override
195 public boolean isReadOnly() throws SQLException {
196 return readOnly;
197 }
198
199 @Override
200 public boolean isValid(final int timeout) throws SQLException {
201 return false;
202 }
203
204 @Override
205 public boolean isWrapperFor(final Class<?> iface) throws SQLException {
206 return false;
207 }
208
209 @Override
210 public String nativeSQL(final String sql) throws SQLException {
211 return null;
212 }
213
214 @Override
215 public CallableStatement prepareCall(final String sql) throws SQLException {
216 return null;
217 }
218
219 @Override
220 public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency)
221 throws SQLException {
222 return null;
223 }
224
225 @Override
226 public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency,
227 final int resultSetHoldability) throws SQLException {
228 return null;
229 }
230
231 @Override
232 public PreparedStatement prepareStatement(final String sql) throws SQLException {
233 return null;
234 }
235
236 @Override
237 public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException {
238 return null;
239 }
240
241 @Override
242 public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency)
243 throws SQLException {
244 return null;
245 }
246
247 @Override
248 public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency,
249 final int resultSetHoldability) throws SQLException {
250 return null;
251 }
252
253 @Override
254 public PreparedStatement prepareStatement(final String sql, final int[] columnIndexes) throws SQLException {
255 return null;
256 }
257
258 @Override
259 public PreparedStatement prepareStatement(final String sql, final String[] columnNames) throws SQLException {
260 return null;
261 }
262
263 @Override
264 public void releaseSavepoint(final Savepoint savepoint) throws SQLException {
265 }
266
267 @Override
268 public void rollback() throws SQLException {
269 rolledback = true;
270 }
271
272 @Override
273 public void rollback(final Savepoint savepoint) throws SQLException {
274 }
275
276 @Override
277 public void setAutoCommit(final boolean autoCommit) throws SQLException {
278 if (throwWhenSetAutoCommit) {
279 throw new SQLException();
280 }
281 this.autoCommit = autoCommit;
282 }
283
284 @Override
285 public void setCatalog(final String catalog) throws SQLException {
286 }
287
288 @Override
289 public void setClientInfo(final Properties properties) throws SQLClientInfoException {
290 }
291
292 @Override
293 public void setClientInfo(final String name, final String value) throws SQLClientInfoException {
294 }
295
296 @Override
297 public void setHoldability(final int holdability) throws SQLException {
298 }
299
300 @Override
301 public void setNetworkTimeout(final Executor executor, final int milliseconds) throws SQLException {
302 }
303
304 @Override
305 public void setReadOnly(final boolean readOnly) throws SQLException {
306 this.readOnly = readOnly;
307 }
308
309 @Override
310 public Savepoint setSavepoint() throws SQLException {
311 return null;
312 }
313
314 @Override
315 public Savepoint setSavepoint(final String name) throws SQLException {
316 return null;
317 }
318
319 @Override
320 public void setSchema(final String schema) throws SQLException {
321 }
322
323 @Override
324 public void setTransactionIsolation(final int level) throws SQLException {
325 }
326
327 @Override
328 public void setTypeMap(final Map<String, Class<?>> map) throws SQLException {
329 }
330
331 @Override
332 public <T> T unwrap(final Class<T> iface) throws SQLException {
333 return null;
334 }
335 }
336 private static final class TestXid implements Xid {
337
338 @Override
339 public byte[] getBranchQualifier() {
340 return null;
341 }
342
343 @Override
344 public int getFormatId() {
345 return 0;
346 }
347
348 @Override
349 public byte[] getGlobalTransactionId() {
350 return null;
351 }
352 }
353
354 private Connection conn;
355
356 private LocalXAConnectionFactory.LocalXAResource resource;
357
358 @BeforeEach
359 public void setUp() {
360 conn = new TestConnection();
361 resource = new LocalXAConnectionFactory.LocalXAResource(conn);
362 }
363
364 @Test
365 public void testCommit() throws SQLException, XAException {
366 final Xid xid = new TestXid();
367 ((TestConnection) conn).closed = false;
368 conn.setReadOnly(false);
369 resource.start(xid, XAResource.TMNOFLAGS);
370 resource.commit(xid, false);
371 assertTrue(((TestConnection) conn).committed);
372 }
373
374 @Test
375 public void testCommitConnectionClosed() throws SQLException, XAException {
376 final Xid xid = new TestXid();
377 ((TestConnection) conn).closed = true;
378 conn.setReadOnly(false);
379 resource.start(xid, XAResource.TMNOFLAGS);
380 assertThrows(XAException.class, () -> resource.commit(xid, false));
381 }
382
383 @Test
384 public void testCommitConnectionNotReadOnly() throws SQLException, XAException {
385 final Xid xid = new TestXid();
386 ((TestConnection) conn).closed = false;
387 conn.setReadOnly(true);
388 resource.start(xid, XAResource.TMNOFLAGS);
389 resource.commit(xid, false);
390 assertFalse(((TestConnection) conn).committed);
391 }
392
393 @Test
394 public void testCommitInvalidXid() throws SQLException, XAException {
395 final Xid xid = new TestXid();
396 ((TestConnection) conn).closed = false;
397 conn.setReadOnly(false);
398 resource.start(xid, XAResource.TMNOFLAGS);
399 assertThrows(XAException.class, () -> resource.commit(new TestXid(), false));
400 }
401
402 @Test
403 public void testCommitMissingXid() {
404 assertThrows(NullPointerException.class, () -> resource.commit(null, false));
405 }
406
407 @Test
408 public void testCommitNoTransaction() throws SQLException {
409 ((TestConnection) conn).closed = false;
410 conn.setReadOnly(false);
411 assertThrows(XAException.class, () -> resource.commit(new TestXid(), false));
412 }
413
414 @Test
415 public void testConstructor() {
416 assertEquals(0, resource.getTransactionTimeout());
417 assertNull(resource.getXid());
418
419 assertFalse(resource.setTransactionTimeout(100));
420
421 assertEquals(0, resource.recover(100).length);
422 }
423
424 @Test
425 public void testForget() throws XAException {
426 final Xid xid = new TestXid();
427 resource.start(xid, XAResource.TMNOFLAGS);
428 resource.forget(xid);
429 assertNull(resource.getXid());
430 }
431
432 @Test
433 public void testForgetDifferentXid() throws XAException {
434 final Xid xid = new TestXid();
435 resource.start(xid, XAResource.TMNOFLAGS);
436 resource.forget(new TestXid());
437 assertEquals(xid, resource.getXid());
438 }
439
440 @Test
441 public void testForgetMissingXid() throws XAException {
442 final Xid xid = new TestXid();
443 resource.start(xid, XAResource.TMNOFLAGS);
444 resource.forget(null);
445 assertEquals(xid, resource.getXid());
446 }
447
448 @Test
449 public void testIsSame() {
450 assertTrue(resource.isSameRM(resource));
451 assertFalse(resource.isSameRM(new LocalXAConnectionFactory.LocalXAResource(conn)));
452 }
453
454 @Test
455 public void testRollback() throws SQLException, XAException {
456 final Xid xid = new TestXid();
457 ((TestConnection) conn).closed = false;
458 conn.setReadOnly(false);
459 resource.start(xid, XAResource.TMNOFLAGS);
460 resource.rollback(xid);
461 assertTrue(((TestConnection) conn).rolledback);
462 }
463
464 @Test
465 public void testRollbackInvalidXid() throws SQLException, XAException {
466 final Xid xid = new TestXid();
467 ((TestConnection) conn).closed = false;
468 conn.setReadOnly(false);
469 resource.start(xid, XAResource.TMNOFLAGS);
470 assertThrows(XAException.class, () -> resource.rollback(new TestXid()));
471 }
472
473 @Test
474 public void testRollbackMissingXid() {
475 assertThrows(NullPointerException.class, () -> resource.rollback(null));
476 }
477
478
479
480
481
482
483
484 @Test
485 public void testStartExceptionOnGetAutoCommit() throws XAException, SQLException {
486 final Xid xid = new TestXid();
487 ((TestConnection) conn).throwWhenGetAutoCommit = true;
488 conn.setAutoCommit(false);
489 conn.setReadOnly(true);
490
491
492 resource.start(xid, XAResource.TMNOFLAGS);
493
494 resource.prepare(xid);
495 ((TestConnection) conn).throwWhenGetAutoCommit = false;
496 assertTrue(conn.getAutoCommit());
497 }
498
499 @Test
500 public void testStartFailsWhenCannotSetAutoCommit() {
501 final Xid xid = new TestXid();
502 ((TestConnection) conn).throwWhenSetAutoCommit = true;
503 assertThrows(XAException.class, () -> resource.start(xid, XAResource.TMNOFLAGS));
504 }
505
506 @Test
507 public void testStartInvalidFlag() {
508
509 assertThrows(XAException.class, () -> resource.start(null, XAResource.TMENDRSCAN));
510 }
511
512 @Test
513 public void testStartNoFlagButAlreadyEnlisted() throws XAException {
514 resource.start(new TestXid(), XAResource.TMNOFLAGS);
515 assertThrows(XAException.class, () -> resource.start(new TestXid(), XAResource.TMNOFLAGS));
516 }
517
518 @Test
519 public void testStartNoFlagResume() throws XAException {
520 final Xid xid = new TestXid();
521 resource.start(xid, XAResource.TMNOFLAGS);
522 resource.start(xid, XAResource.TMRESUME);
523 assertEquals(xid, resource.getXid());
524 }
525
526 @Test
527 public void testStartNoFlagResumeButDifferentXid() throws XAException {
528 resource.start(new TestXid(), XAResource.TMNOFLAGS);
529 assertThrows(XAException.class, () -> resource.start(new TestXid(), XAResource.TMRESUME));
530 }
531
532 @Test
533 public void testStartNoFlagResumeEnd() throws XAException {
534 final Xid xid = new TestXid();
535 resource.start(xid, XAResource.TMNOFLAGS);
536 resource.start(xid, XAResource.TMRESUME);
537
538 resource.end(xid, 0);
539 assertEquals(xid, resource.getXid());
540 }
541
542 @Test
543 public void testStartNoFlagResumeEndDifferentXid() throws XAException {
544 final Xid xid = new TestXid();
545 resource.start(xid, XAResource.TMNOFLAGS);
546 resource.start(xid, XAResource.TMRESUME);
547
548 assertThrows(XAException.class, () -> resource.end(new TestXid(), 0));
549 }
550
551 @Test
552 public void testStartNoFlagResumeEndMissingXid() throws XAException {
553 final Xid xid = new TestXid();
554 resource.start(xid, XAResource.TMNOFLAGS);
555 resource.start(xid, XAResource.TMRESUME);
556
557 assertThrows(NullPointerException.class, () -> resource.end(null, 0));
558 }
559
560
561
562
563
564
565
566
567 @Test
568 public void testStartReadOnlyConnectionExceptionOnGetAutoCommit() throws XAException, SQLException {
569 final Xid xid = new TestXid();
570 ((TestConnection) conn).throwWhenGetAutoCommit = true;
571 conn.setAutoCommit(false);
572 conn.setReadOnly(false);
573
574
575 resource.start(xid, XAResource.TMNOFLAGS);
576
577 resource.prepare(xid);
578 ((TestConnection) conn).throwWhenGetAutoCommit = false;
579 assertFalse(conn.getAutoCommit());
580 }
581
582 @Test
583 public void testStartReadOnlyConnectionPrepare() throws XAException, SQLException {
584 final Xid xid = new TestXid();
585 conn.setAutoCommit(false);
586 conn.setReadOnly(true);
587 resource.start(xid, XAResource.TMNOFLAGS);
588 resource.prepare(xid);
589 assertFalse(conn.getAutoCommit());
590 }
591 }