Skip to content

Commit 7bf75e0

Browse files
committed
Stabilize PPL ITs on the analytics-engine route (case/string/full-text/like/appendpipe)
Analytics-engine route parity for several PPL IT classes; test-only. Uses the @RequiresCapability annotation + Capability registry (#5560) plus matching excludeTestsMatching entries. CalcitePPLCaseFunctionIT: - Guard the weblogs raw-PUT seeding (appendDataForBadResponse) on a pre-load isIndexExist check — the append-only AE store inflated counts per method. - Skip the otel_logs load on the AE route (multi-value keyword the parquet store rejects); only testNestedCaseAggWithAutoDateHistogram uses it, and that test requires BIN_TIME_FIELD_BUCKETING (bucket column typed string). CalcitePPLStringBuiltinFunctionIT: 7 tests re-PUT a shared _id with different data; the append-only AE store can't replace docs (DELETE unsupported) -> DOC_MUTATION. MultiMatchIT / QueryStringIT / SimpleQueryStringIT wildcard tests: full-text relevance functions with no DataFusion equivalent -> new FULLTEXT_RELEVANCE_FUNC. CalciteLikeQueryIT.test_the_default_3rd_option: AE LIKE is case-insensitive but v2/Calcite is case-sensitive -> new LIKE_CASE_SENSITIVITY. CalcitePPLAppendPipeCommandIT.testDoubleAppendPipeWithFilter: appendpipe drops the main pipeline's rows on the AE route -> new APPENDPIPE_MAIN_RESULT_DROPPED. v2/Calcite route unchanged (all run, 0 skips). Signed-off-by: Kai Huang <ahkcs@amazon.com>
1 parent cb80047 commit 7bf75e0

9 files changed

Lines changed: 124 additions & 6 deletions

File tree

integ-test/build.gradle

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,10 +1075,11 @@ task integTestRemote(type: RestIntegTestTask) {
10751075
// GeoPointFormatsIT: EVERY test reads a geo_point field — whole class doomed.
10761076
excludeTestsMatching 'org.opensearch.sql.ppl.GeoPointFormatsIT'
10771077
// datatypes_index_mapping: nested_value=nested, geo_point_value=geo_point.
1078-
excludeTestsMatching 'org.opensearch.sql.ppl.DataTypeIT.test_nonnumeric_data_types'
1079-
excludeTestsMatching 'org.opensearch.sql.ppl.SystemFunctionIT.typeof_opensearch_types'
1078+
// Glob matches the Calcite subclasses too (CalciteDataTypeIT, CalciteSystemFunctionIT).
1079+
excludeTestsMatching '*DataTypeIT.test_nonnumeric_data_types'
1080+
excludeTestsMatching '*SystemFunctionIT.typeof_opensearch_types'
10801081
// alias_index_mapping: alias_col is type=alias; query is `where alias_col > 1`.
1081-
excludeTestsMatching 'org.opensearch.sql.ppl.DataTypeIT.test_alias_data_type'
1082+
excludeTestsMatching '*DataTypeIT.test_alias_data_type'
10821083
// CalciteAliasFieldAggregationIT: raw-PUT alias index can't be created on the AE route
10831084
// and every test queries alias fields directly — whole class doomed.
10841085
excludeTestsMatching 'org.opensearch.sql.calcite.remote.CalciteAliasFieldAggregationIT'
@@ -1176,6 +1177,33 @@ task integTestRemote(type: RestIntegTestTask) {
11761177
// - max() over int operands reports bigint on the AE route (DataFusion widens integers
11771178
// to Int64) where the v2/Calcite path reports int.
11781179
excludeTestsMatching '*CalcitePPLEvalMaxMinFunctionIT.testEvalMaxNumeric'
1180+
1181+
// === Excludes: CalcitePPLCaseFunctionIT route divergences ===
1182+
// bin @timestamp then group by it: bucket column typed string (not timestamp) on AE.
1183+
excludeTestsMatching '*CalcitePPLCaseFunctionIT.testNestedCaseAggWithAutoDateHistogram'
1184+
1185+
// === Excludes: CalcitePPLStringBuiltinFunctionIT route divergences ===
1186+
// Re-PUT a shared _id with different data; the append-only AE store can't replace docs.
1187+
excludeTestsMatching '*CalcitePPLStringBuiltinFunctionIT.testConcatWithField'
1188+
excludeTestsMatching '*CalcitePPLStringBuiltinFunctionIT.testConcatWs'
1189+
excludeTestsMatching '*CalcitePPLStringBuiltinFunctionIT.testReverse'
1190+
excludeTestsMatching '*CalcitePPLStringBuiltinFunctionIT.testRight'
1191+
excludeTestsMatching '*CalcitePPLStringBuiltinFunctionIT.testTrim'
1192+
excludeTestsMatching '*CalcitePPLStringBuiltinFunctionIT.testRTrim'
1193+
excludeTestsMatching '*CalcitePPLStringBuiltinFunctionIT.testLTrim'
1194+
1195+
// === Excludes: full-text relevance functions (unsupported on DataFusion) ===
1196+
excludeTestsMatching '*MultiMatchIT.test_wildcard_multi_match'
1197+
excludeTestsMatching '*QueryStringIT.wildcard_test'
1198+
excludeTestsMatching '*SimpleQueryStringIT.test_wildcard_simple_query_string'
1199+
1200+
// === Excludes: CalciteLikeQueryIT route divergence ===
1201+
// LIKE is case-insensitive on AE (DataFusion); v2/Calcite treats LIKE as case-sensitive.
1202+
excludeTestsMatching '*CalciteLikeQueryIT.test_the_default_3rd_option'
1203+
1204+
// === Excludes: CalcitePPLAppendPipeCommandIT route divergence ===
1205+
// appendpipe drops the main pipeline's rows on AE (subpipe filter applied in place).
1206+
excludeTestsMatching '*CalcitePPLAppendPipeCommandIT.testDoubleAppendPipeWithFilter'
11791207
}
11801208
}
11811209

integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalciteLikeQueryIT.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package org.opensearch.sql.calcite.remote;
77

88
import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_WILDCARD;
9+
import static org.opensearch.sql.util.Capability.LIKE_CASE_SENSITIVITY;
910
import static org.opensearch.sql.util.MatcherUtils.rows;
1011
import static org.opensearch.sql.util.MatcherUtils.verifyDataRows;
1112
import static org.opensearch.sql.util.MatcherUtils.verifyNumOfRows;
@@ -15,6 +16,7 @@
1516
import org.junit.Test;
1617
import org.opensearch.sql.common.setting.Settings;
1718
import org.opensearch.sql.ppl.LikeQueryIT;
19+
import org.opensearch.sql.util.RequiresCapability;
1820

1921
public class CalciteLikeQueryIT extends LikeQueryIT {
2022
@Override
@@ -49,6 +51,9 @@ public void test_ilike_is_case_insensitive() throws IOException {
4951
}
5052

5153
@Test
54+
@RequiresCapability(
55+
value = LIKE_CASE_SENSITIVITY,
56+
note = "case-sensitive LIKE (legacy=false) expects 0 rows; AE LIKE is case-insensitive.")
5257
public void test_the_default_3rd_option() throws IOException {
5358
// only work in v3
5459
String query =

integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLAppendPipeCommandIT.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_ACCOUNT;
99
import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_BANK;
10+
import static org.opensearch.sql.util.Capability.APPENDPIPE_MAIN_RESULT_DROPPED;
1011
import static org.opensearch.sql.util.MatcherUtils.rows;
1112
import static org.opensearch.sql.util.MatcherUtils.schema;
1213
import static org.opensearch.sql.util.MatcherUtils.verifyDataRows;
@@ -17,6 +18,7 @@
1718
import org.json.JSONObject;
1819
import org.junit.Test;
1920
import org.opensearch.sql.ppl.PPLIntegTestCase;
21+
import org.opensearch.sql.util.RequiresCapability;
2022

2123
public class CalcitePPLAppendPipeCommandIT extends PPLIntegTestCase {
2224
@Override
@@ -145,6 +147,9 @@ public void testTripleAppendPipe() throws IOException {
145147

146148
/** Regression test: double appendpipe with non-aggregation (filter) subpipeline. */
147149
@Test
150+
@RequiresCapability(
151+
value = APPENDPIPE_MAIN_RESULT_DROPPED,
152+
note = "appendpipe drops the main pipeline's rows on the AE route (filter applied in place).")
148153
public void testDoubleAppendPipeWithFilter() throws IOException {
149154
JSONObject actual =
150155
executeQuery(

integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLCaseFunctionIT.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55

66
package org.opensearch.sql.calcite.remote;
77

8+
import static org.opensearch.sql.legacy.TestUtils.isIndexExist;
89
import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_BANK;
910
import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_OTEL_LOGS;
1011
import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_STATE_COUNTRY_WITH_NULL;
1112
import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_WEBLOGS;
13+
import static org.opensearch.sql.util.Capability.BIN_TIME_FIELD_BUCKETING;
1214
import static org.opensearch.sql.util.MatcherUtils.closeTo;
1315
import static org.opensearch.sql.util.MatcherUtils.rows;
1416
import static org.opensearch.sql.util.MatcherUtils.schema;
@@ -23,6 +25,7 @@
2325
import org.opensearch.client.Request;
2426
import org.opensearch.sql.legacy.TestsConstants;
2527
import org.opensearch.sql.ppl.PPLIntegTestCase;
28+
import org.opensearch.sql.util.RequiresCapability;
2629

2730
public class CalcitePPLCaseFunctionIT extends PPLIntegTestCase {
2831

@@ -31,12 +34,20 @@ public void init() throws Exception {
3134
super.init();
3235
enableCalcite();
3336

37+
// Seed only on first creation: the AE parquet store is append-only on same-_id PUT.
38+
boolean weblogsExisted = isIndexExist(client(), TEST_INDEX_WEBLOGS);
3439
loadIndex(Index.WEBLOG);
3540
loadIndex(Index.TIME_TEST_DATA);
3641
loadIndex(Index.STATE_COUNTRY_WITH_NULL);
3742
loadIndex(Index.BANK);
38-
loadIndex(Index.OTELLOGS);
39-
appendDataForBadResponse();
43+
// otel_logs has a multi-value keyword the AE store rejects at load; only the (AE-skipped)
44+
// testNestedCaseAggWithAutoDateHistogram needs it.
45+
if (!isAnalyticsParquetIndicesEnabled()) {
46+
loadIndex(Index.OTELLOGS);
47+
}
48+
if (!weblogsExisted) {
49+
appendDataForBadResponse();
50+
}
4051
}
4152

4253
private void appendDataForBadResponse() throws IOException {
@@ -478,6 +489,9 @@ public void testCaseAggWithNullValues() throws IOException {
478489
}
479490

480491
@Test
492+
@RequiresCapability(
493+
value = BIN_TIME_FIELD_BUCKETING,
494+
note = "bin @timestamp then group by it: bucket column typed string (not timestamp) on AE.")
481495
public void testNestedCaseAggWithAutoDateHistogram() throws IOException {
482496
// TODO: Remove after resolving: https://github.com/opensearch-project/sql/issues/4578
483497
Assume.assumeFalse(

integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLStringBuiltinFunctionIT.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_ACCOUNT;
99
import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_STATE_COUNTRY;
1010
import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_STATE_COUNTRY_WITH_NULL;
11+
import static org.opensearch.sql.util.Capability.DOC_MUTATION;
1112
import static org.opensearch.sql.util.MatcherUtils.*;
1213
import static org.opensearch.sql.util.MatcherUtils.rows;
1314

@@ -17,6 +18,7 @@
1718
import org.junit.jupiter.api.Test;
1819
import org.opensearch.client.Request;
1920
import org.opensearch.sql.ppl.PPLIntegTestCase;
21+
import org.opensearch.sql.util.RequiresCapability;
2022

2123
public class CalcitePPLStringBuiltinFunctionIT extends PPLIntegTestCase {
2224
@Override
@@ -60,6 +62,9 @@ public void testConcat() throws IOException {
6062
}
6163

6264
@Test
65+
@RequiresCapability(
66+
value = DOC_MUTATION,
67+
note = "Re-PUTs a shared _id with different data; the append-only AE store can't replace it.")
6368
public void testConcatWithField() throws IOException {
6469
Request request1 =
6570
new Request("PUT", "/opensearch-sql_test_index_state_country/_doc/5?refresh=true");
@@ -78,6 +83,9 @@ public void testConcatWithField() throws IOException {
7883
}
7984

8085
@Test
86+
@RequiresCapability(
87+
value = DOC_MUTATION,
88+
note = "Re-PUTs a shared _id with different data; the append-only AE store can't replace it.")
8189
public void testConcatWs() throws IOException {
8290
Request request1 =
8391
new Request("PUT", "/opensearch-sql_test_index_state_country/_doc/5?refresh=true");
@@ -212,6 +220,9 @@ public void testPosition() throws IOException {
212220
}
213221

214222
@Test
223+
@RequiresCapability(
224+
value = DOC_MUTATION,
225+
note = "Re-PUTs a shared _id with different data; the append-only AE store can't replace it.")
215226
public void testTrim() throws IOException {
216227
prepareTrim();
217228
JSONObject actual =
@@ -226,6 +237,9 @@ public void testTrim() throws IOException {
226237
}
227238

228239
@Test
240+
@RequiresCapability(
241+
value = DOC_MUTATION,
242+
note = "Re-PUTs a shared _id with different data; the append-only AE store can't replace it.")
229243
public void testRTrim() throws IOException {
230244
prepareTrim();
231245
JSONObject actual =
@@ -240,6 +254,9 @@ public void testRTrim() throws IOException {
240254
}
241255

242256
@Test
257+
@RequiresCapability(
258+
value = DOC_MUTATION,
259+
note = "Re-PUTs a shared _id with different data; the append-only AE store can't replace it.")
243260
public void testLTrim() throws IOException {
244261
prepareTrim();
245262
JSONObject actual =
@@ -254,6 +271,9 @@ public void testLTrim() throws IOException {
254271
}
255272

256273
@Test
274+
@RequiresCapability(
275+
value = DOC_MUTATION,
276+
note = "Re-PUTs a shared _id with different data; the append-only AE store can't replace it.")
257277
public void testReverse() throws IOException {
258278
Request request1 =
259279
new Request("PUT", "/opensearch-sql_test_index_state_country/_doc/5?refresh=true");
@@ -272,6 +292,9 @@ public void testReverse() throws IOException {
272292
}
273293

274294
@Test
295+
@RequiresCapability(
296+
value = DOC_MUTATION,
297+
note = "Re-PUTs a shared _id with different data; the append-only AE store can't replace it.")
275298
public void testRight() throws IOException {
276299
Request request1 =
277300
new Request("PUT", "/opensearch-sql_test_index_state_country/_doc/5?refresh=true");

integ-test/src/test/java/org/opensearch/sql/ppl/MultiMatchIT.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
package org.opensearch.sql.ppl;
77

88
import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_BEER;
9+
import static org.opensearch.sql.util.Capability.FULLTEXT_RELEVANCE_FUNC;
910

1011
import java.io.IOException;
1112
import org.json.JSONObject;
1213
import org.junit.Test;
14+
import org.opensearch.sql.util.RequiresCapability;
1315

1416
public class MultiMatchIT extends PPLIntegTestCase {
1517

@@ -45,6 +47,9 @@ public void test_multi_match_all_params() throws IOException {
4547
}
4648

4749
@Test
50+
@RequiresCapability(
51+
value = FULLTEXT_RELEVANCE_FUNC,
52+
note = "multi_match/query_string/simple_query_string are full-text relevance funcs.")
4853
public void test_wildcard_multi_match() throws IOException {
4954
String query1 =
5055
"SOURCE=" + TEST_INDEX_BEER + " | WHERE multi_match(['Tags'], 'taste') | fields Id";

integ-test/src/test/java/org/opensearch/sql/ppl/QueryStringIT.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
package org.opensearch.sql.ppl;
77

88
import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_BEER;
9+
import static org.opensearch.sql.util.Capability.FULLTEXT_RELEVANCE_FUNC;
910

1011
import java.io.IOException;
1112
import org.json.JSONObject;
1213
import org.junit.Test;
14+
import org.opensearch.sql.util.RequiresCapability;
1315

1416
public class QueryStringIT extends PPLIntegTestCase {
1517

@@ -56,6 +58,9 @@ public void all_params_test() throws IOException {
5658
}
5759

5860
@Test
61+
@RequiresCapability(
62+
value = FULLTEXT_RELEVANCE_FUNC,
63+
note = "multi_match/query_string/simple_query_string are full-text relevance funcs.")
5964
public void wildcard_test() throws IOException {
6065

6166
String query1 = "source=" + TEST_INDEX_BEER + " | where query_string(['Tags'], 'taste')";

integ-test/src/test/java/org/opensearch/sql/ppl/SimpleQueryStringIT.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
package org.opensearch.sql.ppl;
77

88
import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_BEER;
9+
import static org.opensearch.sql.util.Capability.FULLTEXT_RELEVANCE_FUNC;
910

1011
import java.io.IOException;
1112
import org.json.JSONObject;
1213
import org.junit.Test;
14+
import org.opensearch.sql.util.RequiresCapability;
1315

1416
public class SimpleQueryStringIT extends PPLIntegTestCase {
1517
@Override
@@ -45,6 +47,9 @@ public void test_simple_query_string_all_params() throws IOException {
4547
}
4648

4749
@Test
50+
@RequiresCapability(
51+
value = FULLTEXT_RELEVANCE_FUNC,
52+
note = "multi_match/query_string/simple_query_string are full-text relevance funcs.")
4853
public void test_wildcard_simple_query_string() throws IOException {
4954
String query1 =
5055
"SOURCE=" + TEST_INDEX_BEER + " | WHERE simple_query_string(['Tags'], 'taste') | fields Id";

integ-test/src/test/java/org/opensearch/sql/util/Capability.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,35 @@ public enum Capability {
192192
EVAL_MAX_MIN_INT_WIDENING(
193193
"eval max()/min() over integer operands reports the result column as bigint on the"
194194
+ " analytics-engine route (DataFusion widens integers to Int64), whereas the v2/Calcite"
195-
+ " path reports int.");
195+
+ " path reports int."),
196+
197+
/**
198+
* Lucene full-text relevance functions ({@code match}, {@code multi_match}, {@code query_string},
199+
* {@code simple_query_string}, …) are unsupported on the analytics-engine route — DataFusion has
200+
* no relevance scorer, so a query that filters on one returns no rows.
201+
*/
202+
FULLTEXT_RELEVANCE_FUNC(
203+
"Full-text relevance functions (match/multi_match/query_string/simple_query_string) are"
204+
+ " unsupported on the analytics-engine route: DataFusion has no relevance scorer, so the"
205+
+ " filter returns no rows."),
206+
207+
/**
208+
* LIKE is case-insensitive on the analytics-engine route (DataFusion), whereas the v2/Calcite
209+
* path treats {@code LIKE} as case-sensitive (only {@code ILIKE} is case-insensitive).
210+
*/
211+
LIKE_CASE_SENSITIVITY(
212+
"LIKE is case-insensitive on the analytics-engine route (DataFusion), whereas the v2/Calcite"
213+
+ " path treats LIKE as case-sensitive."),
214+
215+
/**
216+
* {@code appendpipe [subpipe]} drops the main pipeline's rows on the analytics-engine route: the
217+
* subpipe's filter is applied to the main result instead of its output being appended to it, so
218+
* the original rows are lost (e.g. {@code stats ... | appendpipe [where gender='F']} returns only
219+
* the filtered F rows, not the originals plus the filtered copy).
220+
*/
221+
APPENDPIPE_MAIN_RESULT_DROPPED(
222+
"appendpipe drops the main pipeline's rows on the analytics-engine route: the subpipe filter"
223+
+ " is applied to the main result instead of appended, so the originals are lost.");
196224

197225
private final String reason;
198226

0 commit comments

Comments
 (0)