001: /*
002: * HA-JDBC: High-Availability JDBC
003: * Copyright (c) 2004-2008 Paul Ferraro
004: *
005: * This library is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU Lesser General Public License as published by the
007: * Free Software Foundation; either version 2.1 of the License, or (at your
008: * option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful, but WITHOUT
011: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
012: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
013: * for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public License
016: * along with this library; if not, write to the Free Software Foundation,
017: * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: *
019: * Contact: ferraro@users.sourceforge.net
020: */
021: package net.sf.hajdbc.sql.xa;
022:
023: import java.util.Map;
024: import java.util.Set;
025: import java.util.TreeMap;
026: import java.util.concurrent.ExecutorService;
027: import java.util.concurrent.Executors;
028: import java.util.concurrent.locks.Lock;
029:
030: import javax.sql.XAConnection;
031: import javax.transaction.xa.XAException;
032: import javax.transaction.xa.XAResource;
033: import javax.transaction.xa.Xid;
034:
035: import net.sf.hajdbc.Balancer;
036: import net.sf.hajdbc.Database;
037: import net.sf.hajdbc.DatabaseCluster;
038: import net.sf.hajdbc.LockManager;
039: import net.sf.hajdbc.MockDatabase;
040: import net.sf.hajdbc.sql.Invoker;
041: import net.sf.hajdbc.sql.SQLProxy;
042: import net.sf.hajdbc.util.reflect.ProxyFactory;
043:
044: import org.easymock.EasyMock;
045: import org.testng.annotations.AfterMethod;
046: import org.testng.annotations.BeforeClass;
047: import org.testng.annotations.BeforeMethod;
048: import org.testng.annotations.DataProvider;
049: import org.testng.annotations.Test;
050:
051: /**
052: * @author Paul Ferraro
053: *
054: */
055: @SuppressWarnings("unchecked")
056: public class TestXAResource implements XAResource {
057: private Balancer balancer = EasyMock
058: .createStrictMock(Balancer.class);
059: private DatabaseCluster cluster = EasyMock
060: .createStrictMock(DatabaseCluster.class);
061: private XAResource resource1 = EasyMock
062: .createStrictMock(XAResource.class);
063: private XAResource resource2 = EasyMock
064: .createStrictMock(XAResource.class);
065: private SQLProxy parent = EasyMock.createStrictMock(SQLProxy.class);
066: private SQLProxy root = EasyMock.createStrictMock(SQLProxy.class);
067: private LockManager lockManager = EasyMock
068: .createStrictMock(LockManager.class);
069: private Lock lock = EasyMock.createStrictMock(Lock.class);
070:
071: private Database database1 = new MockDatabase("1");
072: private Database database2 = new MockDatabase("2");
073: private Set<Database> databaseSet;
074: private ExecutorService executor = Executors
075: .newSingleThreadExecutor();
076: private XAResourceInvocationHandler handler;
077: private XAResource resource;
078:
079: @BeforeClass
080: protected void init() throws Exception {
081: Map map = new TreeMap();
082: map.put(this .database1, this .resource1);
083: map.put(this .database2, this .resource2);
084:
085: this .databaseSet = map.keySet();
086:
087: EasyMock.expect(this .parent.getDatabaseCluster()).andReturn(
088: this .cluster);
089:
090: this .parent.addChild(EasyMock
091: .isA(XAResourceInvocationHandler.class));
092:
093: this .replay();
094:
095: this .handler = new XAResourceInvocationHandler(EasyMock
096: .createStrictMock(XAConnection.class), this .parent,
097: EasyMock.createMock(Invoker.class), map);
098: this .resource = ProxyFactory.createProxy(XAResource.class,
099: this .handler);
100:
101: this .verify();
102: this .reset();
103: }
104:
105: private Object[] objects() {
106: return new Object[] { this .cluster, this .balancer,
107: this .resource1, this .resource2, this .parent, this .root,
108: this .lock, this .lockManager };
109: }
110:
111: protected void replay() {
112: EasyMock.replay(this .objects());
113: }
114:
115: protected void verify() {
116: EasyMock.verify(this .objects());
117: }
118:
119: @AfterMethod
120: protected void reset() {
121: EasyMock.reset(this .objects());
122: }
123:
124: @DataProvider(name="xid-boolean")
125: Object[][] xidBooleanProvider() {
126: return new Object[][] { new Object[] {
127: EasyMock.createMock(Xid.class), false } };
128: }
129:
130: /**
131: * @see javax.transaction.xa.XAResource#commit(javax.transaction.xa.Xid, boolean)
132: */
133: @Override
134: @Test(dataProvider="xid-boolean")
135: public void commit(Xid xid, boolean onePhase) throws XAException {
136: // Simulate start transaction
137: EasyMock.expect(this .cluster.isActive()).andReturn(true);
138:
139: EasyMock.expect(this .cluster.getTransactionalExecutor())
140: .andReturn(this .executor);
141:
142: EasyMock.expect(this .cluster.getLockManager()).andReturn(
143: this .lockManager);
144: EasyMock.expect(this .lockManager.readLock(LockManager.GLOBAL))
145: .andReturn(this .lock);
146:
147: this .lock.lock();
148:
149: EasyMock.expect(this .cluster.getBalancer()).andReturn(
150: this .balancer);
151: EasyMock.expect(this .balancer.all())
152: .andReturn(this .databaseSet);
153:
154: EasyMock.expect(this .parent.getRoot()).andReturn(this .root);
155:
156: this .root.retain(this .databaseSet);
157:
158: this .resource1.start(xid, XAResource.TMNOFLAGS);
159: this .resource2.start(xid, XAResource.TMNOFLAGS);
160:
161: this .replay();
162:
163: this .resource.start(xid, XAResource.TMNOFLAGS);
164:
165: this .verify();
166: this .reset();
167:
168: // Begin test
169: EasyMock.expect(this .cluster.isActive()).andReturn(true);
170:
171: EasyMock.expect(this .cluster.getTransactionalExecutor())
172: .andReturn(this .executor);
173:
174: EasyMock.expect(this .cluster.getBalancer()).andReturn(
175: this .balancer);
176: EasyMock.expect(this .balancer.all())
177: .andReturn(this .databaseSet);
178:
179: EasyMock.expect(this .parent.getRoot()).andReturn(this .root);
180:
181: this .root.retain(this .databaseSet);
182:
183: this .resource1.commit(xid, onePhase);
184: this .resource2.commit(xid, onePhase);
185:
186: this .lock.unlock();
187:
188: this .replay();
189:
190: this .resource.commit(xid, onePhase);
191:
192: this .verify();
193: }
194:
195: @DataProvider(name="xid-flags")
196: Object[][] xidIntProvider() {
197: return new Object[][] { new Object[] {
198: EasyMock.createMock(Xid.class), XAResource.TMNOFLAGS } };
199: }
200:
201: /**
202: * @see javax.transaction.xa.XAResource#end(javax.transaction.xa.Xid, int)
203: */
204: @Override
205: @Test(dataProvider="xid-flags")
206: public void end(Xid xid, int flags) throws XAException {
207: EasyMock.expect(this .cluster.isActive()).andReturn(true);
208:
209: EasyMock.expect(this .cluster.getTransactionalExecutor())
210: .andReturn(this .executor);
211:
212: EasyMock.expect(this .cluster.getBalancer()).andReturn(
213: this .balancer);
214: EasyMock.expect(this .balancer.all())
215: .andReturn(this .databaseSet);
216:
217: EasyMock.expect(this .parent.getRoot()).andReturn(this .root);
218:
219: this .root.retain(this .databaseSet);
220:
221: this .resource1.end(xid, flags);
222: this .resource2.end(xid, flags);
223:
224: this .replay();
225:
226: this .resource.end(xid, flags);
227:
228: this .verify();
229: }
230:
231: @DataProvider(name="xid")
232: Object[][] xidProvider() {
233: return new Object[][] { new Object[] { EasyMock
234: .createMock(Xid.class) } };
235: }
236:
237: /**
238: * @see javax.transaction.xa.XAResource#forget(javax.transaction.xa.Xid)
239: */
240: @Override
241: @Test(dataProvider="xid")
242: public void forget(Xid xid) throws XAException {
243: EasyMock.expect(this .cluster.isActive()).andReturn(true);
244:
245: EasyMock.expect(this .cluster.getTransactionalExecutor())
246: .andReturn(this .executor);
247:
248: EasyMock.expect(this .cluster.getBalancer()).andReturn(
249: this .balancer);
250: EasyMock.expect(this .balancer.all())
251: .andReturn(this .databaseSet);
252:
253: EasyMock.expect(this .parent.getRoot()).andReturn(this .root);
254:
255: this .root.retain(this .databaseSet);
256:
257: this .resource1.forget(xid);
258: this .resource2.forget(xid);
259:
260: this .replay();
261:
262: this .resource.forget(xid);
263:
264: this .verify();
265: }
266:
267: /**
268: * @see javax.transaction.xa.XAResource#getTransactionTimeout()
269: */
270: @Override
271: @Test
272: public int getTransactionTimeout() throws XAException {
273: EasyMock.expect(this .cluster.isActive()).andReturn(true);
274:
275: EasyMock.expect(this .resource1.getTransactionTimeout())
276: .andReturn(1);
277:
278: this .replay();
279:
280: int timeout = this .resource.getTransactionTimeout();
281:
282: this .verify();
283:
284: assert timeout == 1 : timeout;
285:
286: return timeout;
287: }
288:
289: @DataProvider(name="resource")
290: Object[][] resourceProvider() {
291: return new Object[][] { new Object[] { EasyMock
292: .createMock(XAResource.class) } };
293: }
294:
295: /**
296: * @see javax.transaction.xa.XAResource#isSameRM(javax.transaction.xa.XAResource)
297: */
298: @Override
299: @Test(dataProvider="resource")
300: public boolean isSameRM(XAResource resource) throws XAException {
301: EasyMock.expect(this .cluster.isActive()).andReturn(true);
302:
303: EasyMock.expect(this .resource1.isSameRM(resource)).andReturn(
304: true);
305:
306: this .replay();
307:
308: boolean same = this .resource.isSameRM(resource);
309:
310: this .verify();
311:
312: assert same;
313:
314: return same;
315: }
316:
317: /**
318: * @see javax.transaction.xa.XAResource#prepare(javax.transaction.xa.Xid)
319: */
320: @Override
321: @Test(dataProvider="xid")
322: public int prepare(Xid xid) throws XAException {
323: EasyMock.expect(this .cluster.isActive()).andReturn(true);
324:
325: EasyMock.expect(this .cluster.getTransactionalExecutor())
326: .andReturn(this .executor);
327:
328: EasyMock.expect(this .cluster.getBalancer()).andReturn(
329: this .balancer);
330: EasyMock.expect(this .balancer.all())
331: .andReturn(this .databaseSet);
332:
333: EasyMock.expect(this .parent.getRoot()).andReturn(this .root);
334:
335: this .root.retain(this .databaseSet);
336:
337: EasyMock.expect(this .resource1.prepare(xid)).andReturn(
338: XAResource.XA_OK);
339: EasyMock.expect(this .resource2.prepare(xid)).andReturn(
340: XAResource.XA_OK);
341:
342: this .replay();
343:
344: int result = this .resource.prepare(xid);
345:
346: this .verify();
347:
348: assert result == XAResource.XA_OK : result;
349:
350: return result;
351: }
352:
353: @DataProvider(name="flags")
354: Object[][] flagsProvider() {
355: return new Object[][] { new Object[] { XAResource.TMNOFLAGS } };
356: }
357:
358: /**
359: * @see javax.transaction.xa.XAResource#recover(int)
360: */
361: @Override
362: @Test(dataProvider="flags")
363: public Xid[] recover(int flags) throws XAException {
364: Xid[] xids = new Xid[0];
365:
366: EasyMock.expect(this .cluster.isActive()).andReturn(true);
367:
368: EasyMock.expect(this .cluster.getTransactionalExecutor())
369: .andReturn(this .executor);
370:
371: EasyMock.expect(this .cluster.getBalancer()).andReturn(
372: this .balancer);
373: EasyMock.expect(this .balancer.all())
374: .andReturn(this .databaseSet);
375:
376: EasyMock.expect(this .parent.getRoot()).andReturn(this .root);
377:
378: this .root.retain(this .databaseSet);
379:
380: EasyMock.expect(this .resource1.recover(flags)).andReturn(xids);
381: EasyMock.expect(this .resource2.recover(flags)).andReturn(xids);
382:
383: this .replay();
384:
385: Xid[] result = this .resource.recover(flags);
386:
387: this .verify();
388:
389: assert result == xids;
390:
391: return result;
392: }
393:
394: /**
395: * @see javax.transaction.xa.XAResource#rollback(javax.transaction.xa.Xid)
396: */
397: @Override
398: @Test(dataProvider="xid")
399: public void rollback(Xid xid) throws XAException {
400: // Simulate start transaction
401: EasyMock.expect(this .cluster.isActive()).andReturn(true);
402:
403: EasyMock.expect(this .cluster.getTransactionalExecutor())
404: .andReturn(this .executor);
405:
406: EasyMock.expect(this .cluster.getLockManager()).andReturn(
407: this .lockManager);
408: EasyMock.expect(this .lockManager.readLock(LockManager.GLOBAL))
409: .andReturn(this .lock);
410:
411: this .lock.lock();
412:
413: EasyMock.expect(this .cluster.getBalancer()).andReturn(
414: this .balancer);
415: EasyMock.expect(this .balancer.all())
416: .andReturn(this .databaseSet);
417:
418: EasyMock.expect(this .parent.getRoot()).andReturn(this .root);
419:
420: this .root.retain(this .databaseSet);
421:
422: this .resource1.start(xid, XAResource.TMNOFLAGS);
423: this .resource2.start(xid, XAResource.TMNOFLAGS);
424:
425: this .replay();
426:
427: this .resource.start(xid, XAResource.TMNOFLAGS);
428:
429: this .verify();
430: this .reset();
431:
432: // Start test
433: EasyMock.expect(this .cluster.isActive()).andReturn(true);
434:
435: EasyMock.expect(this .cluster.getTransactionalExecutor())
436: .andReturn(this .executor);
437:
438: EasyMock.expect(this .cluster.getBalancer()).andReturn(
439: this .balancer);
440: EasyMock.expect(this .balancer.all())
441: .andReturn(this .databaseSet);
442:
443: EasyMock.expect(this .parent.getRoot()).andReturn(this .root);
444:
445: this .root.retain(this .databaseSet);
446:
447: this .resource1.rollback(xid);
448: this .resource2.rollback(xid);
449:
450: this .lock.unlock();
451:
452: this .replay();
453:
454: this .resource.rollback(xid);
455:
456: this .verify();
457: }
458:
459: /**
460: * @see javax.transaction.xa.XAResource#setTransactionTimeout(int)
461: */
462: @Override
463: @Test(dataProvider="flags")
464: public boolean setTransactionTimeout(int timeout)
465: throws XAException {
466: EasyMock.expect(this .cluster.isActive()).andReturn(true);
467:
468: EasyMock.expect(this .cluster.getNonTransactionalExecutor())
469: .andReturn(this .executor);
470:
471: EasyMock.expect(this .cluster.getBalancer()).andReturn(
472: this .balancer);
473: EasyMock.expect(this .balancer.all())
474: .andReturn(this .databaseSet);
475:
476: EasyMock.expect(this .parent.getRoot()).andReturn(this .root);
477:
478: this .root.retain(this .databaseSet);
479:
480: EasyMock.expect(this .resource1.setTransactionTimeout(timeout))
481: .andReturn(true);
482: EasyMock.expect(this .resource2.setTransactionTimeout(timeout))
483: .andReturn(true);
484:
485: this .replay();
486:
487: boolean result = this .resource.setTransactionTimeout(timeout);
488:
489: this .verify();
490:
491: assert result;
492:
493: return result;
494: }
495:
496: /**
497: * @see javax.transaction.xa.XAResource#start(javax.transaction.xa.Xid, int)
498: */
499: @Override
500: @Test(dataProvider="xid-flags")
501: public void start(Xid xid, int flags) throws XAException {
502: EasyMock.expect(this .cluster.isActive()).andReturn(true);
503:
504: EasyMock.expect(this .cluster.getTransactionalExecutor())
505: .andReturn(this .executor);
506:
507: EasyMock.expect(this .cluster.getLockManager()).andReturn(
508: this .lockManager);
509: EasyMock.expect(this .lockManager.readLock(LockManager.GLOBAL))
510: .andReturn(this .lock);
511:
512: this .lock.lock();
513:
514: EasyMock.expect(this .cluster.getBalancer()).andReturn(
515: this .balancer);
516: EasyMock.expect(this .balancer.all())
517: .andReturn(this .databaseSet);
518:
519: EasyMock.expect(this .parent.getRoot()).andReturn(this .root);
520:
521: this .root.retain(this .databaseSet);
522:
523: this .resource1.start(xid, flags);
524: this .resource2.start(xid, flags);
525:
526: this .replay();
527:
528: this .resource.start(xid, flags);
529:
530: this .verify();
531: this .reset();
532:
533: // Test resume
534: EasyMock.expect(this .cluster.isActive()).andReturn(true);
535:
536: EasyMock.expect(this .cluster.getTransactionalExecutor())
537: .andReturn(this .executor);
538:
539: EasyMock.expect(this .cluster.getLockManager()).andReturn(
540: this .lockManager);
541: EasyMock.expect(this .lockManager.readLock(LockManager.GLOBAL))
542: .andReturn(this .lock);
543:
544: EasyMock.expect(this .cluster.getBalancer()).andReturn(
545: this .balancer);
546: EasyMock.expect(this .balancer.all())
547: .andReturn(this .databaseSet);
548:
549: EasyMock.expect(this .parent.getRoot()).andReturn(this .root);
550:
551: this .root.retain(this .databaseSet);
552:
553: this .resource1.start(xid, flags);
554: this .resource2.start(xid, flags);
555:
556: this .replay();
557:
558: this .resource.start(xid, flags);
559:
560: this .verify();
561: this .reset();
562:
563: // Simulate transaction rollback
564: EasyMock.expect(this .cluster.isActive()).andReturn(true);
565:
566: EasyMock.expect(this.cluster.getTransactionalExecutor())
567: .andReturn(this.executor);
568:
569: EasyMock.expect(this.cluster.getBalancer()).andReturn(
570: this.balancer);
571: EasyMock.expect(this.balancer.all())
572: .andReturn(this.databaseSet);
573:
574: EasyMock.expect(this.parent.getRoot()).andReturn(this.root);
575:
576: this.root.retain(this.databaseSet);
577:
578: this.resource1.rollback(xid);
579: this.resource2.rollback(xid);
580:
581: this.lock.unlock();
582:
583: this.replay();
584:
585: this.resource.rollback(xid);
586:
587: this.verify();
588: }
589: }
|