| File: TestServices\RedisProtocolTestClient.cs | Web Access |
| Project: src\tests\Aspire.Hosting.Native.Core.Tests\Aspire.Hosting.Native.Core.Tests.csproj (Aspire.Hosting.Native.Core.Tests) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Net.Sockets; using System.Text; using Aspire.Hosting.Native.Client; namespace Aspire.Hosting.Native.Core.Tests.TestServices; /// <summary>Verifies actual Redis authentication before a contract test publishes dependency readiness.</summary> internal static class RedisProtocolTestClient { public static async Task<bool> PingAsync(WorkloadEndpointAllocation endpoint, string? password, CancellationToken cancellationToken) { using var client = new TcpClient(); await client.ConnectAsync(endpoint.Host, endpoint.Port, cancellationToken); await using var stream = client.GetStream(); using var reader = new StreamReader(stream, Encoding.UTF8, leaveOpen: true); if (password is not null) { // RESP2 command framing: *2\r\n$4\r\nAUTH\r\n$<UTF8 byte length>\r\n<password>\r\n. var authenticate = $"*2\r\n$4\r\nAUTH\r\n${Encoding.UTF8.GetByteCount(password)}\r\n{password}\r\n"; await stream.WriteAsync(Encoding.UTF8.GetBytes(authenticate), cancellationToken); if (await reader.ReadLineAsync(cancellationToken) != "+OK") { return false; } } await stream.WriteAsync("*1\r\n$4\r\nPING\r\n"u8.ToArray(), cancellationToken); return await reader.ReadLineAsync(cancellationToken) == "+PONG"; } public static async Task WaitForAuthenticatedPingAsync(WorkloadEndpointAllocation endpoint, string password, TimeProvider timeProvider, CancellationToken cancellationToken) { while (true) { try { if (await PingAsync(endpoint, password, cancellationToken)) { return; } } catch (Exception exception) when (exception is SocketException or IOException) { } await Task.Delay(TimeSpan.FromMilliseconds(100), timeProvider, cancellationToken); } } }