Skip to content

Commit a0b0aca

Browse files
ES|QL: fix generative tests (#127560)
1 parent 89efe2c commit a0b0aca

File tree

2 files changed

+73
-28
lines changed

2 files changed

+73
-28
lines changed

muted-tests.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -405,9 +405,6 @@ tests:
405405
- class: org.elasticsearch.xpack.esql.heap_attack.HeapAttackIT
406406
method: testLookupExplosionNoFetch
407407
issue: https://github.com/elastic/elasticsearch/issues/127365
408-
- class: org.elasticsearch.xpack.esql.qa.single_node.GenerativeIT
409-
method: test
410-
issue: https://github.com/elastic/elasticsearch/issues/127536
411408
- class: org.elasticsearch.xpack.test.rest.XPackRestIT
412409
method: test {p0=ml/data_frame_analytics_cat_apis/Test cat data frame analytics all jobs with header}
413410
issue: https://github.com/elastic/elasticsearch/issues/127625

x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/EsqlQueryGenerator.java

Lines changed: 73 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ private static String grok(List<Column> previousOutput) {
163163
result.append(randomIdentifier());
164164
} else {
165165
String fieldName = randomRawName(previousOutput);
166-
if (fieldName.isEmpty()) { // it's a bug, managed later, skipping for now
166+
if (fieldName == null) {
167167
fieldName = randomIdentifier();
168168
}
169169
result.append(fieldName);
@@ -191,7 +191,7 @@ private static String dissect(List<Column> previousOutput) {
191191
result.append(randomIdentifier());
192192
} else {
193193
String fieldName = randomRawName(previousOutput);
194-
if (fieldName.isEmpty()) { // it's a bug, managed later, skipping for now
194+
if (fieldName == null) {
195195
fieldName = randomIdentifier();
196196
}
197197
result.append(fieldName);
@@ -210,6 +210,9 @@ private static String keep(List<Column> previousOutput) {
210210
proj.add("*");
211211
} else {
212212
String name = randomName(previousOutput);
213+
if (name == null) {
214+
continue;
215+
}
213216
if (name.length() > 1 && name.startsWith("`") == false && randomIntBetween(0, 100) < 10) {
214217
if (randomBoolean()) {
215218
name = name.substring(0, randomIntBetween(1, name.length() - 1)) + "*";
@@ -220,31 +223,42 @@ private static String keep(List<Column> previousOutput) {
220223
proj.add(name);
221224
}
222225
}
226+
if (proj.isEmpty()) {
227+
return "";
228+
}
223229
return " | keep " + proj.stream().collect(Collectors.joining(", "));
224230
}
225231

226232
private static String randomName(List<Column> previousOutput) {
227233
String result = randomRawName(previousOutput);
228-
if ((randomBoolean() && result.contains("*") == false)) {
234+
if (result == null) {
235+
return null;
236+
}
237+
if (randomBoolean() && result.contains("*") == false) {
229238
result = "`" + result + "`";
230239
}
231240
return result;
232241
}
233242

243+
/**
244+
* Returns a field name from a list of columns.
245+
* Could be null if none of the fields can be considered
246+
*/
234247
private static String randomRawName(List<Column> previousOutput) {
235-
// we need to exclude <all-fields-projected>
236-
// https://github.com/elastic/elasticsearch/issues/121741
237-
String result = randomFrom(previousOutput.stream().filter(x -> x.name().equals("<all-fields-projected>") == false).toList()).name();
248+
var list = previousOutput.stream().filter(EsqlQueryGenerator::fieldCanBeUsed).toList();
249+
if (list.isEmpty()) {
250+
return null;
251+
}
252+
String result = randomFrom(list).name();
238253
return result;
239254
}
240255

256+
/**
257+
* Returns a field that can be used for grouping.
258+
* Can return null
259+
*/
241260
private static String randomGroupableName(List<Column> previousOutput) {
242-
// we need to exclude <all-fields-projected>
243-
// https://github.com/elastic/elasticsearch/issues/121741
244-
var candidates = previousOutput.stream()
245-
.filter(EsqlQueryGenerator::groupable)
246-
.filter(x -> x.name().equals("<all-fields-projected>") == false)
247-
.toList();
261+
var candidates = previousOutput.stream().filter(EsqlQueryGenerator::groupable).filter(EsqlQueryGenerator::fieldCanBeUsed).toList();
248262
if (candidates.isEmpty()) {
249263
return null;
250264
}
@@ -260,13 +274,12 @@ private static boolean groupable(Column col) {
260274
|| col.type.equals("version");
261275
}
262276

277+
/**
278+
* returns a field that can be sorted.
279+
* Null if no fields are sortable.
280+
*/
263281
private static String randomSortableName(List<Column> previousOutput) {
264-
// we need to exclude <all-fields-projected>
265-
// https://github.com/elastic/elasticsearch/issues/121741
266-
var candidates = previousOutput.stream()
267-
.filter(EsqlQueryGenerator::sortable)
268-
.filter(x -> x.name().equals("<all-fields-projected>") == false)
269-
.toList();
282+
var candidates = previousOutput.stream().filter(EsqlQueryGenerator::sortable).filter(EsqlQueryGenerator::fieldCanBeUsed).toList();
270283
if (candidates.isEmpty()) {
271284
return null;
272285
}
@@ -290,10 +303,18 @@ private static String rename(List<Column> previousOutput) {
290303
for (Column column : previousOutput) {
291304
nameToType.put(column.name, column.type);
292305
}
293-
List<String> names = new ArrayList<>(previousOutput.stream().map(Column::name).collect(Collectors.toList()));
306+
List<String> names = new ArrayList<>(
307+
previousOutput.stream().filter(EsqlQueryGenerator::fieldCanBeUsed).map(Column::name).collect(Collectors.toList())
308+
);
309+
if (names.isEmpty()) {
310+
return "";
311+
}
294312
for (int i = 0; i < n; i++) {
313+
if (names.isEmpty()) {
314+
break;
315+
}
295316
var name = randomFrom(names);
296-
if (name.equals("<all-fields-projected>") || nameToType.get(name).endsWith("_range")) {
317+
if (nameToType.get(name).endsWith("_range")) {
297318
// ranges are not fully supported yet
298319
continue;
299320
}
@@ -306,9 +327,6 @@ private static String rename(List<Column> previousOutput) {
306327
} else {
307328
newName = names.get(randomIntBetween(0, names.size() - 1));
308329
}
309-
if (newName.equals("<all-fields-projected>")) { // it's a bug, managed as an error later
310-
continue;
311-
}
312330
nameToType.put(newName, nameToType.get(name));
313331
if (randomBoolean() && name.startsWith("`") == false) {
314332
name = "`" + name + "`";
@@ -332,6 +350,9 @@ private static String drop(List<Column> previousOutput) {
332350
Set<String> proj = new HashSet<>();
333351
for (int i = 0; i < n; i++) {
334352
String name = randomRawName(previousOutput);
353+
if (name == null) {
354+
continue;
355+
}
335356
if (name.length() > 1 && name.startsWith("`") == false && randomIntBetween(0, 100) < 10) {
336357
if (randomBoolean()) {
337358
name = name.substring(0, randomIntBetween(1, name.length() - 1)) + "*";
@@ -343,6 +364,9 @@ private static String drop(List<Column> previousOutput) {
343364
}
344365
proj.add(name);
345366
}
367+
if (proj.isEmpty()) {
368+
return "";
369+
}
346370
return " | drop " + proj.stream().collect(Collectors.joining(", "));
347371
}
348372

@@ -363,7 +387,11 @@ private static String sort(List<Column> previousOutput) {
363387
}
364388

365389
private static String mvExpand(List<Column> previousOutput) {
366-
return " | mv_expand " + randomName(previousOutput);
390+
String toExpand = randomName(previousOutput);
391+
if (toExpand == null) {
392+
return ""; // no columns to expand
393+
}
394+
return " | mv_expand " + toExpand;
367395
}
368396

369397
private static String eval(List<Column> previousOutput) {
@@ -376,6 +404,9 @@ private static String eval(List<Column> previousOutput) {
376404
name = randomIdentifier();
377405
} else {
378406
name = randomName(previousOutput);
407+
if (name == null) {
408+
name = randomIdentifier();
409+
}
379410
}
380411
String expression = expression(previousOutput);
381412
if (i > 0) {
@@ -390,7 +421,10 @@ private static String eval(List<Column> previousOutput) {
390421
}
391422

392423
private static String stats(List<Column> previousOutput) {
393-
List<Column> nonNull = previousOutput.stream().filter(x -> x.type().equals("null") == false).collect(Collectors.toList());
424+
List<Column> nonNull = previousOutput.stream()
425+
.filter(EsqlQueryGenerator::fieldCanBeUsed)
426+
.filter(x -> x.type().equals("null") == false)
427+
.collect(Collectors.toList());
394428
if (nonNull.isEmpty()) {
395429
return ""; // cannot do any stats, just skip
396430
}
@@ -402,6 +436,9 @@ private static String stats(List<Column> previousOutput) {
402436
name = randomIdentifier();
403437
} else {
404438
name = randomName(previousOutput);
439+
if (name == null) {
440+
name = randomIdentifier();
441+
}
405442
}
406443
String expression = agg(nonNull);
407444
if (i > 0) {
@@ -433,6 +470,9 @@ private static String agg(List<Column> previousOutput) {
433470
}
434471
// all types
435472
name = randomName(previousOutput);
473+
if (name == null) {
474+
return "count(*)";
475+
}
436476
return switch (randomIntBetween(0, 2)) {
437477
case 0 -> "count(*)";
438478
case 1 -> "count(" + name + ")";
@@ -529,4 +569,12 @@ private static String randomIdentifier() {
529569
return randomAlphaOfLength(randomIntBetween(8, 12));
530570
}
531571

572+
private static boolean fieldCanBeUsed(Column field) {
573+
return (
574+
// https://github.com/elastic/elasticsearch/issues/121741
575+
field.name().equals("<all-fields-projected>")
576+
// this is a known pathological case, no need to test it for now
577+
|| field.name().equals("<no-fields>")) == false;
578+
}
579+
532580
}

0 commit comments

Comments
 (0)