Skip to content

Commit 64709d9

Browse files
committed
Add AnalyticsExplainIT with expected output files
Add dedicated explain integration test class following the CalciteExplainIT pattern: each test compares actual explain JSON against expected output files in resources/expectedOutput/analytics/. Tests cover simple scan, project, filter+project, aggregation, sort (with collation propagation to LogicalSystemLimit), and eval. Signed-off-by: Kai Huang <kaihuang@amazon.com> Signed-off-by: Kai Huang <ahkcs@amazon.com>
1 parent 71da5d2 commit 64709d9

File tree

7 files changed

+116
-0
lines changed

7 files changed

+116
-0
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package org.opensearch.sql.ppl;
7+
8+
import static org.opensearch.sql.util.MatcherUtils.assertJsonEqualsIgnoreId;
9+
10+
import java.io.IOException;
11+
import org.apache.logging.log4j.LogManager;
12+
import org.apache.logging.log4j.Logger;
13+
import org.junit.Test;
14+
15+
/**
16+
* Explain integration tests for queries routed through the analytics engine path (Project Mustang).
17+
* Validates that PPL queries targeting "parquet_*" indices produce correct logical plans via the
18+
* _plugins/_ppl/_explain endpoint.
19+
*
20+
* <p>Expected output files are in resources/expectedOutput/analytics/. Each test compares the
21+
* explain JSON output against its expected file, following the same pattern as CalciteExplainIT.
22+
*
23+
* <p>Since the analytics engine is not yet available, physical and extended plans are null. Only
24+
* the logical plan (Calcite RelNode tree) is verified.
25+
*/
26+
public class AnalyticsExplainIT extends PPLIntegTestCase {
27+
28+
private static final Logger LOG = LogManager.getLogger(AnalyticsExplainIT.class);
29+
30+
@Override
31+
protected void init() throws Exception {
32+
// No index loading needed -- stub schema and data are hardcoded
33+
}
34+
35+
private String loadAnalyticsExpectedPlan(String fileName) {
36+
return loadFromFile("expectedOutput/analytics/" + fileName);
37+
}
38+
39+
@Test
40+
public void testExplainSimpleScan() throws IOException {
41+
String query = "source = opensearch.parquet_logs";
42+
String result = explainQueryToString(query);
43+
LOG.info("[testExplainSimpleScan] query: {}\nresult:\n{}", query, result);
44+
assertJsonEqualsIgnoreId(loadAnalyticsExpectedPlan("explain_simple_scan.json"), result);
45+
}
46+
47+
@Test
48+
public void testExplainProject() throws IOException {
49+
String query = "source = opensearch.parquet_logs | fields ts, message";
50+
String result = explainQueryToString(query);
51+
LOG.info("[testExplainProject] query: {}\nresult:\n{}", query, result);
52+
assertJsonEqualsIgnoreId(loadAnalyticsExpectedPlan("explain_project.json"), result);
53+
}
54+
55+
@Test
56+
public void testExplainFilterAndProject() throws IOException {
57+
String query = "source = opensearch.parquet_logs | where status = 200 | fields ts, message";
58+
String result = explainQueryToString(query);
59+
LOG.info("[testExplainFilterAndProject] query: {}\nresult:\n{}", query, result);
60+
assertJsonEqualsIgnoreId(loadAnalyticsExpectedPlan("explain_filter_project.json"), result);
61+
}
62+
63+
@Test
64+
public void testExplainAggregation() throws IOException {
65+
String query = "source = opensearch.parquet_logs | stats count() by status";
66+
String result = explainQueryToString(query);
67+
LOG.info("[testExplainAggregation] query: {}\nresult:\n{}", query, result);
68+
assertJsonEqualsIgnoreId(loadAnalyticsExpectedPlan("explain_aggregation.json"), result);
69+
}
70+
71+
@Test
72+
public void testExplainSort() throws IOException {
73+
String query = "source = opensearch.parquet_logs | sort ts";
74+
String result = explainQueryToString(query);
75+
LOG.info("[testExplainSort] query: {}\nresult:\n{}", query, result);
76+
assertJsonEqualsIgnoreId(loadAnalyticsExpectedPlan("explain_sort.json"), result);
77+
}
78+
79+
@Test
80+
public void testExplainEval() throws IOException {
81+
String query = "source = opensearch.parquet_logs | eval error = status = 500";
82+
String result = explainQueryToString(query);
83+
LOG.info("[testExplainEval] query: {}\nresult:\n{}", query, result);
84+
assertJsonEqualsIgnoreId(loadAnalyticsExpectedPlan("explain_eval.json"), result);
85+
}
86+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"calcite": {
3+
"logical": "LogicalSystemLimit(fetch=[10000], type=[QUERY_SIZE_LIMIT])\n LogicalProject(count()=[$1], status=[$0])\n LogicalAggregate(group=[{0}], count()=[COUNT()])\n LogicalProject(status=[$1])\n LogicalTableScan(table=[[opensearch, parquet_logs]])\n"
4+
}
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"calcite": {
3+
"logical": "LogicalSystemLimit(fetch=[10000], type=[QUERY_SIZE_LIMIT])\n LogicalProject(ts=[$0], status=[$1], message=[$2], ip_addr=[$3], error=[=($1, 500)])\n LogicalTableScan(table=[[opensearch, parquet_logs]])\n"
4+
}
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"calcite": {
3+
"logical": "LogicalSystemLimit(fetch=[10000], type=[QUERY_SIZE_LIMIT])\n LogicalProject(ts=[$0], message=[$2])\n LogicalFilter(condition=[=($1, 200)])\n LogicalTableScan(table=[[opensearch, parquet_logs]])\n"
4+
}
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"calcite": {
3+
"logical": "LogicalSystemLimit(fetch=[10000], type=[QUERY_SIZE_LIMIT])\n LogicalProject(ts=[$0], message=[$2])\n LogicalTableScan(table=[[opensearch, parquet_logs]])\n"
4+
}
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"calcite": {
3+
"logical": "LogicalSystemLimit(fetch=[10000], type=[QUERY_SIZE_LIMIT])\n LogicalTableScan(table=[[opensearch, parquet_logs]])\n"
4+
}
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"calcite": {
3+
"logical": "LogicalSystemLimit(sort0=[$0], dir0=[ASC-nulls-first], fetch=[10000], type=[QUERY_SIZE_LIMIT])\n LogicalSort(sort0=[$0], dir0=[ASC-nulls-first])\n LogicalTableScan(table=[[opensearch, parquet_logs]])\n"
4+
}
5+
}

0 commit comments

Comments
 (0)