Package org.infinispan.loaders

Source Code of org.infinispan.loaders.BaseCacheStoreTest

package org.infinispan.loaders;

import org.easymock.EasyMock;
import org.infinispan.Cache;
import org.infinispan.container.entries.InternalCacheEntry;
import org.infinispan.container.entries.InternalEntryFactory;
import org.infinispan.io.UnclosableObjectInputStream;
import org.infinispan.io.UnclosableObjectOutputStream;
import org.infinispan.loaders.modifications.Clear;
import org.infinispan.loaders.modifications.Modification;
import org.infinispan.loaders.modifications.Remove;
import org.infinispan.loaders.modifications.Store;
import org.infinispan.marshall.Marshaller;
import org.infinispan.marshall.TestObjectStreamMarshaller;
import org.infinispan.transaction.xa.GlobalTransaction;
import org.infinispan.util.Util;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;

@SuppressWarnings("unchecked")
// this needs to be here for the test to run in an IDE
@Test(groups = "unit", testName = "loaders.BaseCacheStoreTest")
public abstract class BaseCacheStoreTest {

   protected abstract CacheStore createCacheStore() throws Exception;

   protected CacheStore cs;

   @BeforeMethod
   public void setUp() throws Exception {
      try {
         cs = createCacheStore();
      } catch (Exception e) {
         //in IDEs this won't be printed which makes debugging harder
         e.printStackTrace();
         throw e;
      }
   }

   @AfterMethod
   public void tearDown() throws CacheLoaderException {
      if (cs != null) {
         cs.clear();
         cs.stop();
      }
      cs = null;
   }

   @AfterMethod
   public void assertNoLocksHeld() {
      //doesn't really make sense to add a subclass for this check only
      if (cs instanceof LockSupportCacheStore) {
         assert ((LockSupportCacheStore) cs).getTotalLockCount() == 0;
      }
   }

   /**
    * @return a mock cache for use with the cache store impls
    */
   protected Cache getCache() {
      Cache c = EasyMock.createNiceMock(Cache.class);
      EasyMock.expect(c.getName()).andReturn("mockCache-" + getClass().getName()).anyTimes();
      EasyMock.replay(c);
      return c;
   }

   /**
    * @return a mock marshaller for use with the cache store impls
    */
   protected Marshaller getMarshaller() {
      return new TestObjectStreamMarshaller(false);
   }

   public void testLoadAndStoreImmortal() throws InterruptedException, CacheLoaderException {
      assert !cs.containsKey("k");
      InternalCacheEntry se = InternalEntryFactory.create("k", "v");
      cs.store(se);

      assert cs.load("k").getValue().equals("v");
      assert cs.load("k").getLifespan() == -1;
      assert cs.load("k").getMaxIdle() == -1;
      assert !cs.load("k").isExpired();
      assert cs.containsKey("k");
   }

   public void testLoadAndStoreWithLifespan() throws InterruptedException, CacheLoaderException {
      assert !cs.containsKey("k");

      long lifespan = 120000;
      InternalCacheEntry se = InternalEntryFactory.create("k", "v", lifespan);
      cs.store(se);

      assert cs.load("k").getValue().equals("v");
      assert cs.load("k").getLifespan() == lifespan;
      assert cs.load("k").getMaxIdle() == -1;
      assert !cs.load("k").isExpired();
      assert cs.containsKey("k");

      lifespan = 1;
      se = InternalEntryFactory.create("k", "v", lifespan);
      cs.store(se);
      Thread.sleep(100);
      cs.purgeExpired();
      assert se.isExpired();
      assert cs.load("k") == null;
      assert !cs.containsKey("k");
   }

   public void testLoadAndStoreWithIdle() throws InterruptedException, CacheLoaderException {
      assert !cs.containsKey("k");

      long idle = 120000;
      InternalCacheEntry se = InternalEntryFactory.create("k", "v", -1, idle);
      cs.store(se);

      assert cs.load("k").getValue().equals("v");
      assert cs.load("k").getLifespan() == -1;
      assert cs.load("k").getMaxIdle() == idle;
      assert !cs.load("k").isExpired();
      assert cs.containsKey("k");

      idle = 1;
      se = InternalEntryFactory.create("k", "v", -1, idle);
      cs.store(se);
      Thread.sleep(100);
      cs.purgeExpired();
      assert se.isExpired();
      assert cs.load("k") == null;
      assert !cs.containsKey("k");
   }

   public void testLoadAndStoreWithLifespanAndIdle() throws InterruptedException, CacheLoaderException {
      assert !cs.containsKey("k");

      long lifespan = 200000;
      long idle = 120000;
      InternalCacheEntry se = InternalEntryFactory.create("k", "v", lifespan, idle);
      cs.store(se);

      assert cs.load("k").getValue().equals("v");
      assert cs.load("k").getLifespan() == lifespan;
      assert cs.load("k").getMaxIdle() == idle;
      assert !cs.load("k").isExpired();
      assert cs.containsKey("k");

      idle = 1;
      se = InternalEntryFactory.create("k", "v", lifespan, idle);
      cs.store(se);
      Thread.sleep(100);
      cs.purgeExpired();
      assert se.isExpired();
      assert cs.load("k") == null;
      assert !cs.containsKey("k");
   }

   public void testStopStartDoesntNukeValues() throws InterruptedException, CacheLoaderException {
      assert !cs.containsKey("k1");
      assert !cs.containsKey("k2");

      long lifespan = 1;
      long idle = 1;
      InternalCacheEntry se1 = InternalEntryFactory.create("k1", "v1", lifespan);
      InternalCacheEntry se2 = InternalEntryFactory.create("k2", "v2");
      InternalCacheEntry se3 = InternalEntryFactory.create("k3", "v3", -1, idle);
      InternalCacheEntry se4 = InternalEntryFactory.create("k4", "v4", lifespan, idle);

      cs.store(se1);
      cs.store(se2);
      cs.store(se3);
      cs.store(se4);
      Thread.sleep(100);
      cs.stop();
      cs.start();
      assert se1.isExpired();
      assert cs.load("k1") == null;
      assert !cs.containsKey("k1");
      assert cs.load("k2") != null;
      assert cs.containsKey("k2");
      assert cs.load("k2").getValue().equals("v2");
      assert se3.isExpired();
      assert cs.load("k3") == null;
      assert !cs.containsKey("k3");
      assert se3.isExpired();
      assert cs.load("k3") == null;
      assert !cs.containsKey("k3");
   }


   public void testOnePhaseCommit() throws CacheLoaderException {
      List<Modification> mods = new ArrayList<Modification>();
      mods.add(new Store(InternalEntryFactory.create("k1", "v1")));
      mods.add(new Store(InternalEntryFactory.create("k2", "v2")));
      mods.add(new Remove("k1"));
      GlobalTransaction tx = new GlobalTransaction(true);
      cs.prepare(mods, tx, true);

      assert cs.load("k2").getValue().equals("v2");
      assert !cs.containsKey("k1");

      cs.clear();

      mods = new ArrayList<Modification>();
      mods.add(new Store(InternalEntryFactory.create("k1", "v1")));
      mods.add(new Store(InternalEntryFactory.create("k2", "v2")));
      mods.add(new Clear());
      mods.add(new Store(InternalEntryFactory.create("k3", "v3")));

      cs.prepare(mods, tx, true);
      assert !cs.containsKey("k1");
      assert !cs.containsKey("k2");
      assert cs.containsKey("k3");
   }

   public void testTwoPhaseCommit() throws CacheLoaderException {
      List<Modification> mods = new ArrayList<Modification>();
      mods.add(new Store(InternalEntryFactory.create("k1", "v1")));
      mods.add(new Store(InternalEntryFactory.create("k2", "v2")));
      mods.add(new Remove("k1"));
      GlobalTransaction tx = new GlobalTransaction(false);
      cs.prepare(mods, tx, false);

      assert !cs.containsKey("k1");
      assert !cs.containsKey("k2");

      cs.commit(tx);

      assert cs.load("k2").getValue().equals("v2");
      assert !cs.containsKey("k1");

      cs.clear();

      mods = new ArrayList<Modification>();
      mods.add(new Store(InternalEntryFactory.create("k1", "v1")));
      mods.add(new Store(InternalEntryFactory.create("k2", "v2")));
      mods.add(new Clear());
      mods.add(new Store(InternalEntryFactory.create("k3", "v3")));

      cs.prepare(mods, tx, false);

      assert !cs.containsKey("k1");
      assert !cs.containsKey("k2");
      assert !cs.containsKey("k3");

      cs.commit(tx);

      assert !cs.containsKey("k1");
      assert !cs.containsKey("k2");
      assert cs.containsKey("k3");
   }


   public void testRollback() throws CacheLoaderException {

      cs.store(InternalEntryFactory.create("old", "old"));

      List<Modification> mods = new ArrayList<Modification>();
      mods.add(new Store(InternalEntryFactory.create("k1", "v1")));
      mods.add(new Store(InternalEntryFactory.create("k2", "v2")));
      mods.add(new Remove("k1"));
      mods.add(new Remove("old"));
      GlobalTransaction tx = new GlobalTransaction(false);
      cs.prepare(mods, tx, false);

      assert !cs.containsKey("k1");
      assert !cs.containsKey("k2");
      assert cs.containsKey("old");

      cs.rollback(tx);

      assert !cs.containsKey("k1");
      assert !cs.containsKey("k2");
      assert cs.containsKey("old");

      mods = new ArrayList<Modification>();
      mods.add(new Store(InternalEntryFactory.create("k1", "v1")));
      mods.add(new Store(InternalEntryFactory.create("k2", "v2")));
      mods.add(new Clear());
      mods.add(new Store(InternalEntryFactory.create("k3", "v3")));

      cs.prepare(mods, tx, false);

      assert !cs.containsKey("k1");
      assert !cs.containsKey("k2");
      assert !cs.containsKey("k3");

      cs.rollback(tx);

      assert !cs.containsKey("k1");
      assert !cs.containsKey("k2");
      assert !cs.containsKey("k3");
      assert cs.containsKey("old");
   }

   public void testRollbackFromADifferentThreadReusingTransactionKey() throws CacheLoaderException, InterruptedException {

      cs.store(InternalEntryFactory.create("old", "old"));

      List<Modification> mods = new ArrayList<Modification>();
      mods.add(new Store(InternalEntryFactory.create("k1", "v1")));
      mods.add(new Store(InternalEntryFactory.create("k2", "v2")));
      mods.add(new Remove("k1"));
      mods.add(new Remove("old"));
      final GlobalTransaction tx = new GlobalTransaction(false);
      cs.prepare(mods, tx, false);

      Thread t = new Thread(new Runnable() {
         public void run() {
            cs.rollback(tx);
         }
      });

      t.start();
      t.join();

      assert !cs.containsKey("k1");
      assert !cs.containsKey("k2");
      assert cs.containsKey("old");

      mods = new ArrayList<Modification>();
      mods.add(new Store(InternalEntryFactory.create("k1", "v1")));
      mods.add(new Store(InternalEntryFactory.create("k2", "v2")));
      mods.add(new Clear());
      mods.add(new Store(InternalEntryFactory.create("k3", "v3")));

      cs.prepare(mods, tx, false);

      Thread t2 = new Thread(new Runnable() {
         public void run() {
            cs.rollback(tx);
         }
      });

      t2.start();
      t2.join();
      assert !cs.containsKey("k1");
      assert !cs.containsKey("k2");
      assert !cs.containsKey("k3");
      assert cs.containsKey("old");
   }

   public void testCommitAndRollbackWithoutPrepare() throws CacheLoaderException {
      cs.store(InternalEntryFactory.create("old", "old"));
      GlobalTransaction tx = new GlobalTransaction(false);
      cs.commit(tx);
      cs.store(InternalEntryFactory.create("old", "old"));
      cs.rollback(tx);

      assert cs.containsKey("old");
   }

   public void testPreload() throws CacheLoaderException {
      cs.store(InternalEntryFactory.create("k1", "v1"));
      cs.store(InternalEntryFactory.create("k2", "v2"));
      cs.store(InternalEntryFactory.create("k3", "v3"));

      Set<InternalCacheEntry> set = cs.loadAll();

      assert set.size() == 3;
      Set expected = new HashSet();
      expected.add("k1");
      expected.add("k2");
      expected.add("k3");
      for (InternalCacheEntry se : set) assert expected.remove(se.getKey());
      assert expected.isEmpty();
   }

   @Test
   public void testStoreAndRemoveAll() throws CacheLoaderException {
      cs.store(InternalEntryFactory.create("k1", "v1"));
      cs.store(InternalEntryFactory.create("k2", "v2"));
      cs.store(InternalEntryFactory.create("k3", "v3"));
      cs.store(InternalEntryFactory.create("k4", "v4"));


      Set<InternalCacheEntry> set = cs.loadAll();

      assert set.size() == 4;
      Set expected = new HashSet();
      expected.add("k1");
      expected.add("k2");
      expected.add("k3");
      expected.add("k4");
      for (InternalCacheEntry se : set) assert expected.remove(se.getKey());
      assert expected.isEmpty();

      Set toRemove = new HashSet();
      toRemove.add("k1");
      toRemove.add("k2");
      toRemove.add("k3");
      cs.removeAll(toRemove);

      set = cs.loadAll();
      assert set.size() == 1;
      set.remove("k4");
      assert expected.isEmpty();
   }

   public void testPurgeExpired() throws Exception {
      long lifespan = 1000;
      long idle = 500;
      cs.store(InternalEntryFactory.create("k1", "v1", lifespan));
      cs.store(InternalEntryFactory.create("k2", "v2", -1, idle));
      cs.store(InternalEntryFactory.create("k3", "v3", lifespan, idle));
      assert cs.containsKey("k1");
      assert cs.containsKey("k2");
      assert cs.containsKey("k3");
      Thread.sleep(lifespan + 100);
      cs.purgeExpired();
      assert !cs.containsKey("k1");
      assert !cs.containsKey("k2");
      assert !cs.containsKey("k3");
   }

   public void testStreamingAPI() throws IOException, ClassNotFoundException, CacheLoaderException {
      cs.store(InternalEntryFactory.create("k1", "v1"));
      cs.store(InternalEntryFactory.create("k2", "v2"));
      cs.store(InternalEntryFactory.create("k3", "v3"));

      Marshaller marshaller = getMarshaller();
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      ObjectOutput oo = marshaller.startObjectOutput(out, false);
      try {
         cs.toStream(new UnclosableObjectOutputStream(oo));
      } finally {
         marshaller.finishObjectOutput(oo);
         out.close();
         cs.clear();        
      }

      ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
      ObjectInput oi = marshaller.startObjectInput(in, false);
      try {
         cs.fromStream(new UnclosableObjectInputStream(oi));        
      } finally {
         marshaller.finishObjectInput(oi);
         in.close();
      }

      Set<InternalCacheEntry> set = cs.loadAll();
      assert set.size() == 3;
      Set expected = new HashSet();
      expected.add("k1");
      expected.add("k2");
      expected.add("k3");
      for (InternalCacheEntry se : set) assert expected.remove(se.getKey());
      assert expected.isEmpty();
   }

   public void testStreamingAPIReusingStreams() throws IOException, ClassNotFoundException, CacheLoaderException {
      cs.store(InternalEntryFactory.create("k1", "v1"));
      cs.store(InternalEntryFactory.create("k2", "v2"));
      cs.store(InternalEntryFactory.create("k3", "v3"));

      Marshaller marshaller = getMarshaller();
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      byte[] dummyStartBytes = {1, 2, 3, 4, 5, 6, 7, 8};
      byte[] dummyEndBytes = {8, 7, 6, 5, 4, 3, 2, 1};
      ObjectOutput oo = marshaller.startObjectOutput(out, false);
      try {
         oo.write(dummyStartBytes);
         cs.toStream(new UnclosableObjectOutputStream(oo));
         oo.flush();
         oo.write(dummyEndBytes);
      } finally {
         marshaller.finishObjectOutput(oo);
         out.close();
         cs.clear();        
      }

      // first pop the start bytes
      byte[] dummy = new byte[8];
      ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
      ObjectInput oi = marshaller.startObjectInput(in, false);
      try {
         int bytesRead = oi.read(dummy, 0, 8);
         assert bytesRead == 8;
         for (int i = 1; i < 9; i++) assert dummy[i - 1] == i : "Start byte stream corrupted!";     
         cs.fromStream(new UnclosableObjectInputStream(oi));
         bytesRead = oi.read(dummy, 0, 8);
         assert bytesRead == 8;
         for (int i = 8; i > 0; i--) assert dummy[8 - i] == i : "Start byte stream corrupted!";                 
      } finally {
         marshaller.finishObjectInput(oi);
         in.close();
      }
     
      Set<InternalCacheEntry> set = cs.loadAll();
      assert set.size() == 3;
      Set expected = new HashSet();
      expected.add("k1");
      expected.add("k2");
      expected.add("k3");
      for (InternalCacheEntry se : set) assert expected.remove(se.getKey());
      assert expected.isEmpty();
   }
  
   public void testConfigFile() throws Exception {
      Class<? extends CacheLoaderConfig> cfgClass = cs.getConfigurationClass();
      CacheLoaderConfig clc = Util.getInstance(cfgClass);
      assert clc.getCacheLoaderClassName().equals(cs.getClass().getName()) : "Cache loaders doesn't provide a proper configuration type that is capable of creating the loaders!";
   }

   public void testConcurrency() throws Exception {
      int numThreads = 3;
      final int loops = 500;
      final String[] keys = new String[10];
      final String[] values = new String[10];
      for (int i = 0; i < 10; i++) keys[i] = "k" + i;
      for (int i = 0; i < 10; i++) values[i] = "v" + i;


      final Random r = new Random();
      final List<Exception> exceptions = new LinkedList<Exception>();

      final Runnable store = new Runnable() {
         public void run() {
            try {
               int randomInt = r.nextInt(10);
               cs.store(InternalEntryFactory.create(keys[randomInt], values[randomInt]));
            } catch (Exception e) {
               exceptions.add(e);
            }
         }
      };

      final Runnable remove = new Runnable() {
         public void run() {
            try {
               cs.remove(keys[r.nextInt(10)]);
            } catch (Exception e) {
               exceptions.add(e);
            }
         }
      };

      final Runnable get = new Runnable() {
         public void run() {
            try {
               int randomInt = r.nextInt(10);
               InternalCacheEntry se = cs.load(keys[randomInt]);
               assert se == null || se.getValue().equals(values[randomInt]);
               cs.loadAll();
            } catch (Exception e) {
               exceptions.add(e);
            }
         }
      };

      Thread[] threads = new Thread[numThreads];

      for (int i = 0; i < numThreads; i++) {
         threads[i] = new Thread(getClass().getSimpleName() + "-" + i) {
            public void run() {
               for (int i = 0; i < loops; i++) {
                  store.run();
                  remove.run();
                  get.run();
               }
            }
         };
      }

      for (Thread t : threads) t.start();
      for (Thread t : threads) t.join();

      if (!exceptions.isEmpty()) throw exceptions.get(0);
   }

}
TOP

Related Classes of org.infinispan.loaders.BaseCacheStoreTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.