Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.elasticsearch.test.RandomObjects Maven / Gradle / Ivy
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.test;
import com.carrotsearch.randomizedtesting.RandomizedTest;
import com.carrotsearch.randomizedtesting.generators.RandomNumbers;
import com.carrotsearch.randomizedtesting.generators.RandomPicks;
import com.carrotsearch.randomizedtesting.generators.RandomStrings;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.admin.indices.analyze.AnalyzeAction;
import org.elasticsearch.action.admin.indices.analyze.AnalyzeAction.AnalyzeToken;
import org.elasticsearch.action.support.replication.ReplicationResponse.ShardInfo;
import org.elasticsearch.action.support.replication.ReplicationResponse.ShardInfo.Failure;
import org.elasticsearch.cluster.block.ClusterBlockException;
import org.elasticsearch.cluster.coordination.NoMasterBlockService;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.core.Tuple;
import org.elasticsearch.index.shard.IndexShardRecoveringException;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.index.shard.ShardNotFoundException;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.xcontent.ToXContent;
import org.elasticsearch.xcontent.XContentBuilder;
import org.elasticsearch.xcontent.XContentFactory;
import org.elasticsearch.xcontent.XContentParser;
import org.elasticsearch.xcontent.XContentType;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import static com.carrotsearch.randomizedtesting.generators.RandomNumbers.randomIntBetween;
import static com.carrotsearch.randomizedtesting.generators.RandomStrings.randomAsciiLettersOfLength;
import static com.carrotsearch.randomizedtesting.generators.RandomStrings.randomUnicodeOfLengthBetween;
import static java.util.Collections.singleton;
import static org.elasticsearch.cluster.metadata.IndexMetadata.INDEX_UUID_NA_VALUE;
import static org.elasticsearch.test.ESTestCase.randomFrom;
public final class RandomObjects {
private RandomObjects() {
}
/**
* Returns a tuple containing random stored field values and their corresponding expected values once printed out
* via {@link ToXContent#toXContent(XContentBuilder, ToXContent.Params)} and parsed back via
* {@link org.elasticsearch.xcontent.XContentParser#objectText()}.
* Generates values based on what can get printed out. Stored fields values are retrieved from lucene and converted via
* {@link org.elasticsearch.index.mapper.MappedFieldType#valueForDisplay(Object)} to either strings, numbers or booleans.
*
* @param random Random generator
* @param xContentType the content type, used to determine what the expected values are for float numbers.
*/
public static Tuple, List> randomStoredFieldValues(Random random, XContentType xContentType) {
int numValues = randomIntBetween(random, 1, 5);
List originalValues = randomStoredFieldValues(random, numValues);
List expectedParsedValues = new ArrayList<>(numValues);
for (Object originalValue : originalValues) {
expectedParsedValues.add(getExpectedParsedValue(xContentType, originalValue));
}
return Tuple.tuple(originalValues, expectedParsedValues);
}
private static List randomStoredFieldValues(Random random, int numValues) {
List values = new ArrayList<>(numValues);
int dataType = randomIntBetween(random, 0, 8);
for (int i = 0; i < numValues; i++) {
switch (dataType) {
case 0 -> values.add(random.nextLong());
case 1 -> values.add(random.nextInt());
case 2 -> values.add((short) random.nextInt());
case 3 -> values.add((byte) random.nextInt());
case 4 -> values.add(random.nextDouble());
case 5 -> values.add(random.nextFloat());
case 6 -> values.add(random.nextBoolean());
case 7 -> values.add(
random.nextBoolean()
? RandomStrings.randomAsciiLettersOfLengthBetween(random, 3, 10)
: randomUnicodeOfLengthBetween(random, 3, 10)
);
case 8 -> {
byte[] randomBytes = RandomStrings.randomUnicodeOfLengthBetween(random, 10, 50).getBytes(StandardCharsets.UTF_8);
values.add(new BytesArray(randomBytes));
}
default -> throw new UnsupportedOperationException();
}
}
return values;
}
/**
* Converts the provided field value to its corresponding expected value once printed out
* via {@link ToXContent#toXContent(XContentBuilder, ToXContent.Params)} and parsed back via
* {@link org.elasticsearch.xcontent.XContentParser#objectText()}.
* Generates values based on what can get printed out. Stored fields values are retrieved from lucene and converted via
* {@link org.elasticsearch.index.mapper.MappedFieldType#valueForDisplay(Object)} to either strings, numbers or booleans.
*/
public static Object getExpectedParsedValue(XContentType xContentType, Object value) {
if (value instanceof BytesArray) {
if (xContentType.canonical() == XContentType.JSON) {
// JSON writes base64 format
return Base64.getEncoder().encodeToString(((BytesArray) value).toBytesRef().bytes);
}
}
if (value instanceof Float) {
if (xContentType.canonical() == XContentType.CBOR || xContentType.canonical() == XContentType.SMILE) {
// with binary content types we pass back the object as is
return value;
}
// with JSON AND YAML we get back a double, but with float precision.
return Double.parseDouble(value.toString());
}
if (value instanceof Byte) {
return ((Byte) value).intValue();
}
if (value instanceof Short) {
return ((Short) value).intValue();
}
return value;
}
/**
* Returns a random source containing a random number of fields, objects and array, with maximum depth 5.
*
* @param random Random generator
*/
public static BytesReference randomSource(Random random) {
// the source can be stored in any format and eventually converted when retrieved depending on the format of the response
return randomSource(random, RandomPicks.randomFrom(random, XContentType.values()));
}
/**
* Returns a random source in a given XContentType containing a random number of fields, objects and array, with maximum depth 5.
* The minimum number of fields per object is 1.
*
* @param random Random generator
*/
public static BytesReference randomSource(Random random, XContentType xContentType) {
return randomSource(random, xContentType, 1);
}
/**
* Returns a random source in a given XContentType containing a random number of fields, objects and array, with maximum depth 5.
* The minimum number of fields per object is provided as an argument.
*
* @param random Random generator
*/
public static BytesReference randomSource(Random random, XContentType xContentType, int minNumFields) {
try (XContentBuilder builder = XContentFactory.contentBuilder(xContentType)) {
builder.startObject();
addFields(random, builder, minNumFields, 0);
builder.endObject();
return BytesReference.bytes(builder);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* Randomly adds fields, objects, or arrays to the provided builder. The maximum depth is 5.
*/
private static void addFields(Random random, XContentBuilder builder, int minNumFields, int currentDepth) throws IOException {
int numFields = randomIntBetween(random, minNumFields, 5);
for (int i = 0; i < numFields; i++) {
if (currentDepth < 5 && random.nextInt(100) >= 70) {
if (random.nextBoolean()) {
builder.startObject(RandomStrings.randomAsciiLettersOfLengthBetween(random, 6, 10));
addFields(random, builder, minNumFields, currentDepth + 1);
builder.endObject();
} else {
builder.startArray(RandomStrings.randomAsciiLettersOfLengthBetween(random, 6, 10));
int numElements = randomIntBetween(random, 1, 5);
boolean object = random.nextBoolean();
int dataType = -1;
if (object == false) {
dataType = randomDataType(random);
}
for (int j = 0; j < numElements; j++) {
if (object) {
builder.startObject();
addFields(random, builder, minNumFields, 5);
builder.endObject();
} else {
builder.value(randomFieldValue(random, dataType));
}
}
builder.endArray();
}
} else {
builder.field(
RandomStrings.randomAsciiLettersOfLengthBetween(random, 6, 10),
randomFieldValue(random, randomDataType(random))
);
}
}
}
private static int randomDataType(Random random) {
return randomIntBetween(random, 0, 3);
}
private static Object randomFieldValue(Random random, int dataType) {
return switch (dataType) {
case 0 -> RandomStrings.randomAsciiLettersOfLengthBetween(random, 3, 10);
case 1 -> RandomStrings.randomAsciiLettersOfLengthBetween(random, 3, 10);
case 2 -> random.nextLong();
case 3 -> random.nextDouble();
default -> throw new UnsupportedOperationException();
};
}
/**
* Returns a tuple that contains a randomized {@link ShardInfo} value (left side) and its corresponding
* value (right side) after it has been printed out as a {@link ToXContent} and parsed back using a parsing
* method like {@link ShardInfo#fromXContent(XContentParser)}. The ShardInfo randomly contains shard failures.
*
* @param random Random generator
*/
public static Tuple randomShardInfo(Random random) {
return randomShardInfo(random, random.nextBoolean());
}
/**
* Returns a tuple that contains a randomized {@link ShardInfo} value (left side) and its corresponding
* value (right side) after it has been printed out as a {@link ToXContent} and parsed back using a parsing
* method like {@link ShardInfo#fromXContent(XContentParser)}. A `withShardFailures` parameter indicates if
* the randomized ShardInfo must or must not contain shard failures.
*
* @param random Random generator
* @param withShardFailures indicates if the generated ShardInfo must contain shard failures
*/
public static Tuple randomShardInfo(Random random, boolean withShardFailures) {
int total = randomIntBetween(random, 1, 10);
if (withShardFailures == false) {
return Tuple.tuple(ShardInfo.allSuccessful(total), ShardInfo.allSuccessful(total));
}
int successful = randomIntBetween(random, 1, Math.max(1, (total - 1)));
int failures = Math.max(1, (total - successful));
Failure[] actualFailures = new Failure[failures];
Failure[] expectedFailures = new Failure[failures];
for (int i = 0; i < failures; i++) {
Tuple failure = randomShardInfoFailure(random);
actualFailures[i] = failure.v1();
expectedFailures[i] = failure.v2();
}
return Tuple.tuple(ShardInfo.of(total, successful, actualFailures), ShardInfo.of(total, successful, expectedFailures));
}
/**
* Returns a tuple that contains a randomized {@link Failure} value (left side) and its corresponding
* value (right side) after it has been printed out as a {@link ToXContent} and parsed back using a parsing
* method like {@link ShardInfo.Failure#fromXContent(XContentParser)}.
*
* @param random Random generator
*/
private static Tuple randomShardInfoFailure(Random random) {
String index = randomAsciiLettersOfLength(random, 5);
String indexUuid = randomAsciiLettersOfLength(random, 5);
int shardId = randomIntBetween(random, 1, 10);
String nodeId = randomAsciiLettersOfLength(random, 5);
RestStatus status = randomFrom(random, RestStatus.INTERNAL_SERVER_ERROR, RestStatus.FORBIDDEN, RestStatus.NOT_FOUND);
boolean primary = random.nextBoolean();
ShardId shard = new ShardId(index, indexUuid, shardId);
Exception actualException;
ElasticsearchException expectedException;
int type = randomIntBetween(random, 0, 3);
switch (type) {
case 0 -> {
actualException = new ClusterBlockException(singleton(NoMasterBlockService.NO_MASTER_BLOCK_WRITES));
expectedException = new ElasticsearchException(
"Elasticsearch exception [type=cluster_block_exception, " + "reason=blocked by: [SERVICE_UNAVAILABLE/2/no master];]"
);
}
case 1 -> {
actualException = new ShardNotFoundException(shard);
expectedException = new ElasticsearchException(
"Elasticsearch exception [type=shard_not_found_exception, " + "reason=no such shard]"
);
expectedException.setShard(shard);
}
case 2 -> {
actualException = new IllegalArgumentException("Closed resource", new RuntimeException("Resource"));
expectedException = new ElasticsearchException(
"Elasticsearch exception [type=illegal_argument_exception, " + "reason=Closed resource]",
new ElasticsearchException("Elasticsearch exception [type=runtime_exception, reason=Resource]")
);
}
case 3 -> {
actualException = new IndexShardRecoveringException(shard);
expectedException = new ElasticsearchException(
"Elasticsearch exception [type=index_shard_recovering_exception, "
+ "reason=CurrentState[RECOVERING] Already recovering]"
);
expectedException.setShard(shard);
}
default -> throw new UnsupportedOperationException("No randomized exceptions generated for type [" + type + "]");
}
Failure actual = new Failure(shard, nodeId, actualException, status, primary);
Failure expected = new Failure(new ShardId(index, INDEX_UUID_NA_VALUE, shardId), nodeId, expectedException, status, primary);
return Tuple.tuple(actual, expected);
}
public static AnalyzeToken randomToken(Random random) {
String token = RandomStrings.randomAsciiLettersOfLengthBetween(random, 1, 20);
int position = RandomizedTest.randomIntBetween(0, 1000);
int startOffset = RandomizedTest.randomIntBetween(0, 1000);
int endOffset = RandomizedTest.randomIntBetween(0, 1000);
int posLength = RandomizedTest.randomIntBetween(1, 5);
String type = RandomStrings.randomAsciiLettersOfLengthBetween(random, 1, 20);
Map extras = new HashMap<>();
if (random.nextBoolean()) {
int entryCount = RandomNumbers.randomIntBetween(random, 0, 6);
for (int i = 0; i < entryCount; i++) {
switch (RandomNumbers.randomIntBetween(random, 0, 6)) {
case 0, 1, 2, 3 -> {
String key = RandomStrings.randomAsciiLettersOfLength(random, 5);
String value = RandomStrings.randomAsciiLettersOfLength(random, 10);
extras.put(key, value);
}
case 4 -> {
String objkey = RandomStrings.randomAsciiLettersOfLength(random, 5);
Map obj = new HashMap<>();
obj.put(RandomStrings.randomAsciiLettersOfLength(random, 5), RandomStrings.randomAsciiLettersOfLength(random, 10));
extras.put(objkey, obj);
}
case 5 -> {
String listkey = RandomStrings.randomAsciiLettersOfLength(random, 5);
List list = new ArrayList<>();
list.add(RandomStrings.randomAsciiLettersOfLength(random, 4));
list.add(RandomStrings.randomAsciiLettersOfLength(random, 6));
extras.put(listkey, list);
}
}
}
}
return new AnalyzeAction.AnalyzeToken(token, position, startOffset, endOffset, posLength, type, extras);
}
}