/* * JBoss, Home of Professional Open Source. * Copyright 2013, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This 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 software 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 software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package com.hp.mwtests.ts.arjuna.atomicaction; import com.arjuna.ats.arjuna.AtomicAction; import com.arjuna.ats.arjuna.common.arjPropertyManager; import com.arjuna.ats.arjuna.coordinator.AbstractRecord; import com.arjuna.ats.arjuna.coordinator.ActionStatus; import com.arjuna.ats.arjuna.coordinator.AddOutcome; import com.arjuna.ats.arjuna.coordinator.TwoPhaseOutcome; import com.arjuna.ats.internal.arjuna.abstractrecords.LastResourceRecord; import com.hp.mwtests.ts.arjuna.resources.*; import org.junit.Test; import org.junit.Assert; public class AtomicActionTestBase { protected static void init(boolean isAsync) { arjPropertyManager.getCoordinatorEnvironmentBean().setAsyncPrepare(isAsync); arjPropertyManager.getCoordinatorEnvironmentBean().setAsyncCommit(isAsync); arjPropertyManager.getCoordinatorEnvironmentBean().setAsyncRollback(isAsync); arjPropertyManager.getCoordinatorEnvironmentBean().setAsyncBeforeSynchronization(isAsync); arjPropertyManager.getCoordinatorEnvironmentBean().setAsyncAfterSynchronization(isAsync); } protected void testCommit () throws Exception { executeTest(true, ActionStatus.COMMITTED, null, new BasicRecord(), new BasicRecord()); } protected void testAbort () throws Exception { executeTest(false, ActionStatus.ABORTED, null, new BasicRecord(), new BasicRecord()); } protected void testPrepareWithLRRSuccess() { OnePhase onePhase = new OnePhase(); AbstractRecord lastResourceRecord = new LastResourceRecord(onePhase); AbstractRecord basicRecord = new BasicRecord(); executeTest(true, ActionStatus.COMMITTED, null, basicRecord, lastResourceRecord); Assert.assertEquals(OnePhase.COMMITTED, onePhase.status()); } protected void testPrepareWithLRRFailOn2PCAwareResourcePrepare() { OnePhase onePhase = new OnePhase(); AbstractRecord lastResourceRecord = new LastResourceRecord(onePhase); AbstractRecord shutdownRecord = new ShutdownRecord(ShutdownRecord.FAIL_IN_PREPARE); executeTest(true, ActionStatus.ABORTED, null, shutdownRecord, lastResourceRecord); Assert.assertEquals(OnePhase.ROLLEDBACK, onePhase.status()); } protected void testPrepareWithLRRFailOn2PCUnawareResourcePrepare() { OnePhase onePhase = new OnePhase(); AbstractRecord lastResourceRecord = new LastResourceShutdownRecord(onePhase, true); AbstractRecord basicRecord = new BasicRecord(); executeTest(true, ActionStatus.ABORTED, null, lastResourceRecord, basicRecord); Assert.assertEquals(OnePhase.ROLLEDBACK, onePhase.status()); } protected void testPrepareWithLRRFailOn2PCAwareResourceCommit() { OnePhase onePhase = new OnePhase(); AbstractRecord lastResourceRecord = new LastResourceRecord(onePhase); AbstractRecord shutdownRecord = new ShutdownRecord(ShutdownRecord.FAIL_IN_COMMIT); executeTest(true, ActionStatus.COMMITTED, null, lastResourceRecord, shutdownRecord); Assert.assertEquals(OnePhase.COMMITTED, onePhase.status()); } /** * Tests for correct behaviour of synchronisations (the normal case) * @throws Exception */ protected void testCompletionWithoutFailures() throws Exception { SyncRecord[] syncs = { new SyncRecord(), new SyncRecord(true, SyncRecord.FailureMode.NONE) }; executeTest(true, ActionStatus.COMMITTED, syncs, new BasicRecord(), new BasicRecord()); for (SyncRecord sync : syncs) { // assert that both before and after synchronisation callbacks were triggered Assert.assertTrue(sync.getBeforeTimeStamp() != 0); Assert.assertTrue(sync.getAfterTimeStamp() != 0); } // assert that beforeCompletion was called on the non interposed synchronisation first Assert.assertTrue(syncs[0].getBeforeTimeStamp() <= syncs[1].getBeforeTimeStamp()); // assert that beforeCompletion was called on the non interposed synchronisation last Assert.assertTrue(syncs[0].getAfterTimeStamp() >= syncs[1].getAfterTimeStamp()); } /** * Tests for correct behaviour of synchronisations (in the abnormal case) * @throws Exception */ protected void testCompletionWithFailures() throws Exception { SyncRecord[] syncs = { new SyncRecord(false, SyncRecord.FailureMode.BEFORE_FAIL), new SyncRecord(true, SyncRecord.FailureMode.NONE) }; executeTest(true, ActionStatus.ABORTED, syncs, new BasicRecord(), new BasicRecord()); /* * since the first synch failed during the beforeCompletion callback: * - beforeCompletion should be called on the first one * - beforeCompletion should not be called on the second one * - afterCompletion should be called on all synchronisations * - the final status of the action should be aborted */ Assert.assertTrue(syncs[0].getBeforeTimeStamp() != 0); Assert.assertTrue(syncs[1].getBeforeTimeStamp() == 0); Assert.assertTrue(syncs[0].getAfterTimeStamp() != 0); Assert.assertTrue(syncs[1].getAfterTimeStamp() != 0); Assert.assertTrue(syncs[1].getStatus() == ActionStatus.ABORTED); } /** * Tests for correct behaviour of synchronisations (in the abnormal case) * @throws Exception */ protected void testCompletionWithException() throws Exception { SyncRecord[] syncs = { new SyncRecord(false, SyncRecord.FailureMode.NONE), new SyncRecord(true, SyncRecord.FailureMode.NONE) }; RuntimeException exception = new RuntimeException("testCompletionWithException"); syncs[0].setBeforeThrowable(exception); AtomicAction a= executeTest(true, ActionStatus.ABORTED, syncs, new BasicRecord(), new BasicRecord()); /* * since the first synch failed during the beforeCompletion callback: * - beforeCompletion should be called on the first one * - beforeCompletion should not be called on the second one * - afterCompletion should be called on all synchronisations * - the synchronization should have throw the runtime exception * - the final status of the action should be aborted */ Assert.assertTrue(syncs[0].getBeforeTimeStamp() != 0); Assert.assertTrue(syncs[1].getBeforeTimeStamp() == 0); Assert.assertTrue(syncs[0].getAfterTimeStamp() != 0); Assert.assertTrue(syncs[1].getAfterTimeStamp() != 0); Assert.assertEquals(exception, a.getDeferredThrowable()); Assert.assertTrue(syncs[1].getStatus() == ActionStatus.ABORTED); } protected void testRegistrationDuringCompletion() throws Exception { SyncRecord[] syncs = { new SyncRecord(false, SyncRecord.FailureMode.NONE), new SyncRecord(true, SyncRecord.FailureMode.NONE) }; /* * arrange for the interposed synchronisation to register a non interposed synchronisation during * the beforeCompletion call. This call should fail (resulting in the action being aborted) since * interposed syncs run after non interposed ones */ syncs[1].registerSynchDuringSynch(new SyncRecord(false, SyncRecord.FailureMode.NONE)); executeTest(true, ActionStatus.ABORTED, syncs, new BasicRecord(), new BasicRecord()); } protected void testRegistrationDuringCompletion2() throws Exception { SyncRecord[] syncs = { new SyncRecord(false, SyncRecord.FailureMode.NONE), new SyncRecord(true, SyncRecord.FailureMode.NONE) }; /* * arrange for the interposed synchronisation to register another interposed synchronisation during * the beforeCompletion call. This call should succeed (since interposed synchronisations are * executed in time order) */ syncs[1].registerSynchDuringSynch(new SyncRecord(true, SyncRecord.FailureMode.NONE)); executeTest(true, ActionStatus.COMMITTED, syncs, new BasicRecord(), new BasicRecord()); } protected void testRegistrationDuringCompletion2b() throws Exception { SyncRecord earlierSync = new SyncRecord(true, SyncRecord.FailureMode.NONE); SyncRecord[] syncs = { new SyncRecord(false, SyncRecord.FailureMode.NONE), new SyncRecord(true, SyncRecord.FailureMode.NONE) }; /* * Arrange for the interposed synchronisation to register another interposed synchronisation during * the beforeCompletion but in such a way that this second synchronisation is ordered before the * first one (interposed synchronisations are time ordered). * * If synchronisations are executed in parallel this should succeed but if they are executed in order * then it will fail. */ syncs[1].registerSynchDuringSynch(earlierSync); int expect = arjPropertyManager.getCoordinatorEnvironmentBean().isAsyncBeforeSynchronization() ? ActionStatus.COMMITTED : ActionStatus.ABORTED; executeTest(true, expect, syncs, new BasicRecord(), new BasicRecord()); } protected void testRegistrationDuringCompletion3() throws Exception { SyncRecord[] syncs = { new SyncRecord(false, SyncRecord.FailureMode.NONE), new SyncRecord(true, SyncRecord.FailureMode.NONE) }; /* * arrange for the non interposed synchronisation to register an interposed synchronisation during * the beforeCompletion call. This call should succeed (since non interposed synchronisations run first) */ syncs[0].registerSynchDuringSynch(new SyncRecord(true, SyncRecord.FailureMode.NONE)); executeTest(true, ActionStatus.COMMITTED, syncs, new BasicRecord(), new BasicRecord()); } protected void testRegistrationDuringCompletion4() throws Exception { SyncRecord[] syncs = { new SyncRecord(false, SyncRecord.FailureMode.NONE), new SyncRecord(true, SyncRecord.FailureMode.NONE) }; /* * arrange for the non interposed synchronisation to register another non interposed synchronisation during * the beforeCompletion call. This call should succeed (since non interposed synchronisations are * executed in time order). */ syncs[0].registerSynchDuringSynch(new SyncRecord(false, SyncRecord.FailureMode.NONE)); executeTest(true, ActionStatus.COMMITTED, syncs, new BasicRecord(), new BasicRecord()); } protected void testRegistrationDuringCompletion4b() throws Exception { SyncRecord earlierSync = new SyncRecord(false, SyncRecord.FailureMode.NONE); SyncRecord[] syncs = { new SyncRecord(false, SyncRecord.FailureMode.NONE), new SyncRecord(true, SyncRecord.FailureMode.NONE) }; /* * Arrange for the non interposed synchronisation to register another non interposed synchronisation during * the beforeCompletion but in such a way that this second synchronisation is ordered before the * first one (non interposed synchronisations are time ordered). * * If synchronisations are executed in parallel this should succeed but if they are executed in order * then it will fail. */ syncs[0].registerSynchDuringSynch(earlierSync); int expect = arjPropertyManager.getCoordinatorEnvironmentBean().isAsyncBeforeSynchronization() ? ActionStatus.COMMITTED : ActionStatus.ABORTED; executeTest(true, expect, syncs, new BasicRecord(), new BasicRecord()); } protected void testHeuristicNotification(boolean reportHeuristics) throws Exception { AtomicAction A = new AtomicAction(); DummyHeuristic[] dha = {new DummyHeuristic(), new DummyHeuristic()}; A.begin(); A.add(new BasicRecord()); A.add(new BasicRecord()); A.add(new HeuristicRecord()); for (DummyHeuristic dh : dha) A.addSynchronization(dh); int status = A.commit(reportHeuristics); if (reportHeuristics) Assert.assertEquals(ActionStatus.H_MIXED, status); else if (!arjPropertyManager.getCoordinatorEnvironmentBean().isAsyncCommit()) Assert.assertEquals(ActionStatus.COMMITTED, status); else Assert.assertTrue(status == ActionStatus.COMMITTED || status == ActionStatus.COMMITTING); // we only inform synchronisations of the outcome if report_heuristics is false int expect = reportHeuristics ? -1 : TwoPhaseOutcome.HEURISTIC_MIXED; for (DummyHeuristic dh : dha) Assert.assertEquals(expect, dh.getStatus()); } protected AtomicAction executeTest(boolean isCommit, int expectedResult, SyncRecord[] syncs, AbstractRecord... records) { AtomicAction A = new AtomicAction(); A.begin(); for (AbstractRecord record : records) { A.add(record); } if (syncs != null) { for (SyncRecord sync : syncs) Assert.assertEquals(AddOutcome.AR_ADDED, A.addSynchronization(sync)); Assert.assertEquals(syncs.length, A.getSynchronizations().size()); } if (isCommit) { Assert.assertEquals(expectedResult, A.commit()); } else { Assert.assertEquals(expectedResult, A.abort()); } return A; } }