package org.jboss.cache;

import junit.framework.TestCase;
import org.jboss.cache.TreeCache;
import org.jgroups.Channel;
import org.jgroups.JChannel;
import org.jgroups.Address;
import org.jgroups.ChannelException;
import org.jgroups.conf.ProtocolStackConfigurator;
import org.w3c.dom.Element;

import java.io.File;
import java.net.URL;

/**
 * Tests the behaviour of starting a cache when the JGroups channel is caused to hang.
 *
 * @author <a href="mailto:manik@jboss.org">Manik Surtani</a>
 */
public class HungChannelTest extends TestCase
{
   private TreeCache cache;

   protected void setUp() throws Exception
   {
      cache = new TreeCache();
      cache.setCacheMode("REPL_SYNC");
   }

   protected void tearDown()
   {
      if (cache != null)
      {
         if (cache.channel != null)
         {
            cache.channel.close();
            cache.channel.disconnect();
            cache.channel = null;
         }
         cache.stopService();
         cache = null;
      }
   }

   public void testFailingStateTransfer()
   {
      try
      {
         cache.createService();
         JChannel ch = new FailingStateChannel(cache.cluster_props);
         ch.setOpt(Channel.GET_STATE_EVENTS, Boolean.TRUE);
         ch.setOpt(Channel.AUTO_RECONNECT, Boolean.TRUE);
         ch.setOpt(Channel.AUTO_GETSTATE, Boolean.TRUE);
         cache.channel = ch;
         
         cache.startService(); // the state transfer here should fail, leading to an exception being thrown.
         fail("Expecting the startService() method to throw an exception");
      }
      catch (Exception e)
      {
         // normal behaviour
      }

      Channel c = cache.channel; // hold a reference to this since stopService will set this to null in the cache.

      assertFalse("Channel should not have connected!", c.isConnected());
      assertFalse("Channel should not be open", c.isOpen());

      cache.stopService();

      assertFalse("Channel should not have connected!", c.isConnected());
      assertFalse("Channel should not be open", c.isOpen());

      assertNull("Should be null", cache.channel);
   }

   public void testSucceedingStateTransfer()
   {
      try
      {
         cache.startService();
      }
      catch (Exception e)
      {
         fail("NOT expecting the startService() method to throw an exception");
      }

      Channel c = cache.channel; // hold a reference to this since stopService will set this to null in the cache.

      assertTrue("Channel should have connected!", c.isConnected());
      assertTrue("Channel should be open", c.isOpen());


      cache.stopService();

      assertFalse("Channel should not have connected!", c.isConnected());
      assertFalse("Channel should not be open", c.isOpen());

      assertNull("Should be null", cache.channel);
   }

   static class FailingStateChannel extends JChannel
   {


      public FailingStateChannel() throws ChannelException
      {
         super();
      }

      public FailingStateChannel(File file) throws ChannelException
      {
         super(file);
      }

      public FailingStateChannel(Element element) throws ChannelException
      {
         super(element);
      }

      public FailingStateChannel(URL url) throws ChannelException
      {
         super(url);
      }

      public FailingStateChannel(String string) throws ChannelException
      {
         super(string);
      }

      public FailingStateChannel(ProtocolStackConfigurator protocolStackConfigurator) throws ChannelException
      {
         super(protocolStackConfigurator);
      }

      public boolean getState(Address a, long l)
      {
         throw new RuntimeException("Dummy Exception getting state");
      }
   }

}
