This is an automated email from the ASF dual-hosted git repository.
tkalkirill pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new e503475b3df IGNITE-26095 Add partition Raft log compatibility test
(#6627)
e503475b3df is described below
commit e503475b3df1d6663f53bb4a233539127e23a93d
Author: Kirill Tkalenko <[email protected]>
AuthorDate: Fri Sep 19 17:33:05 2025 +0300
IGNITE-26095 Add partition Raft log compatibility test (#6627)
---
...tionRaftLogOnAnotherNodesCompatibilityTest.java | 82 +++++++++++++++++++
...ItPartitionRaftLogOneNodeCompatibilityTest.java | 94 ++++++++++++++++++++++
.../ignite/internal/CompatibilityTestBase.java | 7 +-
.../org/apache/ignite/internal/IgniteCluster.java | 5 ++
.../org/apache/ignite/internal/RunnerNode.java | 7 +-
5 files changed, 190 insertions(+), 5 deletions(-)
diff --git
a/modules/compatibility-tests/src/integrationTest/java/org/apache/ignite/internal/ItApplyPartitionRaftLogOnAnotherNodesCompatibilityTest.java
b/modules/compatibility-tests/src/integrationTest/java/org/apache/ignite/internal/ItApplyPartitionRaftLogOnAnotherNodesCompatibilityTest.java
new file mode 100644
index 00000000000..7976df6edfa
--- /dev/null
+++
b/modules/compatibility-tests/src/integrationTest/java/org/apache/ignite/internal/ItApplyPartitionRaftLogOnAnotherNodesCompatibilityTest.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+
+import org.apache.ignite.Ignite;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedClass;
+import org.junit.jupiter.params.provider.MethodSource;
+
+/** Partition Raft log compatibility tests when changing replicas. */
+@ParameterizedClass
+@MethodSource("baseVersions")
+public class ItApplyPartitionRaftLogOnAnotherNodesCompatibilityTest extends
CompatibilityTestBase {
+ private static final String ZONE_NAME = "TEST_ZONE";
+
+ private static final String TABLE_NAME = "TEST_TABLE";
+
+ @Override
+ protected int nodesCount() {
+ return 3;
+ }
+
+ @Override
+ protected boolean restartWithCurrentEmbeddedVersion() {
+ return false;
+ }
+
+ @Override
+ protected void setupBaseVersion(Ignite baseIgnite) {
+ String createZoneDdl = String.format(
+ "CREATE ZONE %s WITH PARTITIONS=1, REPLICAS=1,
STORAGE_PROFILES='default', DATA_NODES_FILTER='$[?(@.nodeIndex == \"0\")]'",
+ ZONE_NAME
+ );
+
+ sql(baseIgnite, createZoneDdl);
+
+ sql(baseIgnite, String.format("CREATE TABLE %s(ID INT PRIMARY KEY, VAL
VARCHAR) ZONE %s", TABLE_NAME, ZONE_NAME));
+
+ String insertDml = String.format("INSERT INTO %s (ID, VAL) VALUES (?,
?) ", TABLE_NAME);
+
+ baseIgnite.transactions().runInTransaction(tx -> {
+ for (int i = 0; i < 10; i++) {
+ sql(baseIgnite, tx, insertDml, i, "str_" + i);
+ }
+ });
+ }
+
+ @Disabled("https://issues.apache.org/jira/browse/IGNITE-26479")
+ @Test
+ void testIncreaseReplicas() throws Exception {
+ cluster.stop();
+
+ cluster.startEmbedded(nodesCount(), false);
+
+ sql(String.format("ALTER ZONE %s SET REPLICAS=3,
DATA_NODES_FILTER='$..*'", ZONE_NAME));
+
+ // Let's wait for replication to complete on other nodes.
+ Thread.sleep(3_000);
+
+ assertThat(sql(cluster.node(1), String.format("SELECT * FROM %s",
TABLE_NAME)), hasSize(10));
+ assertThat(sql(cluster.node(2), String.format("SELECT * FROM %s",
TABLE_NAME)), hasSize(10));
+ }
+}
diff --git
a/modules/compatibility-tests/src/integrationTest/java/org/apache/ignite/internal/ItPartitionRaftLogOneNodeCompatibilityTest.java
b/modules/compatibility-tests/src/integrationTest/java/org/apache/ignite/internal/ItPartitionRaftLogOneNodeCompatibilityTest.java
new file mode 100644
index 00000000000..a08095729fb
--- /dev/null
+++
b/modules/compatibility-tests/src/integrationTest/java/org/apache/ignite/internal/ItPartitionRaftLogOneNodeCompatibilityTest.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.stream.Stream;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.internal.util.IgniteUtils;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedClass;
+import org.junit.jupiter.params.provider.MethodSource;
+
+/** Partition raft log compatibility tests for one node. */
+@ParameterizedClass
+@MethodSource("baseVersions")
+public class ItPartitionRaftLogOneNodeCompatibilityTest extends
CompatibilityTestBase {
+ private static final String TABLE_NAME = "TEST_TABLE";
+
+ @Override
+ protected int nodesCount() {
+ return 1;
+ }
+
+ @Override
+ protected boolean restartWithCurrentEmbeddedVersion() {
+ return false;
+ }
+
+ @Override
+ protected void setupBaseVersion(Ignite baseIgnite) {
+ sql(baseIgnite, String.format("CREATE TABLE %s(ID INT PRIMARY KEY, VAL
VARCHAR)", TABLE_NAME));
+
+ String insertDml = String.format("INSERT INTO %s (ID, VAL) VALUES (?,
?)", TABLE_NAME);
+
+ baseIgnite.transactions().runInTransaction(tx -> {
+ for (int i = 0; i < 10; i++) {
+ sql(baseIgnite, tx, insertDml, i, "str_" + i);
+ }
+ });
+ }
+
+ /** Tests a simple node restart scenario with reapplying a partition raft
log. */
+ @Test
+ void testSimpleRestart() {
+ cluster.stop();
+
+ cleanTableStoragesDir();
+
+ cluster.startEmbedded(nodesCount(), false);
+
+ assertThat(sql(String.format("SELECT * FROM %s", TABLE_NAME)),
hasSize(10));
+ }
+
+ private void cleanTableStoragesDir() {
+ Path dbDir =
workDir.resolve(cluster.clusterName()).resolve(cluster.nodeName(0)).resolve("partitions").resolve("db");
+
+ assertThat(dbDir.toString(), isDirectoryExistsAndNotEmpty(dbDir),
is(true));
+
+ assertThat(dbDir.toString(), IgniteUtils.deleteIfExists(dbDir),
is(true));
+ }
+
+ private static boolean isDirectoryExistsAndNotEmpty(Path path) {
+ if (!Files.exists(path) || !Files.isDirectory(path)) {
+ return false;
+ }
+
+ try (Stream<Path> list = Files.list(path)) {
+ return list.findAny().isPresent();
+ } catch (IOException e) {
+ return false;
+ }
+ }
+}
diff --git
a/modules/compatibility-tests/src/testFixtures/java/org/apache/ignite/internal/CompatibilityTestBase.java
b/modules/compatibility-tests/src/testFixtures/java/org/apache/ignite/internal/CompatibilityTestBase.java
index 6115334d3d8..cf261726a63 100644
---
a/modules/compatibility-tests/src/testFixtures/java/org/apache/ignite/internal/CompatibilityTestBase.java
+++
b/modules/compatibility-tests/src/testFixtures/java/org/apache/ignite/internal/CompatibilityTestBase.java
@@ -75,7 +75,10 @@ public abstract class CompatibilityTestBase extends
BaseIgniteAbstractTest {
+ " clientConnector.port: {},\n"
+ " clientConnector.sendServerExceptionStackTraceToClient:
true,\n"
+ " rest.port: {},\n"
- + " failureHandler.dumpThreadsOnFailure: false\n"
+ + " failureHandler.dumpThreadsOnFailure: false,\n"
+ + " nodeAttributes: {\n"
+ + " nodeAttributes: {nodeName: \"{}\", nodeIndex: \"{}\"}\n"
+ + " }\n"
+ "}";
// If there are no fields annotated with @Parameter, constructor injection
will be used, which is incompatible with the
@@ -86,7 +89,7 @@ public abstract class CompatibilityTestBase extends
BaseIgniteAbstractTest {
// Force per class template work directory so that non-static field
doesn't get overwritten by the BeforeEach callback.
@WorkDirectory(forcePerClassTemplate = true)
- private Path workDir;
+ protected Path workDir;
protected IgniteCluster cluster;
diff --git
a/modules/compatibility-tests/src/testFixtures/java/org/apache/ignite/internal/IgniteCluster.java
b/modules/compatibility-tests/src/testFixtures/java/org/apache/ignite/internal/IgniteCluster.java
index a56c8889ca0..0f46446a02e 100644
---
a/modules/compatibility-tests/src/testFixtures/java/org/apache/ignite/internal/IgniteCluster.java
+++
b/modules/compatibility-tests/src/testFixtures/java/org/apache/ignite/internal/IgniteCluster.java
@@ -348,4 +348,9 @@ public class IgniteCluster {
throw new RuntimeException(e);
}
}
+
+ /** Returns cluster name. */
+ public String clusterName() {
+ return clusterConfiguration.clusterName();
+ }
}
diff --git
a/modules/compatibility-tests/src/testFixtures/java/org/apache/ignite/internal/RunnerNode.java
b/modules/compatibility-tests/src/testFixtures/java/org/apache/ignite/internal/RunnerNode.java
index 9031d92ad11..6efa40e8541 100644
---
a/modules/compatibility-tests/src/testFixtures/java/org/apache/ignite/internal/RunnerNode.java
+++
b/modules/compatibility-tests/src/testFixtures/java/org/apache/ignite/internal/RunnerNode.java
@@ -81,7 +81,7 @@ public class RunnerNode {
) throws IOException {
String nodeName =
clusterConfiguration.nodeNamingStrategy().nodeName(clusterConfiguration,
nodeIndex);
Path workDir =
clusterConfiguration.workDir().resolve(clusterConfiguration.clusterName()).resolve(nodeName);
- String configStr = formatConfig(clusterConfiguration, nodeIndex,
nodesCount);
+ String configStr = formatConfig(clusterConfiguration, nodeName,
nodeIndex, nodesCount);
Files.createDirectories(workDir);
Path configPath = workDir.resolve(DEFAULT_CONFIG_NAME);
@@ -179,14 +179,15 @@ public class RunnerNode {
.collect(joining(", "));
}
- private static String formatConfig(ClusterConfiguration
clusterConfiguration, int nodeIndex, int nodesCount) {
+ private static String formatConfig(ClusterConfiguration
clusterConfiguration, String nodeName, int nodeIndex, int nodesCount) {
return IgniteStringFormatter.format(
clusterConfiguration.defaultNodeBootstrapConfigTemplate(),
clusterConfiguration.basePort() + nodeIndex,
seedAddressesString(clusterConfiguration, nodesCount),
clusterConfiguration.baseClientPort() + nodeIndex,
clusterConfiguration.baseHttpPort() + nodeIndex,
- clusterConfiguration.baseHttpsPort() + nodeIndex
+ nodeName,
+ nodeIndex
);
}