mirror of https://github.com/apache/cassandra
Merge branch 'cassandra-4.0' into cassandra-4.1
* cassandra-4.0: Fix few types issues and implement types compatibility tests
This commit is contained in:
commit
445ae1a4b1
|
|
@ -3,6 +3,7 @@
|
|||
* Do not go to disk for reading hints file sizes (CASSANDRA-19477)
|
||||
* Fix system_views.settings to handle array types (CASSANDRA-19475)
|
||||
Merged from 4.0:
|
||||
* Fix few types issues and implement types compatibility tests (CASSANDRA-19479)
|
||||
* Optionally avoid hint transfer during decommission (CASSANDRA-19525)
|
||||
* Change logging to TRACE when failing to get peer certificate (CASSANDRA-19508)
|
||||
* Push LocalSessions info logs to debug (CASSANDRA-18335)
|
||||
|
|
|
|||
|
|
@ -737,9 +737,9 @@
|
|||
<dependency groupId="com.google.j2objc" artifactId="j2objc-annotations" version="1.3"/>
|
||||
<!-- adding this dependency is necessary for assertj. When updating assertj, need to also update the version of
|
||||
this that the new assertj's `assertj-parent-pom` depends on. -->
|
||||
<dependency groupId="org.junit" artifactId="junit-bom" version="5.6.0" type="pom" scope="test"/>
|
||||
<dependency groupId="org.junit" artifactId="junit-bom" version="5.10.1" type="pom" scope="test"/>
|
||||
<!-- when updating assertj, make sure to also update the corresponding junit-bom dependency -->
|
||||
<dependency groupId="org.assertj" artifactId="assertj-core" version="3.15.0" scope="test"/>
|
||||
<dependency groupId="org.assertj" artifactId="assertj-core" version="3.25.3" scope="test"/>
|
||||
<dependency groupId="org.awaitility" artifactId="awaitility" version="4.0.3" scope="test">
|
||||
<exclusion groupId="org.hamcrest" artifactId="hamcrest"/>
|
||||
</dependency>
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ public abstract class AbstractCompositeType extends AbstractType<ByteBuffer>
|
|||
int offsetL = startingOffset(isStaticL);
|
||||
int offsetR = startingOffset(isStaticR);
|
||||
|
||||
while (!accessorL.isEmptyFromOffset(left, offsetL) && !accessorR.isEmptyFromOffset(right, offsetL))
|
||||
while (!accessorL.isEmptyFromOffset(left, offsetL) && !accessorR.isEmptyFromOffset(right, offsetR))
|
||||
{
|
||||
AbstractType<?> comparator = getComparator(i, left, accessorL, right, accessorR, offsetL, offsetR);
|
||||
offsetL += getComparatorSize(i, left, accessorL, offsetL);
|
||||
|
|
|
|||
|
|
@ -248,6 +248,13 @@ public class ByteArrayAccessor implements ValueAccessor<byte[]>
|
|||
return Ballot.deserialize(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int putByte(byte[] dst, int offset, byte value)
|
||||
{
|
||||
dst[offset] = value;
|
||||
return TypeSizes.BYTE_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int putShort(byte[] dst, int offset, short value)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -252,6 +252,13 @@ public class ByteBufferAccessor implements ValueAccessor<ByteBuffer>
|
|||
return Ballot.deserialize(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int putByte(ByteBuffer dst, int offset, byte value)
|
||||
{
|
||||
dst.put(dst.position() + offset, value);
|
||||
return TypeSizes.BYTE_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int putShort(ByteBuffer dst, int offset, short value)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import java.nio.ByteBuffer;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
|
|
@ -29,7 +30,9 @@ import com.google.common.collect.Lists;
|
|||
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.exceptions.SyntaxException;
|
||||
import org.apache.cassandra.serializers.BytesSerializer;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
import static com.google.common.collect.Iterables.any;
|
||||
|
|
@ -62,9 +65,37 @@ import static com.google.common.collect.Iterables.transform;
|
|||
*/
|
||||
public class CompositeType extends AbstractCompositeType
|
||||
{
|
||||
private static class Serializer extends BytesSerializer
|
||||
{
|
||||
// types are held to make sure the serializer is unique for each collection of types, this is to make sure it's
|
||||
// safe to cache in all cases
|
||||
public final List<AbstractType<?>> types;
|
||||
|
||||
public Serializer(List<AbstractType<?>> types)
|
||||
{
|
||||
this.types = types;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Serializer that = (Serializer) o;
|
||||
return types.equals(that.types);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(types);
|
||||
}
|
||||
}
|
||||
|
||||
private static final int STATIC_MARKER = 0xFFFF;
|
||||
|
||||
public final List<AbstractType<?>> types;
|
||||
private final Serializer serializer;
|
||||
|
||||
// interning instances
|
||||
private static final ConcurrentMap<List<AbstractType<?>>, CompositeType> instances = new ConcurrentHashMap<>();
|
||||
|
|
@ -136,8 +167,16 @@ public class CompositeType extends AbstractCompositeType
|
|||
protected CompositeType(List<AbstractType<?>> types)
|
||||
{
|
||||
this.types = ImmutableList.copyOf(types);
|
||||
this.serializer = new Serializer(this.types);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSerializer<ByteBuffer> getSerializer()
|
||||
{
|
||||
return serializer;
|
||||
}
|
||||
|
||||
|
||||
protected <V> AbstractType<?> getComparator(int i, V value, ValueAccessor<V> accessor, int offset)
|
||||
{
|
||||
try
|
||||
|
|
|
|||
|
|
@ -20,8 +20,11 @@ package org.apache.cassandra.db.marshal;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.CharacterCodingException;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
@ -30,6 +33,7 @@ import org.apache.cassandra.cql3.Term;
|
|||
import org.apache.cassandra.db.TypeSizes;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.exceptions.SyntaxException;
|
||||
import org.apache.cassandra.serializers.BytesSerializer;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
|
@ -60,7 +64,36 @@ public class DynamicCompositeType extends AbstractCompositeType
|
|||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(DynamicCompositeType.class);
|
||||
|
||||
private final Map<Byte, AbstractType<?>> aliases;
|
||||
public static class Serializer extends BytesSerializer
|
||||
{
|
||||
// aliases are held to make sure the serializer is unique for each collection of types, this is to make sure it's
|
||||
// safe to cache in all cases
|
||||
private final Map<Byte, AbstractType<?>> aliases;
|
||||
|
||||
public Serializer(Map<Byte, AbstractType<?>> aliases)
|
||||
{
|
||||
this.aliases = aliases;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Serializer that = (Serializer) o;
|
||||
return aliases.equals(that.aliases);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(aliases);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public final Map<Byte, AbstractType<?>> aliases;
|
||||
private final Serializer serializer;
|
||||
|
||||
// interning instances
|
||||
private static final ConcurrentHashMap<Map<Byte, AbstractType<?>>, DynamicCompositeType> instances = new ConcurrentHashMap<>();
|
||||
|
|
@ -80,7 +113,14 @@ public class DynamicCompositeType extends AbstractCompositeType
|
|||
|
||||
private DynamicCompositeType(Map<Byte, AbstractType<?>> aliases)
|
||||
{
|
||||
this.aliases = aliases;
|
||||
this.aliases = ImmutableMap.copyOf(aliases);
|
||||
this.serializer = new Serializer(aliases);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSerializer<ByteBuffer> getSerializer()
|
||||
{
|
||||
return serializer;
|
||||
}
|
||||
|
||||
protected <V> boolean readIsStatic(V value, ValueAccessor<V> accessor)
|
||||
|
|
@ -378,7 +418,8 @@ public class DynamicCompositeType extends AbstractCompositeType
|
|||
* A comparator that always sorts it's first argument before the second
|
||||
* one.
|
||||
*/
|
||||
private static class FixedValueComparator extends AbstractType<Void>
|
||||
@VisibleForTesting
|
||||
public static class FixedValueComparator extends AbstractType<Void>
|
||||
{
|
||||
public static final FixedValueComparator alwaysLesserThan = new FixedValueComparator(-1);
|
||||
public static final FixedValueComparator alwaysGreaterThan = new FixedValueComparator(1);
|
||||
|
|
|
|||
|
|
@ -31,6 +31,12 @@ public class LexicalUUIDType extends AbstractType<UUID>
|
|||
{
|
||||
public static final LexicalUUIDType instance = new LexicalUUIDType();
|
||||
|
||||
// we just need it to be something different to UUIDSerializer
|
||||
private static class Serializer extends UUIDSerializer
|
||||
{
|
||||
public static final Serializer instance = new Serializer();
|
||||
}
|
||||
|
||||
LexicalUUIDType()
|
||||
{
|
||||
super(ComparisonType.CUSTOM);
|
||||
|
|
@ -80,7 +86,7 @@ public class LexicalUUIDType extends AbstractType<UUID>
|
|||
|
||||
public TypeSerializer<UUID> getSerializer()
|
||||
{
|
||||
return UUIDSerializer.instance;
|
||||
return Serializer.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
|
|
@ -63,7 +64,8 @@ public class TupleType extends AbstractType<ByteBuffer>
|
|||
this(types, true);
|
||||
}
|
||||
|
||||
protected TupleType(List<AbstractType<?>> types, boolean freezeInner)
|
||||
@VisibleForTesting
|
||||
public TupleType(List<AbstractType<?>> types, boolean freezeInner)
|
||||
{
|
||||
super(ComparisonType.CUSTOM);
|
||||
|
||||
|
|
@ -441,7 +443,7 @@ public class TupleType extends AbstractType<ByteBuffer>
|
|||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if(!(o instanceof TupleType))
|
||||
if (o.getClass() != TupleType.class)
|
||||
return false;
|
||||
|
||||
TupleType that = (TupleType)o;
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ public class TypeParser
|
|||
|
||||
String alias = readNextIdentifier();
|
||||
if (alias.length() != 1)
|
||||
throwSyntaxError("An alias should be a single character");
|
||||
throwSyntaxError("An alias should be a single character: '" + alias + "', string: " + str);
|
||||
char aliasChar = alias.charAt(0);
|
||||
if (aliasChar < 33 || aliasChar > 127)
|
||||
throwSyntaxError("An alias should be a single character in [0..9a..bA..B-+._&]");
|
||||
|
|
|
|||
|
|
@ -342,7 +342,7 @@ public class UserType extends TupleType implements SchemaElement
|
|||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if(!(o instanceof UserType))
|
||||
if (o.getClass() != UserType.class)
|
||||
return false;
|
||||
|
||||
UserType that = (UserType)o;
|
||||
|
|
|
|||
|
|
@ -330,6 +330,12 @@ public interface ValueAccessor<V>
|
|||
/** returns a TimeUUID from offset 0 */
|
||||
Ballot toBallot(V value);
|
||||
|
||||
/**
|
||||
* writes the byte value {@param value} to {@param dst} at offset {@param offset}
|
||||
* @return the number of bytes written to {@param value}
|
||||
*/
|
||||
int putByte(V dst, int offset, byte value);
|
||||
|
||||
/**
|
||||
* writes the short value {@param value} to {@param dst} at offset {@param offset}
|
||||
* @return the number of bytes written to {@param value}
|
||||
|
|
|
|||
|
|
@ -303,4 +303,9 @@ public class CassandraVersion implements Comparable<CassandraVersion>
|
|||
sb.append('+').append(StringUtils.join(build, "."));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String toMajorMinorString()
|
||||
{
|
||||
return String.format("%d.%d", major, minor);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,6 +70,11 @@ public class FastByteOperations
|
|||
return BestHolder.BEST.compare(b1, b2);
|
||||
}
|
||||
|
||||
public static int compareUnsigned(byte[] b1, byte[] b2)
|
||||
{
|
||||
return compareUnsigned(b1, 0, b1.length, b2, 0, b2.length);
|
||||
}
|
||||
|
||||
public static void copy(byte[] src, int srcPosition, byte[] trg, int trgPosition, int length)
|
||||
{
|
||||
BestHolder.BEST.copy(src, srcPosition, trg, trgPosition, length);
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -526,6 +526,6 @@ public class SSTableIdGenerationTest extends TestBaseImpl
|
|||
SimpleQueryResult result = instance.executeInternalWithResult(format("SELECT * FROM %s.%s", ks, tableName));
|
||||
Object[][] rows = result.toObjectArrays();
|
||||
assertThat(rows).withFailMessage("Invalid results for %s.%s - should have %d rows but has %d: \n%s", ks, tableName, expectedNumber,
|
||||
rows.length, result.toString()).hasSize(expectedNumber);
|
||||
rows.length, result.toString()).hasNumberOfRows(expectedNumber);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import org.apache.cassandra.distributed.api.Row;
|
|||
import org.apache.cassandra.distributed.api.SimpleQueryResult;
|
||||
import org.apache.cassandra.tools.nodetool.formatter.TableBuilder;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.assertj.core.data.Index;
|
||||
|
||||
public class QueryResultUtil
|
||||
{
|
||||
|
|
@ -161,20 +162,20 @@ public class QueryResultUtil
|
|||
public SimpleQueryResultAssertHelper isEqualTo(Object... values)
|
||||
{
|
||||
Assertions.assertThat(qr.toObjectArrays())
|
||||
.hasSize(1)
|
||||
.contains(values);
|
||||
.hasNumberOfRows(1)
|
||||
.contains(values, Index.atIndex(0));
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleQueryResultAssertHelper hasSize(int size)
|
||||
{
|
||||
Assertions.assertThat(qr.toObjectArrays()).hasSize(size);
|
||||
Assertions.assertThat((Object[]) qr.toObjectArrays()).hasSize(size);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleQueryResultAssertHelper hasSizeGreaterThan(int size)
|
||||
{
|
||||
Assertions.assertThat(qr.toObjectArrays()).hasSizeGreaterThan(size);
|
||||
Assertions.assertThat((Object[]) qr.toObjectArrays()).hasSizeGreaterThan(size);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ import org.junit.Test;
|
|||
|
||||
import org.apache.cassandra.cql3.CQLTester;
|
||||
import org.apache.cassandra.cql3.UntypedResultSet;
|
||||
import org.apache.cassandra.db.marshal.DecimalType;
|
||||
import org.apache.cassandra.db.marshal.DurationType;
|
||||
import org.apache.cassandra.db.marshal.TupleType;
|
||||
import org.apache.cassandra.utils.AbstractTypeGenerators.TypeSupport;
|
||||
import org.quicktheories.core.Gen;
|
||||
|
|
@ -332,7 +334,8 @@ public class TupleTypeTest extends CQLTester
|
|||
|
||||
private static Gen<TypeAndRows> typesAndRowsGen(int numRows)
|
||||
{
|
||||
Gen<TupleType> typeGen = tupleTypeGen(primitiveTypeGen(), SourceDSL.integers().between(1, 10));
|
||||
// duration type is invalid for keys and decimal type is problematic for equality checks
|
||||
Gen<TupleType> typeGen = tupleTypeGen(primitiveTypeGen(DurationType.instance, DecimalType.instance), SourceDSL.integers().between(1, 10));
|
||||
Set<ByteBuffer> distinctRows = new HashSet<>(numRows); // reuse the memory
|
||||
Gen<TypeAndRows> gen = rnd -> {
|
||||
TypeAndRows c = new TypeAndRows();
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -37,7 +37,6 @@ import java.util.stream.Collectors;
|
|||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
|
|
@ -76,18 +75,18 @@ import org.apache.cassandra.utils.ObjectSizes;
|
|||
import org.apache.cassandra.utils.Throwables;
|
||||
import org.apache.cassandra.utils.TimeUUID;
|
||||
import org.apache.cassandra.utils.asserts.SyncTaskListAssert;
|
||||
import org.assertj.core.api.Assertions;
|
||||
|
||||
import static java.util.Collections.emptySet;
|
||||
import static org.apache.cassandra.net.Verb.PAXOS2_CLEANUP_REQ;
|
||||
import static org.apache.cassandra.net.Verb.PAXOS2_CLEANUP_START_PREPARE_REQ;
|
||||
import static org.apache.cassandra.repair.RepairParallelism.SEQUENTIAL;
|
||||
import static org.apache.cassandra.streaming.PreviewKind.NONE;
|
||||
import static org.apache.cassandra.utils.TimeUUID.Generator.nextTimeUUID;
|
||||
import static org.apache.cassandra.utils.asserts.SyncTaskAssert.assertThat;
|
||||
import static org.apache.cassandra.utils.asserts.SyncTaskListAssert.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.apache.cassandra.net.Verb.PAXOS2_CLEANUP_START_PREPARE_REQ;
|
||||
import static org.apache.cassandra.net.Verb.PAXOS2_CLEANUP_REQ;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
|
|
@ -712,7 +711,7 @@ public class RepairJobTest
|
|||
false,
|
||||
PreviewKind.ALL));
|
||||
|
||||
assertThat(tasks.values()).areAllInstanceOf(AsymmetricRemoteSyncTask.class);
|
||||
SyncTaskListAssert.assertThat(tasks.values()).areAllInstanceOf(AsymmetricRemoteSyncTask.class);
|
||||
|
||||
// addr1 streams range1 from addr3:
|
||||
assertThat(tasks.get(pair(addr1, addr3)).rangesToSync).contains(RANGE_1);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -33,6 +33,7 @@ import org.apache.commons.lang3.builder.MultilineRecursiveToStringStyle;
|
|||
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
|
||||
|
||||
import org.apache.cassandra.cql3.ColumnIdentifier;
|
||||
import org.apache.cassandra.cql3.Duration;
|
||||
import org.apache.cassandra.cql3.FieldIdentifier;
|
||||
import org.apache.cassandra.db.ReadCommand;
|
||||
import org.apache.cassandra.db.SchemaCQLHelper;
|
||||
|
|
@ -316,4 +317,24 @@ public final class CassandraGenerators
|
|||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
public static Gen<Duration> duration()
|
||||
{
|
||||
Constraint ints = Constraint.between(0, Integer.MAX_VALUE);
|
||||
Constraint longs = Constraint.between(0, Long.MAX_VALUE);
|
||||
Gen<Boolean> neg = SourceDSL.booleans().all();
|
||||
return rnd -> {
|
||||
int months = (int) rnd.next(ints);
|
||||
int days = (int) rnd.next(ints);
|
||||
long nanoseconds = rnd.next(longs);
|
||||
if (neg.generate(rnd))
|
||||
{
|
||||
months = -1 * months;
|
||||
days = -1 * days;
|
||||
nanoseconds = -1 * nanoseconds;
|
||||
}
|
||||
return Duration.newInstance(months, days, nanoseconds);
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
*/
|
||||
package org.apache.cassandra.utils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
|
@ -61,6 +63,10 @@ public final class Generators
|
|||
|
||||
public static final Gen<String> IDENTIFIER_GEN = Generators.regexWord(SourceDSL.integers().between(1, 50));
|
||||
|
||||
public static Gen<Character> letterOrDigit()
|
||||
{
|
||||
return SourceDSL.integers().between(0, LETTER_OR_DIGIT_DOMAIN.length - 1).map(idx -> LETTER_OR_DIGIT_DOMAIN[idx]);
|
||||
}
|
||||
public static final Gen<UUID> UUID_RANDOM_GEN = rnd -> {
|
||||
long most = rnd.next(Constraint.none());
|
||||
most &= 0x0f << 8; /* clear version */
|
||||
|
|
@ -71,6 +77,16 @@ public final class Generators
|
|||
return new UUID(most, least);
|
||||
};
|
||||
|
||||
public static final Gen<UUID> UUID_TIME_GEN = rnd -> {
|
||||
long most = rnd.next(Constraint.none());
|
||||
most &= 0x0f << 8; /* clear version */
|
||||
most += 0x10 << 8; /* set to version 1 */
|
||||
long least = rnd.next(Constraint.none());
|
||||
least &= 0x3fl << 56; /* clear variant */
|
||||
least |= 0x80l << 56; /* set to IETF variant */
|
||||
return new UUID(most, least);
|
||||
};
|
||||
|
||||
public static final Gen<String> DNS_DOMAIN_NAME = rnd -> {
|
||||
// how many parts to generate
|
||||
int numParts = (int) rnd.next(DNS_DOMAIN_PARTS_CONSTRAINT);
|
||||
|
|
@ -331,6 +347,48 @@ public final class Generators
|
|||
.map(s -> new String(s.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public static Gen<BigInteger> bigInt()
|
||||
{
|
||||
return bigInt(SourceDSL.integers().between(1, 32));
|
||||
}
|
||||
|
||||
public static Gen<BigInteger> bigInt(Gen<Integer> numBitsGen)
|
||||
{
|
||||
Gen<Integer> signumGen = SourceDSL.arbitrary().pick(-1, 0, 1);
|
||||
return rnd -> {
|
||||
int signum = signumGen.generate(rnd);
|
||||
if (signum == 0)
|
||||
return BigInteger.ZERO;
|
||||
int numBits = numBitsGen.generate(rnd);
|
||||
if (numBits < 0)
|
||||
throw new IllegalArgumentException("numBits must be non-negative");
|
||||
int numBytes = (int)(((long)numBits+7)/8); // avoid overflow
|
||||
|
||||
// Generate random bytes and mask out any excess bits
|
||||
byte[] randomBits = new byte[0];
|
||||
if (numBytes > 0) {
|
||||
randomBits = bytes(numBytes, numBytes).map(bb -> ByteBufferUtil.getArray(bb)).generate(rnd);
|
||||
int excessBits = 8*numBytes - numBits;
|
||||
randomBits[0] &= (1 << (8-excessBits)) - 1;
|
||||
}
|
||||
return new BigInteger(signum, randomBits);
|
||||
};
|
||||
}
|
||||
|
||||
public static Gen<BigDecimal> bigDecimal()
|
||||
{
|
||||
return bigDecimal(SourceDSL.integers().between(1, 100), bigInt());
|
||||
}
|
||||
|
||||
public static Gen<BigDecimal> bigDecimal(Gen<Integer> scaleGen, Gen<BigInteger> bigIntegerGen)
|
||||
{
|
||||
return rnd -> {
|
||||
int scale = scaleGen.generate(rnd);
|
||||
BigInteger bigInt = bigIntegerGen.generate(rnd);
|
||||
return new BigDecimal(bigInt, scale);
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean isDash(char c)
|
||||
{
|
||||
switch (c)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.utils.asserts;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.assertj.core.api.SoftAssertions;
|
||||
|
||||
public class SoftAssertionsWithLimit extends SoftAssertions
|
||||
{
|
||||
private final AtomicInteger counter = new AtomicInteger();
|
||||
private final int limit;
|
||||
|
||||
public SoftAssertionsWithLimit(int limit)
|
||||
{
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collectAssertionError(AssertionError error)
|
||||
{
|
||||
int cnt = counter.incrementAndGet();
|
||||
if (cnt < limit)
|
||||
super.collectAssertionError(error);
|
||||
else if (cnt == limit)
|
||||
super.collectAssertionError(new AssertionError("Too many assertion errors, stopping collecting them."));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* 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.quicktheories.impl;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
|
||||
import org.quicktheories.core.DetatchedRandomnessSource;
|
||||
import org.quicktheories.core.RandomnessSource;
|
||||
|
||||
/**
|
||||
* The {@link Constraint} class does not expose {@link Constraint#min()} or {@link Constraint#max()} outside the package, so
|
||||
* the only way to build a {@link RandomnessSource} is to define it in the package "org.quicktheories.impl"
|
||||
*/
|
||||
public class JavaRandom implements RandomnessSource, DetatchedRandomnessSource
|
||||
{
|
||||
private final Random random;
|
||||
|
||||
public JavaRandom(long seed)
|
||||
{
|
||||
this.random = new Random(seed);
|
||||
}
|
||||
|
||||
public JavaRandom(Random random)
|
||||
{
|
||||
this.random = Objects.requireNonNull(random);
|
||||
}
|
||||
|
||||
public void setSeed(long seed)
|
||||
{
|
||||
this.random.setSeed(seed);
|
||||
}
|
||||
|
||||
public static JavaRandom wrap(RandomnessSource rnd)
|
||||
{
|
||||
if (rnd instanceof JavaRandom)
|
||||
return (JavaRandom) rnd;
|
||||
return new JavaRandom(rnd.next(Constraint.none().withNoShrinkPoint()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long next(Constraint constraint)
|
||||
{
|
||||
long max = constraint.max();
|
||||
return nextLong(constraint.min(), max == Long.MAX_VALUE ? max : max + 1);
|
||||
}
|
||||
|
||||
private long nextLong(long minInclusive, long maxExclusive)
|
||||
{
|
||||
// pulled from accord.utils.RandomSource#nextLong(long, long)...
|
||||
// long term it will be great to unify the two and drop QuickTheories classes all together
|
||||
// this is diff behavior than ThreadLocalRandom, which returns nextLong
|
||||
if (minInclusive >= maxExclusive)
|
||||
throw new IllegalArgumentException(String.format("Min (%s) should be less than max (%d).", minInclusive, maxExclusive));
|
||||
|
||||
long result = random.nextLong();
|
||||
long delta = maxExclusive - minInclusive;
|
||||
long mask = delta - 1;
|
||||
if ((delta & mask) == 0L) // power of two
|
||||
result = (result & mask) + minInclusive;
|
||||
else if (delta > 0L)
|
||||
{
|
||||
// reject over-represented candidates
|
||||
for (long u = result >>> 1; // ensure nonnegative
|
||||
u + mask - (result = u % delta) < 0L; // rejection check
|
||||
u = random.nextLong() >>> 1) // retry
|
||||
;
|
||||
result += minInclusive;
|
||||
}
|
||||
else
|
||||
{
|
||||
// range not representable as long
|
||||
while (result < minInclusive || result >= maxExclusive)
|
||||
result = random.nextLong();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DetatchedRandomnessSource detach()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerFailedAssumption()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commit()
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue