File: TestServices\DcpCleanupTestHandler.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.Collections.Concurrent;
using System.Net;
using System.Text;
using Aspire.Hosting.Native.Dcp;
using Aspire.Hosting.Native.Server;
 
namespace Aspire.Hosting.Native.Core.Tests.TestServices;
 
internal sealed class DcpCleanupTestHandler : HttpMessageHandler
{
    public ConcurrentDictionary<string, bool> Resources { get; } = new();
    public ConcurrentQueue<string> Deletes { get; } = new();
    public Func<string, CancellationToken, Task>? BeforeDelete { get; set; }
    public bool Exited { get; set; }
    public ConcurrentQueue<string> AdministrativeRequests { get; } = new();
    public ConcurrentQueue<(string ContentType, string Body)> RequestContents { get; } = new();
    public Func<CancellationToken, Task>? BeforeCleanup { get; set; }
    public Func<CancellationToken, Task>? BeforeResponse { get; set; }
    public Func<HttpRequestMessage, HttpResponseMessage>? ResponseFactory { get; set; }
 
    public DcpApiClient CreateClient(NativeServerOptions options)
    {
        return new DcpApiClient(options, new HttpClient(this) { BaseAddress = new Uri("http://localhost") });
    }
 
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (BeforeResponse is { } beforeResponse)
        {
            await beforeResponse(cancellationToken);
        }
        if (ResponseFactory is { } responseFactory)
        {
            return responseFactory(request);
        }
        var path = request.RequestUri!.AbsolutePath;
        var key = string.Join('/', path.Split('/')[^2..]);
        if (request.Content is { } content)
        {
            RequestContents.Enqueue((content.Headers.ContentType!.ToString(),
                await content.ReadAsStringAsync(cancellationToken)));
        }
        if (key == "admin/execution")
        {
            if (request.Method == HttpMethod.Patch)
            {
                AdministrativeRequests.Enqueue(await request.Content!.ReadAsStringAsync(cancellationToken));
                if (BeforeCleanup is { } before)
                {
                    await before(cancellationToken);
                }
                Resources.Clear();
            }
 
            return Json("""{"status":"CleanupComplete"}""");
        }
        if (request.Method == HttpMethod.Post)
        {
            using var body = System.Text.Json.JsonDocument.Parse(await request.Content!.ReadAsStringAsync(cancellationToken));
            Resources[path.Split('/')[^1] + "/" + body.RootElement.GetProperty("metadata").GetProperty("name").GetString()] = true;
            return Json("{}");
        }
        if (request.Method == HttpMethod.Delete)
        {
            Deletes.Enqueue(key);
            if (BeforeDelete is { } before)
            {
                await before(key, cancellationToken);
            }
            return Resources.TryRemove(key, out _) ? Json("{}") : new(HttpStatusCode.NotFound);
        }
        if (key.EndsWith("/log", StringComparison.Ordinal))
        {
            return new(HttpStatusCode.OK) { Content = new StringContent("") };
        }
        if (!Resources.ContainsKey(key))
        {
            return new(HttpStatusCode.NotFound);
        }
 
        return key.StartsWith("services/", StringComparison.Ordinal)
            ? Json("""{"status":{"effectiveAddress":"127.0.0.1","effectivePort":5050}}""")
            : Json(Exited ? """{"status":{"state":"Exited","exitCode":0}}""" :
                """{"status":{"state":"Running","containerId":"test-instance"}}""");
    }
 
    private static HttpResponseMessage Json(string value) => new(HttpStatusCode.OK)
    {
        Content = new StringContent(value, Encoding.UTF8, "application/json")
    };
}