Repository: cassandra Updated Branches: refs/heads/cassandra-3.0 cfbe2d35b -> e94032a23
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,
