Backport to release/3.8.0 so Elsa.Api.Client 3.8.0-rc2 exposes the
Resources/OutputConverters surface that Elsa Studio's release/3.8.0 branch
already consumes. Without it, Studio cannot build against a released client:
it was green against 3.8.0-preview.5397 (built from main) and broke when its
pin moved to 3.8.0-rc1 (built from this branch).
(cherry picked from commit d698e6b005)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
78 lines
3.9 KiB
C#
78 lines
3.9 KiB
C#
using System.Text.Json;
|
|
using Elsa.Common.Serialization;
|
|
using Elsa.Models;
|
|
using Elsa.Workflows.Api.Endpoints.OutputConverters.List;
|
|
using Elsa.Workflows.Models;
|
|
using FastEndpoints;
|
|
using NSubstitute;
|
|
|
|
namespace Elsa.Workflows.Api.UnitTests.OutputConverters;
|
|
|
|
public class OutputConverterEndpointTests
|
|
{
|
|
[Fact]
|
|
public void Configure_ExposesTheAuthorizedDescriptorRoute()
|
|
{
|
|
var endpoint = new List(Substitute.For<IOutputConverterRegistry>(), SerializationTypeRegistry.CreateDefault());
|
|
var definition = new EndpointDefinition(typeof(List), typeof(EmptyRequest), typeof(ListResponse<OutputConverterDescriptorModel>));
|
|
|
|
typeof(List).GetProperty("Definition", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic)!.SetValue(endpoint, definition);
|
|
endpoint.Configure();
|
|
|
|
Assert.Contains("/descriptors/output-converters", definition.Routes);
|
|
var permissions = (IEnumerable<string>)typeof(EndpointDefinition)
|
|
.GetProperty("AllowedPermissions", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic)!
|
|
.GetValue(definition)!;
|
|
Assert.Contains("read:*", permissions);
|
|
Assert.Contains("read:output-converters", permissions);
|
|
}
|
|
|
|
[Fact]
|
|
public void ListCompatible_FiltersThroughTheRegistryAndExposesOnlySafeDescriptorMetadata()
|
|
{
|
|
using var document = JsonDocument.Parse("""{"type":"object","properties":{"format":{"type":"string"}}}""");
|
|
var descriptor = new OutputConverterDescriptor(
|
|
"sample.to-text",
|
|
typeof(string),
|
|
typeof(string),
|
|
"Convert to text",
|
|
"Formats the source as text.",
|
|
document.RootElement);
|
|
var registry = Substitute.For<IOutputConverterRegistry>();
|
|
registry.FindCompatible(typeof(string), typeof(int)).Returns([descriptor]);
|
|
var endpoint = new List(registry, SerializationTypeRegistry.CreateDefault());
|
|
|
|
var listed = endpoint.TryListCompatible("String", "Int32", out var response, out var errors);
|
|
var model = Assert.Single(response.Items);
|
|
|
|
Assert.True(listed);
|
|
Assert.Empty(errors);
|
|
registry.Received(1).FindCompatible(typeof(string), typeof(int));
|
|
Assert.Equal("sample.to-text", model.Id);
|
|
Assert.Equal("String", model.SourceTypeName);
|
|
Assert.Equal("String", model.ResultTypeName);
|
|
Assert.Equal("Convert to text", model.DisplayName);
|
|
Assert.Equal("Formats the source as text.", model.Description);
|
|
Assert.Equal("object", model.SettingsSchema!.Value.GetProperty("type").GetString());
|
|
Assert.DoesNotContain(typeof(OutputConverterDescriptorModel).GetProperties(), property => property.Name is "SourceType" or "ResultType" or "ServiceKey" or "ServiceLifetime");
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(null, "String", "The sourceType query parameter is required.")]
|
|
[InlineData("String", null, "The destinationType query parameter is required.")]
|
|
[InlineData("Unsafe.Type", "String", "The sourceType query parameter must be a registered type alias or resolvable safe type name.")]
|
|
[InlineData("String", "Unsafe.Type", "The destinationType query parameter must be a registered type alias or resolvable safe type name.")]
|
|
public void TryListCompatible_RejectsMissingOrUnsafeQueryTypes(string? sourceTypeName, string? destinationTypeName, string expectedError)
|
|
{
|
|
var registry = Substitute.For<IOutputConverterRegistry>();
|
|
var endpoint = new List(registry, SerializationTypeRegistry.CreateDefault());
|
|
|
|
var listed = endpoint.TryListCompatible(sourceTypeName, destinationTypeName, out var response, out var errors);
|
|
|
|
Assert.False(listed);
|
|
Assert.Empty(response.Items);
|
|
Assert.Contains(expectedError, errors);
|
|
registry.DidNotReceive().FindCompatible(Arg.Any<Type>(), Arg.Any<Type>());
|
|
}
|
|
}
|