This is an automated email from the ASF dual-hosted git repository.
ptupitsyn 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 31292e3213d IGNITE-26312 .NET: Fix port issues in compat tests (#6545)
31292e3213d is described below
commit 31292e3213d0621bc114ee1318aa82fbc0033090
Author: Pavel Tupitsyn <[email protected]>
AuthorDate: Wed Sep 3 17:02:13 2025 +0300
IGNITE-26312 .NET: Fix port issues in compat tests (#6545)
---
.../PlatformCompatibilityTestNodeRunner.java | 33 ++++---
.../CurrentClientWithOldServerCompatibilityTest.cs | 7 +-
.../dotnet/Apache.Ignite.Tests/JavaServer.cs | 106 +++++++++++++--------
3 files changed, 89 insertions(+), 57 deletions(-)
diff --git
a/modules/compatibility-tests/src/testFixtures/java/org/apache/ignite/internal/PlatformCompatibilityTestNodeRunner.java
b/modules/compatibility-tests/src/testFixtures/java/org/apache/ignite/internal/PlatformCompatibilityTestNodeRunner.java
index 87d08986c14..9b19fe29992 100644
---
a/modules/compatibility-tests/src/testFixtures/java/org/apache/ignite/internal/PlatformCompatibilityTestNodeRunner.java
+++
b/modules/compatibility-tests/src/testFixtures/java/org/apache/ignite/internal/PlatformCompatibilityTestNodeRunner.java
@@ -17,10 +17,6 @@
package org.apache.ignite.internal;
-import static
org.apache.ignite.internal.ClusterConfiguration.DEFAULT_BASE_CLIENT_PORT;
-import static
org.apache.ignite.internal.ClusterConfiguration.DEFAULT_BASE_HTTPS_PORT;
-import static
org.apache.ignite.internal.ClusterConfiguration.DEFAULT_BASE_HTTP_PORT;
-import static
org.apache.ignite.internal.ClusterConfiguration.DEFAULT_BASE_PORT;
import static
org.apache.ignite.internal.TestDefaultProfilesNames.DEFAULT_AIMEM_PROFILE_NAME;
import static
org.apache.ignite.internal.TestDefaultProfilesNames.DEFAULT_AIPERSIST_PROFILE_NAME;
import static
org.apache.ignite.internal.TestDefaultProfilesNames.DEFAULT_ROCKSDB_PROFILE_NAME;
@@ -59,22 +55,21 @@ public class PlatformCompatibilityTestNodeRunner {
* @param args Args.
*/
public static void main(String[] args) throws Exception {
- String version = System.getenv("IGNITE_OLD_SERVER_VERSION");
- String workDir = System.getenv("IGNITE_OLD_SERVER_WORK_DIR");
- int portOffset =
Integer.parseInt(System.getenv().getOrDefault("IGNITE_OLD_SERVER_PORT_OFFSET",
"20000"));
+ String version = getEnvOrThrow("IGNITE_OLD_SERVER_VERSION");
+ String workDir = getEnvOrThrow("IGNITE_OLD_SERVER_WORK_DIR");
- if (version == null || workDir == null) {
- throw new Exception("IGNITE_OLD_SERVER_VERSION and
IGNITE_OLD_SERVER_WORK_DIR environment variables are not set.");
- }
+ int port = Integer.parseInt(getEnvOrThrow("IGNITE_OLD_SERVER_PORT"));
+ int httpPort =
Integer.parseInt(getEnvOrThrow("IGNITE_OLD_SERVER_HTTP_PORT"));
+ int clientPort =
Integer.parseInt(getEnvOrThrow("IGNITE_OLD_SERVER_CLIENT_PORT"));
System.out.println(">>> Starting test node with version: " + version +
" in work directory: " + workDir);
+ System.out.println(">>> Ports: node=" + port + ", http=" + httpPort +
", client=" + clientPort);
ClusterConfiguration clusterConfiguration =
ClusterConfiguration.builder(new PlatformTestInfo(), Path.of(workDir))
.defaultNodeBootstrapConfigTemplate(NODE_BOOTSTRAP_CFG_TEMPLATE)
- .basePort(DEFAULT_BASE_PORT + portOffset)
- .baseHttpPort(DEFAULT_BASE_HTTP_PORT + portOffset)
- .baseHttpsPort(DEFAULT_BASE_HTTPS_PORT + portOffset)
- .baseClientPort(DEFAULT_BASE_CLIENT_PORT + portOffset)
+ .basePort(port)
+ .baseHttpPort(httpPort)
+ .baseClientPort(clientPort)
.build();
var cluster = new IgniteCluster(clusterConfiguration);
@@ -92,6 +87,16 @@ public class PlatformCompatibilityTestNodeRunner {
cluster.stop();
}
+ private static String getEnvOrThrow(String name) throws Exception {
+ String val = System.getenv(name);
+
+ if (val == null || val.isEmpty()) {
+ throw new Exception(name + " environment variable is not set or
empty.");
+ }
+
+ return val;
+ }
+
private static class PlatformTestInfo implements TestInfo {
@Override
public String getDisplayName() {
diff --git
a/modules/platforms/dotnet/Apache.Ignite.Tests/Compatibility/CurrentClientWithOldServerCompatibilityTest.cs
b/modules/platforms/dotnet/Apache.Ignite.Tests/Compatibility/CurrentClientWithOldServerCompatibilityTest.cs
index 1c3646e2975..a9fc4e62e34 100644
---
a/modules/platforms/dotnet/Apache.Ignite.Tests/Compatibility/CurrentClientWithOldServerCompatibilityTest.cs
+++
b/modules/platforms/dotnet/Apache.Ignite.Tests/Compatibility/CurrentClientWithOldServerCompatibilityTest.cs
@@ -75,8 +75,11 @@ public class CurrentClientWithOldServerCompatibilityTest
[OneTimeTearDown]
public void OneTimeTearDown()
{
- _client.Dispose();
- _javaServer.Dispose();
+ // ReSharper disable
ConditionalAccessQualifierIsNonNullableAccordingToAPIContract
+ _client?.Dispose();
+ _javaServer?.Dispose();
+
+ // ReSharper restore
ConditionalAccessQualifierIsNonNullableAccordingToAPIContract
_workDir.Dispose();
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Tests/JavaServer.cs
b/modules/platforms/dotnet/Apache.Ignite.Tests/JavaServer.cs
index 74392f3dc5a..12d02b80233 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Tests/JavaServer.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Tests/JavaServer.cs
@@ -23,6 +23,8 @@ namespace Apache.Ignite.Tests
using System.Globalization;
using System.IO;
using System.Linq;
+ using System.Net;
+ using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
@@ -36,10 +38,6 @@ namespace Apache.Ignite.Tests
private const string GradleOptsEnvVar = "IGNITE_DOTNET_GRADLE_OPTS";
private const string RequireExternalJavaServerEnvVar =
"IGNITE_DOTNET_REQUIRE_EXTERNAL_SERVER";
- private const int DefaultClientPort = 10942;
-
- private const int DefaultClientPortOldServer = 10800;
-
private const int ConnectTimeoutSeconds = 4 * 60;
private const string GradleCommandExec =
":ignite-runner:runnerPlatformTest --parallel";
@@ -66,13 +64,12 @@ namespace Apache.Ignite.Tests
/// Starts a server node.
/// </summary>
/// <returns>Disposable object to stop the server.</returns>
- public static async Task<JavaServer> StartAsync() => await
StartInternalAsync(old: false, env: []);
+ public static async Task<JavaServer> StartAsync() => await
StartInternalAsync(old: false, env: [], defaultPort: 10942);
public static async Task<JavaServer> StartOldAsync(string version,
string workDir)
{
- // Calculate port offset based on the server version (minor +
patch) to avoid conflicts with other tests.
- // This way we can have multiple active nodes with different
versions (separate clusters).
- var portOffset = 20_000 + int.Parse(version[2..].Replace(".",
string.Empty));
+ // Get random unused ports to avoid conflicts with other tests.
+ var ports = GetUnusedPorts(3);
return await StartInternalAsync(
old: true,
@@ -80,9 +77,10 @@ namespace Apache.Ignite.Tests
{
{ "IGNITE_OLD_SERVER_VERSION", version },
{ "IGNITE_OLD_SERVER_WORK_DIR", workDir },
- { "IGNITE_OLD_SERVER_PORT_OFFSET",
portOffset.ToString(CultureInfo.InvariantCulture) }
- },
- portOffset: portOffset);
+ { "IGNITE_OLD_SERVER_PORT",
ports[0].ToString(CultureInfo.InvariantCulture) },
+ { "IGNITE_OLD_SERVER_HTTP_PORT",
ports[1].ToString(CultureInfo.InvariantCulture) },
+ { "IGNITE_OLD_SERVER_CLIENT_PORT",
ports[2].ToString(CultureInfo.InvariantCulture) },
+ });
}
public void Dispose()
@@ -109,17 +107,16 @@ namespace Apache.Ignite.Tests
Log(">>> Java server stopped.");
}
- private static async Task<JavaServer> StartInternalAsync(bool old,
Dictionary<string, string?> env, int portOffset = 0)
+ private static async Task<JavaServer> StartInternalAsync(bool old,
Dictionary<string, string?> env, int? defaultPort = null)
{
string gradleCommand = old ? GradleCommandExecOldServer :
GradleCommandExec;
- int defaultPort = (old ? DefaultClientPortOldServer :
DefaultClientPort) + portOffset;
- if (await TryConnect(defaultPort) == null)
+ if (defaultPort != null && await TryConnect(defaultPort.Value) ==
null)
{
// Server started from outside.
Log(">>> Java server is already started on port " +
defaultPort + ".");
- return new JavaServer([defaultPort], null);
+ return new JavaServer([defaultPort.Value], null);
}
if
(bool.TryParse(Environment.GetEnvironmentVariable(RequireExternalJavaServerEnvVar),
out var requireExternalServer)
@@ -133,8 +130,7 @@ namespace Apache.Ignite.Tests
var process = CreateProcess(gradleCommand, env);
- var evt = new ManualResetEventSlim(false);
- int[]? ports = null;
+ var tcs = new TaskCompletionSource<int[]>();
DataReceivedEventHandler handler = (_, eventArgs) =>
{
@@ -148,8 +144,14 @@ namespace Apache.Ignite.Tests
if (line.StartsWith("THIN_CLIENT_PORTS",
StringComparison.Ordinal))
{
- ports =
line.Split('=').Last().Split(',').Select(int.Parse).OrderBy(x => x).ToArray();
- evt.Set();
+ var ports =
line.Split('=').Last().Split(',').Select(int.Parse).OrderBy(x => x).ToArray();
+ tcs.SetResult(ports);
+ }
+
+ if (line.StartsWith("Exception in thread \"main\"",
StringComparison.OrdinalIgnoreCase))
+ {
+ process.Kill(entireProcessTree: true);
+ tcs.SetException(new Exception($"Java server failed:
{line}"));
}
};
@@ -158,37 +160,32 @@ namespace Apache.Ignite.Tests
process.Start();
- process.BeginOutputReadLine();
- process.BeginErrorReadLine();
-
- if (!evt.Wait(TimeSpan.FromSeconds(ConnectTimeoutSeconds)))
+ try
{
- process.Kill(entireProcessTree: true);
+ process.BeginOutputReadLine();
+ process.BeginErrorReadLine();
- throw new InvalidOperationException("Failed to wait for
THIN_CLIENT_PORTS. Check logs for details.");
- }
+ var ports = await
tcs.Task.WaitAsync(TimeSpan.FromSeconds(ConnectTimeoutSeconds));
+ var port = ports.FirstOrDefault();
- if (ports == null)
- {
- process.Kill(entireProcessTree: true);
+ if (!WaitForServer(port))
+ {
+ process.Kill(entireProcessTree: true);
+ KillProcessesOnPorts(ports);
- throw new InvalidOperationException("Failed to get ports.
Check logs for details.");
- }
+ throw new InvalidOperationException(
+ $"Failed to wait for the server to start (can't
connect the client on port {port}). Check logs for details.");
+ }
- var port = ports.FirstOrDefault();
+ Log($">>> Java server started on port {port}.");
- if (!WaitForServer(port))
+ return new JavaServer(ports, process);
+ }
+ catch (Exception)
{
process.Kill(entireProcessTree: true);
- KillProcessesOnPorts(ports);
-
- throw new InvalidOperationException(
- $"Failed to wait for the server to start (can't connect
the client on port {port}). Check logs for details.");
+ throw;
}
-
- Log($">>> Java server started on port {port}.");
-
- return new JavaServer(ports, process);
}
private static Process CreateProcess(string gradleCommand,
IDictionary<string, string?> env)
@@ -331,5 +328,32 @@ namespace Apache.Ignite.Tests
using var process = Process.Start(psi);
process?.WaitForExit();
}
+
+ private static int[] GetUnusedPorts(int count)
+ {
+ var ports = new int[count];
+ var listeners = new List<TcpListener>();
+
+ try
+ {
+ for (var i = 0; i < count; i++)
+ {
+ var listener = new TcpListener(IPAddress.Loopback, 0);
+ listeners.Add(listener);
+
+ listener.Start();
+ ports[i] = ((IPEndPoint)listener.LocalEndpoint).Port;
+ }
+
+ return ports;
+ }
+ finally
+ {
+ foreach (var listener in listeners)
+ {
+ listener.Stop();
+ }
+ }
+ }
}
}