/* * JBoss, Home of Professional Open Source * Copyright 2010 Red Hat Inc. and/or its affiliates and other * contributors as indicated by the @author tags. All rights reserved. * 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.infinispan.loaders.cloud; import org.infinispan.CacheImpl; import org.infinispan.container.entries.InternalCacheEntry; import org.infinispan.test.fwk.TestInternalCacheEntryFactory; import org.infinispan.io.UnclosableObjectInputStream; import org.infinispan.io.UnclosableObjectOutputStream; import org.infinispan.loaders.BaseCacheStoreTest; import org.infinispan.loaders.CacheLoaderException; import org.infinispan.loaders.CacheStore; import org.infinispan.marshall.StreamingMarshaller; 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.io.Serializable; import java.util.Arrays; import java.util.HashSet; import java.util.Set; import static org.testng.Assert.assertEquals; @Test(groups = "unit", testName = "loaders.cloud.CloudCacheStoreTest") public class CloudCacheStoreTest extends BaseCacheStoreTest { private static final String csBucket = "Bucket1"; private static final String cs2Bucket = "Bucket2"; protected CacheStore cs2; private CacheStore buildCloudCacheStoreWithStubCloudService(String bucketName) throws CacheLoaderException { CloudCacheStore cs = new CloudCacheStore(); CloudCacheStoreConfig cfg = new CloudCacheStoreConfig(); cfg.setBucketPrefix(bucketName); cfg.setCloudService("transient"); cfg.setIdentity("unit-test-stub"); cfg.setPassword("unit-test-stub"); cfg.setProxyHost("unit-test-stub"); cfg.setProxyPort("unit-test-stub"); // TODO remove compress = false once ISPN-409 is closed. cfg.setCompress(false); cfg.setPurgeSynchronously(true); // for more accurate unit testing cs.init(cfg, new CacheImpl("aName"), getMarshaller()); return cs; } protected CacheStore createCacheStore() throws Exception { CacheStore store = buildCloudCacheStoreWithStubCloudService(csBucket); store.start(); return store; } protected CacheStore createAnotherCacheStore() throws Exception { CacheStore store = buildCloudCacheStoreWithStubCloudService(cs2Bucket); store.start(); return store; } @BeforeMethod @Override public void setUp() throws Exception { super.setUp(); cs.clear(); Set entries = cs.loadAll(); assert entries.isEmpty(); cs2 = createAnotherCacheStore(); cs2.clear(); entries = cs2.loadAll(); assert entries.isEmpty(); } @AfterMethod @Override public void tearDown() throws CacheLoaderException { for (CacheStore cacheStore : Arrays.asList(cs, cs2)) { if (cacheStore != null) { cacheStore.clear(); cacheStore.stop(); } } cs = null; cs2 = null; } @SuppressWarnings("unchecked") @Override @Test(enabled = false, description = "Disabled until JClouds gains a proper streaming API") public void testStreamingAPI() throws CacheLoaderException, IOException { cs.store(TestInternalCacheEntryFactory.create("k1", "v1", -1, -1)); cs.store(TestInternalCacheEntryFactory.create("k2", "v2", -1, -1)); cs.store(TestInternalCacheEntryFactory.create("k3", "v3", -1, -1)); StreamingMarshaller marshaller = getMarshaller(); ByteArrayOutputStream out = new ByteArrayOutputStream(); ObjectOutput oo = marshaller.startObjectOutput(out, false, 12); try { cs.toStream(new UnclosableObjectOutputStream(oo)); } finally { marshaller.finishObjectOutput(oo); out.close(); } ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); ObjectInput oi = marshaller.startObjectInput(in, false); try { cs2.fromStream(new UnclosableObjectInputStream(oi)); } finally { marshaller.finishObjectInput(oi); in.close(); } Set<InternalCacheEntry> set = cs2.loadAll(); assertEquals(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 testNegativeHashCodes() throws CacheLoaderException { ObjectWithNegativeHashcode objectWithNegativeHashcode = new ObjectWithNegativeHashcode(); cs.store(TestInternalCacheEntryFactory.create(objectWithNegativeHashcode, "hello", -1, -1)); InternalCacheEntry ice = cs.load(objectWithNegativeHashcode); assert ice.getKey().equals(objectWithNegativeHashcode); assert ice.getValue().equals("hello"); } private static class ObjectWithNegativeHashcode implements Serializable { String s = "hello"; private static final long serialVersionUID = 5010691348616186237L; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ObjectWithNegativeHashcode blah = (ObjectWithNegativeHashcode) o; return !(s != null ? !s.equals(blah.s) : blah.s != null); } @Override public int hashCode() { return -700; } } @Override @Test(enabled = false, description = "Disabled until we can build the blobstore stub to retain state somewhere.") public void testStopStartDoesNotNukeValues() throws InterruptedException, CacheLoaderException { } @SuppressWarnings("unchecked") @Override @Test(enabled = false, description = "Disabled until JClouds gains a proper streaming API") public void testStreamingAPIReusingStreams() throws CacheLoaderException, IOException { cs.store(TestInternalCacheEntryFactory.create("k1", "v1", -1, -1)); cs.store(TestInternalCacheEntryFactory.create("k2", "v2", -1, -1)); cs.store(TestInternalCacheEntryFactory.create("k3", "v3", -1, -1)); StreamingMarshaller 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, dummyStartBytes.length); try { oo.write(dummyStartBytes); cs.toStream(new UnclosableObjectOutputStream(oo)); oo.flush(); oo.write(dummyEndBytes); } finally { marshaller.finishObjectOutput(oo); out.close(); } // 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!"; cs2.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 = cs2.loadAll(); assertEquals(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(); } }