[jboss-svn-commits] JBL Code SVN: r33141 - in labs/jbosstm/trunk/txbridge: docs and 9 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Fri May 28 10:50:02 EDT 2010


Author: jhalliday
Date: 2010-05-28 10:50:01 -0400 (Fri, 28 May 2010)
New Revision: 33141

Added:
   labs/jbosstm/trunk/txbridge/tests/dd/outbound/jboss-beans.xml
   labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/inbound/junit/CrashRecoveryTests.java
   labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/outbound/junit/CrashRecoveryTests.java
   labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/outbound/utility/TestRecoveryModule.java
Modified:
   labs/jbosstm/trunk/txbridge/build.xml
   labs/jbosstm/trunk/txbridge/docs/TransactionBridgingGuide.odt
   labs/jbosstm/trunk/txbridge/src/org/jboss/jbossts/txbridge/outbound/OutboundBridgeRecoveryManager.java
   labs/jbosstm/trunk/txbridge/tests/build.xml
   labs/jbosstm/trunk/txbridge/tests/dd/inbound/jboss-beans.xml
   labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/inbound/utility/TestXAResourceRecoveryHelper.java
   labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/outbound/service/TestServiceImpl.java
   labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/outbound/utility/TestDurableParticipant.java
Log:
Added initial prototype crash recovery tests to the txbridge. JBTM-44


Modified: labs/jbosstm/trunk/txbridge/build.xml
===================================================================
--- labs/jbosstm/trunk/txbridge/build.xml	2010-05-28 14:27:47 UTC (rev 33140)
+++ labs/jbosstm/trunk/txbridge/build.xml	2010-05-28 14:50:01 UTC (rev 33141)
@@ -145,6 +145,7 @@
             <report>
                 <fileset dir="${build.dir}" includes="metadata.emma"/>
                 <fileset dir="${jbossas.home}" includes="coverage.ec"/>
+                <fileset dir="${jbossas.home}/bin" includes="coverage.ec"/>
                 <sourcepath>
                     <dirset dir="${src.dir}"/>
                 </sourcepath>

Modified: labs/jbosstm/trunk/txbridge/docs/TransactionBridgingGuide.odt
===================================================================
(Binary files differ)

Modified: labs/jbosstm/trunk/txbridge/src/org/jboss/jbossts/txbridge/outbound/OutboundBridgeRecoveryManager.java
===================================================================
--- labs/jbosstm/trunk/txbridge/src/org/jboss/jbossts/txbridge/outbound/OutboundBridgeRecoveryManager.java	2010-05-28 14:27:47 UTC (rev 33140)
+++ labs/jbosstm/trunk/txbridge/src/org/jboss/jbossts/txbridge/outbound/OutboundBridgeRecoveryManager.java	2010-05-28 14:50:01 UTC (rev 33141)
@@ -75,10 +75,18 @@
     @Override
     public void periodicWorkSecondPass()
     {
+        // by the time we are called, the JTA tx recovery module has already been called, as it is registered
+        // and hence ordered before us. Therefore by the time we get here any BridgeWrappers belonging to
+        // a parent that was logged, will have been resolved top down. Anything left at this point can therefore
+        // be assumed orphaned and hence we apply presumed abort.
+
         log.trace("periodicWorkSecondPass()");
 
         BridgeWrapper[] bridgeWrappers = BridgeWrapper.scan(OutboundBridgeManager.BRIDGEWRAPPER_PREFIX);
-        // TODO: do something useful with the results.
 
+        for(BridgeWrapper bridgeWrapper : bridgeWrappers) {
+            log.info("rolling back orphaned subordinate BridgeWrapper "+bridgeWrapper.getIdentifier());
+            bridgeWrapper.rollback();
+        }
     }
 }

Modified: labs/jbosstm/trunk/txbridge/tests/build.xml
===================================================================
--- labs/jbosstm/trunk/txbridge/tests/build.xml	2010-05-28 14:27:47 UTC (rev 33140)
+++ labs/jbosstm/trunk/txbridge/tests/build.xml	2010-05-28 14:50:01 UTC (rev 33141)
@@ -43,6 +43,9 @@
             <include name="commons-httpclient.jar"/>
             <include name="commons-logging.jar"/>
             <include name="commons-codec.jar"/>
+            <include name="jboss-server-manager.jar"/>
+            <include name="jboss-logging-spi.jar"/>
+            <include name="jnp-client.jar"/>
             <!--<include name="byteman.jar"/>-->
         </fileset>
 
@@ -60,6 +63,7 @@
 
         <pathelement location="/home/jhalli/IdeaProjects/jboss/byteman_trunk/install/lib/byteman.jar"/>        
         <pathelement location="/home/jhalli/IdeaProjects/jboss/byteman_trunk/contrib/dtest/build/lib/byteman-dtest.jar"/>
+        <pathelement location="/home/jhalli/IdeaProjects/jboss/jbossas_trunk/build/target/jboss-6.0.0-SNAPSHOT/client/jboss-system-client.jar"/>
 
 	</path>
 
@@ -108,6 +112,9 @@
 				<include name="org/jboss/jbossts/txbridge/tests/outbound/service/*"/>
                 <include name="org/jboss/jbossts/txbridge/tests/outbound/utility/*"/>
 			</classes>
+            <webinf dir="dd/outbound">
+                <include name="jboss-beans.xml"/>
+            </webinf>
 		</war>
 
         <war warfile="${build.dir}/txbridge-outbound-tests-client.war" webxml="${dd}/outbound/web.xml">
@@ -141,6 +148,15 @@
         </run.tests.macro>
     </target>
 
+    <target name="run-inbound-crashrec-tests" depends="compile">
+        <run.tests.macro>
+            <tests>
+                <fileset dir="src" includes="**/inbound/**/CrashRecoveryTests.java">
+                </fileset>
+            </tests>
+        </run.tests.macro>
+    </target>
+
     <target name="run-outbound-tests" depends="compile">
         <run.tests.macro>
             <tests>
@@ -150,10 +166,18 @@
         </run.tests.macro>
     </target>
 
+    <target name="run-outbound-crashrec-tests" depends="compile">
+        <run.tests.macro>
+            <tests>
+                <fileset dir="src" includes="**/outbound/**/CrashRecoveryTests.java">
+                </fileset>
+            </tests>
+        </run.tests.macro>
+    </target>
 
     <macrodef name="run.tests.macro">
 
-        <attribute name="showoutput" default="false"/>
+        <attribute name="showoutput" default="true"/>
         <element name="tests"/>
         <element name="additional.classpath" optional="true"/>
         <element name="additional.jvmargs" optional="true"/>
@@ -174,8 +198,8 @@
             </batchtest>
 
             <jvmarg value="-Djava.rmi.server.codebase=file://build/classes/"/>
-            <!--<jvmarg value="-Xdebug"/>-->
-            <!--<jvmarg value="-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005"/>-->
+            <jvmarg value="-Xdebug"/>
+            <jvmarg value="-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005"/>
 	        <additional.jvmargs/>
         </junit>
         </sequential>

Modified: labs/jbosstm/trunk/txbridge/tests/dd/inbound/jboss-beans.xml
===================================================================
--- labs/jbosstm/trunk/txbridge/tests/dd/inbound/jboss-beans.xml	2010-05-28 14:27:47 UTC (rev 33140)
+++ labs/jbosstm/trunk/txbridge/tests/dd/inbound/jboss-beans.xml	2010-05-28 14:50:01 UTC (rev 33141)
@@ -23,7 +23,7 @@
 
 <deployment xmlns="urn:jboss:bean-deployer:2.0">
 
-    <bean name="TxBridgeTests" class="org.jboss.jbossts.txbridge.tests.inbound.utility.TestXAResourceRecoveryHelper">
+    <bean name="TxBridgeInboundTests" class="org.jboss.jbossts.txbridge.tests.inbound.utility.TestXAResourceRecoveryHelper">
 
         <constructor factoryClass="org.jboss.jbossts.txbridge.tests.inbound.utility.TestXAResourceRecoveryHelper" factoryMethod="getInstance"/>
 

Added: labs/jbosstm/trunk/txbridge/tests/dd/outbound/jboss-beans.xml
===================================================================
--- labs/jbosstm/trunk/txbridge/tests/dd/outbound/jboss-beans.xml	                        (rev 0)
+++ labs/jbosstm/trunk/txbridge/tests/dd/outbound/jboss-beans.xml	2010-05-28 14:50:01 UTC (rev 33141)
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and/or its affiliates,
+ * and individual contributors as indicated by the @author tags.
+ * See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License, v. 2.1.
+ * This program is distributed in the hope that it will be useful, but WITHOUT A
+ * 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,
+ * v.2.1 along with this distribution; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.
+ *
+ * (C) 2010
+ * @author JBoss, by Red Hat.
+-->
+
+<deployment xmlns="urn:jboss:bean-deployer:2.0">
+
+    <bean name="TxBridgeOutboundTests" class="org.jboss.jbossts.txbridge.tests.outbound.utility.TestRecoveryModule">
+
+        <depends>jboss.xts:service=XTSService</depends>
+
+        <depends>jboss:service=TransactionManager</depends>
+
+    </bean>
+
+</deployment>
\ No newline at end of file

Added: labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/inbound/junit/CrashRecoveryTests.java
===================================================================
--- labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/inbound/junit/CrashRecoveryTests.java	                        (rev 0)
+++ labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/inbound/junit/CrashRecoveryTests.java	2010-05-28 14:50:01 UTC (rev 33141)
@@ -0,0 +1,365 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and/or its affiliates,
+ * and individual contributors as indicated by the @author tags.
+ * See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License, v. 2.1.
+ * This program is distributed in the hope that it will be useful, but WITHOUT A
+ * 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,
+ * v.2.1 along with this distribution; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.
+ *
+ * (C) 2010,
+ * @author JBoss, by Red Hat.
+ */
+package org.jboss.jbossts.txbridge.tests.inbound.junit;
+
+import com.arjuna.ats.arjuna.common.recoveryPropertyManager;
+import org.apache.commons.httpclient.HttpMethodBase;
+import org.jboss.jbossas.servermanager.Argument;
+import org.jboss.jbossas.servermanager.Property;
+import org.jboss.jbossas.servermanager.Server;
+import org.jboss.jbossas.servermanager.ServerManager;
+import org.jboss.jbossts.txbridge.inbound.BridgeDurableParticipant;
+import org.jboss.jbossts.txbridge.tests.inbound.client.TestClient;
+import org.jboss.jbossts.txbridge.tests.inbound.service.TestServiceImpl;
+import org.jboss.jbossts.txbridge.tests.inbound.utility.TestSynchronization;
+import org.jboss.jbossts.txbridge.tests.inbound.utility.TestXAResource;
+
+import org.jboss.jbossts.txbridge.tests.inbound.utility.TestXAResourceRecovered;
+import org.junit.*;
+import static org.junit.Assert.*;
+
+import org.jboss.byteman.agent.submit.Submit;
+import org.jboss.byteman.contrib.dtest.*;
+
+import com.arjuna.qa.junit.HttpUtils;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.net.Socket;
+import java.net.URL;
+import java.net.ConnectException;
+
+/**
+ * Crash Recovery test cases for the inbound side of the transaction bridge.
+ *
+ * @author Jonathan Halliday (jonathan.halliday at redhat.com) 2010-05
+ */
+public class CrashRecoveryTests
+{
+    private static final String baseURL = "http://localhost:8080/txbridge-inbound-tests-client/testclient";
+
+    private static Instrumentor instrumentor;
+    private InstrumentedClass instrumentedTestSynchronization;
+    private InstrumentedClass instrumentedTestXAResource;
+    
+
+    private static final ServerManager manager = new ServerManager(); // ASTestConfig.java/ServerTask.java
+    private static final Argument bytemanArgument = new Argument();
+
+    /*
+-Xdebug
+-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5006
+-Xmx1024m
+-javaagent:/home/jhalli/IdeaProjects/jboss/byteman_trunk/install/lib/byteman.jar=port:9091,listener:true
+-Dorg.jboss.byteman.debug=true
+-Dorg.jboss.byteman.verbose=true
+-Dorg.jboss.byteman.dump.generated.classes=true
+-Dorg.jboss.byteman.dump.generated.classes.dir=dump
+-Demma.exit.delay=10
+     */
+
+    @BeforeClass
+    public static void beforeClass() throws Exception {
+        instrumentor = new Instrumentor(new Submit(), 1199);
+
+        manager.setJbossHome("/home/jhalli/IdeaProjects/jboss/jbossas_trunk/build/target/jboss-6.0.0-SNAPSHOT/");
+        manager.setJavaHome("/usr/local/jdk1.6.0_20/");
+
+//        byteman.jar=script:$SCRIPT_HOME/HeuristicSaveAndRecover.txt
+
+
+        Server server = new Server();
+        server.setName("default");
+
+        server.addJvmArg(bytemanArgument);
+        Argument arg2 = new Argument();
+        arg2.setValue("-Xmx1024m");
+        server.addJvmArg(arg2);
+
+        Argument arg3 = new Argument();
+        arg3.setValue("-Xdebug");
+        server.addJvmArg(arg3);
+        Argument arg4 = new Argument();
+        arg4.setValue("-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5006");
+        server.addJvmArg(arg4);
+
+        Property property1 = new Property();
+        property1.setKey("org.jboss.byteman.debug");
+        property1.setValue("true");
+        server.addSysProperty(property1);
+        Property property2 = new Property();
+        property2.setKey(BytemanTestHelper.RMIREGISTRY_PORT_PROPERTY_NAME);
+        property2.setValue("1199");
+        server.addSysProperty(property2);
+
+        Property property3 = new Property();
+        property3.setKey("emma.exit.delay");
+        property3.setValue("10");
+        server.addSysProperty(property3);
+
+        manager.addServer(server);
+    }
+
+    @Before
+    public void setUp() throws Exception {
+
+        bytemanArgument.setValue("-javaagent:/home/jhalli/IdeaProjects/jboss/byteman_trunk/install/lib/byteman.jar=port:9091,listener:true,sys:/home/jhalli/IdeaProjects/jboss/byteman_trunk/contrib/dtest/build/lib/byteman-dtest.jar");
+        removeContents(new File("/home/jhalli/IdeaProjects/jboss/jbossas_trunk/build/target/jboss-6.0.0-SNAPSHOT/server/default/data/tx-object-store/"));
+
+
+        // TODO: fix JMXAdapter leak.
+        manager.getServer("default").setServerConnection(null);
+        manager.startServer("default");
+        
+        //instrumentor.installHelperJar("/home/jhalli/IdeaProjects/jboss/byteman_trunk/contrib/dtest/build/lib/byteman-dtest.jar");
+        instrumentor.setRedirectedSubmissionsFile(null);
+
+        instrumentedTestSynchronization = instrumentor.instrumentClass(TestSynchronization.class);
+        instrumentedTestXAResource = instrumentor.instrumentClass(TestXAResource.class);
+
+        instrumentor.injectOnCall(TestServiceImpl.class, "doNothing", "$0.enlistSynchronization(1), $0.enlistXAResource(1)");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        instrumentor.removeAllInstrumentation();
+
+        manager.stopServer("default");
+    }
+
+    private void execute(boolean expectResponse) throws Exception {
+
+        HttpMethodBase request = null;
+
+        try {
+            request = HttpUtils.accessURL(new URL(baseURL));
+        } catch(ConnectException e) {
+            if(expectResponse) {
+                throw e;
+            }
+        }
+
+        if(expectResponse) {
+            String response = request.getResponseBodyAsString().trim();
+            assertEquals("finished", response);
+        }
+    }
+
+    private void rebootServer() throws Exception {
+        
+        instrumentor.removeLocalState();
+        File rulesFile = new File("/tmp/bar3");
+        rulesFile.delete();
+        instrumentor.setRedirectedSubmissionsFile(rulesFile);
+        bytemanArgument.setValue(bytemanArgument.getValue()+",script:"+rulesFile.getCanonicalPath());
+
+        instrumentedTestSynchronization = instrumentor.instrumentClass(TestSynchronization.class);
+        instrumentedTestXAResource = instrumentor.instrumentClass(TestXAResourceRecovered.class);
+
+        manager.getServer("default").setServerConnection(null);        
+        Thread.sleep(2000);
+        manager.startServer("default");
+    }
+
+    @Test
+    public void testCrashOneLog() throws Exception {
+
+        instrumentor.injectOnCall(TestClient.class,  "terminateTransaction", "$2 = true"); // shouldCommit=true
+        instrumentor.crashAtMethodExit(TestXAResource.class, "prepare");
+        
+        execute(false);
+
+        instrumentedTestSynchronization.assertKnownInstances(1);
+        instrumentedTestSynchronization.assertMethodCalled("beforeCompletion");
+        instrumentedTestSynchronization.assertMethodNotCalled("afterCompletion");
+
+        instrumentedTestXAResource.assertKnownInstances(1);
+        instrumentedTestXAResource.assertMethodCalled("prepare");
+        instrumentedTestXAResource.assertMethodNotCalled("rollback");
+        instrumentedTestXAResource.assertMethodNotCalled("commit");
+
+        rebootServer();
+
+        doRecovery();
+        doRecovery();
+
+        instrumentedTestXAResource.assertKnownInstances(1);
+        instrumentedTestXAResource.assertMethodCalled("recover");
+        instrumentedTestXAResource.assertMethodCalled("rollback");
+        instrumentedTestXAResource.assertMethodNotCalled("commit");
+    }
+
+    @Test
+    public void testCrashTwoLogs() throws Exception {
+
+        InstrumentedClass durableParticipant = instrumentor.instrumentClass(BridgeDurableParticipant.class);
+
+        instrumentor.injectOnCall(TestClient.class,  "terminateTransaction", "$2 = true"); // shouldCommit=true
+        instrumentor.crashAtMethodExit(BridgeDurableParticipant.class, "prepare");
+
+        execute(false);
+
+        durableParticipant.assertMethodCalled("prepare");
+        durableParticipant.assertMethodNotCalled("rollback");
+        durableParticipant.assertMethodNotCalled("commit");
+
+        instrumentedTestSynchronization.assertKnownInstances(1);
+        instrumentedTestSynchronization.assertMethodCalled("beforeCompletion");
+        instrumentedTestSynchronization.assertMethodNotCalled("afterCompletion");
+
+        instrumentedTestXAResource.assertKnownInstances(1);
+        instrumentedTestXAResource.assertMethodCalled("prepare");
+        instrumentedTestXAResource.assertMethodNotCalled("rollback");
+        instrumentedTestXAResource.assertMethodNotCalled("commit");
+
+        rebootServer();
+
+        doRecovery();
+        doRecovery();
+
+        instrumentedTestXAResource.assertKnownInstances(1);
+        instrumentedTestXAResource.assertMethodCalled("recover");
+        instrumentedTestXAResource.assertMethodCalled("rollback");
+        instrumentedTestXAResource.assertMethodNotCalled("commit");
+    }
+
+    @Test
+    public void testCrashThreeLogs() throws Exception {
+
+        InstrumentedClass durableParticipant = instrumentor.instrumentClass(BridgeDurableParticipant.class);
+
+        instrumentor.injectOnCall(TestClient.class,  "terminateTransaction", "$2 = true"); // shouldCommit=true
+        instrumentor.crashAtMethodExit("^XTSATRecoveryManager", "writeParticipantRecoveryRecord");
+
+        execute(false);
+
+        durableParticipant.assertMethodCalled("prepare");
+        durableParticipant.assertMethodNotCalled("rollback");
+        durableParticipant.assertMethodNotCalled("commit");
+
+        instrumentedTestSynchronization.assertKnownInstances(1);
+        instrumentedTestSynchronization.assertMethodCalled("beforeCompletion");
+        instrumentedTestSynchronization.assertMethodNotCalled("afterCompletion");
+
+        instrumentedTestXAResource.assertKnownInstances(1);
+        instrumentedTestXAResource.assertMethodCalled("prepare");
+        instrumentedTestXAResource.assertMethodNotCalled("rollback");
+        instrumentedTestXAResource.assertMethodNotCalled("commit");
+
+        rebootServer();
+
+        doRecovery();
+        doRecovery();
+
+        instrumentedTestXAResource.assertKnownInstances(1);
+        instrumentedTestXAResource.assertMethodCalled("recover");
+        instrumentedTestXAResource.assertMethodCalled("rollback");
+        instrumentedTestXAResource.assertMethodNotCalled("commit");
+    }
+
+    // TODO: add test for 4log case i.e. commit
+
+    /////////////////
+
+    // stolen from CrashRecoveryDelays - should probably just add that to the classpath?
+    // prod the recovery manager via its socket. This avoid any sleep delay.
+    private static void doRecovery() throws InterruptedException
+    {
+        int port = recoveryPropertyManager.getRecoveryEnvironmentBean().getRecoveryPort();
+        String host = recoveryPropertyManager.getRecoveryEnvironmentBean().getRecoveryAddress();
+
+        BufferedReader in = null;
+        PrintStream out = null;
+        Socket sckt = null;
+
+        try
+        {
+            sckt = new Socket(host,port);
+
+            in = new BufferedReader(new InputStreamReader(sckt.getInputStream()));
+            out = new PrintStream(sckt.getOutputStream());
+
+            // Output ping message
+            out.println("SCAN");
+            out.flush();
+
+            // Receive pong message
+            String inMessage = in.readLine();
+
+            if(!inMessage.equals("DONE")) {
+                System.err.println("Recovery failed with message: "+inMessage);
+            }
+        }
+        catch (Exception ex)
+        {
+            ex.printStackTrace();
+        }
+        finally
+        {
+            try {
+                if ( in != null )
+                {
+                    in.close();
+                }
+
+                if ( out != null )
+                {
+                    out.close();
+                }
+
+                sckt.close();
+            } catch(Exception e) {}
+        }
+   }
+
+    // stolen from EmptyObjectStore.java
+    public static void removeContents(File directory)
+    {
+        if ((directory != null) &&
+                directory.isDirectory() &&
+                (!directory.getName().equals("")) &&
+                (!directory.getName().equals("/")) &&
+                (!directory.getName().equals("\\")) &&
+                (!directory.getName().equals(".")) &&
+                (!directory.getName().equals("..")))
+        {
+            File[] contents = directory.listFiles();
+
+            for (int index = 0; index < contents.length; index++)
+            {
+                if (contents[index].isDirectory())
+                {
+                    removeContents(contents[index]);
+
+                    //System.err.println("Deleted: " + contents[index]);
+                    contents[index].delete();
+                }
+                else
+                {
+                    System.err.println("Deleted: " + contents[index]);
+                    contents[index].delete();
+                }
+            }
+        }
+    }
+}

Modified: labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/inbound/utility/TestXAResourceRecoveryHelper.java
===================================================================
--- labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/inbound/utility/TestXAResourceRecoveryHelper.java	2010-05-28 14:27:47 UTC (rev 33140)
+++ labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/inbound/utility/TestXAResourceRecoveryHelper.java	2010-05-28 14:50:01 UTC (rev 33141)
@@ -46,6 +46,7 @@
     private static Logger log = Logger.getLogger(TestXAResourceRecoveryHelper.class);
 
     private static final TestXAResourceRecoveryHelper instance = new TestXAResourceRecoveryHelper();
+    private static final TestXAResourceRecovered xaResourceInstance = new TestXAResourceRecovered();
 
     private final Set<Xid> preparedXids = new HashSet<Xid>();
 
@@ -102,7 +103,7 @@
         log.trace("getXAResources()");
 
         XAResource values[] = new XAResource[1];
-        values[0] = new TestXAResourceRecovered();
+        values[0] = xaResourceInstance;
 
         return values;
     }

Added: labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/outbound/junit/CrashRecoveryTests.java
===================================================================
--- labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/outbound/junit/CrashRecoveryTests.java	                        (rev 0)
+++ labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/outbound/junit/CrashRecoveryTests.java	2010-05-28 14:50:01 UTC (rev 33141)
@@ -0,0 +1,361 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and/or its affiliates,
+ * and individual contributors as indicated by the @author tags.
+ * See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License, v. 2.1.
+ * This program is distributed in the hope that it will be useful, but WITHOUT A
+ * 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,
+ * v.2.1 along with this distribution; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.
+ *
+ * (C) 2010,
+ * @author JBoss, by Red Hat.
+ */
+package org.jboss.jbossts.txbridge.tests.outbound.junit;
+
+import com.arjuna.ats.arjuna.common.recoveryPropertyManager;
+import org.apache.commons.httpclient.HttpMethodBase;
+import org.jboss.jbossas.servermanager.Argument;
+import org.jboss.jbossas.servermanager.Property;
+import org.jboss.jbossas.servermanager.Server;
+import org.jboss.jbossas.servermanager.ServerManager;
+import org.jboss.jbossts.txbridge.outbound.BridgeXAResource;
+import org.jboss.jbossts.txbridge.tests.outbound.client.TestClient;
+import org.jboss.jbossts.txbridge.tests.outbound.service.TestServiceImpl;
+import org.jboss.jbossts.txbridge.tests.outbound.utility.TestDurableParticipant;
+import org.jboss.jbossts.txbridge.tests.outbound.utility.TestVolatileParticipant;
+import org.junit.*;
+import static org.junit.Assert.*;
+
+import org.jboss.byteman.agent.submit.Submit;
+import org.jboss.byteman.contrib.dtest.*;
+
+import com.arjuna.qa.junit.HttpUtils;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.URL;
+import java.net.ConnectException;
+
+/**
+ * Crash Recovery test cases for the outbound side of the transaction bridge.
+ *
+ * @author Jonathan Halliday (jonathan.halliday at redhat.com) 2010-05
+ */
+
+public class CrashRecoveryTests
+{
+    private static final String baseURL = "http://localhost:8080/txbridge-outbound-tests-client/testclient";
+
+    private static Instrumentor instrumentor;
+    private InstrumentedClass instrumentedTestVolatileParticipant;
+    private InstrumentedClass instrumentedTestDurableParticipant;
+
+    private static final ServerManager manager = new ServerManager(); // ASTestConfig.java/ServerTask.java
+    private static final Argument bytemanArgument = new Argument();
+
+    /*
+-Xdebug
+-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5006
+-Xmx1024m
+-javaagent:/home/jhalli/IdeaProjects/jboss/byteman_trunk/install/lib/byteman.jar=port:9091,listener:true
+-Dorg.jboss.byteman.debug=true
+-Dorg.jboss.byteman.verbose=true
+-Dorg.jboss.byteman.dump.generated.classes=true
+-Dorg.jboss.byteman.dump.generated.classes.dir=dump
+-Demma.exit.delay=10
+     */
+
+    @BeforeClass
+    public static void beforeClass() throws Exception {
+        instrumentor = new Instrumentor(new Submit(), 1199);
+
+        manager.setJbossHome("/home/jhalli/IdeaProjects/jboss/jbossas_trunk/build/target/jboss-6.0.0-SNAPSHOT/");
+        manager.setJavaHome("/usr/local/jdk1.6.0_20/");
+
+//        byteman.jar=script:$SCRIPT_HOME/HeuristicSaveAndRecover.txt
+
+
+        Server server = new Server();
+        server.setName("default");
+
+        server.addJvmArg(bytemanArgument);
+        Argument arg2 = new Argument();
+        arg2.setValue("-Xmx1024m");
+        server.addJvmArg(arg2);
+
+        Argument arg3 = new Argument();
+        arg3.setValue("-Xdebug");
+        server.addJvmArg(arg3);
+        Argument arg4 = new Argument();
+        arg4.setValue("-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5006");
+        server.addJvmArg(arg4);
+
+        Property property1 = new Property();
+        property1.setKey("org.jboss.byteman.debug");
+        property1.setValue("true");
+        server.addSysProperty(property1);
+        Property property2 = new Property();
+        property2.setKey(BytemanTestHelper.RMIREGISTRY_PORT_PROPERTY_NAME);
+        property2.setValue("1199");
+        server.addSysProperty(property2);
+
+        Property property3 = new Property();
+        property3.setKey("emma.exit.delay");
+        property3.setValue("10");
+        server.addSysProperty(property3);
+
+        manager.addServer(server);
+    }
+
+    @Before
+    public void setUp() throws Exception {
+
+        bytemanArgument.setValue("-javaagent:/home/jhalli/IdeaProjects/jboss/byteman_trunk/install/lib/byteman.jar=port:9091,listener:true,sys:/home/jhalli/IdeaProjects/jboss/byteman_trunk/contrib/dtest/build/lib/byteman-dtest.jar");
+        removeContents(new File("/home/jhalli/IdeaProjects/jboss/jbossas_trunk/build/target/jboss-6.0.0-SNAPSHOT/server/default/data/tx-object-store/"));
+
+
+        // TODO: fix JMXAdapter leak.
+        manager.getServer("default").setServerConnection(null);
+        manager.startServer("default");
+
+        //instrumentor.installHelperJar("/home/jhalli/IdeaProjects/jboss/byteman_trunk/contrib/dtest/build/lib/byteman-dtest.jar");
+        instrumentor.setRedirectedSubmissionsFile(null);
+
+        instrumentedTestVolatileParticipant = instrumentor.instrumentClass(TestVolatileParticipant.class);
+        instrumentedTestDurableParticipant = instrumentor.instrumentClass(TestDurableParticipant.class);
+
+        instrumentor.injectOnCall(TestServiceImpl.class, "doNothing", "$0.enlistVolatileParticipant(1), $0.enlistDurableParticipant(1)");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        instrumentor.removeAllInstrumentation();
+
+        manager.stopServer("default");
+    }
+
+    private void execute(boolean expectResponse) throws Exception {
+
+        HttpMethodBase request = null;
+
+        try {
+            request = HttpUtils.accessURL(new URL(baseURL));
+        } catch(ConnectException e) {
+            if(expectResponse) {
+                throw e;
+            }
+        } catch(SocketException e) {
+            if(expectResponse) {
+                throw e;
+            }
+        }
+
+        if(expectResponse) {
+            String response = request.getResponseBodyAsString().trim();
+            assertEquals("finished", response);
+        }
+    }
+
+    private void rebootServer() throws Exception {
+
+        instrumentor.removeLocalState();
+        File rulesFile = new File("/tmp/bar3");
+        rulesFile.delete();
+        instrumentor.setRedirectedSubmissionsFile(rulesFile);
+        bytemanArgument.setValue(bytemanArgument.getValue()+",script:"+rulesFile.getCanonicalPath());
+
+        instrumentedTestVolatileParticipant = instrumentor.instrumentClass(TestVolatileParticipant.class);
+        instrumentedTestDurableParticipant = instrumentor.instrumentClass(TestDurableParticipant.class);
+
+        manager.getServer("default").setServerConnection(null);
+        Thread.sleep(2000);
+        manager.startServer("default");
+    }
+
+    //@Test
+    public void testCrashOneLog() throws Exception {
+
+        instrumentor.injectOnCall(TestClient.class,  "terminateTransaction", "$1 = true"); // shouldCommit=true
+
+        instrumentor.crashAtMethodExit("^XTSATRecoveryManager", "writeParticipantRecoveryRecord");
+
+        execute(false);
+
+        instrumentedTestVolatileParticipant.assertKnownInstances(1);
+        instrumentedTestVolatileParticipant.assertMethodCalled("prepare");
+        instrumentedTestVolatileParticipant.assertMethodNotCalled("commit");
+        instrumentedTestVolatileParticipant.assertMethodNotCalled("rollback");
+
+        instrumentedTestDurableParticipant.assertKnownInstances(1);
+        instrumentedTestDurableParticipant.assertMethodCalled("prepare");
+        instrumentedTestDurableParticipant.assertMethodNotCalled("commit");
+        instrumentedTestDurableParticipant.assertMethodNotCalled("rollback");
+
+        rebootServer();
+
+        doRecovery();
+        doRecovery();
+
+        instrumentedTestDurableParticipant.assertKnownInstances(1);
+        instrumentedTestDurableParticipant.assertMethodNotCalled("prepare");
+        instrumentedTestDurableParticipant.assertMethodCalled("rollback");
+        instrumentedTestDurableParticipant.assertMethodNotCalled("commit");
+    }
+
+    @Test
+    public void testCrashTwoLogs() throws Exception {
+
+        instrumentor.injectOnCall(TestClient.class,  "terminateTransaction", "$1 = true"); // shouldCommit=true
+
+        instrumentor.crashAtMethodExit(BridgeXAResource.class, "prepare");
+
+        execute(false);
+
+        instrumentedTestVolatileParticipant.assertKnownInstances(1);
+        instrumentedTestVolatileParticipant.assertMethodCalled("prepare");
+        instrumentedTestVolatileParticipant.assertMethodNotCalled("commit");
+        instrumentedTestVolatileParticipant.assertMethodNotCalled("rollback");
+
+        instrumentedTestDurableParticipant.assertKnownInstances(1);
+        instrumentedTestDurableParticipant.assertMethodCalled("prepare");
+        instrumentedTestDurableParticipant.assertMethodNotCalled("commit");
+        instrumentedTestDurableParticipant.assertMethodNotCalled("rollback");
+
+        rebootServer();
+
+        doRecovery();
+        doRecovery();
+
+        instrumentedTestDurableParticipant.assertKnownInstances(1);
+        instrumentedTestDurableParticipant.assertMethodNotCalled("prepare");
+        instrumentedTestDurableParticipant.assertMethodCalled("rollback");
+        instrumentedTestDurableParticipant.assertMethodNotCalled("commit");
+    }
+
+    // this one requires <property name="commitOnePhase">false</property> on CoordinatorEnvironmentBean
+    //@Test
+    public void testCrashThreeLogs() throws Exception {
+
+        instrumentor.injectOnCall(TestClient.class,  "terminateTransaction", "$1 = true"); // shouldCommit=true
+
+        instrumentor.crashAtMethodEntry(BridgeXAResource.class, "commit");
+
+        execute(false);
+
+        instrumentedTestVolatileParticipant.assertKnownInstances(1);
+        instrumentedTestVolatileParticipant.assertMethodCalled("prepare");
+        instrumentedTestVolatileParticipant.assertMethodNotCalled("commit");
+        instrumentedTestVolatileParticipant.assertMethodNotCalled("rollback");
+
+        instrumentedTestDurableParticipant.assertKnownInstances(1);
+        instrumentedTestDurableParticipant.assertMethodCalled("prepare");
+        instrumentedTestDurableParticipant.assertMethodNotCalled("commit");
+        instrumentedTestDurableParticipant.assertMethodNotCalled("rollback");
+
+        rebootServer();
+
+        doRecovery();
+        doRecovery();
+
+        instrumentedTestDurableParticipant.assertKnownInstances(1);
+        instrumentedTestDurableParticipant.assertMethodNotCalled("prepare");
+        instrumentedTestDurableParticipant.assertMethodNotCalled("rollback");
+        instrumentedTestDurableParticipant.assertMethodCalled("commit");
+    }
+
+    /////////////////
+
+    // stolen from CrashRecoveryDelays - should probably just add that to the classpath?
+    // prod the recovery manager via its socket. This avoid any sleep delay.
+    private static void doRecovery() throws InterruptedException
+    {
+        int port = recoveryPropertyManager.getRecoveryEnvironmentBean().getRecoveryPort();
+        String host = recoveryPropertyManager.getRecoveryEnvironmentBean().getRecoveryAddress();
+
+        BufferedReader in = null;
+        PrintStream out = null;
+        Socket sckt = null;
+
+        try
+        {
+            sckt = new Socket(host,port);
+
+            in = new BufferedReader(new InputStreamReader(sckt.getInputStream()));
+            out = new PrintStream(sckt.getOutputStream());
+
+            // Output ping message
+            out.println("SCAN");
+            out.flush();
+
+            // Receive pong message
+            String inMessage = in.readLine();
+
+            if(!inMessage.equals("DONE")) {
+                System.err.println("Recovery failed with message: "+inMessage);
+            }
+        }
+        catch (Exception ex)
+        {
+            ex.printStackTrace();
+        }
+        finally
+        {
+            try {
+                if ( in != null )
+                {
+                    in.close();
+                }
+
+                if ( out != null )
+                {
+                    out.close();
+                }
+
+                sckt.close();
+            } catch(Exception e) {}
+        }
+   }
+
+    // stolen from EmptyObjectStore.java
+    public static void removeContents(File directory)
+    {
+        if ((directory != null) &&
+                directory.isDirectory() &&
+                (!directory.getName().equals("")) &&
+                (!directory.getName().equals("/")) &&
+                (!directory.getName().equals("\\")) &&
+                (!directory.getName().equals(".")) &&
+                (!directory.getName().equals("..")))
+        {
+            File[] contents = directory.listFiles();
+
+            for (int index = 0; index < contents.length; index++)
+            {
+                if (contents[index].isDirectory())
+                {
+                    removeContents(contents[index]);
+
+                    //System.err.println("Deleted: " + contents[index]);
+                    contents[index].delete();
+                }
+                else
+                {
+                    System.err.println("Deleted: " + contents[index]);
+                    contents[index].delete();
+                }
+            }
+        }
+    }
+}

Modified: labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/outbound/service/TestServiceImpl.java
===================================================================
--- labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/outbound/service/TestServiceImpl.java	2010-05-28 14:27:47 UTC (rev 33140)
+++ labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/outbound/service/TestServiceImpl.java	2010-05-28 14:50:01 UTC (rev 33141)
@@ -70,7 +70,7 @@
         try {
             for(int i = 0; i < count; i++) {
                 TestDurableParticipant durableParticipant = new TestDurableParticipant();
-                tm.enlistForDurableTwoPhase(durableParticipant, "org.jboss.jbossts.txbridge.tests.outbound.Durable:" + new Uid().toString());
+                tm.enlistForDurableTwoPhase(durableParticipant, TestDurableParticipant.TYPE_IDENTIFIER + new Uid().toString());
             }
         } catch(Exception e) {
             log.error("could not enlist", e);

Modified: labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/outbound/utility/TestDurableParticipant.java
===================================================================
--- labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/outbound/utility/TestDurableParticipant.java	2010-05-28 14:27:47 UTC (rev 33140)
+++ labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/outbound/utility/TestDurableParticipant.java	2010-05-28 14:50:01 UTC (rev 33141)
@@ -34,6 +34,12 @@
 {
     private static Logger log = Logger.getLogger(TestDurableParticipant.class);
 
+    /*
+     * Uniq String used to prefix ids at participant registration,
+     * so that the recovery module can identify relevant instances.
+     */
+    public static final String TYPE_IDENTIFIER = "TestDurableParticipant_";
+    
     private String prepareOutcome = "prepared";
 
     /**

Added: labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/outbound/utility/TestRecoveryModule.java
===================================================================
--- labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/outbound/utility/TestRecoveryModule.java	                        (rev 0)
+++ labs/jbosstm/trunk/txbridge/tests/src/org/jboss/jbossts/txbridge/tests/outbound/utility/TestRecoveryModule.java	2010-05-28 14:50:01 UTC (rev 33141)
@@ -0,0 +1,98 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and/or its affiliates,
+ * and individual contributors as indicated by the @author tags.
+ * See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License, v. 2.1.
+ * This program is distributed in the hope that it will be useful, but WITHOUT A
+ * 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,
+ * v.2.1 along with this distribution; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.
+ *
+ * (C) 2010,
+ * @author JBoss, by Red Hat.
+ */
+package org.jboss.jbossts.txbridge.tests.outbound.utility;
+
+import com.arjuna.wst.Durable2PCParticipant;
+import org.apache.log4j.Logger;
+import org.jboss.jbossts.xts.recovery.participant.at.XTSATRecoveryManager;
+import org.jboss.jbossts.xts.recovery.participant.at.XTSATRecoveryModule;
+
+import java.io.ObjectInputStream;
+
+/**
+ * Implementation of XTSATRecoveryModule for deserializing TestDurableParticipant instances in tx test cases.
+ *
+ * @author Jonathan Halliday (jonathan.halliday at redhat.com) 2010-05
+ */
+public class TestRecoveryModule implements XTSATRecoveryModule
+{
+    private static final Logger log = Logger.getLogger(TestRecoveryModule.class);
+
+    private final XTSATRecoveryManager xtsATRecoveryManager = XTSATRecoveryManager.getRecoveryManager();
+
+    /**
+     * MC lifecycle callback, used to register components with the recovery manager.
+     */
+    public void start()
+    {
+        log.info("TestRecoveryModule starting");
+
+        xtsATRecoveryManager.registerRecoveryModule(this);
+    }
+
+    /**
+     * MC lifecycle callback, used to unregister components from the recovery manager.
+     */
+    public void stop()
+    {
+        log.info("TestRecoveryModule stopping");
+
+        xtsATRecoveryManager.unregisterRecoveryModule(this);
+    }
+
+    /**
+     * called during recovery processing to allow an application to identify a participant id
+     * belonging to one of its participants and recreate the participant by deserializing
+     * it from the supplied object input stream. n.b. this is only appropriate in case the
+     * participant was originally saved using serialization.
+     *
+     * @param id     the id used when the participant was created
+     * @param objectInputStream a stream from which the application should deserialise the participant
+     *               if it recognises that the id belongs to the module's application
+     * @return
+     * @throws Exception if an error occurs deserializing the durable participant
+     */
+    @Override
+    public Durable2PCParticipant deserialize(String id, ObjectInputStream objectInputStream) throws Exception
+    {
+        log.trace("deserialize(id="+id+")");
+
+        if(id.startsWith(TestDurableParticipant.TYPE_IDENTIFIER))
+        {
+            Object participant = objectInputStream.readObject();
+            TestDurableParticipant testDurableParticipant = (TestDurableParticipant)participant;
+            return testDurableParticipant;
+        }
+        else
+        {
+            return null; // it belongs to some other XTS app, ignore it.
+        }
+    }
+
+    /**
+     * Unused recovery callback. We use serialization instead, so this method will always throw an exception if called.
+     */
+    @Override
+    public Durable2PCParticipant recreate(String id, byte[] recoveryState) throws Exception
+    {
+        throw new Exception("recreation not supported - should use deserialization instead.");
+    }
+}



More information about the jboss-svn-commits mailing list