Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import org.elasticsearch.xpack.esql.CsvTestsDataLoader;
import org.elasticsearch.xpack.esql.qa.rest.generative.command.CommandGenerator;
import org.elasticsearch.xpack.esql.qa.rest.generative.command.pipe.ChangePointGenerator;
import org.elasticsearch.xpack.esql.qa.rest.generative.command.pipe.DissectGenerator;
import org.elasticsearch.xpack.esql.qa.rest.generative.command.pipe.DropGenerator;
import org.elasticsearch.xpack.esql.qa.rest.generative.command.pipe.EnrichGenerator;
Expand Down Expand Up @@ -49,6 +50,7 @@ public record QueryExecuted(String query, int depth, List<Column> outputSchema,
* These are downstream commands, ie. that cannot appear as the first command in a query
*/
static List<CommandGenerator> PIPE_COMMANDS = List.of(
ChangePointGenerator.INSTANCE,
DissectGenerator.INSTANCE,
DropGenerator.INSTANCE,
EnrichGenerator.INSTANCE,
Expand Down Expand Up @@ -197,6 +199,10 @@ public static String randomNumericOrDateField(List<Column> previousOutput) {
return randomName(previousOutput, Set.of("long", "integer", "double", "date"));
}

public static String randomDateField(List<Column> previousOutput) {
return randomName(previousOutput, Set.of("date"));
}

public static String randomNumericField(List<Column> previousOutput) {
return randomName(previousOutput, Set.of("long", "integer", "double"));
}
Expand Down Expand Up @@ -255,6 +261,22 @@ public static String constantExpression() {

}

/**
* returns a random identifier or one of the existing names
*/
public static String randomAttributeOrIdentifier(List<EsqlQueryGenerator.Column> previousOutput) {
String name;
if (randomBoolean()) {
name = EsqlQueryGenerator.randomIdentifier();
} else {
name = EsqlQueryGenerator.randomName(previousOutput);
if (name == null) {
name = EsqlQueryGenerator.randomIdentifier();
}
}
return name;
}

public static String randomIdentifier() {
// Let's create identifiers that are long enough to avoid collisions with reserved keywords.
// There could be a smarter way (introspection on the lexer class?), but probably it's not worth the effort
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.elasticsearch.client.Request;
import org.elasticsearch.client.ResponseException;
import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.xpack.esql.AssertWarnings;
import org.elasticsearch.xpack.esql.CsvTestsDataLoader;
import org.elasticsearch.xpack.esql.qa.rest.RestEsqlTestCase;
import org.elasticsearch.xpack.esql.qa.rest.generative.command.CommandGenerator;
Expand Down Expand Up @@ -44,10 +45,6 @@ public abstract class GenerativeRestTest extends ESRestTestCase {
"The field names are too complex to process", // field_caps problem
"must be \\[any type except counter types\\]", // TODO refine the generation of count()

// warnings
"Field '.*' shadowed by field at line .*",
"evaluation of \\[.*\\] failed, treating result as null", // TODO investigate?

// Awaiting fixes for query failure
"Unknown column \\[<all-fields-projected>\\]", // https://github.com/elastic/elasticsearch/issues/121741,
"Plan \\[ProjectExec\\[\\[<no-fields>.* optimized incorrectly due to missing references", // https://github.com/elastic/elasticsearch/issues/125866
Expand Down Expand Up @@ -99,10 +96,10 @@ public void test() throws IOException {
EsqlQueryGenerator.QueryExecuted result = execute(command, 0);
if (result.exception() != null) {
checkException(result);
break;
continue;
}
if (checkResults(List.of(), commandGenerator, desc, null, result).success() == false) {
break;
continue;
}
previousResult = result;
previousCommands.add(desc);
Expand Down Expand Up @@ -168,7 +165,11 @@ private void checkException(EsqlQueryGenerator.QueryExecuted query) {
@SuppressWarnings("unchecked")
private EsqlQueryGenerator.QueryExecuted execute(String command, int depth) {
try {
Map<String, Object> a = RestEsqlTestCase.runEsqlSync(new RestEsqlTestCase.RequestObjectBuilder().query(command).build());
Map<String, Object> a = RestEsqlTestCase.runEsql(
new RestEsqlTestCase.RequestObjectBuilder().query(command).build(),
new AssertWarnings.AllowedRegexes(List.of(Pattern.compile(".*"))),// we don't care about warnings
RestEsqlTestCase.Mode.SYNC
);
List<EsqlQueryGenerator.Column> outputSchema = outputSchema(a);
List<List<Object>> values = (List<List<Object>>) a.get("values");
return new EsqlQueryGenerator.QueryExecuted(command, depth, outputSchema, values, null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,22 @@ static ValidationResult expectSameColumns(List<EsqlQueryGenerator.Column> previo

return VALIDATION_OK;
}

/**
* The command doesn't have to produce LESS columns than the previous query
*/
static ValidationResult expectAtLeastSameNumberOfColumns(
List<EsqlQueryGenerator.Column> previousColumns,
List<EsqlQueryGenerator.Column> columns
) {
if (previousColumns.stream().anyMatch(x -> x.name().contains("<all-fields-projected>"))) {
return VALIDATION_OK; // known bug
}

if (previousColumns.size() > columns.size()) {
return new ValidationResult(false, "Expecting at least [" + previousColumns.size() + "] columns, got [" + columns.size() + "]");
}

return VALIDATION_OK;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

package org.elasticsearch.xpack.esql.qa.rest.generative.command.pipe;

import org.elasticsearch.xpack.esql.qa.rest.generative.EsqlQueryGenerator;
import org.elasticsearch.xpack.esql.qa.rest.generative.command.CommandGenerator;

import java.util.List;
import java.util.Map;

import static org.elasticsearch.xpack.esql.qa.rest.generative.EsqlQueryGenerator.randomAttributeOrIdentifier;

public class ChangePointGenerator implements CommandGenerator {
public static final String CHANGE_POINT = "change_point";
public static final CommandGenerator INSTANCE = new ChangePointGenerator();

@Override
public CommandDescription generate(
List<CommandDescription> previousCommands,
List<EsqlQueryGenerator.Column> previousOutput,
QuerySchema schema
) {
String timestampField = EsqlQueryGenerator.randomDateField(previousOutput);
String numericField = EsqlQueryGenerator.randomNumericField(previousOutput);
if (timestampField == null || numericField == null) {
return EMPTY_DESCRIPTION;
}
String alias1 = randomAttributeOrIdentifier(previousOutput);
String alias2 = randomAttributeOrIdentifier(previousOutput);
while (alias1.equals(alias2)) {
alias2 = randomAttributeOrIdentifier(previousOutput);
}

String cmd = " | CHANGE_POINT " + numericField + " ON " + timestampField + " AS " + alias1 + ", " + alias2;

return new CommandDescription(CHANGE_POINT, this, cmd, Map.of());
}

@Override
public ValidationResult validateOutput(
List<CommandDescription> previousCommands,
CommandDescription command,
List<EsqlQueryGenerator.Column> previousColumns,
List<List<Object>> previousOutput,
List<EsqlQueryGenerator.Column> columns,
List<List<Object>> output
) {
return CommandGenerator.expectAtLeastSameNumberOfColumns(previousColumns, columns);
}
}