/*
 * JBoss, Home of Professional Open Source
 * Copyright 2005, JBoss Inc., and individual contributors as indicated
 * by the @authors tag. See the copyright.txt 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 org.jboss.test.cache.test.replicated;


import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.jboss.cache.PropertyConfigurator;
import org.jboss.cache.TreeCache;

/**
 * Unit test for replicated async TreeCache. Use locking and multiple threads to test
 * concurrent access to the tree.
 *
 * @version $Revision: 1.4.2.7 $
 */
public class AsyncUnitTestCase extends TestCase {
   TreeCache cache1, cache2;
   String props=null;

   public AsyncUnitTestCase(String name) {
      super(name);
   }

   public void setUp() throws Exception {
      super.setUp();

      log("creating cache1");
      cache1=createCache("CacheGroup");

      log("creating cache2");
      cache2=createCache("CacheGroup");
   }

   private TreeCache createCache(String name) throws Exception {
      TreeCache tree=new TreeCache();
      PropertyConfigurator config=new PropertyConfigurator();
      config.configure(tree, "META-INF/replAsync-service.xml"); // read in generic replAsync xml
      tree.setClusterName(name);
      tree.createService();
      tree.startService();
      return tree;
   }

   public void tearDown() throws Exception {
      super.tearDown();
      if(cache1 != null) {
         log("stopping cache1");
         cache1.stopService();
      }

      if(cache2 != null) {
         log("stopping cache2");
         cache2.stopService();
      }
   }


   public void testPutShouldNotReplicateToDifferentCluster() {
      TreeCache cache3=null;
      try {
         cache3=createCache("DifferentGroup");
         cache1.put("/a/b/c", "age", new Integer(38));
         // because we use async repl, modfication may not yet have been propagated to cache2, so
         // we have to wait a little
         sleep(2000);
         assertNull("Should not have replicated", cache3.get("/a/b/c", "age"));
      }
      catch(Exception e) {
         fail(e.toString());
      }
      finally {
         if(cache3 != null)
            cache3.stopService();
      }
   }

   public void testStateTransfer() {
      TreeCache cache4=null;
      try {
         cache1.put("a/b/c", "age", new Integer(38));
         cache4=createCache("CacheGroup");
         assertEquals(3, cache4.getMembers().size()); // cache1, cache2 and cache4
         assertEquals("\"age\" should be 38", new Integer(38), cache4.get("/a/b/c", "age"));
      }
      catch(Exception e) {
         fail(e.toString());
      }
      finally {
         if(cache4 != null) {
            System.out.println("cache4's view: " + cache4.getMembers());
            cache4.stopService();
         }
      }
   }


   public void testAsyncReplDelay() {
      Integer age;

      try {
         cache1.put("/a/b/c", "age", new Integer(38));

         // value on cache2 may be 38 or not yet replicated
         age=(Integer)cache2.get("/a/b/c", "age");
         log("attr \"age\" of \"/a/b/c\" on cache2=" + age);
         assertTrue("should be either null or 38", age == null || age.intValue() == 38);
      }
      catch(Exception e) {
         fail(e.toString());
      }
   }

   public void testSyncRepl() throws Exception {
      Integer age;
      cache1.setCacheMode(TreeCache.REPL_SYNC);
      cache2.setCacheMode(TreeCache.REPL_SYNC);

      try {
         cache1.put("/a/b/c", "age", new Integer(38));

         // value on cache2 must be 38
         age=(Integer)cache2.get("/a/b/c", "age");
         log("attr \"age\" of \"/a/b/c\" on cache2=" + age);
         assertNotNull("\"age\" obtained from cache2 is null ", age);
         assertTrue("\"age\" must be 38", age.intValue() == 38);
      }
      catch(Exception e) {
         fail(e.toString());
      }
   }


   private void sleep(long timeout) {
      try {
         Thread.sleep(timeout);
      }
      catch(Throwable t) {
         ;
      }
   }

   void log(String msg) {
      System.out.println("-- [" + Thread.currentThread() + "]: " + msg);
   }


   public static Test suite() {
      return new TestSuite(AsyncUnitTestCase.class);
   }

   public static void main(String[] args) {
      junit.textui.TestRunner.run(suite());
   }
}
