/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
package org.teiid.dqp.internal.process;
import static org.junit.Assert.*;
import javax.resource.spi.XATerminator;
import javax.transaction.TransactionManager;
import javax.transaction.xa.XAResource;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.teiid.adminapi.Transaction;
import org.teiid.client.xa.XATransactionException;
import org.teiid.client.xa.XidImpl;
import org.teiid.common.queue.FakeWorkManager;
import org.teiid.dqp.service.TransactionContext;
public class TestTransactionServer {
private TransactionServerImpl server;
private XATerminator xaTerminator;
private TransactionManager tm;
private javax.transaction.Transaction txn;
private static final String THREAD1 = "abc1"; //$NON-NLS-1$
private static final String THREAD2 = "abc2"; //$NON-NLS-1$
private static final XidImpl XID1 = new XidImpl(0, new byte[] {
1
}, new byte[0]);
private static final XidImpl XID2 = new XidImpl(0, new byte[] {
2
}, new byte[0]);
@Before public void setUp() throws Exception {
server = new TransactionServerImpl();
xaTerminator = Mockito.mock(XATerminator.class);
tm = Mockito.mock(TransactionManager.class);
txn = Mockito.mock(javax.transaction.Transaction.class);
Mockito.stub(tm.getTransaction()).toReturn(txn);
Mockito.stub(tm.suspend()).toReturn(txn);
server.setXaTerminator(xaTerminator);
server.setTransactionManager(tm);
server.setWorkManager(new FakeWorkManager());
}
/**
* once in a local, cannot start a global
*/
@Test public void testTransactionExclusion() throws Exception {
server.begin(THREAD1);
try {
server.start(THREAD1, XID1, XAResource.TMNOFLAGS, 100, false);
fail("exception expected"); //$NON-NLS-1$
} catch (XATransactionException ex) {
assertEquals("TEIID30517 Client thread already involved in a transaction. Transaction nesting is not supported. The current transaction must be completed first.", //$NON-NLS-1$
ex.getMessage());
}
}
/**
* once in a global, cannot start a local
*/
@Test public void testTransactionExclusion1() throws Exception {
server.start(THREAD1, XID1, XAResource.TMNOFLAGS, 100, false);
try {
server.begin(THREAD1);
fail("exception expected"); //$NON-NLS-1$
} catch (XATransactionException ex) {
assertEquals("TEIID30517 Client thread already involved in a transaction. Transaction nesting is not supported. The current transaction must be completed first.", //$NON-NLS-1$
ex.getMessage());
}
}
/**
* global can only be started once
*/
@Test public void testTransactionExclusion2() throws Exception {
server.start(THREAD1, XID1, XAResource.TMNOFLAGS, 100,false);
try {
server.start(THREAD2, XID1, XAResource.TMNOFLAGS, 100,false);
fail("exception expected"); //$NON-NLS-1$
} catch (XATransactionException ex) {
assertEquals("TEIID30522 Global transaction Teiid-Xid global:1 branch:null format:0 already exists.", ex.getMessage()); //$NON-NLS-1$
}
}
/**
* global cannot be nested
*/
@Test public void testTransactionExclusion3() throws Exception {
server.start(THREAD1, XID1, XAResource.TMNOFLAGS, 100,false);
try {
server.start(THREAD1, XID2, XAResource.TMNOFLAGS, 100,false);
fail("exception expected"); //$NON-NLS-1$
} catch (XATransactionException ex) {
assertEquals("TEIID30517 Client thread already involved in a transaction. Transaction nesting is not supported. The current transaction must be completed first.", //$NON-NLS-1$
ex.getMessage());
}
}
/**
* local cannot be nested
*/
@Test public void testTransactionExclusion4() throws Exception {
server.begin(THREAD1);
try {
server.begin(THREAD1);
fail("exception expected"); //$NON-NLS-1$
} catch (XATransactionException ex) {
assertEquals("TEIID30517 Client thread already involved in a transaction. Transaction nesting is not supported. The current transaction must be completed first.", //$NON-NLS-1$
ex.getMessage());
}
}
/**
* global cannot be nested
*/
@Test public void testTransactionExclusion5() throws Exception {
server.start(THREAD1, XID1, XAResource.TMNOFLAGS, 100,false);
server.start(THREAD2, XID2, XAResource.TMNOFLAGS, 100,false);
server.end(THREAD2, XID2, XAResource.TMSUCCESS,false);
try {
server.start(THREAD1, XID2, XAResource.TMJOIN, 100,false);
fail("exception expected"); //$NON-NLS-1$
} catch (XATransactionException ex) {
assertEquals("TEIID30517 Client thread already involved in a transaction. Transaction nesting is not supported. The current transaction must be completed first.", //$NON-NLS-1$
ex.getMessage());
}
}
@Test public void testLocalCommit() throws Exception {
server.begin(THREAD1);
server.commit(THREAD1);
Mockito.verify(tm).commit();
try {
server.commit(THREAD1);
} catch (XATransactionException e) {
assertEquals("TEIID30526 javax.transaction.InvalidTransactionException: No transaction found for client abc1.", e.getMessage()); //$NON-NLS-1$
}
}
@Test public void testTwoPhaseCommit() throws Exception {
server.start(THREAD1, XID1, XAResource.TMNOFLAGS, 100,false);
server.end(THREAD1, XID1, XAResource.TMSUCCESS, false);
server.commit(THREAD1, XID1, false, false);
Mockito.verify(xaTerminator).commit(XID1, false);
}
@Test public void testLocalRollback() throws Exception {
server.begin(THREAD1);
server.rollback(THREAD1);
Mockito.verify(tm).rollback();
try {
server.rollback(THREAD1);
} catch (XATransactionException e) {
assertEquals("TEIID30526 javax.transaction.InvalidTransactionException: No transaction found for client abc1.", e.getMessage()); //$NON-NLS-1$
}
}
@Test public void testConcurrentEnlistment() throws Exception {
server.start(THREAD1, XID1, XAResource.TMNOFLAGS, 100,false);
try {
server.start(THREAD1, XID1, XAResource.TMJOIN, 100,false);
fail("exception expected"); //$NON-NLS-1$
} catch (XATransactionException ex) {
assertEquals("TEIID30525 Concurrent enlistment in global transaction Teiid-Xid global:1 branch:null format:0 is not supported.", //$NON-NLS-1$
ex.getMessage());
}
}
@Test public void testSuspend() throws Exception {
server.start(THREAD1, XID1, XAResource.TMNOFLAGS, 100,false);
server.end(THREAD1, XID1, XAResource.TMSUSPEND,false);
try {
server.end(THREAD1, XID1, XAResource.TMSUSPEND,false);
fail("exception expected"); //$NON-NLS-1$
} catch (XATransactionException ex) {
assertEquals("TEIID30524 Client is not currently enlisted in transaction Teiid-Xid global:1 branch:null format:0.", ex.getMessage()); //$NON-NLS-1$
}
}
@Test public void testSuspendResume() throws Exception {
server.start(THREAD1, XID1, XAResource.TMNOFLAGS, 100,false);
server.end(THREAD1, XID1, XAResource.TMSUSPEND,false);
server.start(THREAD1, XID1, XAResource.TMRESUME, 100,false);
server.end(THREAD1, XID1, XAResource.TMSUSPEND,false);
try {
server.start(THREAD2, XID1, XAResource.TMRESUME, 100,false);
fail("exception expected"); //$NON-NLS-1$
} catch (XATransactionException ex) {
assertEquals("TEIID30518 Cannot resume, transaction Teiid-Xid global:1 branch:null format:0 was not suspended by client abc2.", ex.getMessage()); //$NON-NLS-1$
}
}
@Test public void testUnknownFlags() throws Exception {
try {
server.start(THREAD1, XID1, Integer.MAX_VALUE, 100,false);
fail("exception expected"); //$NON-NLS-1$
} catch (XATransactionException ex) {
assertEquals("TEIID30519 Unknown START flags", ex.getMessage()); //$NON-NLS-1$
}
}
@Test public void testUnknownGlobalTransaction() throws Exception {
try {
server.end(THREAD1, XID1, XAResource.TMSUCCESS,false);
fail("exception expected"); //$NON-NLS-1$
} catch (XATransactionException ex) {
assertEquals("TEIID30521 No global transaction found for Teiid-Xid global:1 branch:null format:0.", ex.getMessage()); //$NON-NLS-1$
}
}
@Test public void testPrepareWithSuspended() throws Exception {
server.start(THREAD1, XID1, XAResource.TMNOFLAGS, 100,false);
server.end(THREAD1, XID1, XAResource.TMSUSPEND,false);
try {
server.prepare(THREAD1, XID1,false);
fail("exception expected"); //$NON-NLS-1$
} catch (XATransactionException ex) {
assertEquals("TEIID30505 Suspended work still exists on transaction Teiid-Xid global:1 branch:null format:0.", ex.getMessage()); //$NON-NLS-1$
}
}
@Test public void testGetTransactionContext() throws Exception {
assertSame(server.getOrCreateTransactionContext(THREAD1), server.getOrCreateTransactionContext(THREAD1));
}
@Test public void testGetTransactions() throws Exception {
server.start(THREAD1, XID1, XAResource.TMNOFLAGS, 100,false);
server.begin(THREAD2);
assertEquals(2, server.getTransactions().size());
server.commit(THREAD2);
assertEquals(1, server.getTransactions().size());
Transaction t = server.getTransactions().iterator().next();
assertEquals(THREAD1, t.getAssociatedSession());
assertNotNull(t.getId());
}
@Test public void testGlobalPrepare() throws Exception {
server.start(THREAD1, XID1, XAResource.TMNOFLAGS, 100,false);
TransactionContext tc = server.getOrCreateTransactionContext(THREAD1);
server.end(THREAD1, XID1, XAResource.TMSUCCESS, false);
server.prepare(THREAD1, XID1, false);
Mockito.verify(xaTerminator).prepare(tc.getXid());
server.commit(THREAD1, XID1, true, false);
}
@Test public void testGlobalPrepareFail() throws Exception {
server.start(THREAD1, XID1, XAResource.TMNOFLAGS, 100,false);
server.end(THREAD1, XID1, XAResource.TMFAIL, false);
Mockito.verify(txn).setRollbackOnly();
}
@Test public void testGlobalOnePhaseCommit() throws Exception {
server.start(THREAD1, XID1, XAResource.TMNOFLAGS, 100,false);
TransactionContext tc = server.getOrCreateTransactionContext(THREAD1);
server.end(THREAD1, XID1, XAResource.TMSUCCESS, false);
server.prepare(THREAD1, XID1, false);
server.commit(THREAD1, XID1, true, false);
Mockito.verify(xaTerminator).commit(tc.getXid(), false);
}
@Test public void testGlobalOnePhaseCommit_force_prepare_through() throws Exception {
server.start(THREAD1, XID1, XAResource.TMNOFLAGS, 100,false);
TransactionContext tc = server.getOrCreateTransactionContext(THREAD1);
server.end(THREAD1, XID1, XAResource.TMSUCCESS, false);
server.commit(THREAD1, XID1, true, false);
Mockito.verify(xaTerminator).prepare(tc.getXid());
Mockito.verify(xaTerminator).commit(tc.getXid(), false);
}
@Test public void testGlobalOnePhaseCommit_force_prepare() throws Exception {
server.start(THREAD1, XID1, XAResource.TMNOFLAGS, 100,false);
TransactionContext tc = server.getOrCreateTransactionContext(THREAD1);
server.end(THREAD1, XID1, XAResource.TMSUCCESS, false);
server.commit(THREAD1, XID1, true, false);
// since there are two sources the commit is not single phase
Mockito.verify(xaTerminator).prepare(tc.getXid());
Mockito.verify(xaTerminator).commit(tc.getXid(), false);
}
@Test public void testGlobalOnePhase_teiid_multiple() throws Exception {
server.start(THREAD1, XID1, XAResource.TMNOFLAGS, 100,false);
TransactionContext tc = server.getOrCreateTransactionContext(THREAD1);
server.end(THREAD1, XID1, XAResource.TMSUCCESS, false);
server.prepare(THREAD1, XID1, false);
server.commit(THREAD1, XID1, true, false);
// since there are two sources the commit is not single phase
Mockito.verify(xaTerminator).commit(tc.getXid(), false);
}
@Test public void testGlobalOnePhaseRoolback() throws Exception {
server.start(THREAD1, XID1, XAResource.TMNOFLAGS, 100,false);
TransactionContext tc = server.getOrCreateTransactionContext(THREAD1);
server.end(THREAD1, XID1, XAResource.TMSUCCESS, false);
server.prepare(THREAD1, XID1, false);
server.rollback(THREAD1, XID1, false);
// since there are two sources the commit is not single phase
Mockito.verify(xaTerminator).rollback(tc.getXid());
}
@Test public void testRequestCommit() throws Exception{
TransactionContext tc = server.getOrCreateTransactionContext(THREAD1);
server.begin(tc);
server.commit(tc);
assertEquals(TransactionContext.Scope.NONE, tc.getTransactionType());
Mockito.verify(tm).commit();
}
@Test public void testRequestRollback() throws Exception{
TransactionContext tc = server.getOrCreateTransactionContext(THREAD1);
server.begin(tc);
server.rollback(tc);
assertEquals(TransactionContext.Scope.NONE, tc.getTransactionType());
Mockito.verify(tm).rollback();
}
@Test public void testLocalCancel() throws Exception {
server.begin(THREAD1);
server.cancelTransactions(THREAD1, false);
Mockito.verify(txn).setRollbackOnly();
}
@Test public void testRequestCancel() throws Exception{
TransactionContext tc = server.getOrCreateTransactionContext(THREAD1);
server.begin(tc);
server.cancelTransactions(THREAD1, true);
Mockito.verify(txn).setRollbackOnly();
}
}