This is an automated email from the ASF dual-hosted git repository.
zstan pushed a commit to branch ignite-3.1.0
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/ignite-3.1.0 by this push:
new 228572c4181 IGNITE-26100 Add Metastore Raft log compatibility test
(#6721)
228572c4181 is described below
commit 228572c4181f09a63934112ca0609bcae7db4560
Author: Phillippko <[email protected]>
AuthorDate: Thu Oct 9 17:05:36 2025 +0400
IGNITE-26100 Add Metastore Raft log compatibility test (#6721)
---
modules/compatibility-tests/build.gradle | 4 +
.../internal/MetastorageRaftCompatibilityTest.java | 134 +++++++++++++++++++++
.../internal/PersistentCompatibilityTest.java | 53 +-------
.../SendAllMetastorageCommandTypesJob.java | 71 +++++++++++
.../ignite/internal/CompatibilityTestBase.java | 9 ++
.../ignite/internal/CompatibilityTestCommon.java | 53 ++++++++
.../org/apache/ignite/internal/IgniteCluster.java | 91 ++++++++++++--
.../org/apache/ignite/internal/RunnerNode.java | 11 +-
8 files changed, 359 insertions(+), 67 deletions(-)
diff --git a/modules/compatibility-tests/build.gradle
b/modules/compatibility-tests/build.gradle
index 2928884d00b..8978c90ccb0 100644
--- a/modules/compatibility-tests/build.gradle
+++ b/modules/compatibility-tests/build.gradle
@@ -48,6 +48,8 @@ dependencies {
integrationTestImplementation project(':ignite-storage-api')
integrationTestImplementation project(':ignite-storage-page-memory')
integrationTestImplementation project(':ignite-rest-api')
+ integrationTestImplementation project(':ignite-metastorage-api')
+ integrationTestImplementation project(':ignite-metastorage')
integrationTestAnnotationProcessor
libs.micronaut.inject.annotation.processor
integrationTestImplementation libs.micronaut.junit5
@@ -64,6 +66,8 @@ dependencies {
}
testFixturesImplementation libs.cytodynamics.nucleus
testFixturesImplementation libs.japicmp
+ testFixturesImplementation libs.micronaut.http.client
+
testFixturesImplementation testFixtures(project(':ignite-core'))
testFixturesImplementation testFixtures(project(':ignite-runner'))
diff --git
a/modules/compatibility-tests/src/integrationTest/java/org/apache/ignite/internal/MetastorageRaftCompatibilityTest.java
b/modules/compatibility-tests/src/integrationTest/java/org/apache/ignite/internal/MetastorageRaftCompatibilityTest.java
new file mode 100644
index 00000000000..d88e2718dbe
--- /dev/null
+++
b/modules/compatibility-tests/src/integrationTest/java/org/apache/ignite/internal/MetastorageRaftCompatibilityTest.java
@@ -0,0 +1,134 @@
+/*
+ * 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.apache.ignite.internal.CompatibilityTestCommon.TABLE_NAME_TEST;
+import static
org.apache.ignite.internal.CompatibilityTestCommon.createDefaultTables;
+import static org.apache.ignite.internal.TestWrappers.unwrapIgniteImpl;
+import static
org.apache.ignite.internal.lang.IgniteSystemProperties.COLOCATION_FEATURE_FLAG;
+import static
org.apache.ignite.internal.testframework.IgniteTestUtils.waitForCondition;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.client.IgniteClient;
+import org.apache.ignite.compute.JobDescriptor;
+import org.apache.ignite.compute.JobTarget;
+import org.apache.ignite.deployment.DeploymentUnit;
+import org.apache.ignite.internal.configuration.ComponentWorkingDir;
+import org.apache.ignite.internal.metastorage.MetaStorageManager;
+import org.apache.ignite.internal.testframework.WithSystemProperty;
+import org.apache.ignite.internal.util.IgniteUtils;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedClass;
+import org.junit.jupiter.params.provider.MethodSource;
+
+/** Compatibility tests for metastorage raft log. */
+@ParameterizedClass
+@MethodSource("baseVersions")
+@MicronautTest(rebuildContext = true)
+// Old version node starts with disabled colocation. New version nodes that
start from scratch would fail to join cluster.
+@WithSystemProperty(key = COLOCATION_FEATURE_FLAG, value = "false")
+public class MetastorageRaftCompatibilityTest extends CompatibilityTestBase {
+ @Override
+ protected boolean restartWithCurrentEmbeddedVersion() {
+ return false;
+ }
+
+ @Override
+ protected int nodesCount() {
+ return 1;
+ }
+
+ @Override
+ protected void setupBaseVersion(Ignite baseIgnite) {
+ createDefaultTables(baseIgnite);
+
+ Path nodeWorkDir = cluster.runnerNodeWorkDir(0);
+
+ try {
+ deploySendAllMetastorageCommandTypesJob();
+
+ runSendAllMetastorageCommandTypesJob();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ cluster.stop();
+
+ // To force metastorage recovery from the raft log.
+ deleteMetastorageDbDir(nodeWorkDir);
+ }
+
+ @AfterEach
+ void tearDown() {
+ cluster.stop();
+ }
+
+ @Test
+ void testReapplication() {
+ cluster.startEmbedded(1, false);
+
+ checkMetastorage();
+ }
+
+ @Test
+ void testStreamToFollower() throws InterruptedException {
+ cluster.startEmbedded(2, false);
+
+ checkMetastorage();
+
+ MetaStorageManager newNodeMetastorage =
unwrapIgniteImpl(cluster.node(1)).metaStorageManager();
+ MetaStorageManager oldNodeMetastorage =
unwrapIgniteImpl(cluster.node(0)).metaStorageManager();
+
+ // Assert that new node got all log entries from old one.
+ assertTrue(waitForCondition(() -> oldNodeMetastorage.appliedRevision()
== newNodeMetastorage.appliedRevision(), 10_000));
+ }
+
+ private void checkMetastorage() {
+ // Will fail if metastorage is corrupted.
+ sql("SELECT * FROM " + TABLE_NAME_TEST);
+ }
+
+ private static void deleteMetastorageDbDir(Path nodeWorkDir) {
+ Path metastorageDbDir = new
ComponentWorkingDir(nodeWorkDir.resolve("metastorage")).dbPath();
+
+ // There is no IgniteUtils.delete() method yet.
+ assertTrue(Files.exists(metastorageDbDir));
+ assertTrue(IgniteUtils.deleteIfExists(metastorageDbDir));
+ }
+
+ private <T, R> void deploySendAllMetastorageCommandTypesJob() throws
IOException {
+
CompatibilityTestCommon.deployJob(SendAllMetastorageCommandTypesJob.class,
workDir, deploymentClient);
+ }
+
+ private void runSendAllMetastorageCommandTypesJob() {
+ try (IgniteClient client = cluster.createClient()) {
+ JobDescriptor<String, Void> job =
JobDescriptor.builder(SendAllMetastorageCommandTypesJob.class)
+ .units(new
DeploymentUnit(SendAllMetastorageCommandTypesJob.class.getName(),
"1.0.0")).build();
+
+ JobTarget jobTarget = JobTarget.anyNode(client.cluster().nodes());
+
+ client.compute().execute(jobTarget, job, "");
+ }
+ }
+}
diff --git
a/modules/compatibility-tests/src/integrationTest/java/org/apache/ignite/internal/PersistentCompatibilityTest.java
b/modules/compatibility-tests/src/integrationTest/java/org/apache/ignite/internal/PersistentCompatibilityTest.java
index c6c138491e5..1c790cb96c4 100644
---
a/modules/compatibility-tests/src/integrationTest/java/org/apache/ignite/internal/PersistentCompatibilityTest.java
+++
b/modules/compatibility-tests/src/integrationTest/java/org/apache/ignite/internal/PersistentCompatibilityTest.java
@@ -20,25 +20,9 @@ package org.apache.ignite.internal;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
-import io.micronaut.http.HttpRequest;
-import io.micronaut.http.HttpResponse;
-import io.micronaut.http.HttpStatus;
-import io.micronaut.http.MediaType;
-import io.micronaut.http.MutableHttpRequest;
-import io.micronaut.http.client.HttpClient;
-import io.micronaut.http.client.annotation.Client;
-import io.micronaut.http.client.multipart.MultipartBody;
-import io.micronaut.http.client.multipart.MultipartBody.Builder;
import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
-import jakarta.inject.Inject;
-import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
import java.util.List;
-import java.util.jar.JarEntry;
-import java.util.jar.JarOutputStream;
import org.apache.ignite.Ignite;
import org.apache.ignite.client.IgniteClient;
import org.apache.ignite.compute.JobDescriptor;
@@ -87,8 +71,6 @@ import org.junit.jupiter.params.provider.ValueSource;
// PersistentPageMemoryStorageEngine
@WithSystemProperty(key = IgniteSystemProperties.THREAD_ASSERTIONS_ENABLED,
value = "false")
public class PersistentCompatibilityTest extends CompatibilityTestBase {
- private static final String NODE_URL = "http://localhost:" +
ClusterConfiguration.DEFAULT_BASE_HTTP_PORT;
-
/** Delta files are not compacted before updating the cluster. */
private static final String TABLE_WITH_DELTA_FILES =
"TEST_WITH_DELTA_FILES";
@@ -107,10 +89,6 @@ public class PersistentCompatibilityTest extends
CompatibilityTestBase {
private static final String ORIGINAL_ROW_VALUE = "original_value";
private static final String UPDATED_ROW_VALUE = "updated_value";
- @Inject
- @Client(NODE_URL + "/management/v1/deployment")
- private HttpClient deploymentClient;
-
@Override
protected int nodesCount() {
return 1;
@@ -207,36 +185,7 @@ public class PersistentCompatibilityTest extends
CompatibilityTestBase {
}
private <T, R> void deployCheckpointJob() throws IOException {
- Path jarFile = createJar(CheckpointJob.class);
-
- HttpResponse<Object> deploy = deploy(CheckpointJob.class.getName(),
"1.0.0", jarFile.toFile());
- assertThat(deploy.status(), is(HttpStatus.OK));
- }
-
- private Path createJar(Class<?> clazz) throws IOException {
- String resource = clazz.getName().replace('.', '/') + ".class";
- Path path =
Path.of(clazz.getClassLoader().getResource(resource).getPath());
- Path jarFile = Files.createFile(workDir.resolve("CheckpointJob.jar"));
-
- try (FileOutputStream fos = new FileOutputStream(jarFile.toFile());
JarOutputStream jos = new JarOutputStream(fos)) {
- JarEntry entry = new JarEntry(resource);
- jos.putNextEntry(entry);
- Files.copy(path, jos);
- jos.closeEntry();
- }
-
- return jarFile;
- }
-
- private HttpResponse<Object> deploy(String id, String version, File file) {
- Builder builder = MultipartBody.builder();
- builder.addPart("unitContent", file);
- MultipartBody body = builder.build();
-
- MutableHttpRequest<MultipartBody> post = HttpRequest.POST("units/" +
id + "/" + version, body)
- .contentType(MediaType.MULTIPART_FORM_DATA);
-
- return deploymentClient.toBlocking().exchange(post);
+ CompatibilityTestCommon.deployJob(CheckpointJob.class, workDir,
deploymentClient);
}
private static void insertRow(Ignite baseIgnite, String tableName, int id,
String name) {
diff --git
a/modules/compatibility-tests/src/integrationTest/java/org/apache/ignite/internal/SendAllMetastorageCommandTypesJob.java
b/modules/compatibility-tests/src/integrationTest/java/org/apache/ignite/internal/SendAllMetastorageCommandTypesJob.java
new file mode 100644
index 00000000000..e2c255990b1
--- /dev/null
+++
b/modules/compatibility-tests/src/integrationTest/java/org/apache/ignite/internal/SendAllMetastorageCommandTypesJob.java
@@ -0,0 +1,71 @@
+/*
+ * 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 java.util.concurrent.CompletableFuture.allOf;
+import static org.apache.ignite.internal.metastorage.dsl.Conditions.exists;
+import static org.apache.ignite.internal.metastorage.dsl.Operations.noop;
+import static org.apache.ignite.internal.metastorage.dsl.Operations.ops;
+import static org.apache.ignite.internal.metastorage.dsl.Statements.iif;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import org.apache.ignite.compute.ComputeJob;
+import org.apache.ignite.compute.JobExecutionContext;
+import org.apache.ignite.internal.app.IgniteImpl;
+import org.apache.ignite.internal.hlc.HybridTimestamp;
+import org.apache.ignite.internal.lang.ByteArray;
+import org.apache.ignite.internal.metastorage.impl.MetaStorageManagerImpl;
+import org.apache.ignite.internal.wrapper.Wrappers;
+
+/** A job that runs different MetastorageWriteCommands. */
+class SendAllMetastorageCommandTypesJob implements ComputeJob<String, Void> {
+ @Override
+ public CompletableFuture<Void> executeAsync(JobExecutionContext context,
String arg) {
+ IgniteImpl igniteImpl = Wrappers.unwrap(context.ignite(),
IgniteImpl.class);
+
+ try {
+ byte[] value = "value".getBytes();
+
+ MetaStorageManagerImpl metastorage = (MetaStorageManagerImpl)
igniteImpl.metaStorageManager();
+
+ return allOf(
+ metastorage.put(ByteArray.fromString("put"), value),
+ metastorage.putAll(Map.of(ByteArray.fromString("putAll"),
value)),
+ metastorage.remove(ByteArray.fromString("remove")),
+
metastorage.removeAll(Set.of(ByteArray.fromString("removeAll"))),
+
metastorage.removeByPrefix(ByteArray.fromString("removeByPrefix")),
+ metastorage.invoke(exists(ByteArray.fromString("key")),
noop(), noop()),
+
metastorage.invoke(iif(exists(ByteArray.fromString("key")), ops().yield(),
ops().yield())),
+
metastorage.evictIdempotentCommandsCache(HybridTimestamp.MAX_VALUE),
+ sendCompactionCommand(metastorage)
+ );
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static CompletableFuture<Void>
sendCompactionCommand(MetaStorageManagerImpl metastorage)
+ throws Exception {
+ Method sendCompactionCommand =
metastorage.getClass().getDeclaredMethod("sendCompactionCommand", long.class);
+ sendCompactionCommand.setAccessible(true);
+ return (CompletableFuture<Void>)
sendCompactionCommand.invoke(metastorage, metastorage.appliedRevision());
+ }
+}
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 7c70867fc8b..b260d82b092 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
@@ -25,6 +25,9 @@ import static
org.apache.ignite.internal.testframework.flow.TestFlowUtils.subscr
import static
org.apache.ignite.internal.testframework.matchers.CompletableFutureMatcher.willBe;
import static org.awaitility.Awaitility.await;
+import io.micronaut.http.client.HttpClient;
+import io.micronaut.http.client.annotation.Client;
+import jakarta.inject.Inject;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
@@ -81,6 +84,8 @@ public abstract class CompatibilityTestBase extends
BaseIgniteAbstractTest {
+ " }\n"
+ "}";
+ private static final String NODE_URL = "http://localhost:" +
ClusterConfiguration.DEFAULT_BASE_HTTP_PORT;
+
// If there are no fields annotated with @Parameter, constructor injection
will be used, which is incompatible with the
// Lifecycle.PER_CLASS.
@SuppressWarnings("unused")
@@ -97,6 +102,10 @@ public abstract class CompatibilityTestBase extends
BaseIgniteAbstractTest {
return Collections.emptyList();
}
+ @Inject
+ @Client(NODE_URL + "/management/v1/deployment")
+ protected HttpClient deploymentClient;
+
@SuppressWarnings("unused")
@BeforeParameterizedClassInvocation
void startCluster(String baseVersion, TestInfo testInfo) {
diff --git
a/modules/compatibility-tests/src/testFixtures/java/org/apache/ignite/internal/CompatibilityTestCommon.java
b/modules/compatibility-tests/src/testFixtures/java/org/apache/ignite/internal/CompatibilityTestCommon.java
index 69b8e9b1825..f5c10891cc1 100644
---
a/modules/compatibility-tests/src/testFixtures/java/org/apache/ignite/internal/CompatibilityTestCommon.java
+++
b/modules/compatibility-tests/src/testFixtures/java/org/apache/ignite/internal/CompatibilityTestCommon.java
@@ -17,9 +17,27 @@
package org.apache.ignite.internal;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+import io.micronaut.http.HttpRequest;
+import io.micronaut.http.HttpResponse;
+import io.micronaut.http.HttpStatus;
+import io.micronaut.http.MediaType;
+import io.micronaut.http.MutableHttpRequest;
+import io.micronaut.http.client.HttpClient;
+import io.micronaut.http.client.multipart.MultipartBody;
+import io.micronaut.http.client.multipart.MultipartBody.Builder;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
import org.apache.ignite.Ignite;
import org.apache.ignite.sql.SqlRow;
import org.jetbrains.annotations.Nullable;
@@ -85,4 +103,39 @@ public class CompatibilityTestCommon {
return cursor.wasApplied();
}
}
+
+ /** Deploys class to the cluster using the given deployment client. */
+ public static void deployJob(Class<?> clazz, Path workDir, HttpClient
deploymentClient) throws IOException {
+ Path jarFile = createJar(clazz, workDir);
+
+ HttpResponse<Object> deploy = deploy(clazz.getName(), "1.0.0",
jarFile.toFile(), deploymentClient);
+ assertThat(deploy.status(), is(HttpStatus.OK));
+
+ }
+
+ private static Path createJar(Class<?> clazz, Path workDir) throws
IOException {
+ String resource = clazz.getName().replace('.', '/') + ".class";
+ Path path =
Path.of(clazz.getClassLoader().getResource(resource).getPath());
+ Path jarFile = Files.createFile(workDir.resolve(clazz.getName() +
".jar"));
+
+ try (FileOutputStream fos = new FileOutputStream(jarFile.toFile());
JarOutputStream jos = new JarOutputStream(fos)) {
+ JarEntry entry = new JarEntry(resource);
+ jos.putNextEntry(entry);
+ Files.copy(path, jos);
+ jos.closeEntry();
+ }
+
+ return jarFile;
+ }
+
+ private static HttpResponse<Object> deploy(String id, String version, File
file, HttpClient deploymentClient) {
+ Builder builder = MultipartBody.builder();
+ builder.addPart("unitContent", file);
+ MultipartBody body = builder.build();
+
+ MutableHttpRequest<MultipartBody> post = HttpRequest.POST("units/" +
id + "/" + version, body)
+ .contentType(MediaType.MULTIPART_FORM_DATA);
+
+ return deploymentClient.toBlocking().exchange(post);
+ }
}
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 0f46446a02e..594ea267cf9 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
@@ -18,9 +18,13 @@
package org.apache.ignite.internal;
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
+import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
+import static org.apache.ignite.internal.ClusterConfiguration.configOverrides;
+import static
org.apache.ignite.internal.ClusterConfiguration.containsOverrides;
import static org.apache.ignite.internal.Dependencies.constructArgFile;
import static org.apache.ignite.internal.Dependencies.getProjectRoot;
+import static org.apache.ignite.internal.lang.IgniteStringFormatter.format;
import static
org.apache.ignite.internal.testframework.matchers.CompletableFutureMatcher.willCompleteSuccessfully;
import static
org.apache.ignite.internal.testframework.matchers.HttpResponseMatcher.hasStatusCode;
import static org.apache.ignite.internal.util.CollectionUtils.setListAtIndex;
@@ -40,6 +44,7 @@ import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpRequest.Builder;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -51,7 +56,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
-import java.util.stream.Collectors;
+import java.util.stream.IntStream;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteServer;
import org.apache.ignite.InitParameters;
@@ -65,6 +70,8 @@ import
org.apache.ignite.internal.testframework.TestIgnitionManager;
import org.gradle.tooling.GradleConnector;
import org.gradle.tooling.ProjectConnection;
import org.gradle.tooling.model.build.BuildEnvironment;
+import org.jetbrains.annotations.Nullable;
+import org.junit.jupiter.api.TestInfo;
/**
* Cluster of nodes. Can be started with nodes of previous Ignite versions
running in the external processes or in the embedded mode
@@ -114,6 +121,15 @@ public class IgniteCluster {
* @param nodesCount Number of nodes in the cluster.
*/
public void startEmbedded(int nodesCount, boolean initCluster) {
+ startEmbedded(null, nodesCount, initCluster);
+ }
+
+ /**
+ * Starts cluster in embedded mode with nodes of current version.
+ *
+ * @param nodesCount Number of nodes in the cluster.
+ */
+ public void startEmbedded(@Nullable TestInfo testInfo, int nodesCount,
boolean initCluster) {
if (started) {
throw new IllegalStateException("The cluster is already started");
}
@@ -123,7 +139,7 @@ public class IgniteCluster {
List<ServerRegistration> nodeRegistrations = new ArrayList<>();
for (int nodeIndex = 0; nodeIndex < nodesCount; nodeIndex++) {
- nodeRegistrations.add(startEmbeddedNode(nodeIndex));
+ nodeRegistrations.add(startEmbeddedNode(testInfo, nodeIndex,
nodesCount));
}
if (initCluster) {
@@ -269,14 +285,27 @@ public class IgniteCluster {
return
clusterConfiguration.nodeNamingStrategy().nodeName(clusterConfiguration,
nodeIndex);
}
- private ServerRegistration startEmbeddedNode(int nodeIndex) {
+ private ServerRegistration startEmbeddedNode(
+ @Nullable TestInfo testInfo,
+ int nodeIndex,
+ int nodesCount
+ ) {
String nodeName = nodeName(nodeIndex);
+ String config = formatConfig(clusterConfiguration, nodeName,
nodeIndex, nodesCount);
- IgniteServer node = TestIgnitionManager.start(
+ if (testInfo != null && containsOverrides(testInfo, nodeIndex)) {
+ config = TestIgnitionManager.applyOverridesToConfig(config,
configOverrides(testInfo, nodeIndex));
+ }
+
+ IgniteServer node =
clusterConfiguration.usePreConfiguredStorageProfiles()
+ ? TestIgnitionManager.start(
nodeName,
- null,
-
clusterConfiguration.workDir().resolve(clusterConfiguration.clusterName()).resolve(nodeName)
- );
+ config,
+
clusterConfiguration.workDir().resolve(clusterConfiguration.clusterName()).resolve(nodeName))
+ : TestIgnitionManager.startWithoutPreConfiguredStorageProfiles(
+ nodeName,
+ config,
+
clusterConfiguration.workDir().resolve(clusterConfiguration.clusterName()).resolve(nodeName));
synchronized (igniteServers) {
setListAtIndex(igniteServers, nodeIndex, node);
@@ -311,13 +340,16 @@ public class IgniteCluster {
String dependenciesListNotation = dependencyIds.stream()
.map(dependency -> dependency + ":" + igniteVersion)
- .collect(Collectors.joining(","));
+ .collect(joining(","));
File argFile = constructArgFile(connection,
dependenciesListNotation, false);
List<RunnerNode> result = new ArrayList<>();
for (int nodeIndex = 0; nodeIndex < nodesCount; nodeIndex++) {
- result.add(RunnerNode.startNode(javaHome, argFile,
igniteVersion, clusterConfiguration, nodesCount, nodeIndex));
+ String nodeName =
clusterConfiguration.nodeNamingStrategy().nodeName(clusterConfiguration,
nodeIndex);
+ String nodeConfig = formatConfig(clusterConfiguration,
nodeName, nodeIndex, nodesCount);
+
+ result.add(RunnerNode.startNode(javaHome, argFile,
igniteVersion, clusterConfiguration, nodeConfig, nodesCount, nodeName));
}
return result;
@@ -353,4 +385,45 @@ public class IgniteCluster {
public String clusterName() {
return clusterConfiguration.clusterName();
}
+
+ /** Returns list of runner nodes. */
+ public List<RunnerNode> getRunnerNodes() {
+ return runnerNodes;
+ }
+
+ /** Returns embedded node's work directory. */
+ public Path embeddedNodeWorkDir(int nodeIndex) {
+ return workDir(nodeIndex, true);
+ }
+
+ /** Returns runner node's work directory. */
+ public Path runnerNodeWorkDir(int nodeIndex) {
+ return workDir(nodeIndex, false);
+ }
+
+ private Path workDir(int nodeIndex, boolean embedded) {
+ String nodeName = embedded ? igniteServers.get(nodeIndex).name() :
runnerNodes.get(nodeIndex).nodeName();
+
+ return
clusterConfiguration.workDir().resolve(clusterConfiguration.clusterName()).resolve(nodeName);
+ }
+
+ private static String seedAddressesString(ClusterConfiguration
clusterConfiguration, int seedsCount) {
+ return IntStream.range(0, seedsCount)
+ .map(nodeIndex -> clusterConfiguration.basePort() + nodeIndex)
+ .mapToObj(port -> "\"localhost:" + port + '\"')
+ .collect(joining(", "));
+ }
+
+ private static String formatConfig(ClusterConfiguration
clusterConfiguration, String nodeName, int nodeIndex, int nodesCount) {
+ return format(
+ clusterConfiguration.defaultNodeBootstrapConfigTemplate(),
+ clusterConfiguration.basePort() + nodeIndex,
+ seedAddressesString(clusterConfiguration, nodesCount),
+ clusterConfiguration.baseClientPort() + nodeIndex,
+ clusterConfiguration.baseHttpPort() + nodeIndex,
+ clusterConfiguration.baseHttpsPort() + nodeIndex,
+ nodeName,
+ nodeIndex
+ );
+ }
}
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 6efa40e8541..e8935c05d2b 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
@@ -67,7 +67,7 @@ public class RunnerNode {
* @param igniteVersion Version of the Ignite. Used to get the
configuration defaults.
* @param clusterConfiguration Test cluster configuration.
* @param nodesCount Overall number of nodes.
- * @param nodeIndex Current node index.
+ * @param nodeName Node name.
* @return Instance of the control object.
* @throws IOException If an I/O exception occurs.
*/
@@ -76,12 +76,11 @@ public class RunnerNode {
File argFile,
String igniteVersion,
ClusterConfiguration clusterConfiguration,
+ String nodeConfig,
int nodesCount,
- int nodeIndex
+ String nodeName
) throws IOException {
- String nodeName =
clusterConfiguration.nodeNamingStrategy().nodeName(clusterConfiguration,
nodeIndex);
Path workDir =
clusterConfiguration.workDir().resolve(clusterConfiguration.clusterName()).resolve(nodeName);
- String configStr = formatConfig(clusterConfiguration, nodeName,
nodeIndex, nodesCount);
Files.createDirectories(workDir);
Path configPath = workDir.resolve(DEFAULT_CONFIG_NAME);
@@ -91,13 +90,13 @@ public class RunnerNode {
Map<String, String> defaultsPerVersion =
DEFAULTS_PER_VERSION.get(igniteVersion);
Map<String, String> storageProfilesPerVersion =
STORAGE_PROFILES_PER_VERSION.get(igniteVersion);
writeConfigurationFileApplyingTestDefaults(
- configStr,
+ nodeConfig,
configPath,
defaultsPerVersion != null ? defaultsPerVersion : DEFAULTS,
storageProfilesPerVersion != null ?
storageProfilesPerVersion : STORAGE_PROFILES
);
} else {
- writeConfigurationFile(configStr, configPath);
+ writeConfigurationFile(nodeConfig, configPath);
}
Process process = executeRunner(javaHome, argFile, configPath,
workDir, nodeName);