w4c-workflows-api/w4c-workflows-api.Tests/CredentialInjectorTests.cs

119 lines
3.9 KiB
C#
Raw Normal View History

2026-09-11 22:02:46 +00:00
using System.Text;
using System.Text.Json.Nodes;
using w4c_workflows.Models.Credentials;
using w4c_workflows.Services.Credentials;
using Xunit;
namespace w4c_workflows.Tests;
/// <summary>
/// The injection strategy turns a resolved credential into request material:
/// Basic/Bearer authorization, a custom header, or a query parameter.
/// </summary>
public class CredentialInjectorTests
{
private static readonly CredentialTypeCatalog Catalog = new();
private static HttpRequestMessage Request() => new(HttpMethod.Get, "https://api.example.com/items");
[Fact]
public void Basic_sets_the_authorization_header()
{
var request = Request();
var credential = new CredentialData("httpBasicAuth", new JsonObject
{
["username"] = "ada",
["password"] = "secret",
});
Assert.Null(CredentialInjector.Apply(credential, Catalog, request));
var expected = "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes("ada:secret"));
Assert.Equal(expected, request.Headers.Authorization!.ToString());
}
[Fact]
public void Bearer_sets_the_authorization_header_with_the_prefix()
{
var request = Request();
var credential = new CredentialData("httpBearerAuth", new JsonObject { ["token"] = "tok-123" });
Assert.Null(CredentialInjector.Apply(credential, Catalog, request));
Assert.Equal("Bearer tok-123", request.Headers.Authorization!.ToString());
}
[Fact]
public void Header_adds_a_custom_request_header()
{
var request = Request();
var credential = new CredentialData("httpHeaderAuth", new JsonObject
{
["name"] = "X-API-Key",
["value"] = "abc",
});
Assert.Null(CredentialInjector.Apply(credential, Catalog, request));
Assert.Equal("abc", request.Headers.GetValues("X-API-Key").Single());
}
[Fact]
public void Query_appends_a_parameter()
{
var request = Request();
var credential = new CredentialData("httpQueryAuth", new JsonObject
{
["name"] = "api_key",
["value"] = "abc",
});
Assert.Null(CredentialInjector.Apply(credential, Catalog, request));
Assert.Contains("api_key=abc", request.RequestUri!.Query);
}
[Fact]
public void A_missing_required_field_is_reported()
{
var request = Request();
var credential = new CredentialData("httpBearerAuth", new JsonObject());
var error = CredentialInjector.Apply(credential, Catalog, request);
Assert.NotNull(error);
Assert.Contains("token", error);
}
[Fact]
public void An_unknown_type_is_reported()
{
var request = Request();
var credential = new CredentialData("nope", new JsonObject());
Assert.Equal("unknown credential type 'nope'", CredentialInjector.Apply(credential, Catalog, request));
}
[Fact]
public void None_injection_leaves_the_request_untouched()
{
var request = Request();
var credential = new CredentialData("telegramApi", new JsonObject { ["token"] = "123:ABC" });
Assert.Null(CredentialInjector.Apply(credential, Catalog, request));
Assert.Equal("https://api.example.com/items", request.RequestUri!.ToString());
Assert.Null(request.Headers.Authorization);
}
[Fact]
public void Catalog_exposes_the_url_embedded_credential_types()
{
var telegram = Catalog.Get("telegramApi");
var discord = Catalog.Get("discordWebhook");
Assert.NotNull(telegram);
Assert.NotNull(discord);
Assert.Equal(CredentialInjectionKind.None, telegram!.Injection.Kind);
Assert.Equal(CredentialInjectionKind.None, discord!.Injection.Kind);
Assert.Contains(telegram.Fields, f => f.Name == "token");
Assert.Contains(discord.Fields, f => f.Name == "url");
}
}