Skip to content
Open
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
2 changes: 0 additions & 2 deletions tests/KubernetesClient.Tests/PodExecTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@ public async Task ExecDefaultContainerStdOut()
TimeSpan.FromSeconds(5));
}

await Host.StartAsync(TestCancellation).ConfigureAwait(true);

using (Kubernetes client = CreateTestClient())
{
testOutput.WriteLine("Invoking exec operation...");
Expand Down
31 changes: 19 additions & 12 deletions tests/KubernetesClient.Tests/WebSocketTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
using k8s.Tests.Mock.Server;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.IO;
using System.Linq;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
Expand All @@ -21,10 +23,6 @@ namespace k8s.Tests
/// </summary>
public abstract class WebSocketTestBase : IDisposable
{
/// <summary>
/// The next server port to use.
/// </summary>
private static int nextPort = 13255;
private bool disposedValue;
private readonly ITestOutputHelper testOutput;

Expand All @@ -39,32 +37,41 @@ protected WebSocketTestBase(ITestOutputHelper testOutput)
{
this.testOutput = testOutput;

int port = Interlocked.Increment(ref nextPort);

// Useful to diagnose test timeouts.
TestCancellation.Register(
() => testOutput.WriteLine("Test-level cancellation token has been canceled."));

ServerBaseAddress = new Uri($"http://localhost:{port}");
WebSocketBaseAddress = new Uri($"ws://localhost:{port}");

// Use port 0 to let the OS assign a free port dynamically
Host = WebHost.CreateDefaultBuilder()
.UseStartup<Startup>()
.ConfigureServices(ConfigureTestServerServices)
.ConfigureLogging(ConfigureTestServerLogging)
.UseUrls(ServerBaseAddress.AbsoluteUri)
.UseUrls("http://127.0.0.1:0")
.Build();

// Start the host to get the actual assigned port
Host.Start();

// Get the actual server address after binding
var serverAddress = Host.ServerFeatures.Get<IServerAddressesFeature>()?.Addresses.FirstOrDefault();
if (serverAddress == null)
{
throw new InvalidOperationException("Failed to determine server address");
}

ServerBaseAddress = new Uri(serverAddress);
WebSocketBaseAddress = new Uri(serverAddress.Replace("http://", "ws://"));
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The string replacement approach serverAddress.Replace("http://", "ws://") could be fragile. Consider using UriBuilder for a more robust conversion:

var uriBuilder = new UriBuilder(serverAddress)
{
    Scheme = "ws"
};
WebSocketBaseAddress = uriBuilder.Uri;

This handles edge cases better (e.g., https/wss, preserving all URI components).

Suggested change
WebSocketBaseAddress = new Uri(serverAddress.Replace("http://", "ws://"));
var uriBuilder = new UriBuilder(serverAddress)
{
Scheme = "ws"
};
WebSocketBaseAddress = uriBuilder.Uri;

Copilot uses AI. Check for mistakes.
}

/// <summary>
/// The test server's base address (http://).
/// </summary>
protected Uri ServerBaseAddress { get; }
protected Uri ServerBaseAddress { get; private set; }

/// <summary>
/// The test server's base WebSockets address (ws://).
/// </summary>
protected Uri WebSocketBaseAddress { get; }
protected Uri WebSocketBaseAddress { get; private set; }

/// <summary>
/// The test server's web host.
Expand Down
Loading