package me.prettyprint.hector.api; import java.util.UUID; import static me.prettyprint.hector.api.ddl.ComparatorType.UUIDTYPE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.math.BigInteger; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.UUID; import me.prettyprint.cassandra.serializers.BigIntegerSerializer; import me.prettyprint.cassandra.serializers.ByteBufferSerializer; import me.prettyprint.cassandra.serializers.StringSerializer; import me.prettyprint.cassandra.serializers.UUIDSerializer; import me.prettyprint.cassandra.utils.TimeUUIDUtils; import me.prettyprint.hector.api.beans.AbstractComposite.ComponentEquality; import me.prettyprint.hector.api.beans.Composite; import me.prettyprint.hector.api.beans.DynamicComposite; import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.db.marshal.AsciiType; import org.apache.cassandra.db.marshal.BytesType; import org.apache.cassandra.db.marshal.DynamicCompositeType; import org.apache.cassandra.db.marshal.IntegerType; import org.apache.cassandra.db.marshal.LexicalUUIDType; import org.apache.cassandra.db.marshal.LongType; import org.apache.cassandra.db.marshal.TimeUUIDType; import org.apache.cassandra.db.marshal.UTF8Type; import org.apache.cassandra.db.marshal.UUIDType; import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.UUIDGen; import org.junit.Test; public class CompositeTest { @Test public void testDynamicSerialization() throws Exception { // test correct serialization sizes for strings DynamicComposite c = new DynamicComposite(); c.add("String1"); ByteBuffer b = c.serialize(); assertEquals(b.remaining(), 12); c.add("String2"); b = c.serialize(); assertEquals(b.remaining(), 24); // test deserialization of strings c = new DynamicComposite(); c.deserialize(b); assertEquals(2, c.size()); Object o = c.get(0); assertEquals("String1", o); o = c.get(1); assertEquals("String2", o); // test serialization and deserialization of longs c = new DynamicComposite(); c.add(new Long(10)); b = c.serialize(); c = new DynamicComposite(); c.deserialize(b); o = c.get(0); assertTrue(o instanceof Long); // test serialization and deserialization of floats c = new DynamicComposite(); c.add(new Float(10)); b = c.serialize(); c = new DynamicComposite(); c.deserialize(b); o = c.get(0); assertTrue(o instanceof Float); // test serialization and deserialization of random UUIDS c = new DynamicComposite(); c.add(UUID.randomUUID()); b = c.serialize(); c = DynamicComposite.fromByteBuffer(b); o = c.get(0); assertTrue(o instanceof UUID); assertEquals(UUIDTYPE.getTypeName(), c.getComponent(0).getComparator()); // test serialization and deserialization of time-based UUIDS c = new DynamicComposite(); c.add(TimeUUIDUtils.getUniqueTimeUUIDinMillis()); b = c.serialize(); c = DynamicComposite.fromByteBuffer(b); o = c.get(0); assertTrue(o instanceof UUID); assertEquals(UUIDTYPE.getTypeName(), c.getComponent(0).getComparator()); // test compatibility with Cassandra unit tests b = createDynamicCompositeKey("Hello", TimeUUIDUtils.getUniqueTimeUUIDinMillis(), 10, false); c = new DynamicComposite(); c.deserialize(b.slice()); o = c.get(0); assertTrue(o instanceof ByteBuffer); assertEquals("Hello", c.get(0, StringSerializer.get())); o = c.get(1); assertEquals(UUID.class, o.getClass()); o = c.get(2); assertEquals(BigInteger.class, o.getClass()); assertEquals(BigInteger.valueOf(10), o); // test using supplied deserializer rather than auto-mapped c = new DynamicComposite(); c.deserialize(b.slice()); assertTrue(c.get(0, ByteBufferSerializer.get()) instanceof ByteBuffer); assertTrue(c.get(1, ByteBufferSerializer.get()) instanceof ByteBuffer); assertTrue(c.get(2, ByteBufferSerializer.get()) instanceof ByteBuffer); // test setting a deserializer for specific components c = new DynamicComposite(); c.setSerializersByPosition(StringSerializer.get(), null, ByteBufferSerializer.get()); c.deserialize(b.slice()); assertTrue(c.get(0) instanceof String); assertTrue(c.get(1) instanceof UUID); assertTrue(c.get(2) instanceof ByteBuffer); b = DynamicComposite.toByteBuffer(1, "string", TimeUUIDUtils.getUniqueTimeUUIDinMillis()); c = DynamicComposite.fromByteBuffer(b); assertTrue(c.get(0) instanceof BigInteger); assertTrue(c.get(1) instanceof String); assertTrue(c.get(2) instanceof UUID); b = DynamicComposite.toByteBuffer((long) 1, "string", TimeUUIDUtils.getUniqueTimeUUIDinMillis()); c = DynamicComposite.fromByteBuffer(b); assertTrue(c.get(0) instanceof Long); assertTrue(c.get(1) instanceof String); assertTrue(c.get(2) instanceof UUID); b = DynamicComposite.toByteBuffer((byte) 1, "string", UUID.randomUUID()); c = DynamicComposite.fromByteBuffer(b); assertTrue(c.get(0) instanceof BigInteger); assertTrue(c.get(1) instanceof String); assertTrue(c.get(2) instanceof UUID); b = DynamicComposite.toByteBuffer(Arrays.asList(Arrays.asList(0, 1, 2), 3, 4, 5, Arrays.asList(6, 7, 8))); c = DynamicComposite.fromByteBuffer(b); for (int i = 0; i < 9; i++) { o = c.get(i); assertTrue(o instanceof BigInteger); assertEquals(i, ((BigInteger) o).intValue()); } b = DynamicComposite.toByteBuffer("foo"); c = DynamicComposite.fromByteBuffer(b); b = c.getComponent(0).getBytes(); UTF8Type.instance.validate(b); } @Test public void testNullValueSerialization() throws Exception { // test correct serialization with null values and user specified // serialization DynamicComposite c = new DynamicComposite(); try { c.addComponent(null, StringSerializer.get()); fail("Null values not allowed"); } catch (NullPointerException e) { } } @Test public void testStaticSerialization() throws Exception { ByteBuffer b = createCompositeKey("Hello", TimeUUIDUtils.getUniqueTimeUUIDinMillis(), 10, false); Composite c = new Composite(); c.setSerializersByPosition(StringSerializer.get(), UUIDSerializer.get(), BigIntegerSerializer.get()); c.deserialize(b.slice()); assertTrue(c.get(0) instanceof String); assertTrue(c.get(1) instanceof UUID); assertTrue(c.get(2) instanceof BigInteger); } @Test public void testEmptyStringSerialization() throws Exception { ByteBuffer b = createCompositeKey("", TimeUUIDUtils.getUniqueTimeUUIDinMillis(), 10, false); Composite c = new Composite(); c.setSerializersByPosition(StringSerializer.get(), UUIDSerializer.get(), BigIntegerSerializer.get()); c.deserialize(b.slice()); assertTrue(c.get(0) instanceof String); assertTrue(c.get(1) instanceof UUID); assertTrue(c.get(2) instanceof BigInteger); } @Test public void testEquality() throws Exception { DynamicCompositeType instance = getDefaultDynamicComparator(); DynamicComposite c1 = new DynamicComposite(10, "foo"); DynamicComposite c2 = new DynamicComposite(10, "foo"); assertEquals(0, instance.compare(c1.serialize(), c2.serialize())); c2.setEquality(ComponentEquality.GREATER_THAN_EQUAL); assertEquals(-1, instance.compare(c1.serialize(), c2.serialize())); c2.setEquality(ComponentEquality.LESS_THAN_EQUAL); assertEquals(1, instance.compare(c1.serialize(), c2.serialize())); c2.setEquality(ComponentEquality.EQUAL); assertEquals(0, instance.compare(c1.serialize(), c2.serialize())); c1.setEquality(ComponentEquality.LESS_THAN_EQUAL); assertEquals(-1, instance.compare(c1.serialize(), c2.serialize())); c1.setEquality(ComponentEquality.GREATER_THAN_EQUAL); assertEquals(1, instance.compare(c1.serialize(), c2.serialize())); } // from the Casssandra DynamicCompositeTypeTest unit test private ByteBuffer createDynamicCompositeKey(String s, UUID uuid, int i, boolean lastIsOne) { ByteBuffer bytes = ByteBufferUtil.bytes(s); int totalSize = 0; if (s != null) { totalSize += 2 + 2 + bytes.remaining() + 1; if (uuid != null) { totalSize += 2 + 2 + 16 + 1; if (i != -1) { totalSize += 2 + "IntegerType".length() + 2 + 1 + 1; } } } ByteBuffer bb = ByteBuffer.allocate(totalSize); if (s != null) { bb.putShort((short) (0x8000 | 'b')); bb.putShort((short) bytes.remaining()); bb.put(bytes); bb.put((uuid == null) && lastIsOne ? (byte) 1 : (byte) 0); if (uuid != null) { bb.putShort((short) (0x8000 | 't')); bb.putShort((short) 16); bb.put(UUIDGen.decompose(uuid)); bb.put((i == -1) && lastIsOne ? (byte) 1 : (byte) 0); if (i != -1) { bb.putShort((short) "IntegerType".length()); bb.put(ByteBufferUtil.bytes("IntegerType")); // We are putting a byte only because our test use ints that // fit in a byte *and* IntegerType.fromString() will // return something compatible (i.e, putting a full int here // would break 'fromStringTest') bb.putShort((short) 1); bb.put((byte) i); bb.put(lastIsOne ? (byte) 1 : (byte) 0); } } } bb.rewind(); return bb; } // from the Casssandra CompositeTypeTest unit test static ByteBuffer createCompositeKey(String s, UUID uuid, int i, boolean lastIsOne) { ByteBuffer bytes = ByteBufferUtil.bytes(s); int totalSize = 0; if (s != null) { totalSize += 2 + bytes.remaining() + 1; if (uuid != null) { totalSize += 2 + 16 + 1; if (i != -1) { totalSize += 2 + 1 + 1; } } } ByteBuffer bb = ByteBuffer.allocate(totalSize); if (s != null) { bb.putShort((short) bytes.remaining()); bb.put(bytes); bb.put((uuid == null) && lastIsOne ? (byte) 1 : (byte) 0); if (uuid != null) { bb.putShort((short) 16); bb.put(UUIDGen.decompose(uuid)); bb.put((i == -1) && lastIsOne ? (byte) 1 : (byte) 0); if (i != -1) { // We are putting a byte only because our test use ints that fit in a // byte *and* IntegerType.fromString() will // return something compatible (i.e, putting a full int here would // break 'fromStringTest') bb.putShort((short) 1); bb.put((byte) i); bb.put(lastIsOne ? (byte) 1 : (byte) 0); } } } bb.rewind(); return bb; } @SuppressWarnings("rawtypes") public DynamicCompositeType getDefaultDynamicComparator() { //Well if ? makes you happy then :) Generics FTWhatever Map<Byte, AbstractType<?>> aliases = new HashMap<Byte, AbstractType<?>>(); aliases.put((byte) 'a', AsciiType.instance); aliases.put((byte) 'b', BytesType.instance); aliases.put((byte) 'i', IntegerType.instance); aliases.put((byte) 'x', LexicalUUIDType.instance); aliases.put((byte) 'l', LongType.instance); aliases.put((byte) 't', TimeUUIDType.instance); aliases.put((byte) 's', UTF8Type.instance); aliases.put((byte) 'u', UUIDType.instance); DynamicCompositeType comparator = DynamicCompositeType.getInstance(aliases); return comparator; } }