Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions integration-test/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,16 @@ These instructions apply to `integration-test/` and supplement the repository-le
### Result ordering across DataNodes

- When row order is not part of the query's contract and may differ across DataNodes, use
`TestUtils.resultSetEqualTestUnordered(sql, expectedHeader, expectedRetArray)` for tree-model
SQL cases. When the test already owns a result set (including table-model queries), use
`TestUtils.treeResultSetEqualTestUnordered(sql, expectedHeader, expectedRetArray)` for tree-model
SQL cases, or
`TestUtils.tableResultSetEqualTestUnordered(sql, expectedHeader, expectedRetArray, database)`
for table-model SQL cases (`database` may be `null` when no `USE` is needed).
When the test already owns a result set, use
`TestUtils.assertResultSetEqualUnordered(resultSet, expectedHeader, expectedRows)` and close
the original result set after the assertion. Reuse these helpers instead of writing per-node
comparison loops in individual tests.
- These helpers check every node independently, including headers, values, and duplicate counts.
They use `ClusterTestResultSet.getNodeResultSets` to read each DataNode's underlying result set.
The default `ClusterTestResultSet` compares nodes at the same cursor position; collecting or
sorting rows after reading through that wrapper cannot avoid row-order mismatches. Do not
replace the helpers with set equality or single-node checks that weaken these assertions.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
import static org.apache.iotdb.db.it.utils.TestUtils.assertTestFail;
import static org.apache.iotdb.db.it.utils.TestUtils.prepareData;
import static org.apache.iotdb.db.it.utils.TestUtils.resultSetEqualTest;
import static org.apache.iotdb.db.it.utils.TestUtils.resultSetEqualTestUnordered;
import static org.apache.iotdb.db.it.utils.TestUtils.treeResultSetEqualTestUnordered;

@RunWith(IoTDBTestRunner.class)
@Category({LocalStandaloneIT.class, ClusterIT.class})
Expand Down Expand Up @@ -346,7 +346,7 @@ public void testTimeDurationManyColumnOnManyDataRegion() {
// group by tags
expectedHeader = new String[] {"city", "time_duration(s1)"};
retArray = new String[] {"Beijing,1677570933,", "Nanjing,1677570938,"};
resultSetEqualTestUnordered(
treeResultSetEqualTestUnordered(
"select time_duration(s1) from root.db1.**,root.db.** group by tags(city)",
expectedHeader,
retArray);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.apache.iotdb.it.env.cluster.node.DataNodeWrapper;
import org.apache.iotdb.itbase.env.BaseEnv;
import org.apache.iotdb.itbase.runtime.ClusterTestConnection;
import org.apache.iotdb.itbase.runtime.ClusterTestResultSet;
import org.apache.iotdb.rpc.IoTDBConnectionException;
import org.apache.iotdb.rpc.RpcUtils;
import org.apache.iotdb.rpc.StatementExecutionException;
Expand Down Expand Up @@ -283,10 +284,17 @@ public static void resultSetEqualTest(

/**
* Executes a tree-model query and checks unordered rows on every read node, including duplicate
* multiplicity. Use only when the query's final result does not require a particular row order or
* select a nondeterministic subset of rows.
* multiplicity.
*
* <p>Delegates to {@link #assertResultSetEqualUnordered(ResultSet, String, List)}, which uses
* {@link ClusterTestResultSet#getNodeResultSets(ResultSet)} to obtain each DataNode's underlying
* result set. Iterating those results bypasses the cluster wrapper's default cross-node,
* row-by-row comparison.
*
* <p>Use only when the query's final result does not require a particular row order or select a
* nondeterministic subset of rows.
*/
public static void resultSetEqualTestUnordered(
public static void treeResultSetEqualTestUnordered(
String sql, String[] expectedHeader, String[] expectedRetArray) {
try (Connection connection = EnvFactory.getEnv().getConnection();
Statement statement = connection.createStatement()) {
Expand All @@ -301,6 +309,37 @@ public static void resultSetEqualTestUnordered(
}
}

/**
* Executes a table-model query and checks unordered rows on every read node, including duplicate
* multiplicity. Selects {@code database} before the query when it is non-null.
*
* <p>Delegates to {@link #assertResultSetEqualUnordered(ResultSet, String, List)}, which uses
* {@link ClusterTestResultSet#getNodeResultSets(ResultSet)} to obtain each DataNode's underlying
* result set. Iterating those results bypasses the cluster wrapper's default cross-node,
* row-by-row comparison.
*
* <p>Use only when the query's final result does not require a particular row order or select a
* nondeterministic subset of rows.
*/
public static void tableResultSetEqualTestUnordered(
String sql, String[] expectedHeader, String[] expectedRetArray, String database) {
try (Connection connection = EnvFactory.getEnv().getTableConnection()) {
connection.setClientInfo("time_zone", "+00:00");
try (Statement statement = connection.createStatement()) {
if (database != null) {
statement.execute("use " + database);
}
try (ResultSet resultSet = statement.executeQuery(sql)) {
assertResultSetEqualUnordered(
resultSet, String.join(",", expectedHeader) + ",", Arrays.asList(expectedRetArray));
}
}
} catch (SQLException e) {
e.printStackTrace();
fail(e.getMessage());
}
}

public static void tableResultSetEqualTest(
String sql, String[] expectedHeader, String[] expectedRetArray, String database) {
tableResultSetEqualTest(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import java.util.Set;

import static org.apache.iotdb.db.it.utils.TestUtils.assertResultSetEqualUnordered;
import static org.apache.iotdb.db.it.utils.TestUtils.tableResultSetEqualTestUnordered;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
Expand Down Expand Up @@ -101,16 +102,23 @@ public void testUnorderedUnionPreservesEveryDuplicateOnEachNode() throws Excepti
expectedRows.add(row);
}
}
try (Connection connection = EnvFactory.getEnv().getTableConnection();
Statement statement = connection.createStatement()) {
statement.execute("USE " + DATABASE);
String sql =
"SELECT device, zone, value FROM readings1 UNION ALL "
+ "SELECT device, zone, value FROM readings1";
try (ResultSet result = statement.executeQuery(sql)) {
assertResultSetEqualUnordered(result, "device,zone,value,", expectedRows);
}
}
String[] expectedHeader = {"device", "zone", "value"};
String[] expectedRetArray = expectedRows.toArray(new String[0]);
tableResultSetEqualTestUnordered(
"SELECT device, zone, value FROM readings1 UNION ALL "
+ "SELECT device, zone, value FROM readings1",
expectedHeader,
expectedRetArray,
DATABASE);
tableResultSetEqualTestUnordered(
"SELECT device, zone, value FROM "
+ DATABASE
+ ".readings1 UNION ALL SELECT device, zone, value FROM "
+ DATABASE
+ ".readings1",
expectedHeader,
expectedRetArray,
null);
}

@Test
Expand Down
Loading