cassandra-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sn...@apache.org
Subject [1/3] cassandra git commit: Store UDA initcond as CQL literal in the schema table, instead of a blob
Date Fri, 06 Nov 2015 17:29:49 GMT
Repository: cassandra
Updated Branches:
  refs/heads/trunk d91fb581e -> fb9e75eb3


http://git-wip-us.apache.org/repos/asf/cassandra/blob/e94032a2/test/unit/org/apache/cassandra/cql3/CQL3TypeLiteralTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/CQL3TypeLiteralTest.java b/test/unit/org/apache/cassandra/cql3/CQL3TypeLiteralTest.java
new file mode 100644
index 0000000..f6cd8df
--- /dev/null
+++ b/test/unit/org/apache/cassandra/cql3/CQL3TypeLiteralTest.java
@@ -0,0 +1,786 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.cql3;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.EnumMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.regex.Pattern;
+
+import org.junit.Test;
+
+import org.apache.cassandra.db.marshal.*;
+import org.apache.cassandra.serializers.*;
+import org.apache.cassandra.transport.Server;
+import org.apache.cassandra.utils.ByteBufferUtil;
+import org.apache.cassandra.utils.UUIDGen;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test functionality to re-create a CQL literal from its serialized representation.
+ * This test uses some randomness to generate the values and nested structures (collections,tuples,UDTs).
+ */
+public class CQL3TypeLiteralTest
+{
+    private static final Pattern QUOTE = Pattern.compile("'");
+
+    /**
+     * Container holding the expected CQL literal for a type and serialized value.
+     * The CQL literal is generated independently from the code in {@link CQL3Type}.
+     */
+    static class Value
+    {
+        final String expected;
+        final CQL3Type cql3Type;
+        final ByteBuffer value;
+
+        Value(String expected, CQL3Type cql3Type, ByteBuffer value)
+        {
+            this.expected = expected;
+            this.cql3Type = cql3Type;
+            this.value = value;
+        }
+    }
+
+    static final Map<CQL3Type.Native, List<Value>> nativeTypeValues = new EnumMap<>(CQL3Type.Native.class);
+
+    static void addNativeValue(String expected, CQL3Type.Native cql3Type, ByteBuffer value)
+    {
+        List<Value> l = nativeTypeValues.get(cql3Type);
+        if (l == null)
+            nativeTypeValues.put(cql3Type, l = new ArrayList<>());
+        l.add(new Value(expected, cql3Type, value));
+    }
+
+    static
+    {
+        // Add some (random) values for each native type.
+        // Also adds null values and empty values, if the type allows this.
+
+        for (int i = 0; i < 20; i++)
+        {
+            String v = randString(true);
+            addNativeValue(quote(v), CQL3Type.Native.ASCII, AsciiSerializer.instance.serialize(v));
+        }
+        addNativeValue("''", CQL3Type.Native.ASCII, AsciiSerializer.instance.serialize(""));
+        addNativeValue("''", CQL3Type.Native.ASCII, ByteBufferUtil.EMPTY_BYTE_BUFFER);
+        addNativeValue("null", CQL3Type.Native.ASCII, null);
+
+        for (int i = 0; i < 20; i++)
+        {
+            String v = randString(false);
+            addNativeValue(quote(v), CQL3Type.Native.TEXT, UTF8Serializer.instance.serialize(v));
+        }
+        addNativeValue("''", CQL3Type.Native.TEXT, UTF8Serializer.instance.serialize(""));
+        addNativeValue("''", CQL3Type.Native.TEXT, ByteBufferUtil.EMPTY_BYTE_BUFFER);
+        addNativeValue("null", CQL3Type.Native.TEXT, null);
+
+        for (int i = 0; i < 20; i++)
+        {
+            String v = randString(false);
+            addNativeValue(quote(v), CQL3Type.Native.VARCHAR, UTF8Serializer.instance.serialize(v));
+        }
+        addNativeValue("''", CQL3Type.Native.VARCHAR, UTF8Serializer.instance.serialize(""));
+        addNativeValue("''", CQL3Type.Native.VARCHAR, ByteBufferUtil.EMPTY_BYTE_BUFFER);
+        addNativeValue("null", CQL3Type.Native.VARCHAR, null);
+
+        addNativeValue("0", CQL3Type.Native.BIGINT, LongType.instance.decompose(0L));
+        for (int i = 0; i < 20; i++)
+        {
+            long v = randLong();
+            addNativeValue(Long.toString(v), CQL3Type.Native.BIGINT, LongType.instance.decompose(v));
+        }
+        addNativeValue("null", CQL3Type.Native.BIGINT, ByteBufferUtil.EMPTY_BYTE_BUFFER);
+        addNativeValue("null", CQL3Type.Native.BIGINT, null);
+
+        addNativeValue("0", CQL3Type.Native.COUNTER, LongType.instance.decompose(0L));
+        for (int i = 0; i < 20; i++)
+        {
+            long v = randLong();
+            addNativeValue(Long.toString(v), CQL3Type.Native.COUNTER, LongType.instance.decompose(v));
+        }
+        addNativeValue("null", CQL3Type.Native.COUNTER, ByteBufferUtil.EMPTY_BYTE_BUFFER);
+        addNativeValue("null", CQL3Type.Native.COUNTER, null);
+
+        addNativeValue("0", CQL3Type.Native.INT, Int32Type.instance.decompose(0));
+        for (int i = 0; i < 20; i++)
+        {
+            int v = randInt();
+            addNativeValue(Integer.toString(v), CQL3Type.Native.INT, Int32Type.instance.decompose(v));
+        }
+        addNativeValue("null", CQL3Type.Native.INT, ByteBufferUtil.EMPTY_BYTE_BUFFER);
+        addNativeValue("null", CQL3Type.Native.INT, null);
+
+        addNativeValue("0", CQL3Type.Native.SMALLINT, ShortType.instance.decompose((short)
0));
+        for (int i = 0; i < 20; i++)
+        {
+            short v = randShort();
+            addNativeValue(Short.toString(v), CQL3Type.Native.SMALLINT, ShortType.instance.decompose(v));
+        }
+        addNativeValue("null", CQL3Type.Native.SMALLINT, null);
+
+        addNativeValue("0", CQL3Type.Native.TINYINT, ByteType.instance.decompose((byte) 0));
+        for (int i = 0; i < 20; i++)
+        {
+            byte v = randByte();
+            addNativeValue(Short.toString(v), CQL3Type.Native.TINYINT, ByteType.instance.decompose(v));
+        }
+        addNativeValue("null", CQL3Type.Native.TINYINT, null);
+
+        addNativeValue("0.0", CQL3Type.Native.FLOAT, FloatType.instance.decompose((float)
0));
+        for (int i = 0; i < 20; i++)
+        {
+            float v = randFloat();
+            addNativeValue(Float.toString(v), CQL3Type.Native.FLOAT, FloatType.instance.decompose(v));
+        }
+        addNativeValue("NaN", CQL3Type.Native.FLOAT, FloatType.instance.decompose(Float.NaN));
+        addNativeValue("null", CQL3Type.Native.FLOAT, ByteBufferUtil.EMPTY_BYTE_BUFFER);
+        addNativeValue("null", CQL3Type.Native.FLOAT, null);
+
+        addNativeValue("0.0", CQL3Type.Native.DOUBLE, DoubleType.instance.decompose((double)
0));
+        for (int i = 0; i < 20; i++)
+        {
+            double v = randDouble();
+            addNativeValue(Double.toString(v), CQL3Type.Native.DOUBLE, DoubleType.instance.decompose(v));
+        }
+        addNativeValue("NaN", CQL3Type.Native.DOUBLE, DoubleType.instance.decompose(Double.NaN));
+        addNativeValue("null", CQL3Type.Native.DOUBLE, ByteBufferUtil.EMPTY_BYTE_BUFFER);
+        addNativeValue("null", CQL3Type.Native.DOUBLE, null);
+
+        addNativeValue("0", CQL3Type.Native.DECIMAL, DecimalType.instance.decompose(BigDecimal.ZERO));
+        for (int i = 0; i < 20; i++)
+        {
+            BigDecimal v = BigDecimal.valueOf(randDouble());
+            addNativeValue(v.toString(), CQL3Type.Native.DECIMAL, DecimalType.instance.decompose(v));
+        }
+        addNativeValue("null", CQL3Type.Native.DECIMAL, ByteBufferUtil.EMPTY_BYTE_BUFFER);
+        addNativeValue("null", CQL3Type.Native.DECIMAL, null);
+
+        addNativeValue("0", CQL3Type.Native.VARINT, IntegerType.instance.decompose(BigInteger.ZERO));
+        for (int i = 0; i < 20; i++)
+        {
+            BigInteger v = BigInteger.valueOf(randLong());
+            addNativeValue(v.toString(), CQL3Type.Native.VARINT, IntegerType.instance.decompose(v));
+        }
+        addNativeValue("null", CQL3Type.Native.VARINT, ByteBufferUtil.EMPTY_BYTE_BUFFER);
+        addNativeValue("null", CQL3Type.Native.VARINT, null);
+
+        // boolean doesn't have that many possible values...
+        addNativeValue("false", CQL3Type.Native.BOOLEAN, BooleanType.instance.decompose(false));
+        addNativeValue("true", CQL3Type.Native.BOOLEAN, BooleanType.instance.decompose(true));
+        addNativeValue("null", CQL3Type.Native.BOOLEAN, ByteBufferUtil.EMPTY_BYTE_BUFFER);
+        addNativeValue("null", CQL3Type.Native.BOOLEAN, null);
+
+        // (mostly generates date values with surreal values like in year 14273)
+        for (int i = 0; i < 20; i++)
+        {
+            int v = randInt();
+            addNativeValue(SimpleDateSerializer.instance.toString(v), CQL3Type.Native.DATE,
SimpleDateSerializer.instance.serialize(v));
+        }
+        addNativeValue("null", CQL3Type.Native.DATE, null);
+
+        for (int i = 0; i < 100; i++)
+        {
+            long v = randLong(24L * 60 * 60 * 1000 * 1000 * 1000);
+            addNativeValue(TimeSerializer.instance.toString(v), CQL3Type.Native.TIME, TimeSerializer.instance.serialize(v));
+        }
+        addNativeValue("null", CQL3Type.Native.TIME, null);
+
+        // (mostly generates timestamp values with surreal values like in year 14273)
+        for (int i = 0; i < 20; i++)
+        {
+            long v = randLong();
+            addNativeValue(TimestampSerializer.instance.toStringUTC(new Date(v)), CQL3Type.Native.TIMESTAMP,
TimestampType.instance.fromString(Long.toString(v)));
+        }
+        addNativeValue("null", CQL3Type.Native.TIMESTAMP, ByteBufferUtil.EMPTY_BYTE_BUFFER);
+        addNativeValue("null", CQL3Type.Native.TIMESTAMP, null);
+
+        for (int i = 0; i < 20; i++)
+        {
+            UUID v = UUIDGen.getTimeUUID(randLong(System.currentTimeMillis()));
+            addNativeValue(v.toString(), CQL3Type.Native.TIMEUUID, TimeUUIDType.instance.decompose(v));
+        }
+        addNativeValue("null", CQL3Type.Native.TIMEUUID, ByteBufferUtil.EMPTY_BYTE_BUFFER);
+        addNativeValue("null", CQL3Type.Native.TIMEUUID, null);
+
+        for (int i = 0; i < 20; i++)
+        {
+            UUID v = UUID.randomUUID();
+            addNativeValue(v.toString(), CQL3Type.Native.UUID, UUIDType.instance.decompose(v));
+        }
+        addNativeValue("null", CQL3Type.Native.UUID, ByteBufferUtil.EMPTY_BYTE_BUFFER);
+        addNativeValue("null", CQL3Type.Native.UUID, null);
+
+        for (int i = 0; i < 20; i++)
+        {
+            ByteBuffer v = randBytes();
+            addNativeValue("0x" + BytesSerializer.instance.toString(v), CQL3Type.Native.BLOB,
BytesType.instance.decompose(v));
+        }
+        addNativeValue("0x", CQL3Type.Native.BLOB, ByteBufferUtil.EMPTY_BYTE_BUFFER);
+        addNativeValue("null", CQL3Type.Native.BLOB, null);
+
+        for (int i = 0; i < 20; i++)
+        {
+            InetAddress v;
+            try
+            {
+                v = InetAddress.getByAddress(new byte[]{ randByte(), randByte(), randByte(),
randByte() });
+            }
+            catch (UnknownHostException e)
+            {
+                throw new RuntimeException(e);
+            }
+            addNativeValue(v.getHostAddress(), CQL3Type.Native.INET, InetAddressSerializer.instance.serialize(v));
+        }
+        addNativeValue("null", CQL3Type.Native.INET, ByteBufferUtil.EMPTY_BYTE_BUFFER);
+        addNativeValue("null", CQL3Type.Native.INET, null);
+    }
+
+    @Test
+    public void testNative()
+    {
+        // test each native type against each supported protocol version (although it doesn't
make sense to
+        // iterate through all protocol versions as of C* 3.0).
+
+        for (int version = Server.MIN_SUPPORTED_VERSION; version <= Server.CURRENT_VERSION;
version++)
+        {
+            for (Map.Entry<CQL3Type.Native, List<Value>> entry : nativeTypeValues.entrySet())
+            {
+                for (Value value : entry.getValue())
+                {
+                    compareCqlLiteral(version, value);
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testCollectionWithNatives()
+    {
+        // test 100 collections with varying element/key/value types against each supported
protocol version,
+        // type of collection is randomly chosen
+
+        for (int version = Server.MIN_SUPPORTED_VERSION; version <= Server.CURRENT_VERSION;
version++)
+        {
+            for (int n = 0; n < 100; n++)
+            {
+                Value value = generateCollectionValue(version, randomCollectionType(0), true);
+                compareCqlLiteral(version, value);
+            }
+        }
+    }
+
+    @Test
+    public void testCollectionNullAndEmpty()
+    {
+        for (int version = Server.MIN_SUPPORTED_VERSION; version <= Server.CURRENT_VERSION;
version++)
+        {
+            // empty, frozen collections
+            Value value = new Value("[]", ListType.getInstance(UTF8Type.instance, false).asCQL3Type(),
ByteBufferUtil.EMPTY_BYTE_BUFFER);
+            compareCqlLiteral(version, value);
+            value = new Value("{}", SetType.getInstance(UTF8Type.instance, false).asCQL3Type(),
ByteBufferUtil.EMPTY_BYTE_BUFFER);
+            compareCqlLiteral(version, value);
+            value = new Value("{}", MapType.getInstance(UTF8Type.instance, UTF8Type.instance,
false).asCQL3Type(), ByteBufferUtil.EMPTY_BYTE_BUFFER);
+            compareCqlLiteral(version, value);
+
+            // empty, non-frozen collections
+            value = new Value("[]", ListType.getInstance(UTF8Type.instance, true).asCQL3Type(),
ByteBufferUtil.EMPTY_BYTE_BUFFER);
+            compareCqlLiteral(version, value);
+            value = new Value("{}", SetType.getInstance(UTF8Type.instance, true).asCQL3Type(),
ByteBufferUtil.EMPTY_BYTE_BUFFER);
+            compareCqlLiteral(version, value);
+            value = new Value("{}", MapType.getInstance(UTF8Type.instance, UTF8Type.instance,
true).asCQL3Type(), ByteBufferUtil.EMPTY_BYTE_BUFFER);
+            compareCqlLiteral(version, value);
+
+            // null, frozen collections
+            value = new Value("null", ListType.getInstance(UTF8Type.instance, false).asCQL3Type(),
null);
+            compareCqlLiteral(version, value);
+            value = new Value("null", SetType.getInstance(UTF8Type.instance, false).asCQL3Type(),
null);
+            compareCqlLiteral(version, value);
+            value = new Value("null", MapType.getInstance(UTF8Type.instance, UTF8Type.instance,
false).asCQL3Type(), null);
+            compareCqlLiteral(version, value);
+
+            // null, non-frozen collections
+            value = new Value("[]", ListType.getInstance(UTF8Type.instance, true).asCQL3Type(),
null);
+            compareCqlLiteral(version, value);
+            value = new Value("{}", SetType.getInstance(UTF8Type.instance, true).asCQL3Type(),
null);
+            compareCqlLiteral(version, value);
+            value = new Value("{}", MapType.getInstance(UTF8Type.instance, UTF8Type.instance,
true).asCQL3Type(), null);
+            compareCqlLiteral(version, value);
+        }
+    }
+
+    @Test
+    public void testTupleWithNatives()
+    {
+        // test 100 tuples with varying element/key/value types against each supported protocol
version
+
+        for (int version = Server.MIN_SUPPORTED_VERSION; version <= Server.CURRENT_VERSION;
version++)
+        {
+            for (int n = 0; n < 100; n++)
+            {
+                Value value = generateTupleValue(version, randomTupleType(0), true);
+                compareCqlLiteral(version, value);
+            }
+        }
+    }
+
+    @Test
+    public void testUserDefinedWithNatives()
+    {
+        // test 100 UDTs with varying element/key/value types against each supported protocol
version
+
+        for (int version = Server.MIN_SUPPORTED_VERSION; version <= Server.CURRENT_VERSION;
version++)
+        {
+            for (int n = 0; n < 100; n++)
+            {
+                Value value = generateUserDefinedValue(version, randomUserType(0), true);
+                compareCqlLiteral(version, value);
+            }
+        }
+    }
+
+    @Test
+    public void testNested()
+    {
+        // This is the "nice" part of this unit test - it tests (probably) nested type structures
+        // like 'tuple<map, list<user>, tuple, user>' or 'map<tuple<int,
text>, set<inet>>' with
+        // random types  against each supported protocol version.
+
+        for (int version = Server.MIN_SUPPORTED_VERSION; version <= Server.CURRENT_VERSION;
version++)
+        {
+            for (int n = 0; n < 100; n++)
+            {
+                Value value = randomNested(version);
+                compareCqlLiteral(version, value);
+            }
+        }
+    }
+
+    static void compareCqlLiteral(int version, Value value)
+    {
+        ByteBuffer buffer = value.value != null ? value.value.duplicate() : null;
+        String msg = "Failed to get expected value for type " + value.cql3Type + " / " +
value.cql3Type.getType() + " with protocol-version " + version + " expected:\"" + value.expected
+ '"';
+        try
+        {
+            assertEquals(msg,
+                         value.expected,
+                         value.cql3Type.asCQLLiteral(buffer, version));
+        }
+        catch (RuntimeException e)
+        {
+            throw new RuntimeException(msg, e);
+        }
+    }
+
+    static Value randomNested(int version)
+    {
+        AbstractType type = randomNestedType(2);
+
+        return generateAnyValue(version, type.asCQL3Type());
+    }
+
+    /**
+     * Generates type of randomly nested type structures.
+     */
+    static AbstractType randomNestedType(int level)
+    {
+        if (level == 0)
+            return randomNativeType();
+        switch (randInt(level == 2 ? 3 : 4))
+        {
+            case 0:
+                return randomCollectionType(level - 1);
+            case 1:
+                return randomTupleType(level - 1);
+            case 2:
+                return randomUserType(level - 1);
+            case 3:
+                return randomNativeType();
+        }
+        throw new AssertionError();
+    }
+
+    static Value generateCollectionValue(int version, CollectionType collectionType, boolean
allowNull)
+    {
+        StringBuilder expected = new StringBuilder();
+        ByteBuffer buffer;
+
+        if (allowNull && randBool(0.05d))
+        {
+            // generate 'null' collection
+            if (collectionType.isMultiCell())
+            {
+                switch (collectionType.kind)
+                {
+                    case LIST:
+                        expected.append("[]");
+                        break;
+                    case SET:
+                    case MAP:
+                        expected.append("{}");
+                        break;
+                }
+            }
+            else
+            {
+                expected.append("null");
+            }
+            buffer = null;
+        }
+        else
+        {
+            int size = randInt(20);
+
+            CQL3Type elements;
+            CQL3Type values = null;
+            char bracketOpen;
+            char bracketClose;
+            switch (collectionType.kind)
+            {
+                case LIST:
+                    elements = ((ListType) collectionType).getElementsType().asCQL3Type();
+                    bracketOpen = '[';
+                    bracketClose = ']';
+                    break;
+                case SET:
+                    elements = ((SetType) collectionType).getElementsType().asCQL3Type();
+                    bracketOpen = '{';
+                    bracketClose = '}';
+                    break;
+                case MAP:
+                    elements = ((MapType) collectionType).getKeysType().asCQL3Type();
+                    values = ((MapType) collectionType).getValuesType().asCQL3Type();
+                    bracketOpen = '{';
+                    bracketClose = '}';
+                    break;
+                default:
+                    throw new AssertionError();
+            }
+
+            expected.append(bracketOpen);
+            Collection<ByteBuffer> buffers = new ArrayList<>();
+            Set<ByteBuffer> added = new HashSet<>();
+            for (int i = 0; i < size; i++)
+            {
+                Value el = generateAnyValue(version, elements);
+                if (!added.add(el.value))
+                    continue;
+
+                buffers.add(el.value.duplicate());
+                if (expected.length() > 1)
+                    expected.append(", ");
+                el.cql3Type.toCQLLiteral(el.value, version, expected);
+
+                if (collectionType.kind == CollectionType.Kind.MAP)
+                {
+                    // add map value
+                    el = generateAnyValue(version, values);
+                    buffers.add(el.value.duplicate());
+                    expected.append(": ");
+                    el.cql3Type.toCQLLiteral(el.value, version, expected);
+                }
+            }
+            expected.append(bracketClose);
+            buffer = CollectionSerializer.pack(buffers, added.size(), version);
+        }
+
+        return new Value(expected.toString(), collectionType.asCQL3Type(), buffer);
+    }
+
+    /**
+     * Generates a value for any type or type structure.
+     */
+    static Value generateAnyValue(int version, CQL3Type type)
+    {
+        if (type instanceof CQL3Type.Native)
+            return generateNativeValue(type, false);
+        if (type instanceof CQL3Type.Tuple)
+            return generateTupleValue(version, (TupleType) type.getType(), false);
+        if (type instanceof CQL3Type.UserDefined)
+            return generateUserDefinedValue(version, (UserType) type.getType(), false);
+        if (type instanceof CQL3Type.Collection)
+            return generateCollectionValue(version, (CollectionType) type.getType(), false);
+        throw new AssertionError();
+    }
+
+    static Value generateTupleValue(int version, TupleType tupleType, boolean allowNull)
+    {
+        StringBuilder expected = new StringBuilder();
+        ByteBuffer buffer;
+
+        if (allowNull && randBool(0.05d))
+        {
+            // generate 'null' collection
+            expected.append("null");
+            buffer = null;
+        }
+        else
+        {
+            expected.append('(');
+
+            // # of fields in this value
+            int fields = tupleType.size();
+            if (randBool(0.2d))
+                fields = randInt(fields);
+
+            ByteBuffer[] buffers = new ByteBuffer[fields];
+            for (int i = 0; i < fields; i++)
+            {
+                AbstractType<?> fieldType = tupleType.type(i);
+
+                if (i > 0)
+                    expected.append(", ");
+
+                if (allowNull && randBool(.1))
+                {
+                    expected.append("null");
+                    continue;
+                }
+
+                Value value = generateAnyValue(version, fieldType.asCQL3Type());
+                expected.append(value.expected);
+                buffers[i] = value.value.duplicate();
+            }
+            expected.append(')');
+            buffer = TupleType.buildValue(buffers);
+        }
+
+        return new Value(expected.toString(), tupleType.asCQL3Type(), buffer);
+    }
+
+    static Value generateUserDefinedValue(int version, UserType userType, boolean allowNull)
+    {
+        StringBuilder expected = new StringBuilder();
+        ByteBuffer buffer;
+
+        if (allowNull && randBool(0.05d))
+        {
+            // generate 'null' collection
+            expected.append("null");
+            buffer = null;
+        }
+        else
+        {
+            expected.append('{');
+
+            // # of fields in this value
+            int fields = userType.size();
+            if (randBool(0.2d))
+                fields = randInt(fields);
+
+            ByteBuffer[] buffers = new ByteBuffer[fields];
+            for (int i = 0; i < fields; i++)
+            {
+                AbstractType<?> fieldType = userType.type(i);
+
+                if (i > 0)
+                    expected.append(", ");
+
+                expected.append(ColumnIdentifier.maybeQuote(userType.fieldNameAsString(i)));
+                expected.append(": ");
+
+                if (randBool(.1))
+                {
+                    expected.append("null");
+                    continue;
+                }
+
+                Value value = generateAnyValue(version, fieldType.asCQL3Type());
+                expected.append(value.expected);
+                buffers[i] = value.value.duplicate();
+            }
+            expected.append('}');
+            buffer = TupleType.buildValue(buffers);
+        }
+
+        return new Value(expected.toString(), userType.asCQL3Type(), buffer);
+    }
+
+    static Value generateNativeValue(CQL3Type type, boolean allowNull)
+    {
+        List<Value> values = nativeTypeValues.get(type);
+        assert values != null : type.toString() + " needs to be defined";
+        while (true)
+        {
+            Value v = values.get(randInt(values.size()));
+            if (allowNull || v.value != null)
+                return v;
+        }
+    }
+
+    static CollectionType randomCollectionType(int level)
+    {
+        CollectionType.Kind kind = CollectionType.Kind.values()[randInt(CollectionType.Kind.values().length)];
+        switch (kind)
+        {
+            case LIST:
+            case SET:
+                return ListType.getInstance(randomNestedType(level), randBool());
+            case MAP:
+                return MapType.getInstance(randomNestedType(level), randomNestedType(level),
randBool());
+        }
+        throw new AssertionError();
+    }
+
+    static TupleType randomTupleType(int level)
+    {
+        int typeCount = 2 + randInt(5);
+        List<AbstractType<?>> types = new ArrayList<>();
+        for (int i = 0; i < typeCount; i++)
+            types.add(randomNestedType(level));
+        return new TupleType(types);
+    }
+
+    static UserType randomUserType(int level)
+    {
+        int typeCount = 2 + randInt(5);
+        List<ByteBuffer> names = new ArrayList<>();
+        List<AbstractType<?>> types = new ArrayList<>();
+        for (int i = 0; i < typeCount; i++)
+        {
+            names.add(UTF8Type.instance.fromString('f' + randLetters(i)));
+            types.add(randomNestedType(level));
+        }
+        return new UserType("ks", UTF8Type.instance.fromString("u" + randInt(1000000)), names,
types);
+    }
+
+    //
+    // Following methods are just helper methods. Mostly to generate many kinds of random
values.
+    //
+
+    private static String randLetters(int len)
+    {
+        StringBuilder sb = new StringBuilder(len);
+        while (len-- > 0)
+        {
+            int i = randInt(52);
+            if (i < 26)
+                sb.append((char) ('A' + i));
+            else
+                sb.append((char) ('a' + i - 26));
+        }
+        return sb.toString();
+    }
+
+    static AbstractType randomNativeType()
+    {
+        while (true)
+        {
+            CQL3Type.Native t = CQL3Type.Native.values()[randInt(CQL3Type.Native.values().length)];
+            if (t != CQL3Type.Native.EMPTY)
+                return t.getType();
+        }
+    }
+
+    static boolean randBool()
+    {
+        return randBool(0.5d);
+    }
+
+    static boolean randBool(double probability)
+    {
+        return ThreadLocalRandom.current().nextDouble() < probability;
+    }
+
+    static long randLong()
+    {
+        return ThreadLocalRandom.current().nextLong();
+    }
+
+    static long randLong(long max)
+    {
+        return ThreadLocalRandom.current().nextLong(max);
+    }
+
+    static int randInt()
+    {
+        return ThreadLocalRandom.current().nextInt();
+    }
+
+    static int randInt(int max)
+    {
+        return ThreadLocalRandom.current().nextInt(max);
+    }
+
+    static short randShort()
+    {
+        return (short) ThreadLocalRandom.current().nextInt();
+    }
+
+    static byte randByte()
+    {
+        return (byte) ThreadLocalRandom.current().nextInt();
+    }
+
+    static double randDouble()
+    {
+        return ThreadLocalRandom.current().nextDouble();
+    }
+
+    static float randFloat()
+    {
+        return ThreadLocalRandom.current().nextFloat();
+    }
+
+    static String randString(boolean ascii)
+    {
+        int l = randInt(20);
+        StringBuilder sb = new StringBuilder(l);
+        for (int i = 0; i < l; i++)
+        {
+            if (randBool(.05))
+                sb.append('\'');
+            else
+            {
+                char c = (char) (ascii ? randInt(128) : randShort());
+                sb.append(c);
+            }
+        }
+        return UTF8Serializer.instance.deserialize(UTF8Serializer.instance.serialize(sb.toString()));
+    }
+
+    static ByteBuffer randBytes()
+    {
+        int l = randInt(20);
+        byte[] v = new byte[l];
+        for (int i = 0; i < l; i++)
+        {
+            v[i] = randByte();
+        }
+        return ByteBuffer.wrap(v);
+    }
+
+    private static String quote(String v)
+    {
+        return '\'' + QUOTE.matcher(v).replaceAll("''") + '\'';
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e94032a2/test/unit/org/apache/cassandra/cql3/validation/operations/AggregationTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/AggregationTest.java
b/test/unit/org/apache/cassandra/cql3/validation/operations/AggregationTest.java
index 4341258..1a532ac 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/operations/AggregationTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/operations/AggregationTest.java
@@ -809,6 +809,9 @@ public class AggregationTest extends CQLTester
                                    "FINALFUNC " + shortFunctionName(fFinal) + " " +
                                    "INITCOND 42");
 
+        assertRows(execute("SELECT initcond FROM system_schema.aggregates WHERE keyspace_name=?
AND aggregate_name=?", KEYSPACE, shortFunctionName(a)),
+                   row("42"));
+
         // 42 + 1 + 2 + 3 = 48
         assertRows(execute("SELECT " + a + "(b) FROM %s"), row("48"));
 
@@ -896,6 +899,9 @@ public class AggregationTest extends CQLTester
                                    "FINALFUNC " + shortFunctionName(fFinal) + " " +
                                    "INITCOND (0, 0)");
 
+        assertRows(execute("SELECT initcond FROM system_schema.aggregates WHERE keyspace_name=?
AND aggregate_name=?", KEYSPACE, shortFunctionName(a)),
+                   row("(0, 0)"));
+
         // 1 + 2 + 3 = 6 / 3 = 2
         assertRows(execute("SELECT " + a + "(b) FROM %s"), row(2d));
 
@@ -1364,6 +1370,9 @@ public class AggregationTest extends CQLTester
                                              "FINALFUNC " + parseFunctionName(fFinal).name
+ ' ' +
                                              "INITCOND null");
 
+        assertRows(execute("SELECT initcond FROM system_schema.aggregates WHERE keyspace_name=?
AND aggregate_name=?", KEYSPACE, shortFunctionName(aggregation)),
+                   row(null));
+
         assertRows(execute("SELECT " + aggregation + "(b) FROM %s"),
                    row(set(7, 8, 9)));
 
@@ -1600,6 +1609,9 @@ public class AggregationTest extends CQLTester
                                       "FINALFUNC " + shortFunctionName(fCONf) + ' ' +
                                       "INITCOND ''");
 
+        assertRows(execute("SELECT initcond FROM system_schema.aggregates WHERE keyspace_name=?
AND aggregate_name=?", KEYSPACE, shortFunctionName(aCON)),
+                   row("''"));
+
         String fRNON = createFunction(KEYSPACE,
                                       "text, text",
                                       "CREATE FUNCTION %s(a text, b text) " +
@@ -1655,6 +1667,9 @@ public class AggregationTest extends CQLTester
                                        "STYPE list<text> " +
                                        "INITCOND [  ]");
 
+        assertRows(execute("SELECT initcond FROM system_schema.aggregates WHERE keyspace_name=?
AND aggregate_name=?", KEYSPACE, shortFunctionName(a)),
+                   row("[]"));
+
         createTable("CREATE TABLE %s (a int primary key, b int)");
         execute("INSERT INTO %s (a, b) VALUES (1, 1)");
         execute("INSERT INTO %s (a, b) VALUES (2, null)");

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e94032a2/test/unit/org/apache/cassandra/schema/LegacySchemaMigratorTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/schema/LegacySchemaMigratorTest.java b/test/unit/org/apache/cassandra/schema/LegacySchemaMigratorTest.java
index ad75fd0..7d0be4d 100644
--- a/test/unit/org/apache/cassandra/schema/LegacySchemaMigratorTest.java
+++ b/test/unit/org/apache/cassandra/schema/LegacySchemaMigratorTest.java
@@ -511,13 +511,17 @@ public class LegacySchemaMigratorTest
                                               null
         );
 
+        ByteBuffer twoNullEntries = ByteBuffer.allocate(8);
+        twoNullEntries.putInt(-1);
+        twoNullEntries.putInt(-1);
+        twoNullEntries.flip();
         UDAggregate uda2 = UDAggregate.create(udfs, new FunctionName(keyspace, "uda2"),
                                               ImmutableList.of(udf2.argTypes().get(1)),
                                               udf3.returnType(),
                                               udf2.name(),
                                               udf3.name(),
                                               udf2.argTypes().get(0),
-                                              LongType.instance.decompose(0L)
+                                              twoNullEntries
         );
 
         return KeyspaceMetadata.create(keyspace,


Mime
View raw message