Skip to content

Commit 8c41ce3

Browse files
author
Andras Palinkas
committed
Extracted the non-tested function list into a separate file (to keep spotless happy and the code short)
1 parent 1e8caf5 commit 8c41ce3

File tree

2 files changed

+160
-52
lines changed

2 files changed

+160
-52
lines changed

x-pack/plugin/sql/qa/server/single-node/src/test/java/org/elasticsearch/xpack/sql/qa/single_node/ConsistentFunctionArgHandlingIT.java

Lines changed: 53 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@
77
package org.elasticsearch.xpack.sql.qa.single_node;
88

99
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
10-
1110
import org.elasticsearch.common.CheckedConsumer;
1211
import org.elasticsearch.common.UUIDs;
1312
import org.elasticsearch.common.collect.Tuple;
1413
import org.elasticsearch.xpack.sql.qa.jdbc.JdbcIntegrationTestCase;
1514

1615
import java.io.IOException;
16+
import java.nio.file.Files;
17+
import java.nio.file.Path;
1718
import java.sql.ResultSet;
1819
import java.util.ArrayList;
1920
import java.util.LinkedHashMap;
@@ -23,7 +24,6 @@
2324
import java.util.Map;
2425
import java.util.Objects;
2526
import java.util.Set;
26-
import java.util.stream.Stream;
2727

2828
import static java.lang.String.join;
2929
import static java.util.Arrays.asList;
@@ -33,16 +33,16 @@
3333
import static org.hamcrest.collection.IsEmptyCollection.empty;
3434

3535
/**
36-
* <p>This test was introduced because of the inconsistencies regarding NULL argument handling. NULL literal vs NULL field
36+
* <p>This test was introduced because of the inconsistencies regarding NULL argument handling. NULL literal vs NULL field
3737
* value as function arguments in some case result in different function return values.</p>
3838
*
3939
* <p>Functions should return with the same value no matter if the argument(s) came from a field or from a literal.</p>
40-
*
41-
* <p>The test class based on the example function calls (and argument specifications) generates all the
42-
* permutations of the function arguments (4 options per argument: value/NULL as literal/field) and tests that the
43-
* function calls with the same argument values provide the same result regardless of the source (literal, field)
40+
*
41+
* <p>The test class based on the example function calls (and argument specifications) generates all the
42+
* permutations of the function arguments (4 options per argument: value/NULL as literal/field) and tests that the
43+
* function calls with the same argument values provide the same result regardless of the source (literal, field)
4444
* of the arguments.</p>
45-
*
45+
*
4646
* <p>To ignore any of the tests, add an .ignore() method call after the Fn ctors in the FUNCTION_CALLS_TO_TEST list below, like:
4747
* <code> new Fn("ASCII", "foobar").ignore()</code></p>
4848
*/
@@ -73,51 +73,51 @@ public class ConsistentFunctionArgHandlingIT extends JdbcIntegrationTestCase {
7373
new Fn("UCASE", "foobar")
7474
);
7575

76-
private static final List<String> NON_TESTED_FUNCTIONS = asList(
77-
"CURDATE", "CURRENT_DATE", "CURRENT_TIME", "CURRENT_TIMESTAMP", "CURTIME", "DATEADD", "DATEDIFF", "DATEPART",
78-
"DATETIME_FORMAT", "DATETIME_PARSE", "DATETRUNC", "DATE_ADD", "DATE_DIFF", "DATE_PARSE", "DATE_PART", "DATE_TRUNC", "DAY",
79-
"DAYNAME", "DAYOFMONTH", "DAYOFWEEK", "DAYOFYEAR", "DAY_NAME", "DAY_OF_MONTH", "DAY_OF_WEEK", "DAY_OF_YEAR", "DOM", "DOW", "DOY",
80-
"FORMAT", "HOUR", "HOUR_OF_DAY", "IDOW", "ISODAYOFWEEK", "ISODOW", "ISOWEEK", "ISOWEEKOFYEAR", "ISO_DAY_OF_WEEK",
81-
"ISO_WEEK_OF_YEAR", "IW", "IWOY", "MINUTE", "MINUTE_OF_DAY", "MINUTE_OF_HOUR", "MONTH", "MONTHNAME", "MONTH_NAME",
82-
"MONTH_OF_YEAR", "NOW", "QUARTER", "SECOND", "SECOND_OF_MINUTE", "TIMESTAMPADD", "TIMESTAMPDIFF", "TIMESTAMP_ADD",
83-
"TIMESTAMP_DIFF", "TIME_PARSE", "TODAY", "TO_CHAR", "WEEK", "WEEK_OF_YEAR", "YEAR", "ABS", "ACOS", "ASIN", "ATAN",
84-
"ATAN2", "CBRT", "CEIL", "CEILING", "COS", "COSH", "COT", "DEGREES", "E", "EXP", "EXPM1", "FLOOR", "LOG", "LOG10",
85-
"MOD", "PI", "POWER", "RADIANS", "RAND", "RANDOM", "ROUND", "SIGN", "SIGNUM", "SIN", "SINH", "SQRT", "TAN", "TRUNC",
86-
"TRUNCATE", "CAST", "CONVERT", "DATABASE", "USER", "ST_ASTEXT", "ST_ASWKT", "ST_DISTANCE",
87-
"ST_GEOMETRYTYPE", "ST_GEOMFROMTEXT", "ST_WKTTOSQL", "ST_X", "ST_Y", "ST_Z");
88-
89-
private enum Source { FIELD, LITERAL }
90-
76+
private static final List<String> NON_TESTED_FUNCTIONS;
77+
static {
78+
try {
79+
Class<?> c = ConsistentFunctionArgHandlingIT.class;
80+
NON_TESTED_FUNCTIONS = Files.readAllLines(Path.of(c.getResource(c.getSimpleName() + "-non-tested-functions.txt").toURI()));
81+
} catch (Exception ex) {
82+
throw new RuntimeException(ex);
83+
}
84+
}
85+
86+
private enum Source {
87+
FIELD,
88+
LITERAL
89+
}
90+
9191
private static class Fn {
9292
private final String name;
9393
private final List<Argument> arguments;
9494
private List<String> aliases = new ArrayList<>();
9595
private boolean ignored = false;
96-
96+
9797
private Fn(String name, Object... arguments) {
9898
this.name = name;
9999
this.arguments = new ArrayList<>();
100100
for (Object a : arguments) {
101101
this.arguments.add(Argument.class.isAssignableFrom(a.getClass()) ? (Argument) a : new Argument(a));
102102
}
103103
}
104-
104+
105105
public Fn aliases(String... aliases) {
106106
this.aliases = asList(aliases);
107107
return this;
108-
}
109-
108+
}
109+
110110
public Fn ignore() {
111111
this.ignored = true;
112112
return this;
113113
}
114-
114+
115115
@Override
116116
public String toString() {
117117
return name + "(" + arguments.stream().map(a -> String.valueOf(a.exampleValue)).collect(joining(", ")) + ")";
118118
}
119119
}
120-
120+
121121
private static class Argument {
122122
private final Object exampleValue;
123123
private final Source[] acceptedSources;
@@ -127,27 +127,27 @@ private Argument(Object exampleValue, Source... acceptedSources) {
127127
this.acceptedSources = acceptedSources.length == 0 ? Source.values() : acceptedSources;
128128
}
129129
}
130-
130+
131131
@ParametersFactory
132132
public static Iterable<Object[]> testFactory() {
133133
List<Object[]> tests = new ArrayList<>();
134-
tests.add(new Object[]{ null });
135-
FUNCTION_CALLS_TO_TEST.forEach(f -> tests.add(new Object[]{ f }));
134+
tests.add(new Object[] { null });
135+
FUNCTION_CALLS_TO_TEST.forEach(f -> tests.add(new Object[] { f }));
136136
return tests;
137137
}
138-
138+
139139
private final Fn fn;
140-
140+
141141
public ConsistentFunctionArgHandlingIT(Fn fn) {
142142
this.fn = fn;
143143
}
144-
144+
145145
public void test() throws Exception {
146146
if (fn == null) {
147147
checkScalarFunctionCoverage();
148148
return;
149149
}
150-
150+
151151
assumeFalse("Ignored", fn.ignored);
152152

153153
// create a record for the function, where all the example (non-null) argument values are stored in fields
@@ -157,20 +157,20 @@ public void test() throws Exception {
157157
final String argPrefix = "arg_" + functionName + "_";
158158
final String nullArgPrefix = "arg_null_" + functionName + "_";
159159
final String testDocId = functionName + "_" + UUIDs.base64UUID();
160-
160+
161161
indexTestDocForFunction(functionName, indexName, argPrefix, nullArgPrefix, testDocId);
162162

163163
List<List<Object>> possibleValuesPerArguments = fn.arguments.stream().map(a -> asList(a.exampleValue, null)).collect(toList());
164164
List<List<Source>> acceptedSourcesPerArguments = fn.arguments.stream().map(a -> asList(a.acceptedSources)).collect(toList());
165-
165+
166166
iterateAllPermutations(possibleValuesPerArguments, argValues -> {
167167
// we only want to check the function calls that have at least a single NULL argument
168168
if (argValues.stream().noneMatch(Objects::isNull)) {
169169
return;
170170
}
171171

172172
List<Tuple<String, Object>> results = new ArrayList<>();
173-
173+
174174
iterateAllPermutations(acceptedSourcesPerArguments, argSources -> {
175175
List<String> functionCallArgs = new ArrayList<>();
176176
List<String> functionCallArgsForAssert = new ArrayList<>();
@@ -193,18 +193,17 @@ public void test() throws Exception {
193193
final String functionCall = functionName + "(" + join(", ", functionCallArgs) + ")";
194194
final String query = "SELECT " + functionCall + " FROM " + indexName + " WHERE docId = '" + testDocId + "'";
195195
ResultSet retVal = esJdbc().createStatement().executeQuery(query);
196-
196+
197197
assertTrue(retVal.next());
198198
results.add(tuple(functionName + "(" + join(", ", functionCallArgsForAssert) + ")", retVal.getObject(1)));
199199
// only a single row should be returned
200200
assertFalse(retVal.next());
201201

202-
Stream<Object> returnValueStream = results.stream().map(Tuple::v2);
203-
if (returnValueStream.distinct().count() > 1) {
204-
int maxResultWidth = returnValueStream.mapToInt(o -> asLiteralInQuery(o).length()).max().orElse(20);
202+
if (results.stream().map(Tuple::v2).distinct().count() > 1) {
203+
int maxResultWidth = results.stream().map(Tuple::v2).mapToInt(o -> asLiteralInQuery(o).length()).max().orElse(20);
205204
String resultsAsString = results.stream()
206-
.map(r -> String.format(Locale.ROOT, "%2$-" + maxResultWidth + "s // %1$s", r.v1(), asLiteralInQuery(r.v2())))
207-
.collect(joining("\n"));
205+
.map(r -> String.format(Locale.ROOT, "%2$-" + maxResultWidth + "s // %1$s", r.v1(), asLiteralInQuery(r.v2())))
206+
.collect(joining("\n"));
208207
fail("The result of the last call differs from the other calls:\n" + resultsAsString);
209208
}
210209
});
@@ -246,9 +245,12 @@ private void checkScalarFunctionCoverage() throws Exception {
246245
functions.removeAll(fn.aliases);
247246
}
248247
functions.removeAll(NON_TESTED_FUNCTIONS);
249-
250-
assertThat("Missing function checks: [" + functions.stream().map(s -> "\"" + s + "\"").collect(joining(", ")) + "]",
251-
functions, empty());
248+
249+
assertThat(
250+
"Some functions are not covered by this test",
251+
functions,
252+
empty()
253+
);
252254
}
253255

254256
private static String asLiteralInQuery(Object argValue) {
@@ -264,9 +266,9 @@ private static String asLiteralInQuery(Object argValue) {
264266
return argInQuery;
265267
}
266268

267-
private static <T> void iterateAllPermutations(List<List<T>> possibleValuesPerItem, CheckedConsumer<List<T>, Exception> consumer)
269+
private static <T> void iterateAllPermutations(List<List<T>> possibleValuesPerItem, CheckedConsumer<List<T>, Exception> consumer)
268270
throws Exception {
269-
271+
270272
if (possibleValuesPerItem.isEmpty()) {
271273
consumer.accept(new ArrayList<>());
272274
return;
@@ -280,6 +282,5 @@ private static <T> void iterateAllPermutations(List<List<T>> possibleValuesPerIt
280282
}
281283
});
282284
}
283-
284-
}
285285

286+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
CURDATE
2+
CURRENT_DATE
3+
CURRENT_TIME
4+
CURRENT_TIMESTAMP
5+
CURTIME
6+
DATEADD
7+
DATEDIFF
8+
DATEPART
9+
DATETIME_FORMAT
10+
DATETIME_PARSE
11+
DATETRUNC
12+
DATE_ADD
13+
DATE_DIFF
14+
DATE_PARSE
15+
DATE_PART
16+
DATE_TRUNC
17+
DAY
18+
DAYNAME
19+
DAYOFMONTH
20+
DAYOFWEEK
21+
DAYOFYEAR
22+
DAY_NAME
23+
DAY_OF_MONTH
24+
DAY_OF_WEEK
25+
DAY_OF_YEAR
26+
DOM
27+
DOW
28+
DOY
29+
FORMAT
30+
HOUR
31+
HOUR_OF_DAY
32+
IDOW
33+
ISODAYOFWEEK
34+
ISODOW
35+
ISOWEEK
36+
ISOWEEKOFYEAR
37+
ISO_DAY_OF_WEEK
38+
ISO_WEEK_OF_YEAR
39+
IW
40+
IWOY
41+
MINUTE
42+
MINUTE_OF_DAY
43+
MINUTE_OF_HOUR
44+
MONTH
45+
MONTHNAME
46+
MONTH_NAME
47+
MONTH_OF_YEAR
48+
NOW
49+
QUARTER
50+
SECOND
51+
SECOND_OF_MINUTE
52+
TIMESTAMPADD
53+
TIMESTAMPDIFF
54+
TIMESTAMP_ADD
55+
TIMESTAMP_DIFF
56+
TIME_PARSE
57+
TODAY
58+
TO_CHAR
59+
WEEK
60+
WEEK_OF_YEAR
61+
YEAR
62+
ABS
63+
ACOS
64+
ASIN
65+
ATAN
66+
ATAN2
67+
CBRT
68+
CEIL
69+
CEILING
70+
COS
71+
COSH
72+
COT
73+
DEGREES
74+
E
75+
EXP
76+
EXPM1
77+
FLOOR
78+
LOG
79+
LOG10
80+
MOD
81+
PI
82+
POWER
83+
RADIANS
84+
RAND
85+
RANDOM
86+
ROUND
87+
SIGN
88+
SIGNUM
89+
SIN
90+
SINH
91+
SQRT
92+
TAN
93+
TRUNC
94+
TRUNCATE
95+
CAST
96+
CONVERT
97+
DATABASE
98+
USER
99+
ST_ASTEXT
100+
ST_ASWKT
101+
ST_DISTANCE
102+
ST_GEOMETRYTYPE
103+
ST_GEOMFROMTEXT
104+
ST_WKTTOSQL
105+
ST_X
106+
ST_Y
107+
ST_Z

0 commit comments

Comments
 (0)