Package com.taobao.metamorphosis.client.transaction

Source Code of com.taobao.metamorphosis.client.transaction.TransactionContextUnitTest$MockSession

/*
* (C) 2007-2012 Alibaba Group Holding Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Authors:
*   wuhua <wq163@163.com> , boyan <killme2008@gmail.com>
*/
package com.taobao.metamorphosis.client.transaction;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;

import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.taobao.gecko.core.util.OpaqueGenerator;
import com.taobao.gecko.service.RemotingClient;
import com.taobao.gecko.service.exception.NotifyRemotingException;
import com.taobao.metamorphosis.exception.MetaClientException;
import com.taobao.metamorphosis.network.BooleanCommand;
import com.taobao.metamorphosis.network.HttpStatus;
import com.taobao.metamorphosis.network.TransactionCommand;
import com.taobao.metamorphosis.transaction.LocalTransactionId;
import com.taobao.metamorphosis.transaction.TransactionId;
import com.taobao.metamorphosis.transaction.TransactionInfo;
import com.taobao.metamorphosis.transaction.TransactionInfo.TransactionType;
import com.taobao.metamorphosis.transaction.XATransactionId;
import com.taobao.metamorphosis.utils.IdGenerator;
import com.taobao.metamorphosis.utils.LongSequenceGenerator;


public class TransactionContextUnitTest {
    private static final String UNIQUE_QUALIFIER = XIDGenerator.UNIQUE_QUALIFIER;
    private TransactionContext context;
    private MockSession session;
    private RemotingClient remotingClient;

    private IdGenerator idGenerator;

    private String sessionId;

    private static final long DEFAULT_REQ_TIMEOUT = 5000L;

    static class MockSession implements TransactionSession {
        private final String sessionId;
        private boolean removeCtx = false;


        public MockSession(final String sessionId) {
            super();
            this.sessionId = sessionId;
        }


        @Override
        public void removeContext(final TransactionContext ctx) {
            this.removeCtx = true;

        }


        @Override
        public String getSessionId() {
            return this.sessionId;
        }

    }


    @Before
    public void setUp() {
        this.idGenerator = new IdGenerator();
        this.remotingClient = EasyMock.createMock(RemotingClient.class);
        this.sessionId = this.idGenerator.generateId();
        this.session = new MockSession(this.sessionId);
        this.context =
                new TransactionContext(this.remotingClient, null, this.session, new LongSequenceGenerator(), 0,
                    DEFAULT_REQ_TIMEOUT);
        this.context.setUniqueQualifier(UNIQUE_QUALIFIER);
        OpaqueGenerator.resetOpaque();
    }


    @After
    public void tearDown() {
        this.verify();
    }


    private void verify() {
        EasyMock.verify(this.remotingClient);
    }


    private void replay() {
        EasyMock.replay(this.remotingClient);
    }


    @Test
    public void testLocalBeginCommit() throws Exception {
        final String serverUrl = "meta://localhost:8123";
        this.mockIsConnected(serverUrl, true);
        this.context.setServerUrl(serverUrl);
        final TransactionId id = new LocalTransactionId(this.sessionId, 1);
        this.mockInvokeSuccess(serverUrl, new TransactionInfo(id, this.sessionId, TransactionType.BEGIN), null);
        this.mockInvokeSuccess(serverUrl, new TransactionInfo(id, this.sessionId, TransactionType.COMMIT_ONE_PHASE),
            null);
        assertNull(this.context.getTransactionId());
        assertFalse(this.context.isInTransaction());
        OpaqueGenerator.resetOpaque();
        this.replay();
        this.context.begin();
        final TransactionId xid = this.context.getTransactionId();
        assertNotNull(xid);
        assertTrue(xid.isLocalTransaction());
        assertTrue(this.context.isInLocalTransaction());
        assertFalse(this.context.isInXATransaction());
        assertTrue(this.context.isInTransaction());

        this.context.commit();
        assertNull(this.context.getTransactionId());
        assertFalse(this.context.isInTransaction());
    }


    @Test(expected = XAException.class)
    public void testSetTxTimeoutInvalidValue() throws Exception {
        this.replay();
        this.context.setTransactionTimeout(-1);
    }


    @Test
    public void testSetTxTimeout() throws Exception {
        final String serverUrl = "meta://localhost:8123";
        this.mockIsConnected(serverUrl, true);
        this.context.setServerUrl(serverUrl);
        final XATransactionId id = XIDGenerator.createXID(1);
        this.context.setTransactionTimeout(3);
        this.mockInvokeSuccess(serverUrl, new TransactionInfo(id, this.sessionId, TransactionType.BEGIN, null, 3), null);
        // this.mockSend(serverUrl, new TransactionInfo(id, this.sessionId,
        // TransactionType.SET_TIMEOUT, 3));
        OpaqueGenerator.resetOpaque();
        this.replay();
        this.context.start(id, XAResource.TMNOFLAGS);
    }


    @Test(expected = MetaClientException.class)
    public void testBeginUnConnected() throws Exception {
        final String serverUrl = "meta://localhost:8123";
        this.mockIsConnected(serverUrl, false);
        this.context.setServerUrl(serverUrl);
        this.replay();
        this.context.begin();
    }


    @Test(expected = MetaClientException.class)
    public void testCommitUnBeginTx() throws Exception {
        final String serverUrl = "meta://localhost:8123";
        this.context.setServerUrl(serverUrl);
        this.replay();
        this.context.commit();
    }


    @Test(expected = MetaClientException.class)
    public void testRollbackUnBeginTx() throws Exception {
        final String serverUrl = "meta://localhost:8123";
        this.context.setServerUrl(serverUrl);
        this.replay();
        this.context.rollback();
    }


    @Test
    public void testLocalBeginRollback() throws Exception {
        final String serverUrl = "meta://localhost:8123";
        this.mockIsConnected(serverUrl, true);
        this.context.setServerUrl(serverUrl);
        final TransactionId id = new LocalTransactionId(this.sessionId, 1);
        this.mockInvokeSuccess(serverUrl, new TransactionInfo(id, this.sessionId, TransactionType.BEGIN), null);
        this.mockInvokeSuccess(serverUrl, new TransactionInfo(id, this.sessionId, TransactionType.ROLLBACK), null);
        assertNull(this.context.getTransactionId());
        assertFalse(this.context.isInTransaction());
        OpaqueGenerator.resetOpaque();
        this.replay();
        this.context.begin();
        final TransactionId xid = this.context.getTransactionId();
        assertNotNull(xid);
        assertTrue(xid.isLocalTransaction());
        assertTrue(this.context.isInLocalTransaction());
        assertFalse(this.context.isInXATransaction());
        assertTrue(this.context.isInTransaction());

        this.context.rollback();
        assertNull(this.context.getTransactionId());
        assertFalse(this.context.isInTransaction());
    }


    @Test
    public void testBeginXAWithServerUrl() throws Exception {
        final String serverUrl = "meta://localhost:8123";
        this.mockIsConnected(serverUrl, true);
        this.context.setServerUrl(serverUrl);

        final XATransactionId id = XIDGenerator.createXID(1);
        this.mockInvokeSuccess(serverUrl, new TransactionInfo(id, this.sessionId, TransactionType.BEGIN), null);

        assertNull(this.context.getTransactionId());
        assertFalse(this.context.isInTransaction());
        OpaqueGenerator.resetOpaque();
        this.replay();
        this.context.start(id, XAResource.TMNOFLAGS);

        final TransactionId xid = this.context.getTransactionId();
        assertNotNull(xid);
        assertEquals(id, xid);
        assertFalse(xid.isLocalTransaction());
        assertFalse(this.context.isInLocalTransaction());
        assertTrue(this.context.isInXATransaction());
        assertTrue(this.context.isInTransaction());
    }


    @Test
    public void testBeginXAEndPrepareCommit() throws Exception {
        final String serverUrl = "meta://localhost:8123";
        this.mockIsConnected(serverUrl, true);
        this.context.setServerUrl(serverUrl);

        final XATransactionId id = XIDGenerator.createXID(1);
        this.mockInvokeSuccess(serverUrl, new TransactionInfo(id, this.sessionId, TransactionType.BEGIN), null);
        this.mockSend(serverUrl, new TransactionInfo(id, this.sessionId, TransactionType.END));
        this.mockInvokeSuccess(serverUrl, new TransactionInfo(id, this.sessionId, TransactionType.PREPARE),
            String.valueOf(XAResource.XA_OK));
        this.mockInvokeSuccess(serverUrl, new TransactionInfo(id, this.sessionId, TransactionType.COMMIT_TWO_PHASE),
            null);

        OpaqueGenerator.resetOpaque();
        this.replay();
        this.context.start(id, XAResource.TMNOFLAGS);
        assertTrue(this.context.isInXATransaction());
        this.context.end(id, XAResource.TMSUCCESS);
        assertFalse(this.context.isInXATransaction());
        this.context.prepare(id);
        this.context.commit(id, false);
        assertFalse(this.context.isInXATransaction());
        assertTrue(this.session.removeCtx);
    }


    @Test(expected = XAException.class)
    public void testBeginXAPrepare() throws Exception {
        final String serverUrl = "meta://localhost:8123";
        this.mockIsConnected(serverUrl, true);
        this.context.setServerUrl(serverUrl);

        final XATransactionId id = XIDGenerator.createXID(1);
        this.mockInvokeSuccess(serverUrl, new TransactionInfo(id, this.sessionId, TransactionType.BEGIN), null);

        OpaqueGenerator.resetOpaque();
        this.replay();
        this.context.start(id, XAResource.TMNOFLAGS);
        assertTrue(this.context.isInXATransaction());
        // û�е���end��ֱ��prepare
        this.context.prepare(id);
        fail();
    }


    @Test(expected = XAException.class)
    public void testBeginXACommit() throws Exception {
        final String serverUrl = "meta://localhost:8123";
        this.mockIsConnected(serverUrl, true);
        this.context.setServerUrl(serverUrl);

        final XATransactionId id = XIDGenerator.createXID(1);
        this.mockInvokeSuccess(serverUrl, new TransactionInfo(id, this.sessionId, TransactionType.BEGIN), null);

        OpaqueGenerator.resetOpaque();
        this.replay();
        this.context.start(id, XAResource.TMNOFLAGS);
        assertTrue(this.context.isInXATransaction());
        // û�е���end��ֱ��commit
        this.context.commit(id, false);
        fail();
    }


    @Test
    public void testBeginXARollback() throws Exception {
        final String serverUrl = "meta://localhost:8123";
        this.mockIsConnected(serverUrl, true);
        this.context.setServerUrl(serverUrl);

        final XATransactionId id = XIDGenerator.createXID(1);
        this.mockInvokeSuccess(serverUrl, new TransactionInfo(id, this.sessionId, TransactionType.BEGIN), null);
        this.mockInvokeSuccess(serverUrl, new TransactionInfo(id, this.sessionId, TransactionType.ROLLBACK), null);

        OpaqueGenerator.resetOpaque();
        this.replay();
        this.context.start(id, XAResource.TMNOFLAGS);
        assertFalse(this.session.removeCtx);
        this.context.rollback(id);
        assertTrue(this.session.removeCtx);
    }


    @Test
    public void testBeginXAEndPrepareRollback() throws Exception {
        final String serverUrl = "meta://localhost:8123";
        this.mockIsConnected(serverUrl, true);
        this.context.setServerUrl(serverUrl);

        final XATransactionId id = XIDGenerator.createXID(1);
        this.mockInvokeSuccess(serverUrl, new TransactionInfo(id, this.sessionId, TransactionType.BEGIN), null);
        this.mockSend(serverUrl, new TransactionInfo(id, this.sessionId, TransactionType.END));
        this.mockInvokeSuccess(serverUrl, new TransactionInfo(id, this.sessionId, TransactionType.PREPARE),
            String.valueOf(XAResource.XA_OK));
        this.mockInvokeSuccess(serverUrl, new TransactionInfo(id, this.sessionId, TransactionType.ROLLBACK), null);

        OpaqueGenerator.resetOpaque();
        this.replay();
        this.context.start(id, XAResource.TMNOFLAGS);
        assertFalse(this.session.removeCtx);
        this.context.end(id, XAResource.TMSUCCESS);
        this.context.prepare(id);
        this.context.rollback(id);
        assertTrue(this.session.removeCtx);
        assertFalse(this.context.isInXATransaction());
    }


    @Test
    public void testCommitUnBeginXA() throws Exception {
        // ��������ģ�������recover����������
        final String serverUrl = "meta://localhost:8123";
        this.mockIsConnected(serverUrl, true);
        this.context.setServerUrl(serverUrl);
        final XATransactionId id = XIDGenerator.createXID(1);
        this.mockInvokeSuccess(serverUrl, new TransactionInfo(id, this.sessionId, TransactionType.COMMIT_TWO_PHASE),
            null);
        OpaqueGenerator.resetOpaque();
        this.replay();
        this.context.commit(id, false);

    }


    @Test
    public void testPrepareUnBeginXA() throws Exception {
        // ��������ģ�������recover����������
        final String serverUrl = "meta://localhost:8123";
        this.mockIsConnected(serverUrl, true);
        this.context.setServerUrl(serverUrl);
        final XATransactionId id = XIDGenerator.createXID(1);
        this.mockInvokeSuccess(serverUrl, new TransactionInfo(id, this.sessionId, TransactionType.PREPARE),
            String.valueOf(XAResource.XA_OK));
        OpaqueGenerator.resetOpaque();
        this.replay();
        this.context.prepare(id);

    }


    @Test
    public void testRecover() throws Exception {
        final String serverURL1 = "meta://localhost:8123";
        final String serverURL2 = "meta://localhost:8124";
        final XATransactionId id1 = XIDGenerator.createXID(1);
        final XATransactionId id2 = XIDGenerator.createXID(2);
        final XATransactionId id3 = XIDGenerator.createXID(3);
        final XATransactionId id4 = XIDGenerator.createXID(4);

        this.mockInvokeSuccess(serverURL1, new TransactionInfo(null, this.sessionId, TransactionType.RECOVER),
            id2.getTransactionKey() + "\r\n" + id3.getTransactionKey());
        this.mockInvokeSuccess(serverURL2, new TransactionInfo(null, this.sessionId, TransactionType.RECOVER),
            id1.getTransactionKey() + "\r\n" + id4.getTransactionKey());
        this.replay();
        OpaqueGenerator.resetOpaque();
        this.context.setXareresourceURLs(new String[] { serverURL1, serverURL2 });
        final Xid[] xids = this.context.recover(XAResource.TMNOFLAGS);
        assertEquals(4, xids.length);
        this.assertContains(xids, id1);
        this.assertContains(xids, id2);
        this.assertContains(xids, id3);
        this.assertContains(xids, id4);
    }


    @Test
    public void testIsSameRM() throws Exception {
        final String serverUrl = "meta://localhost:8123";
        this.context.setServerUrl(serverUrl);

        final TransactionContext ctx2 =
                new TransactionContext(this.remotingClient, null, this.session, new LongSequenceGenerator(), 0,
                    DEFAULT_REQ_TIMEOUT);
        ctx2.setServerUrl(serverUrl);
        assertTrue(this.context.isSameRM(ctx2));
        this.replay();
    }


    @Test
    public void testToXAException() {
        final XAException e = new XAException();
        e.errorCode = XAException.XA_HEURCOM;
        assertSame(e, this.context.toXAException(e));
        XAException xe = this.context.toXAException(new RuntimeException(e));
        assertEquals(XAException.XA_HEURCOM, xe.errorCode);

        xe = this.context.toXAException(new RuntimeException("test"));
        assertEquals(XAException.XAER_RMFAIL, xe.errorCode);
        assertEquals("test", xe.getCause().getMessage());
        this.replay();
    }


    @Test
    public void testRecoverBlank() throws Exception {
        final String serverUrl = "meta://localhost:8123";
        this.mockIsConnected(serverUrl, true);
        this.context.setXareresourceURLs(new String[] { serverUrl });

        this.mockInvokeSuccess(serverUrl, new TransactionInfo(null, this.sessionId, TransactionType.RECOVER), null);
        this.replay();
        OpaqueGenerator.resetOpaque();
        final Xid[] xids = this.context.recover(XAResource.TMNOFLAGS);
        assertEquals(0, xids.length);
    }


    private void assertContains(final Xid[] a, final Xid key) {
        boolean contains = false;
        for (final Xid e : a) {
            if (e.equals(key)) {
                contains = true;
                break;
            }
        }
        if (!contains) {
            throw new AssertionError();
        }
    }


    private void mockIsConnected(final String serverUrl, final boolean rt) {
        EasyMock.expect(this.remotingClient.isConnected(serverUrl)).andReturn(rt).anyTimes();
    }


    private void mockInvokeSuccess(final String serverUrl, final TransactionInfo info, final String result)
            throws InterruptedException, TimeoutException, NotifyRemotingException {
        info.setUniqueQualifier(UNIQUE_QUALIFIER);
        EasyMock.expect(
            this.remotingClient.invokeToGroup(serverUrl, new TransactionCommand(info, OpaqueGenerator.getNextOpaque()),
                DEFAULT_REQ_TIMEOUT, TimeUnit.MILLISECONDS)).andReturn(
                    new BooleanCommand(HttpStatus.Success, result, 0));
    }


    private void mockSend(final String serverUrl, final TransactionInfo info) throws NotifyRemotingException {
        info.setUniqueQualifier(UNIQUE_QUALIFIER);
        this.remotingClient.sendToGroup(serverUrl, new TransactionCommand(info, OpaqueGenerator.getNextOpaque()),
            TransactionContext.END_XA_TX_LISTENER, 5000, TimeUnit.MILLISECONDS);
        EasyMock.expectLastCall();
    }

}
TOP

Related Classes of com.taobao.metamorphosis.client.transaction.TransactionContextUnitTest$MockSession

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.