package io.eguan.dtx; /* * #%L * Project eguan * %% * Copyright (C) 2012 - 2017 Oodrive * %% * 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. * #L% */ import static io.eguan.dtx.DtxTaskStatus.COMMITTED; import static io.eguan.dtx.DtxTaskStatus.PENDING; import static io.eguan.dtx.DtxTaskStatus.PREPARED; import static io.eguan.dtx.DtxTaskStatus.ROLLED_BACK; import static io.eguan.dtx.DtxTaskStatus.STARTED; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import io.eguan.dtx.DtxResourceManager; import io.eguan.dtx.DtxResourceManagerContext; import io.eguan.dtx.DtxTaskStatus; import java.util.Random; import java.util.UUID; import javax.annotation.Nonnull; import javax.transaction.xa.XAException; import org.junit.Test; /** * Abstract superclass for all implementations of {@link DtxResourceManager}. * * @author oodrive * @author pwehrle * */ // TODO: parameterize the test with respect to context states triggering protocol errors public abstract class TestDtxResourceManager { private static final int BAD_PAYLOAD_LENGTH = 384; /** * Gets an instance of the concrete implementation to test. * * @return a functional {@link DtxResourceManager} instance * @throws XAException * in case resource manager construction fails */ @Nonnull protected abstract DtxResourceManager getResourceManagerInstance() throws XAException; /** * Gets the opaque binary payload to include as operation in the {@link DtxResourceManager#start(byte[])} call. * * @return a valid byte array payload */ @Nonnull protected abstract byte[] getPayload(); /** * Tests the {@link DtxResourceManager#start(byte[])} method. * * Failure due to a <code>null</code> payload must be attributed to the concrete test's implementation of * {@link #getPayload()}. * * @throws NullPointerException * if the payload is null, not part of this test. * @throws XAException * not part of this test */ @Test public final void testStart() throws NullPointerException, XAException { final DtxResourceManager target = getResourceManagerInstance(); final DtxResourceManagerContext ctx = target.start(getPayload()); assertNotNull(ctx); assertEquals(DtxTaskStatus.STARTED, ctx.getTxStatus()); } /** * Tests the {@link DtxResourceManager#start(byte[])} method's failure due to a <code>null</code> payload. * * @throws NullPointerException * expected for this test * @throws XAException * not part of this test */ @Test(expected = NullPointerException.class) public final void testStartFailPayloadNull() throws NullPointerException, XAException { final DtxResourceManager target = getResourceManagerInstance(); target.start(null); } /** * Tests the {@link DtxResourceManager#start(byte[])} method's failure due to a bad payload made of random bytes. * * @throws NullPointerException * not part of this test * @throws XAException * expected for this test */ @Test(expected = XAException.class) public final void testStartFailInvalidPayload() throws NullPointerException, XAException { final DtxResourceManager target = getResourceManagerInstance(); final Random rnd = new Random(System.currentTimeMillis()); final byte[] fakePayload = new byte[rnd.nextInt(BAD_PAYLOAD_LENGTH) + 1]; rnd.nextBytes(fakePayload); try { target.start(fakePayload); } catch (final XAException xe) { assertEquals(XAException.XAER_INVAL, xe.errorCode); throw xe; } } /** * Tests the {@link DtxResourceManager#prepare(DtxResourceManagerContext)} method. * * @throws XAException * if the prepare operation fails, not part of this test */ @Test public final void testPrepare() throws XAException { final DtxResourceManager target = getResourceManagerInstance(); final DtxResourceManagerContext ctx = target.start(getPayload()); assertNotNull(ctx); assertEquals(DtxTaskStatus.STARTED, ctx.getTxStatus()); assertEquals(Boolean.TRUE, target.prepare(ctx)); assertEquals(DtxTaskStatus.PREPARED, ctx.getTxStatus()); } /** * Tests the {@link DtxResourceManager#prepare(DtxResourceManagerContext)} method's failure due to an invalid * context argument. * * @throws XAException * if the prepare operation fails, not part of this test */ @Test(expected = XAException.class) public final void testPrepareFailBadContext() throws XAException { final DtxResourceManager target = getResourceManagerInstance(); final DtxResourceManagerContext ctx = target.start(getPayload()); assertNotNull(ctx); assertEquals(DtxTaskStatus.STARTED, ctx.getTxStatus()); final DtxResourceManagerContext badCtx = new DtxResourceManagerContext(UUID.randomUUID(), STARTED) { }; try { target.prepare(badCtx); } catch (final XAException xe) { assertEquals(XAException.XAER_INVAL, xe.errorCode); throw xe; } } /** * Tests the {@link DtxResourceManager#prepare(DtxResourceManagerContext)} method's failure due to the * {@link DtxTaskStatus#PENDING} status of the context. * * @throws XAException * if the prepare operation fails, expected for this test */ @Test(expected = XAException.class) public final void testPrepareFailPending() throws XAException { final DtxResourceManager target = getResourceManagerInstance(); final DtxResourceManagerContext pendingCtx = new DtxResourceManagerContext(target.getId(), PENDING) { }; try { target.prepare(pendingCtx); } catch (final XAException xe) { assertEquals(XAException.XAER_PROTO, xe.errorCode); throw xe; } } /** * Tests the {@link DtxResourceManager#prepare(DtxResourceManagerContext)} method's failure due to the * {@link DtxTaskStatus#PREPARED} status of the context. * * @throws XAException * if the prepare operation fails, expected for this test */ @Test(expected = XAException.class) public final void testPrepareFailPrepared() throws XAException { final DtxResourceManager target = getResourceManagerInstance(); final DtxResourceManagerContext preparedCtx = new DtxResourceManagerContext(target.getId(), PREPARED) { }; try { target.prepare(preparedCtx); } catch (final XAException xe) { assertEquals(XAException.XAER_PROTO, xe.errorCode); throw xe; } } /** * Tests the {@link DtxResourceManager#prepare(DtxResourceManagerContext)} method's failure due to the * {@link DtxTaskStatus#COMMITTED} status of the context. * * @throws XAException * if the prepare operation fails, expected for this test */ @Test(expected = XAException.class) public final void testPrepareFailCommitted() throws XAException { final DtxResourceManager target = getResourceManagerInstance(); final DtxResourceManagerContext committedCtx = new DtxResourceManagerContext(target.getId(), COMMITTED) { }; try { target.prepare(committedCtx); } catch (final XAException xe) { assertEquals(XAException.XAER_PROTO, xe.errorCode); throw xe; } } /** * Tests the {@link DtxResourceManager#prepare(DtxResourceManagerContext)} method's failure due to the * {@link DtxTaskStatus#ROLLED_BACK} status of the context. * * @throws XAException * if the prepare operation fails, expected for this test */ @Test(expected = XAException.class) public final void testPrepareFailRolledBack() throws XAException { final DtxResourceManager target = getResourceManagerInstance(); final DtxResourceManagerContext ctx = target.start(getPayload()); assertNotNull(ctx); assertEquals(DtxTaskStatus.STARTED, ctx.getTxStatus()); target.rollback(ctx); assertEquals(DtxTaskStatus.ROLLED_BACK, ctx.getTxStatus()); try { target.prepare(ctx); } catch (final XAException xe) { assertEquals(XAException.XAER_PROTO, xe.errorCode); throw xe; } } /** * Tests the {@link DtxResourceManager#commit(DtxResourceManagerContext)} method. * * @throws XAException * if the commit operation fails, not part of this test */ @Test public final void testCommit() throws XAException { final DtxResourceManager target = getResourceManagerInstance(); final DtxResourceManagerContext ctx = target.start(getPayload()); assertNotNull(ctx); assertEquals(DtxTaskStatus.STARTED, ctx.getTxStatus()); target.prepare(ctx); assertEquals(DtxTaskStatus.PREPARED, ctx.getTxStatus()); target.commit(ctx); assertEquals(DtxTaskStatus.COMMITTED, ctx.getTxStatus()); } /** * Tests the {@link DtxResourceManager#commit(DtxResourceManagerContext)} method's failure due to an invalid * context. * * @throws XAException * expected for this test */ @Test(expected = XAException.class) public final void testCommitFailBadContext() throws XAException { final DtxResourceManager target = getResourceManagerInstance(); final DtxResourceManagerContext badCtx = new DtxResourceManagerContext(UUID.randomUUID(), PREPARED) { }; try { target.commit(badCtx); } catch (final XAException xe) { assertEquals(XAException.XAER_INVAL, xe.errorCode); throw xe; } } /** * Tests the {@link DtxResourceManager#commit(DtxResourceManagerContext)} method's failure due to the * {@link DtxTaskStatus#PENDING} status of the context. * * @throws XAException * if the commit operation fails, expected for this test */ @Test(expected = XAException.class) public final void testCommitFailPending() throws XAException { final DtxResourceManager target = getResourceManagerInstance(); final DtxResourceManagerContext pendingCtx = new DtxResourceManagerContext(target.getId(), PENDING) { }; try { target.commit(pendingCtx); } catch (final XAException xe) { assertEquals(XAException.XAER_PROTO, xe.errorCode); throw xe; } } /** * Tests the {@link DtxResourceManager#commit(DtxResourceManagerContext)} method's failure due to the * {@link DtxTaskStatus#STARTED} status of the context. * * @throws XAException * if the commit operation fails, expected for this test */ @Test(expected = XAException.class) public final void testCommitFailStarted() throws XAException { final DtxResourceManager target = getResourceManagerInstance(); final DtxResourceManagerContext startedCtx = new DtxResourceManagerContext(target.getId(), STARTED) { }; try { target.commit(startedCtx); } catch (final XAException xe) { assertEquals(XAException.XAER_PROTO, xe.errorCode); throw xe; } } /** * Tests the {@link DtxResourceManager#commit(DtxResourceManagerContext)} method's failure due to the * {@link DtxTaskStatus#STARTED} status of the context. * * @throws XAException * if the commit operation fails, expected for this test */ @Test(expected = XAException.class) public final void testCommitFailCommitted() throws XAException { final DtxResourceManager target = getResourceManagerInstance(); final DtxResourceManagerContext committedCtx = new DtxResourceManagerContext(target.getId(), COMMITTED) { }; try { target.commit(committedCtx); } catch (final XAException xe) { assertEquals(XAException.XAER_PROTO, xe.errorCode); throw xe; } } /** * Tests the {@link DtxResourceManager#commit(DtxResourceManagerContext)} method's failure due to the * {@link DtxTaskStatus#ROLLED_BACK} status of the context. * * @throws XAException * if the commit operation fails, expected for this test */ @Test(expected = XAException.class) public final void testCommitFailRolledBack() throws XAException { final DtxResourceManager target = getResourceManagerInstance(); final DtxResourceManagerContext ctx = target.start(getPayload()); assertNotNull(ctx); assertEquals(DtxTaskStatus.STARTED, ctx.getTxStatus()); target.rollback(ctx); assertEquals(DtxTaskStatus.ROLLED_BACK, ctx.getTxStatus()); try { target.commit(ctx); } catch (final XAException xe) { assertEquals(XAException.XAER_PROTO, xe.errorCode); throw xe; } } /** * Tests the {@link DtxResourceManager#commit(DtxResourceManagerContext)} method on a started context. * * @throws XAException * if the rollback operation fails, not part of this test */ @Test public final void testRollbackStarted() throws XAException { final DtxResourceManager target = getResourceManagerInstance(); final DtxResourceManagerContext ctx = target.start(getPayload()); target.rollback(ctx); } /** * Tests the {@link DtxResourceManager#commit(DtxResourceManagerContext)} method on a prepared context. * * @throws XAException * if the roll-back operation fails, not part of this test */ @Test public final void testRollbackPrepared() throws XAException { final DtxResourceManager target = getResourceManagerInstance(); final DtxResourceManagerContext ctx = target.start(getPayload()); assertNotNull(ctx); assertEquals(DtxTaskStatus.STARTED, ctx.getTxStatus()); assertEquals(Boolean.TRUE, target.prepare(ctx)); assertEquals(DtxTaskStatus.PREPARED, ctx.getTxStatus()); target.rollback(ctx); assertEquals(DtxTaskStatus.ROLLED_BACK, ctx.getTxStatus()); } /** * Tests the {@link DtxResourceManager#commit(DtxResourceManagerContext)} method's failure due to a context in * {@link DtxTaskStatus#PENDING} state. * * * @throws XAException * expected for this test */ @Test(expected = XAException.class) public final void testRollbackFailPending() throws XAException { final DtxResourceManager target = getResourceManagerInstance(); final DtxResourceManagerContext pendingCtx = new DtxResourceManagerContext(target.getId(), PENDING) { }; try { target.rollback(pendingCtx); } catch (final XAException xe) { assertEquals(XAException.XAER_PROTO, xe.errorCode); throw xe; } } /** * Tests the {@link DtxResourceManager#commit(DtxResourceManagerContext)} method's failure due to an invalid * context. * * @throws XAException * expected for this test */ @Test(expected = XAException.class) public final void testRollbackFailBadContext() throws XAException { final DtxResourceManager target = getResourceManagerInstance(); final DtxResourceManagerContext badCtx = new DtxResourceManagerContext(UUID.randomUUID(), PREPARED) { }; try { target.rollback(badCtx); } catch (final XAException xe) { assertEquals(XAException.XAER_INVAL, xe.errorCode); throw xe; } } /** * Tests the {@link DtxResourceManager#commit(DtxResourceManagerContext)} method's failure due to a context in * {@link DtxTaskStatus#COMMITTED} state. * * * @throws XAException * expected for this test */ @Test(expected = XAException.class) public final void testRollbackFailCommitted() throws XAException { final DtxResourceManager target = getResourceManagerInstance(); final DtxResourceManagerContext committedCtx = new DtxResourceManagerContext(target.getId(), COMMITTED) { }; try { target.rollback(committedCtx); } catch (final XAException xe) { assertEquals(XAException.XAER_PROTO, xe.errorCode); throw xe; } } /** * Tests the {@link DtxResourceManager#commit(DtxResourceManagerContext)} method's failure due to a context in * {@link DtxTaskStatus#ROLLED_BACK} state. * * * @throws XAException * expected for this test */ @Test(expected = XAException.class) public final void testRollbackFailRolledBack() throws XAException { final DtxResourceManager target = getResourceManagerInstance(); final DtxResourceManagerContext rolledbackCtx = new DtxResourceManagerContext(target.getId(), ROLLED_BACK) { }; try { target.rollback(rolledbackCtx); } catch (final XAException xe) { assertEquals(XAException.XAER_PROTO, xe.errorCode); throw xe; } } }