[jboss-cvs] JBossAS SVN: r73329 - branches/JBPAPP_4_3_0_GA_CP01_JBPAPP-825/testsuite/src/main/org/jboss/test/cluster/invokerha.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Tue May 13 03:00:45 EDT 2008


Author: galder.zamarreno at jboss.com
Date: 2008-05-13 03:00:45 -0400 (Tue, 13 May 2008)
New Revision: 73329

Modified:
   branches/JBPAPP_4_3_0_GA_CP01_JBPAPP-825/testsuite/src/main/org/jboss/test/cluster/invokerha/AbstractInvokerHa.java
   branches/JBPAPP_4_3_0_GA_CP01_JBPAPP-825/testsuite/src/main/org/jboss/test/cluster/invokerha/UnifiedInvokerHaMockUtils.java
   branches/JBPAPP_4_3_0_GA_CP01_JBPAPP-825/testsuite/src/main/org/jboss/test/cluster/invokerha/UnifiedInvokerHaUnitTestCase.java
Log:
[JBPAPP-825] Added a thread safety test to check whether the chosen and used target are the same when multiple threads call the same proxy concurrently. Simplified remoting mock objects to make them behave closer to the production code. Added test that slow downs client.connect() in Remoting to be able to replicate an NPE that happens under load. Without synchronising getClient in UnifiedInvokerHAProxy, this new test would fail.

Modified: branches/JBPAPP_4_3_0_GA_CP01_JBPAPP-825/testsuite/src/main/org/jboss/test/cluster/invokerha/AbstractInvokerHa.java
===================================================================
--- branches/JBPAPP_4_3_0_GA_CP01_JBPAPP-825/testsuite/src/main/org/jboss/test/cluster/invokerha/AbstractInvokerHa.java	2008-05-13 06:10:06 UTC (rev 73328)
+++ branches/JBPAPP_4_3_0_GA_CP01_JBPAPP-825/testsuite/src/main/org/jboss/test/cluster/invokerha/AbstractInvokerHa.java	2008-05-13 07:00:45 UTC (rev 73329)
@@ -22,6 +22,13 @@
 package org.jboss.test.cluster.invokerha;
 
 import java.rmi.server.UID;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
 
 import javax.transaction.Transaction;
 
@@ -36,6 +43,7 @@
 import org.jboss.test.cluster.invokerha.InvokerHaInfrastructure.TraceRoundRobin;
 import org.jboss.test.cluster.invokerha.InvokerHaTransactionalMockUtils.MockTransaction;
 
+import junit.framework.AssertionFailedError;
 import junit.framework.TestCase;
 
 /**
@@ -65,6 +73,8 @@
    {
       super.setUp();
       
+      log.info(getName());
+      
       invokerHaFactory = factory; 
       
       transactionalMockUtils = new InvokerHaTransactionalMockUtils();
@@ -186,6 +196,36 @@
       }
    }
    
+   protected void performConcurrentCalls(int numberThreads, 
+         int numberCallsPerThread, Class<? extends LoadBalancePolicy> policyClass) throws Exception
+   {
+      ExecutorService executor = Executors.newCachedThreadPool();
+      CyclicBarrier barrier = new CyclicBarrier(numberThreads + 1);
+      List<Future<Void>> futures = new ArrayList<Future<Void>>();
+      
+      log.debug("create proxies");
+      createNewProxies(0, policyClass, true);
+      for (int i = 0; i < numberThreads; i++)
+      {
+         log.debug("schedule execution");
+         Future<Void> future = executor.submit(new InvokerProxyBatch(barrier, numberCallsPerThread, policyClass));
+         futures.add(future);
+      }
+      barrier.await(); // wait for all threads to be ready
+      barrier.await(); // wait for all threads to finish
+      
+      log.debug("all threads finished, let's shutdown the executor and check whether any exceptions were reported");
+      
+      for (Future<Void> future : futures)
+      {
+         future.get();
+      }
+      
+      executor.shutdown();
+      
+      log.debug("no exceptions reported, good :)");
+   }
+   
    protected Object assertSuccessfulPostConditions(Invocation inv, Object prevChosenTarget, Transaction tx, Class<? extends LoadBalancePolicy> policyClass)
    {
       assertEquals(0, inv.getAsIsValue("FAILOVER_COUNTER"));
@@ -271,5 +311,89 @@
    protected Object checkFirstAvailableIndenticalAllProxies(Object chosenTarget, Object prevChosenTarget)
    {
       return checkFirstAvailable(chosenTarget, prevChosenTarget);
-   }   
+   }
+   
+   /** Classes **/
+   
+   public class InvokerProxyBatch implements Callable<Void>
+   {
+      private final CyclicBarrier barrier;
+      
+      private final int numberCallsPerThread;
+      
+      private final Class<? extends LoadBalancePolicy> policyClass;
+      
+      public InvokerProxyBatch(CyclicBarrier ciclycBarrier, int numberCalls, Class<? extends LoadBalancePolicy> policy)
+      {
+         barrier = ciclycBarrier;
+         numberCallsPerThread = numberCalls;
+         policyClass = policy;
+      }
+
+      public Void call() throws Exception
+      {
+         try
+         {
+            log.debug("wait for all executions paths to be ready to perform calls");
+            barrier.await();
+            
+            log.debug("perform invoker proxy calls");
+            performThreadSafeCalls(numberCallsPerThread, policyClass);
+         }
+         catch(AssertionFailedError afe)
+         {
+            logAndThrow("Assertion failed in thread: " + Thread.currentThread().getName(), afe);
+         }
+         finally
+         {
+            log.debug("wait for all execution paths to finish");
+            barrier.await();
+         }
+         
+         return null;
+      }
+      
+      protected void performThreadSafeCalls(int numberPairCalls, Class<? extends LoadBalancePolicy> policyClass) throws Exception
+      {
+         Invocation inv;
+         
+         for (int i = 0; i < numberPairCalls; i++)
+         {
+            /* create invocation to date time teller */
+            inv = infrastructure.createDateTimeTellerInvocation(null, null);
+            /* invoke on proxy passing the invocation */
+            log.debug(timeTellerProxy.invoke(inv));
+            /* assert post conditions after invocation */
+            assertThreadSafePostConditions(inv, timeTellerProxy);
+            
+            /* create invocation to system time teller */
+            inv = infrastructure.createSystemTimeTellerInvocation(null, null);
+            /* invoke on proxy passing the invocation */
+            log.debug(systemTimeProxy.invoke(inv));
+            /* assert post conditions after invocation */
+            assertThreadSafePostConditions(inv, systemTimeProxy);
+         }
+      }
+
+      protected void assertThreadSafePostConditions(Invocation inv, Invoker invoker)
+      {
+         assertEquals(0, inv.getAsIsValue("FAILOVER_COUNTER"));
+         Object chosenTarget = inv.getTransientValue(invokerHaFactory.getChosenTargetKey());
+         assertNotNull(chosenTarget);
+         
+         /* NOTE: currently, the following assertion is only valid for unified 
+          * invokers, do not call from thread safety tests related to other 
+          * invokers */
+         
+         /* assert that target chosen by load balance policy and target to which 
+          * invocation was directed is the same */      
+         assertEquals(chosenTarget, inv.getTransientValue("TEST_USED_TARGET"));
+      } 
+      
+      private void logAndThrow(String message, Throwable t) throws Exception
+      {
+         log.error(message, t);
+         throw new Exception(message, t);
+      }
+   }
 }

Modified: branches/JBPAPP_4_3_0_GA_CP01_JBPAPP-825/testsuite/src/main/org/jboss/test/cluster/invokerha/UnifiedInvokerHaMockUtils.java
===================================================================
--- branches/JBPAPP_4_3_0_GA_CP01_JBPAPP-825/testsuite/src/main/org/jboss/test/cluster/invokerha/UnifiedInvokerHaMockUtils.java	2008-05-13 06:10:06 UTC (rev 73328)
+++ branches/JBPAPP_4_3_0_GA_CP01_JBPAPP-825/testsuite/src/main/org/jboss/test/cluster/invokerha/UnifiedInvokerHaMockUtils.java	2008-05-13 07:00:45 UTC (rev 73329)
@@ -40,7 +40,6 @@
 import org.jboss.remoting.ConnectionFailedException;
 import org.jboss.remoting.InvocationRequest;
 import org.jboss.remoting.InvokerLocator;
-import org.jboss.remoting.ServerInvoker;
 import org.jboss.remoting.callback.InvokerCallbackHandler;
 import org.jboss.remoting.marshal.Marshaller;
 import org.jboss.remoting.marshal.UnMarshaller;
@@ -58,6 +57,8 @@
  */
 public class UnifiedInvokerHaMockUtils
 {
+   public static boolean SLOW_DOWN_CLIENT_CONNECT = false;
+   
    public static class MockUnifiedInvokerHA extends UnifiedInvokerHA
    {
       private String name;
@@ -139,7 +140,7 @@
       @Override
       protected Client createClient(InvokerLocator locator, String subSystem) throws Exception
       {
-         return ((MockInvokerLocator)locator).getClient();
+         return new MockClient(locator);
       }
 
       @Override
@@ -153,6 +154,11 @@
          
          super.putIfExistsTransactionTarget(invocation, tpc);
       }
+      
+      public InvokerLocator getLocator()
+      {
+         return super.getLocator();
+      }
    }
 
    public static class MockInvokerLocator extends InvokerLocator
@@ -160,24 +166,23 @@
       /** The serialVersionUID */
       private static final long serialVersionUID = 8641387521254685628L;
       
-      /* client that will be returned when locator is initialised */
-      private MockClient client;
+      private MockUnifiedInvokerHA invoker;
       
-      public MockInvokerLocator(String host, int port, MockClient client)
+      public MockInvokerLocator(String host, int port, MockUnifiedInvokerHA invoker)
       {
          super("unittest", host, port, "mock", null);
-         this.client = client;
+         this.invoker = invoker;
       }
 
-      public MockClient getClient()
+      public MockUnifiedInvokerHA getInvoker()
       {
-         return client;
+         return invoker;
       }
       
       @Override
       public String toString()
       {
-         return super.toString() + ",[client=" + client + "]";
+         return super.toString() + ",[invoker=" + invoker + "]";
       }
       
       @Override
@@ -185,35 +190,39 @@
       {
          /* reimplemented equals to avoid lingering static family cluster info 
           * references being valid in latter tests */
-         return super.equals(obj) && client.equals(((MockInvokerLocator)obj).getClient());
+         return super.equals(obj) && invoker.equals(((MockInvokerLocator)obj).getInvoker());
       }      
    }
 
    public static class MockClient extends Client
    {
-      /** underlying invoker target */
-      private MockUnifiedInvokerHA invoker;
+      /* temporary invoker locator to be able to mimic what remoting does 
+       * setting the invoker in connect() */
+      private InvokerLocator locatorTmp;
 
-      public MockClient(MockUnifiedInvokerHA invoker)
+      public MockClient(InvokerLocator locator) throws Exception
       {
-         this.invoker = invoker;
+         super(locator);
+         locatorTmp = locator;
       }
 
       @Override
       public void connect() throws Exception
       {
-         /* do nothing on connect for unit tests */
+         if (SLOW_DOWN_CLIENT_CONNECT)
+         {
+            Thread.sleep(50);
+         }
+         
+         setInvoker(new MockClientInvoker(locatorTmp));
       }
 
       @Override
-      public ClientInvoker getInvoker()
-      {
-         return new MockClientInvoker(invoker.getLocator());
-      }
-
-      @Override
       public Object invoke(Object param, Map metadata) throws Throwable
       {
+         Invocation inv = (Invocation) param;
+         inv.getTransientPayload().put("TEST_USED_TARGET", this.getInvoker().getLocator());
+         
          /* Down the call stack in Remoting's Client.invoke, marshaller is 
           * called which via org.jboss.invocation.unified.marshall.InvocationMarshaller 
           * sets the transaction progagation context.
@@ -224,10 +233,11 @@
           * Not ideal, as I try avoiding production code in UTs as much as 
           * possible, but makes the mock implementation a lot simpler.
           */
-         Invocation inv = (Invocation) param;
          MarshalledInvocation marshInv = new MarshalledInvocation(inv);
          marshInv.setTransactionPropagationContext(getTransactionPropagationContext());
          
+         MockUnifiedInvokerHA invoker = ((MockInvokerLocator)getInvoker().getLocator()).getInvoker();
+         
          return invoker.invoke(new InvocationRequest("", "", marshInv,
                metadata, null, null));
       }
@@ -241,11 +251,11 @@
       @Override
       public String toString()
       {
-         return invoker.toString();
+         return ((MockInvokerLocator)getInvoker().getLocator()).getInvoker().toString();
       }      
    }
    
-   public static class MockClientInvoker implements ClientInvoker
+   static class MockClientInvoker implements ClientInvoker
    {
       private InvokerLocator locator;
       
@@ -332,5 +342,4 @@
       {
       }
    }
-
 }

Modified: branches/JBPAPP_4_3_0_GA_CP01_JBPAPP-825/testsuite/src/main/org/jboss/test/cluster/invokerha/UnifiedInvokerHaUnitTestCase.java
===================================================================
--- branches/JBPAPP_4_3_0_GA_CP01_JBPAPP-825/testsuite/src/main/org/jboss/test/cluster/invokerha/UnifiedInvokerHaUnitTestCase.java	2008-05-13 06:10:06 UTC (rev 73328)
+++ branches/JBPAPP_4_3_0_GA_CP01_JBPAPP-825/testsuite/src/main/org/jboss/test/cluster/invokerha/UnifiedInvokerHaUnitTestCase.java	2008-05-13 07:00:45 UTC (rev 73329)
@@ -32,6 +32,7 @@
 import org.jboss.invocation.unified.interfaces.UnifiedInvokerHAProxy;
 import org.jboss.remoting.InvokerLocator;
 import org.jboss.test.cluster.invokerha.InvokerHaInfrastructure.InvokerHaFactory;
+import org.jboss.test.cluster.invokerha.InvokerHaInfrastructure.TraceRoundRobin;
 import org.jboss.test.cluster.invokerha.UnifiedInvokerHaMockUtils.MockClient;
 import org.jboss.test.cluster.invokerha.UnifiedInvokerHaMockUtils.MockInvokerLocator;
 import org.jboss.test.cluster.invokerha.UnifiedInvokerHaMockUtils.MockUnifiedInvokerHA;
@@ -58,6 +59,18 @@
       super.tearDown();
    }
    
+   public void testProxyThreadSafety() throws Throwable
+   {
+      performConcurrentCalls(50, 50, TraceRoundRobin.class);
+   }
+   
+   public void testProxyThreadSafetyNullPointerException() throws Throwable
+   {
+      UnifiedInvokerHaMockUtils.SLOW_DOWN_CLIENT_CONNECT = true;
+      performConcurrentCalls(5, 5, TraceRoundRobin.class);
+      UnifiedInvokerHaMockUtils.SLOW_DOWN_CLIENT_CONNECT = false;
+   }
+   
    /** Classes **/
    
    /**
@@ -83,8 +96,7 @@
       public InvokerHA createInvokerHaServer(String serverName, int serverNumber)
       {
          MockUnifiedInvokerHA invoker = new MockUnifiedInvokerHA(getInvokerTypeName() + "-" + serverName + "-" + serverNumber);
-         MockClient client = new MockClient(invoker);
-         MockInvokerLocator locator = new MockInvokerLocator("127.0.0.1", serverNumber, client);
+         MockInvokerLocator locator = new MockInvokerLocator("127.0.0.1", serverNumber, invoker);
          invoker.setLocator(locator);
          
          return invoker;          




More information about the jboss-cvs-commits mailing list