dotnet-sdk/test/Dapr.Client.Test/InvocationHandlerTests.cs

186 lines
6.6 KiB
C#

// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
#nullable enable
namespace Dapr.Client
{
public class InvocationHandlerTests
{
[Fact]
public void DaprEndpoint_InvalidScheme()
{
var handler = new InvocationHandler();
var ex = Assert.Throws<ArgumentException>(() =>
{
handler.DaprEndpoint = "ftp://localhost:3500";
});
Assert.Contains("The URI scheme of the Dapr endpoint must be http or https.", ex.Message);
}
[Fact]
public void DaprEndpoint_InvalidUri()
{
var handler = new InvocationHandler();
Assert.Throws<UriFormatException>(() =>
{
handler.DaprEndpoint = "";
});
// Exception message comes from the runtime, not validating it here
}
[Fact]
public void TryRewriteUri_FailsForNullUri()
{
var handler = new InvocationHandler();
Assert.False(handler.TryRewriteUri(null!, out var rewritten));
Assert.Null(rewritten);
}
[Fact]
public void TryRewriteUri_FailsForBadScheme()
{
var uri = new Uri("ftp://test", UriKind.Absolute);
var handler = new InvocationHandler();
Assert.False(handler.TryRewriteUri(uri, out var rewritten));
Assert.Null(rewritten);
}
[Fact]
public void TryRewriteUri_FailsForRelativeUris()
{
var uri = new Uri("test", UriKind.Relative);
var handler = new InvocationHandler();
Assert.False(handler.TryRewriteUri(uri, out var rewritten));
Assert.Null(rewritten);
}
[Theory]
[InlineData("http://bank", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("http://bank:3939", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("http://app-id.with.dots", "https://some.host:3499/v1.0/invoke/app-id.with.dots/method/")]
[InlineData("http://bank:3939/", "https://some.host:3499/v1.0/invoke/bank/method/")]
[InlineData("http://bank:3939/some/path", "https://some.host:3499/v1.0/invoke/bank/method/some/path")]
[InlineData("http://bank:3939/some/path?q=test&p=another#fragment", "https://some.host:3499/v1.0/invoke/bank/method/some/path?q=test&p=another#fragment")]
public void TryRewriteUri_RewritesUriToDaprInvoke(string uri, string expected)
{
var handler = new InvocationHandler()
{
DaprEndpoint = "https://some.host:3499",
};
Assert.True(handler.TryRewriteUri(new Uri(uri), out var rewritten));
Assert.Equal(expected, rewritten!.OriginalString);
}
[Fact]
public async Task SendAsync_InvalidUri_ThrowsException()
{
var handler = new InvocationHandler();
var ex = await Assert.ThrowsAsync<ArgumentException>(async () =>
{
await CallSendAsync(handler, new HttpRequestMessage(){ }); // No URI set
});
Assert.Contains("The request URI '' is not a valid Dapr service invocation destination.", ex.Message);
}
[Fact]
public async Task SendAsync_RewritesUri()
{
var uri = "http://bank/accounts/17?";
var capture = new CaptureHandler();
var handler = new InvocationHandler()
{
InnerHandler = capture,
DaprEndpoint = "https://localhost:5000",
DaprApiToken = null,
};
var request = new HttpRequestMessage(HttpMethod.Post, uri);
var response = await CallSendAsync(handler, request);
Assert.Equal("https://localhost:5000/v1.0/invoke/bank/method/accounts/17?", capture.RequestUri?.OriginalString);
Assert.Null(capture.DaprApiToken);
Assert.Equal(uri, request.RequestUri?.OriginalString);
Assert.False(request.Headers.TryGetValues("dapr-api-token", out _));
}
[Fact]
public async Task SendAsync_RewritesUri_AndAddsApiToken()
{
var uri = "http://bank/accounts/17?";
var capture = new CaptureHandler();
var handler = new InvocationHandler()
{
InnerHandler = capture,
DaprEndpoint = "https://localhost:5000",
DaprApiToken = "super-duper-secure",
};
var request = new HttpRequestMessage(HttpMethod.Post, uri);
var response = await CallSendAsync(handler, request);
Assert.Equal("https://localhost:5000/v1.0/invoke/bank/method/accounts/17?", capture.RequestUri?.OriginalString);
Assert.Equal("super-duper-secure", capture.DaprApiToken);
Assert.Equal(uri, request.RequestUri?.OriginalString);
Assert.False(request.Headers.TryGetValues("dapr-api-token", out _));
}
private async Task<HttpResponseMessage> CallSendAsync(InvocationHandler handler, HttpRequestMessage message, CancellationToken cancellationToken = default)
{
// SendAsync is protected, can't call it directly.
var method = handler.GetType().GetMethod("SendAsync", BindingFlags.Instance | BindingFlags.NonPublic);
Assert.NotNull(method);
try
{
return await (Task<HttpResponseMessage>)method!.Invoke(handler, new object[]{ message, cancellationToken, })!;
}
catch (TargetInvocationException tie) // reflection always adds an extra layer of exceptions.
{
throw tie.InnerException!;
}
}
private class CaptureHandler : HttpMessageHandler
{
public Uri? RequestUri { get; private set; }
public string? DaprApiToken { get; private set; }
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
RequestUri = request.RequestUri;
if (request.Headers.TryGetValues("dapr-api-token", out var tokens))
{
DaprApiToken = tokens.SingleOrDefault();
}
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK));
}
}
}
}