From 1afd6d0f20777e1597fe7a55dccbebc9c927ea71 Mon Sep 17 00:00:00 2001 From: Eric Wei Date: Wed, 2 Sep 2026 20:14:09 +0000 Subject: [PATCH] test(integ-test): stabilize eval max/min schema assertions across shards The eval max()/min() result column has no plan-time type, so the reported type is taken from the first row of the result set. On a single shard that row is always the same document, so the assertions were stable. On multiple shards the arriving row varies and the reported type varies with it, which failed testEvalMaxNumeric, testEvalMinNumeric and testEvalMinIgnoresNulls. Each of those tests now filters to a single known document, so the sampled row is deterministic under any shard count, and a companion test covers the other selection direction that the original two-row query also asserted. Values, method names and the remaining tests are unchanged. The int-asserting tests are gated on EVAL_MAX_MIN_INT_WIDENING because the analytics-engine route reports a wider type for the same value. Signed-off-by: Eric Wei --- .../CalcitePPLEvalMaxMinFunctionIT.java | 61 +++++++++++++++++-- 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLEvalMaxMinFunctionIT.java b/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLEvalMaxMinFunctionIT.java index 27b0343d6ac..8487e06686f 100644 --- a/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLEvalMaxMinFunctionIT.java +++ b/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLEvalMaxMinFunctionIT.java @@ -29,6 +29,9 @@ public void init() throws Exception { loadIndex(Index.NULL_MISSING); } + // `new` has no plan-time type, so its reported type is taken from the first result row. Filtering + // to a single row makes that row deterministic under any shard count. Both directions are kept so + // the int-selected and bigint-selected results stay covered. @Test @RequiresCapability( value = EVAL_MAX_MIN_INT_WIDENING, @@ -37,9 +40,21 @@ public void testEvalMaxNumeric() throws Exception { JSONObject result = executeQuery( String.format( - "source=%s | eval new = max(1, 3, age) | fields age, new", TEST_INDEX_DOG)); + "source=%s | where age = 2 | eval new = max(1, 3, age) | fields age, new", + TEST_INDEX_DOG)); verifySchema(result, schema("age", "bigint"), schema("new", "int")); - verifyDataRows(result, rows(2, 3), rows(4, 4)); + verifyDataRows(result, rows(2, 3)); + } + + @Test + public void testEvalMaxNumericWhenFieldSelected() throws Exception { + JSONObject result = + executeQuery( + String.format( + "source=%s | where age = 4 | eval new = max(1, 3, age) | fields age, new", + TEST_INDEX_DOG)); + verifySchema(result, schema("age", "bigint"), schema("new", "bigint")); + verifyDataRows(result, rows(4, 4)); } @Test @@ -76,9 +91,24 @@ public void testEvalMinNumeric() throws Exception { JSONObject result = executeQuery( String.format( - "source=%s | eval new = min(14, 3, age) | fields age, new", TEST_INDEX_DOG)); + "source=%s | where age = 2 | eval new = min(14, 3, age) | fields age, new", + TEST_INDEX_DOG)); verifySchema(result, schema("age", "bigint"), schema("new", "bigint")); - verifyDataRows(result, rows(2, 2), rows(4, 3)); + verifyDataRows(result, rows(2, 2)); + } + + @Test + @RequiresCapability( + value = EVAL_MAX_MIN_INT_WIDENING, + note = "min(14, 3, age) selects an int-valued result; the AE route reports it as bigint.") + public void testEvalMinNumericWhenLiteralSelected() throws Exception { + JSONObject result = + executeQuery( + String.format( + "source=%s | where age = 4 | eval new = min(14, 3, age) | fields age, new", + TEST_INDEX_DOG)); + verifySchema(result, schema("age", "bigint"), schema("new", "int")); + verifyDataRows(result, rows(4, 3)); } @Test @@ -136,11 +166,30 @@ public void testEvalMinIgnoresNulls() throws Exception { JSONObject result = executeQuery( String.format( - "source=%s | eval new = min(dbl, 5) | fields dbl, new", TEST_INDEX_NULL_MISSING)); + "source=%s | where key = 'values' | eval new = min(dbl, 5) | fields dbl, new", + TEST_INDEX_NULL_MISSING)); verifySchema(result, schema("dbl", "double"), schema("new", "double")); + verifyDataRows(result, rows(3.1415, 3.1415)); + } + + // Keeps the null-skipping assertion on its own rows, covering both explicit-null and + // missing-field documents. Every row here selects the int literal, so the reported type no longer + // depends on which row arrives first. + @Test + @RequiresCapability( + value = EVAL_MAX_MIN_INT_WIDENING, + note = + "min(dbl, 5) over null-valued rows selects the int literal; the AE route reports the" + + " column using the wider double type.") + public void testEvalMinIgnoresNullsWhenLiteralSelected() throws Exception { + JSONObject result = + executeQuery( + String.format( + "source=%s | where key != 'values' | eval new = min(dbl, 5) | fields dbl, new", + TEST_INDEX_NULL_MISSING)); + verifySchema(result, schema("dbl", "double"), schema("new", "int")); verifyDataRows( result, - rows(3.1415, 3.1415), rows(null, 5), rows(null, 5), rows(null, 5),