Skip to content

Commit 24bf1dd

Browse files
committed
Add integration tests for chart command
Signed-off-by: Yuanchun Shen <[email protected]>
1 parent d785276 commit 24bf1dd

File tree

1 file changed

+280
-45
lines changed

1 file changed

+280
-45
lines changed

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

Lines changed: 280 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,58 +5,293 @@
55

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

8-
import org.json.JSONObject;
9-
import org.junit.jupiter.api.Test;
10-
import org.opensearch.sql.ppl.PPLIntegTestCase;
11-
12-
import java.io.IOException;
13-
148
import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_BANK;
9+
import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_BANK_WITH_NULL_VALUES;
10+
import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_OTEL_LOGS;
11+
import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_TIME_DATA;
1512
import static org.opensearch.sql.util.MatcherUtils.assertJsonEquals;
1613
import static org.opensearch.sql.util.MatcherUtils.rows;
1714
import static org.opensearch.sql.util.MatcherUtils.schema;
1815
import static org.opensearch.sql.util.MatcherUtils.verifyDataRows;
1916
import static org.opensearch.sql.util.MatcherUtils.verifySchema;
2017

18+
import java.io.IOException;
19+
import org.json.JSONObject;
20+
import org.junit.jupiter.api.Test;
21+
import org.opensearch.sql.ppl.PPLIntegTestCase;
22+
2123
public class CalciteChartCommandIT extends PPLIntegTestCase {
22-
@Override
23-
protected void init() throws Exception {
24-
super.init();
25-
enableCalcite();
26-
loadIndex(Index.BANK);
27-
loadIndex(Index.BANK_WITH_NULL_VALUES);
28-
loadIndex(Index.OTELLOGS);
29-
}
30-
31-
@Test
32-
public void testChartWithSingleGroupKey() throws IOException {
33-
JSONObject result1 = executeQuery(String.format("source=%s | chart avg(balance) by gender", TEST_INDEX_BANK));
34-
verifySchema(
35-
result1,
36-
schema("avg(balance)", "double"),
37-
schema("gender", "string"));
38-
verifyDataRows(result1, rows(40488, "F"), rows(16377.25, "M"));
39-
JSONObject result2 = executeQuery(String.format("source=%s | chart avg(balance) over gender", TEST_INDEX_BANK));
40-
assertJsonEquals(result1.toString(), result2.toString());
41-
}
42-
43-
@Test
44-
public void testChartWithMultipleGroupKeys() throws IOException {
45-
JSONObject result1 = executeQuery(String.format("source=%s | chart avg(balance) by gender, age", TEST_INDEX_BANK));
46-
verifySchema(
47-
result1,
48-
schema("avg(balance)", "double"),
49-
schema("gender", "string"),
50-
schema("age", "string"));
51-
verifyDataRows(result1, rows(40488, "F", "36"), rows(16377.25, "M", 36));
52-
JSONObject result2 = executeQuery(String.format("source=%s | chart avg(balance) over gender, age", TEST_INDEX_BANK));
53-
assertJsonEquals(result1.toString(), result2.toString());
54-
}
55-
56-
// TODOs:
57-
// Param nullstr: source=opensearch-sql_test_index_bank_with_null_values | eval age = cast(age as string) | chart nullstr='nil' max(account_number) over gender by age
58-
// Param usenull: source=opensearch-sql_test_index_bank_with_null_values | eval age = cast(age as string) | chart usenull=false nullstr='nil' max(account_number) over gender by age
59-
// Param limit = 0: source=bank | chart limit=0 avg(balance) over state by gender
60-
// SPAN:
24+
@Override
25+
public void init() throws Exception {
26+
super.init();
27+
enableCalcite();
28+
loadIndex(Index.BANK);
29+
loadIndex(Index.BANK_WITH_NULL_VALUES);
30+
loadIndex(Index.OTELLOGS);
31+
loadIndex(Index.TIME_TEST_DATA);
32+
}
33+
34+
@Test
35+
public void testChartWithSingleGroupKey() throws IOException {
36+
JSONObject result1 =
37+
executeQuery(String.format("source=%s | chart avg(balance) by gender", TEST_INDEX_BANK));
38+
verifySchema(result1, schema("avg(balance)", "double"), schema("gender", "string"));
39+
verifyDataRows(result1, rows(40488, "F"), rows(16377.25, "M"));
40+
JSONObject result2 =
41+
executeQuery(String.format("source=%s | chart avg(balance) over gender", TEST_INDEX_BANK));
42+
assertJsonEquals(result1.toString(), result2.toString());
43+
}
44+
45+
@Test
46+
public void testChartWithMultipleGroupKeys() throws IOException {
47+
JSONObject result1 =
48+
executeQuery(
49+
String.format("source=%s | chart avg(balance) over gender by age", TEST_INDEX_BANK));
50+
verifySchema(
51+
result1,
52+
schema("gender", "string"),
53+
schema("age", "string"),
54+
schema("avg(balance)", "double"));
55+
verifyDataRows(
56+
result1,
57+
rows("F", "28", 32838),
58+
rows("F", "39", 40540),
59+
rows("M", "32", 39225),
60+
rows("M", "33", 4180),
61+
rows("M", "36", 11052),
62+
rows("F", "34", 48086));
63+
JSONObject result2 =
64+
executeQuery(
65+
String.format("source=%s | chart avg(balance) by gender, age", TEST_INDEX_BANK));
66+
assertJsonEquals(result1.toString(), result2.toString());
67+
}
68+
69+
@Test
70+
public void testChartCombineOverByWithLimit0() throws IOException {
71+
JSONObject result =
72+
executeQuery(
73+
String.format(
74+
"source=%s | chart limit=0 avg(balance) over state by gender", TEST_INDEX_BANK));
75+
verifySchema(
76+
result,
77+
schema("avg(balance)", "double"),
78+
schema("state", "string"),
79+
schema("gender", "string"));
80+
verifyDataRows(
81+
result,
82+
rows(39225.0, "IL", "M"),
83+
rows(48086.0, "IN", "F"),
84+
rows(4180.0, "MD", "M"),
85+
rows(40540.0, "PA", "F"),
86+
rows(5686.0, "TN", "M"),
87+
rows(32838.0, "VA", "F"),
88+
rows(16418.0, "WA", "M"));
89+
}
90+
91+
@Test
92+
public void testChartMaxBalanceByAgeSpan() throws IOException {
93+
JSONObject result =
94+
executeQuery(
95+
String.format("source=%s | chart max(balance) by age span=10", TEST_INDEX_BANK));
96+
verifySchema(result, schema("max(balance)", "bigint"), schema("age", "int"));
97+
verifyDataRows(result, rows(32838, 20), rows(48086, 30));
98+
}
99+
100+
@Test
101+
public void testChartMaxValueOverTimestampSpanWeekByCategory() throws IOException {
102+
JSONObject result =
103+
executeQuery(
104+
String.format(
105+
"source=%s | chart max(value) over timestamp span=1week by category",
106+
TEST_INDEX_TIME_DATA));
107+
verifySchema(
108+
result,
109+
schema("timestamp", "timestamp"),
110+
schema("category", "string"),
111+
schema("max(value)", "int"));
112+
// Data spans from 2025-07-28 to 2025-08-01, all within same week
113+
verifyDataRows(
114+
result,
115+
rows("2025-07-28 00:00:00", "A", 9367),
116+
rows("2025-07-28 00:00:00", "B", 9521),
117+
rows("2025-07-28 00:00:00", "C", 9187),
118+
rows("2025-07-28 00:00:00", "D", 8736));
119+
}
120+
121+
@Test
122+
public void testChartMaxValueOverCategoryByTimestampSpanWeek() throws IOException {
123+
JSONObject result =
124+
executeQuery(
125+
String.format(
126+
"source=%s | chart max(value) over category by timestamp span=1week",
127+
TEST_INDEX_TIME_DATA));
128+
verifySchema(
129+
result,
130+
schema("category", "string"),
131+
schema("timestamp", "string"),
132+
schema("max(value)", "int"));
133+
// All data within same week span
134+
verifyDataRows(
135+
result,
136+
rows("A", "2025-07-28 00:00:00", 9367),
137+
rows("B", "2025-07-28 00:00:00", 9521),
138+
rows("C", "2025-07-28 00:00:00", 9187),
139+
rows("D", "2025-07-28 00:00:00", 8736));
140+
}
141+
142+
@Test
143+
public void testChartMaxValueByTimestampSpanDayAndWeek() throws IOException {
144+
JSONObject result =
145+
executeQuery(
146+
String.format(
147+
"source=%s | chart max(value) by timestamp span=1day, @timestamp span=2weeks",
148+
TEST_INDEX_TIME_DATA));
149+
// column split are converted to string in order to be compatible with nullstr and otherstr
150+
verifySchema(
151+
result,
152+
schema("timestamp", "timestamp"),
153+
schema("@timestamp", "string"),
154+
schema("max(value)", "int"));
155+
// Data grouped by day spans
156+
verifyDataRows(
157+
result,
158+
rows("2025-07-28 00:00:00", "2025-07-28 00:00:00", 9367),
159+
rows("2025-07-29 00:00:00", "2025-07-28 00:00:00", 9521),
160+
rows("2025-07-30 00:00:00", "2025-07-28 00:00:00", 9234),
161+
rows("2025-07-31 00:00:00", "2025-07-28 00:00:00", 9318),
162+
rows("2025-08-01 00:00:00", "2025-07-28 00:00:00", 9015));
163+
}
164+
165+
@Test
166+
public void testChartLimit0WithUseOther() throws IOException {
167+
JSONObject result =
168+
executeQuery(
169+
String.format(
170+
"source=%s | chart limit=0 useother=true otherstr='max_among_other'"
171+
+ " max(severityNumber) over flags by severityText",
172+
TEST_INDEX_OTEL_LOGS));
173+
verifySchema(
174+
result,
175+
schema("max(severityNumber)", "bigint"),
176+
schema("flags", "bigint"),
177+
schema("severityText", "string"));
178+
verifyDataRows(
179+
result,
180+
rows(5, 0, "DEBUG"),
181+
rows(6, 0, "DEBUG2"),
182+
rows(7, 0, "DEBUG3"),
183+
rows(8, 0, "DEBUG4"),
184+
rows(17, 0, "ERROR"),
185+
rows(18, 0, "ERROR2"),
186+
rows(19, 0, "ERROR3"),
187+
rows(20, 0, "ERROR4"),
188+
rows(21, 0, "FATAL"),
189+
rows(22, 0, "FATAL2"),
190+
rows(23, 0, "FATAL3"),
191+
rows(24, 0, "FATAL4"),
192+
rows(9, 0, "INFO"),
193+
rows(10, 0, "INFO2"),
194+
rows(11, 0, "INFO3"),
195+
rows(12, 0, "INFO4"),
196+
rows(2, 0, "TRACE2"),
197+
rows(3, 0, "TRACE3"),
198+
rows(4, 0, "TRACE4"),
199+
rows(13, 0, "WARN"),
200+
rows(14, 0, "WARN2"),
201+
rows(15, 0, "WARN3"),
202+
rows(16, 0, "WARN4"),
203+
rows(17, 1, "ERROR"),
204+
rows(9, 1, "INFO"),
205+
rows(1, 1, "TRACE"));
206+
}
207+
208+
@Test
209+
public void testChartLimitTopWithUseOther() throws IOException {
210+
JSONObject result =
211+
executeQuery(
212+
String.format(
213+
"source=%s | chart limit=top 2 useother=true otherstr='max_among_other'"
214+
+ " max(severityNumber) over flags by severityText",
215+
TEST_INDEX_OTEL_LOGS));
216+
verifySchema(
217+
result,
218+
schema("flags", "bigint"),
219+
schema("severityText", "string"),
220+
schema("max(severityNumber)", "bigint"));
221+
verifyDataRows(
222+
result,
223+
rows(1, "max_among_other", 17),
224+
rows(0, "max_among_other", 22),
225+
rows(0, "FATAL3", 23),
226+
rows(0, "FATAL4", 24));
227+
}
228+
229+
@Test
230+
public void testChartLimitBottomWithUseOther() throws IOException {
231+
JSONObject result =
232+
executeQuery(
233+
String.format(
234+
"source=%s | chart limit=bottom 2 useother=false otherstr='other_small_not_shown'"
235+
+ " max(severityNumber) over flags by severityText",
236+
TEST_INDEX_OTEL_LOGS));
237+
verifySchema(
238+
result,
239+
schema("flags", "bigint"),
240+
schema("severityText", "string"),
241+
schema("max(severityNumber)", "bigint"));
242+
verifyDataRows(result, rows(1, "TRACE", 1), rows(0, "TRACE2", 2));
243+
}
244+
245+
@Test
246+
public void testChartLimitTopWithMinAgg() throws IOException {
247+
JSONObject result =
248+
executeQuery(
249+
String.format(
250+
"source=%s | chart limit=top 2 min(severityNumber) over flags by severityText",
251+
TEST_INDEX_OTEL_LOGS));
252+
verifySchema(
253+
result,
254+
schema("flags", "bigint"),
255+
schema("severityText", "string"),
256+
schema("min(severityNumber)", "bigint"));
257+
verifyDataRows(
258+
result,
259+
rows(1, "OTHER", 9),
260+
rows(1, "TRACE", 1),
261+
rows(0, "OTHER", 3),
262+
rows(0, "TRACE2", 2));
263+
}
264+
265+
@Test
266+
public void testChartUseNullTrueWithNullStr() throws IOException {
267+
JSONObject result =
268+
executeQuery(
269+
String.format(
270+
"source=%s | chart nullstr='nil' avg(balance) over gender by age span=10",
271+
TEST_INDEX_BANK_WITH_NULL_VALUES));
272+
verifySchema(
273+
result,
274+
schema("gender", "string"),
275+
schema("age", "string"),
276+
schema("avg(balance)", "double"));
277+
verifyDataRows(
278+
result,
279+
rows("M", "30", 21702.5),
280+
rows("F", "30", 48086.0),
281+
rows("F", "20", 32838.0),
282+
rows("F", "nil", null));
283+
}
61284

285+
@Test
286+
public void testChartUseNullFalseWithNullStr() throws IOException {
287+
JSONObject result =
288+
executeQuery(
289+
String.format(
290+
"source=%s | chart usenull=false nullstr='not_shown' count() over gender by age"
291+
+ " span=10",
292+
TEST_INDEX_BANK_WITH_NULL_VALUES));
293+
verifySchema(
294+
result, schema("gender", "string"), schema("age", "string"), schema("count()", "bigint"));
295+
verifyDataRows(result, rows("M", "30", 4), rows("F", "30", 1), rows("F", "20", 1));
296+
}
62297
}

0 commit comments

Comments
 (0)