mirror of https://github.com/dapr/dotnet-sdk.git
Fix pattern for tests that use HttpClient (#589)
This change introduces a better API for us to test the DaprClient or other HttpClient based APIs. This will resolve the flakiness problems that we're seeing with some of the actors tests. Fixes: #573 Fixes: #588 Additionally fixed an issue where DaprHttpInteractor was misuing HttpClientHandler. This would result in a new handler being created when it isn't needed.
This commit is contained in:
parent
847cd310c2
commit
94fc926170
|
@ -0,0 +1,18 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace System.Runtime.CompilerServices
|
||||
{
|
||||
/// <summary>
|
||||
/// Reserved to be used by the compiler for tracking metadata.
|
||||
/// This class should not be used by developers in source code.
|
||||
/// </summary>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
internal static class IsExternalInit
|
||||
{
|
||||
}
|
||||
|
||||
// This is a polyfill for init only properties in netcoreapp3.1
|
||||
}
|
|
@ -3,11 +3,16 @@
|
|||
<Import Project="dapr_common.props" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<LangVersion>9.0</LangVersion>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<WarnOnPackingNonPackableProject>false</WarnOnPackingNonPackableProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)\IsExternalInit.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Cls Compliant -->
|
||||
<PropertyGroup>
|
||||
<AssemblyClsCompliant>true</AssemblyClsCompliant>
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace Dapr.Actors.Client
|
|||
public class ActorProxyFactory : IActorProxyFactory
|
||||
{
|
||||
private ActorProxyOptions defaultOptions;
|
||||
private readonly HttpClientHandler handler;
|
||||
private readonly HttpMessageHandler handler;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ActorProxyOptions DefaultOptions
|
||||
|
@ -32,7 +32,16 @@ namespace Dapr.Actors.Client
|
|||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ActorProxyFactory"/> class.
|
||||
/// </summary>
|
||||
public ActorProxyFactory(ActorProxyOptions options = null, HttpClientHandler handler = null)
|
||||
[Obsolete("Use the constructor that accepts HttpMessageHandler. This will be removed in the future.")]
|
||||
public ActorProxyFactory(ActorProxyOptions options, HttpClientHandler handler)
|
||||
: this(options, (HttpMessageHandler)handler)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ActorProxyFactory"/> class.
|
||||
/// </summary>
|
||||
public ActorProxyFactory(ActorProxyOptions options = null, HttpMessageHandler handler = null)
|
||||
{
|
||||
this.defaultOptions = options ?? new ActorProxyOptions();
|
||||
this.handler = handler;
|
||||
|
|
|
@ -28,19 +28,20 @@ namespace Dapr.Actors
|
|||
private readonly JsonSerializerOptions jsonSerializerOptions = JsonSerializerDefaults.Web;
|
||||
private const string DaprEndpoint = Constants.DaprDefaultEndpoint;
|
||||
private readonly string daprPort;
|
||||
private static HttpClientHandler innerHandler = new HttpClientHandler();
|
||||
private HttpClient httpClient = null;
|
||||
private bool disposed = false;
|
||||
private readonly static HttpMessageHandler defaultHandler = new HttpClientHandler();
|
||||
private readonly HttpMessageHandler handler;
|
||||
private HttpClient httpClient;
|
||||
private bool disposed;
|
||||
private string daprApiToken;
|
||||
|
||||
public DaprHttpInteractor(
|
||||
HttpClientHandler clientHandler = null,
|
||||
HttpMessageHandler clientHandler = null,
|
||||
string apiToken = null)
|
||||
{
|
||||
// Get Dapr port from Environment Variable if it has been overridden.
|
||||
this.daprPort = Environment.GetEnvironmentVariable("DAPR_HTTP_PORT") ?? Constants.DaprDefaultPort;
|
||||
|
||||
innerHandler = clientHandler ?? new HttpClientHandler();
|
||||
this.handler = clientHandler ?? defaultHandler;
|
||||
this.daprApiToken = apiToken;
|
||||
this.httpClient = this.CreateHttpClient();
|
||||
}
|
||||
|
@ -433,7 +434,7 @@ namespace Dapr.Actors
|
|||
|
||||
private HttpClient CreateHttpClient()
|
||||
{
|
||||
return new HttpClient(innerHandler, false);
|
||||
return new HttpClient(this.handler, false);
|
||||
}
|
||||
|
||||
private void AddDaprApiTokenHeader(HttpRequestMessage request)
|
||||
|
|
|
@ -48,6 +48,8 @@ namespace Dapr.Client
|
|||
// property exposed for testing purposes
|
||||
internal string HttpEndpoint { get; private set; }
|
||||
|
||||
private Func<HttpClient> HttpClientFactory { get; set; }
|
||||
|
||||
// property exposed for testing purposes
|
||||
internal JsonSerializerOptions JsonSerializerOptions { get; private set; }
|
||||
|
||||
|
@ -71,6 +73,13 @@ namespace Dapr.Client
|
|||
return this;
|
||||
}
|
||||
|
||||
// Internal for testing of DaprClient
|
||||
internal DaprClientBuilder UseHttpClientFactory(Func<HttpClient> factory)
|
||||
{
|
||||
this.HttpClientFactory = factory;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the gRPC endpoint used by <see cref="DaprClient" /> for communicating with the Dapr runtime.
|
||||
/// </summary>
|
||||
|
@ -153,7 +162,8 @@ namespace Dapr.Client
|
|||
var client = new Autogenerated.Dapr.DaprClient(channel);
|
||||
|
||||
var apiTokenHeader = DaprClient.GetDaprApiTokenHeader(this.DaprApiToken);
|
||||
return new DaprClientGrpc(channel, client, new HttpClient(), httpEndpoint, this.JsonSerializerOptions, apiTokenHeader);
|
||||
var httpClient = HttpClientFactory is object ? HttpClientFactory() : new HttpClient();
|
||||
return new DaprClientGrpc(channel, client, httpClient, httpEndpoint, this.JsonSerializerOptions, apiTokenHeader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// Licensed under the MIT License.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Dapr.Actors.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b1f597635c44597fcecb493e2b1327033b29b1a98ac956a1a538664b68f87d45fbaada0438a15a6265e62864947cc067d8da3a7d93c5eb2fcbb850e396c8684dba74ea477d82a1bbb18932c0efb30b64ff1677f85ae833818707ac8b49ad8062ca01d2c89d8ab1843ae73e8ba9649cd28666b539444dcdee3639f95e2a099bb2")]
|
||||
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Dapr.Client.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b1f597635c44597fcecb493e2b1327033b29b1a98ac956a1a538664b68f87d45fbaada0438a15a6265e62864947cc067d8da3a7d93c5eb2fcbb850e396c8684dba74ea477d82a1bbb18932c0efb30b64ff1677f85ae833818707ac8b49ad8062ca01d2c89d8ab1843ae73e8ba9649cd28666b539444dcdee3639f95e2a099bb2")]
|
||||
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Dapr.AspNetCore.IntegrationTest, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b1f597635c44597fcecb493e2b1327033b29b1a98ac956a1a538664b68f87d45fbaada0438a15a6265e62864947cc067d8da3a7d93c5eb2fcbb850e396c8684dba74ea477d82a1bbb18932c0efb30b64ff1677f85ae833818707ac8b49ad8062ca01d2c89d8ab1843ae73e8ba9649cd28666b539444dcdee3639f95e2a099bb2")]
|
||||
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Dapr.AspNetCore.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b1f597635c44597fcecb493e2b1327033b29b1a98ac956a1a538664b68f87d45fbaada0438a15a6265e62864947cc067d8da3a7d93c5eb2fcbb850e396c8684dba74ea477d82a1bbb18932c0efb30b64ff1677f85ae833818707ac8b49ad8062ca01d2c89d8ab1843ae73e8ba9649cd28666b539444dcdee3639f95e2a099bb2")]
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
// ------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Dapr.Actors.Client;
|
||||
|
@ -16,107 +14,96 @@ namespace Dapr.Actors.Test
|
|||
{
|
||||
public class ApiTokenTests
|
||||
{
|
||||
[Fact(Skip = "Failing due to #573")]
|
||||
public void CreateProxyWithRemoting_WithApiToken()
|
||||
[Fact]
|
||||
public async Task CreateProxyWithRemoting_WithApiToken()
|
||||
{
|
||||
await using var client = TestClient.CreateForMessageHandler();
|
||||
|
||||
var actorId = new ActorId("abc");
|
||||
var handler = new TestHttpClientHandler();
|
||||
var options = new ActorProxyOptions
|
||||
{
|
||||
DaprApiToken = "test_token",
|
||||
};
|
||||
var factory = new ActorProxyFactory(options, handler);
|
||||
var proxy = factory.CreateActorProxy<ITestActor>(actorId, "TestActor");
|
||||
var task = proxy.SetCountAsync(1, new CancellationToken());
|
||||
|
||||
handler.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var headerValues = entry.Request.Headers.GetValues("dapr-api-token");
|
||||
var request = await client.CaptureHttpRequestAsync(async handler =>
|
||||
{
|
||||
var factory = new ActorProxyFactory(options, handler);
|
||||
var proxy = factory.CreateActorProxy<ITestActor>(actorId, "TestActor");
|
||||
await proxy.SetCountAsync(1, new CancellationToken());
|
||||
});
|
||||
|
||||
request.Dismiss();
|
||||
|
||||
var headerValues = request.Request.Headers.GetValues("dapr-api-token");
|
||||
headerValues.Should().Contain("test_token");
|
||||
}
|
||||
|
||||
[Fact(Skip = "Failing due to #573")]
|
||||
public void CreateProxyWithRemoting_WithNoApiToken()
|
||||
[Fact]
|
||||
public async Task CreateProxyWithRemoting_WithNoApiToken()
|
||||
{
|
||||
var actorId = new ActorId("abc");
|
||||
var handler = new TestHttpClientHandler();
|
||||
var factory = new ActorProxyFactory(null, handler);
|
||||
var proxy = factory.CreateActorProxy<ITestActor>(actorId, "TestActor");
|
||||
var task = proxy.SetCountAsync(1, new CancellationToken());
|
||||
await using var client = TestClient.CreateForMessageHandler();
|
||||
|
||||
handler.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
Action action = () => entry.Request.Headers.GetValues("dapr-api-token");
|
||||
action.Should().Throw<InvalidOperationException>();
|
||||
var actorId = new ActorId("abc");
|
||||
|
||||
var request = await client.CaptureHttpRequestAsync(async handler =>
|
||||
{
|
||||
var factory = new ActorProxyFactory(null, handler);
|
||||
var proxy = factory.CreateActorProxy<ITestActor>(actorId, "TestActor");
|
||||
await proxy.SetCountAsync(1, new CancellationToken());
|
||||
});
|
||||
|
||||
request.Dismiss();
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() =>
|
||||
{
|
||||
request.Request.Headers.GetValues("dapr-api-token");
|
||||
});
|
||||
}
|
||||
|
||||
[Fact(Skip = "Failing due to #573")]
|
||||
public void CreateProxyWithNoRemoting_WithApiToken()
|
||||
[Fact]
|
||||
public async Task CreateProxyWithNoRemoting_WithApiToken()
|
||||
{
|
||||
await using var client = TestClient.CreateForMessageHandler();
|
||||
|
||||
var actorId = new ActorId("abc");
|
||||
var handler = new TestHttpClientHandler();
|
||||
var options = new ActorProxyOptions
|
||||
{
|
||||
DaprApiToken = "test_token",
|
||||
};
|
||||
var factory = new ActorProxyFactory(options, handler);
|
||||
var proxy = factory.Create(actorId, "TestActor");
|
||||
var task = proxy.InvokeMethodAsync("SetCountAsync", 1, new CancellationToken());
|
||||
|
||||
handler.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var headerValues = entry.Request.Headers.GetValues("dapr-api-token");
|
||||
var request = await client.CaptureHttpRequestAsync(async handler =>
|
||||
{
|
||||
var factory = new ActorProxyFactory(options, handler);
|
||||
var proxy = factory.Create(actorId, "TestActor");
|
||||
await proxy.InvokeMethodAsync("SetCountAsync", 1, new CancellationToken());
|
||||
});
|
||||
|
||||
request.Dismiss();
|
||||
|
||||
var headerValues = request.Request.Headers.GetValues("dapr-api-token");
|
||||
headerValues.Should().Contain("test_token");
|
||||
}
|
||||
|
||||
[Fact(Skip = "Failing due to #573")]
|
||||
public void CreateProxyWithNoRemoting_WithNoApiToken()
|
||||
[Fact]
|
||||
public async Task CreateProxyWithNoRemoting_WithNoApiToken()
|
||||
{
|
||||
await using var client = TestClient.CreateForMessageHandler();
|
||||
|
||||
var actorId = new ActorId("abc");
|
||||
var handler = new TestHttpClientHandler();
|
||||
var factory = new ActorProxyFactory(null, handler);
|
||||
var proxy = factory.Create(actorId, "TestActor");
|
||||
var task = proxy.InvokeMethodAsync("SetCountAsync", 1, new CancellationToken());
|
||||
|
||||
handler.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
Action action = () => entry.Request.Headers.GetValues("dapr-api-token");
|
||||
action.Should().Throw<InvalidOperationException>();
|
||||
}
|
||||
|
||||
|
||||
public class Entry
|
||||
{
|
||||
public Entry(HttpRequestMessage request)
|
||||
var request = await client.CaptureHttpRequestAsync(async handler =>
|
||||
{
|
||||
this.Request = request;
|
||||
var factory = new ActorProxyFactory(null, handler);
|
||||
var proxy = factory.Create(actorId, "TestActor");
|
||||
await proxy.InvokeMethodAsync("SetCountAsync", 1, new CancellationToken());
|
||||
});
|
||||
|
||||
this.Completion = new TaskCompletionSource<HttpResponseMessage>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
}
|
||||
request.Dismiss();
|
||||
|
||||
public TaskCompletionSource<HttpResponseMessage> Completion { get; }
|
||||
|
||||
public HttpRequestMessage Request { get; }
|
||||
}
|
||||
|
||||
private class TestHttpClientHandler : HttpClientHandler
|
||||
{
|
||||
public TestHttpClientHandler()
|
||||
Assert.Throws<InvalidOperationException>(() =>
|
||||
{
|
||||
this.Requests = new ConcurrentQueue<Entry>();
|
||||
}
|
||||
|
||||
public ConcurrentQueue<Entry> Requests { get; }
|
||||
|
||||
public Action<Entry> Handler { get; set; }
|
||||
|
||||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
var entry = new Entry(request);
|
||||
this.Handler?.Invoke(entry);
|
||||
this.Requests.Enqueue(entry);
|
||||
|
||||
using (cancellationToken.Register(() => entry.Completion.TrySetCanceled()))
|
||||
{
|
||||
return await entry.Completion.Task.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
request.Request.Headers.GetValues("dapr-api-token");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<PropertyGroup>
|
||||
<TargetFrameworks>netcoreapp3.1;net5</TargetFrameworks>
|
||||
<RootNamespace>Dapr.Actors</RootNamespace>
|
||||
<DefineConstants>$(DefineConstants);ACTORS</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -20,6 +21,11 @@
|
|||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\Shared\GrpcUtils.cs" />
|
||||
<Compile Include="..\Shared\TestClient.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Dapr.Actors\Dapr.Actors.csproj" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -5,15 +5,13 @@
|
|||
|
||||
namespace Dapr.Actors.Test
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Security;
|
||||
using System.Security.Authentication;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
@ -23,224 +21,226 @@ namespace Dapr.Actors.Test
|
|||
/// </summary>
|
||||
public class DaprHttpInteractorTest
|
||||
{
|
||||
public class Entry
|
||||
[Fact]
|
||||
public async Task GetState_ValidateRequest()
|
||||
{
|
||||
public Entry(HttpRequestMessage request)
|
||||
{
|
||||
this.Request = request;
|
||||
await using var client = TestClient.CreateForDaprHttpInterator();
|
||||
|
||||
this.Completion = new TaskCompletionSource<HttpResponseMessage>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
}
|
||||
|
||||
public TaskCompletionSource<HttpResponseMessage> Completion { get; }
|
||||
|
||||
public HttpRequestMessage Request { get; }
|
||||
}
|
||||
|
||||
private class TestHttpClientHandler : HttpClientHandler
|
||||
{
|
||||
public TestHttpClientHandler()
|
||||
{
|
||||
this.Requests = new ConcurrentQueue<Entry>();
|
||||
}
|
||||
|
||||
public ConcurrentQueue<Entry> Requests { get; }
|
||||
|
||||
public Action<Entry> Handler { get; set; }
|
||||
|
||||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
var entry = new Entry(request);
|
||||
this.Handler?.Invoke(entry);
|
||||
this.Requests.Enqueue(entry);
|
||||
|
||||
using (cancellationToken.Register(() => entry.Completion.TrySetCanceled()))
|
||||
{
|
||||
return await entry.Completion.Task.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact(Skip = "Failing due to #573")]
|
||||
public void GetState_ValidateRequest()
|
||||
{
|
||||
var handler = new TestHttpClientHandler();
|
||||
var httpInteractor = new DaprHttpInteractor(handler);
|
||||
var actorType = "ActorType_Test";
|
||||
var actorId = "ActorId_Test";
|
||||
var keyName = "StateKey_Test";
|
||||
|
||||
var task = httpInteractor.GetStateAsync(actorType, actorId, keyName);
|
||||
var request = await client.CaptureHttpRequestAsync(async httpInteractor =>
|
||||
{
|
||||
await httpInteractor.GetStateAsync(actorType, actorId, keyName);
|
||||
});
|
||||
|
||||
handler.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var actualPath = entry.Request.RequestUri.LocalPath.TrimStart('/');
|
||||
request.Dismiss();
|
||||
|
||||
var actualPath = request.Request.RequestUri.LocalPath.TrimStart('/');
|
||||
var expectedPath = string.Format(CultureInfo.InvariantCulture, Constants.ActorStateKeyRelativeUrlFormat, actorType, actorId, keyName);
|
||||
|
||||
actualPath.Should().Be(expectedPath);
|
||||
entry.Request.Method.Should().Be(HttpMethod.Get);
|
||||
request.Request.Method.Should().Be(HttpMethod.Get);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SaveStateTransactionally_ValidateRequest()
|
||||
public async Task SaveStateTransactionally_ValidateRequest()
|
||||
{
|
||||
var handler = new TestHttpClientHandler();
|
||||
var httpInteractor = new DaprHttpInteractor(handler);
|
||||
await using var client = TestClient.CreateForDaprHttpInterator();
|
||||
|
||||
var actorType = "ActorType_Test";
|
||||
var actorId = "ActorId_Test";
|
||||
var data = "StateData";
|
||||
|
||||
var task = httpInteractor.SaveStateTransactionallyAsync(actorType, actorId, data);
|
||||
var request = await client.CaptureHttpRequestAsync(async httpInteractor =>
|
||||
{
|
||||
await httpInteractor.SaveStateTransactionallyAsync(actorType, actorId, data);
|
||||
});
|
||||
|
||||
handler.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var actualPath = entry.Request.RequestUri.LocalPath.TrimStart('/');
|
||||
request.Dismiss();
|
||||
|
||||
var actualPath = request.Request.RequestUri.LocalPath.TrimStart('/');
|
||||
var expectedPath = string.Format(CultureInfo.InvariantCulture, Constants.ActorStateRelativeUrlFormat, actorType, actorId);
|
||||
|
||||
actualPath.Should().Be(expectedPath);
|
||||
entry.Request.Method.Should().Be(HttpMethod.Put);
|
||||
request.Request.Method.Should().Be(HttpMethod.Put);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InvokeActorMethodWithoutRemoting_ValidateRequest()
|
||||
public async Task InvokeActorMethodWithoutRemoting_ValidateRequest()
|
||||
{
|
||||
var handler = new TestHttpClientHandler();
|
||||
var httpInteractor = new DaprHttpInteractor(handler);
|
||||
await using var client = TestClient.CreateForDaprHttpInterator();
|
||||
|
||||
var actorType = "ActorType_Test";
|
||||
var actorId = "ActorId_Test";
|
||||
var methodName = "MethodName";
|
||||
var payload = "JsonData";
|
||||
|
||||
var task = httpInteractor.InvokeActorMethodWithoutRemotingAsync(actorType, actorId, methodName, payload);
|
||||
var request = await client.CaptureHttpRequestAsync(async httpInteractor =>
|
||||
{
|
||||
await httpInteractor.InvokeActorMethodWithoutRemotingAsync(actorType, actorId, methodName, payload);
|
||||
});
|
||||
|
||||
handler.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var actualPath = entry.Request.RequestUri.LocalPath.TrimStart('/');
|
||||
request.Dismiss();
|
||||
|
||||
var actualPath = request.Request.RequestUri.LocalPath.TrimStart('/');
|
||||
var expectedPath = string.Format(CultureInfo.InvariantCulture, Constants.ActorMethodRelativeUrlFormat, actorType, actorId, methodName);
|
||||
|
||||
actualPath.Should().Be(expectedPath);
|
||||
entry.Request.Method.Should().Be(HttpMethod.Put);
|
||||
request.Request.Method.Should().Be(HttpMethod.Put);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RegisterReminder_ValidateRequest()
|
||||
public async Task RegisterReminder_ValidateRequest()
|
||||
{
|
||||
var handler = new TestHttpClientHandler();
|
||||
var httpInteractor = new DaprHttpInteractor(handler);
|
||||
await using var client = TestClient.CreateForDaprHttpInterator();
|
||||
|
||||
var actorType = "ActorType_Test";
|
||||
var actorId = "ActorId_Test";
|
||||
var reminderName = "ReminderName";
|
||||
var payload = "JsonData";
|
||||
|
||||
var task = httpInteractor.RegisterReminderAsync(actorType, actorId, reminderName, payload);
|
||||
var request = await client.CaptureHttpRequestAsync(async httpInteractor =>
|
||||
{
|
||||
await httpInteractor.RegisterReminderAsync(actorType, actorId, reminderName, payload);
|
||||
});
|
||||
|
||||
handler.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var actualPath = entry.Request.RequestUri.LocalPath.TrimStart('/');
|
||||
request.Dismiss();
|
||||
|
||||
var actualPath = request.Request.RequestUri.LocalPath.TrimStart('/');
|
||||
var expectedPath = string.Format(CultureInfo.InvariantCulture, Constants.ActorReminderRelativeUrlFormat, actorType, actorId, reminderName);
|
||||
|
||||
actualPath.Should().Be(expectedPath);
|
||||
entry.Request.Method.Should().Be(HttpMethod.Put);
|
||||
request.Request.Method.Should().Be(HttpMethod.Put);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UnregisterReminder_ValidateRequest()
|
||||
public async Task UnregisterReminder_ValidateRequest()
|
||||
{
|
||||
var handler = new TestHttpClientHandler();
|
||||
var httpInteractor = new DaprHttpInteractor(handler);
|
||||
await using var client = TestClient.CreateForDaprHttpInterator();
|
||||
|
||||
var actorType = "ActorType_Test";
|
||||
var actorId = "ActorId_Test";
|
||||
var reminderName = "ReminderName";
|
||||
|
||||
var task = httpInteractor.UnregisterReminderAsync(actorType, actorId, reminderName);
|
||||
var request = await client.CaptureHttpRequestAsync(async httpInteractor =>
|
||||
{
|
||||
await httpInteractor.UnregisterReminderAsync(actorType, actorId, reminderName);
|
||||
});
|
||||
|
||||
handler.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var actualPath = entry.Request.RequestUri.LocalPath.TrimStart('/');
|
||||
request.Dismiss();
|
||||
|
||||
var actualPath = request.Request.RequestUri.LocalPath.TrimStart('/');
|
||||
var expectedPath = string.Format(CultureInfo.InvariantCulture, Constants.ActorReminderRelativeUrlFormat, actorType, actorId, reminderName);
|
||||
|
||||
actualPath.Should().Be(expectedPath);
|
||||
entry.Request.Method.Should().Be(HttpMethod.Delete);
|
||||
request.Request.Method.Should().Be(HttpMethod.Delete);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RegisterTimer_ValidateRequest()
|
||||
public async Task RegisterTimer_ValidateRequest()
|
||||
{
|
||||
var handler = new TestHttpClientHandler();
|
||||
var httpInteractor = new DaprHttpInteractor(handler);
|
||||
await using var client = TestClient.CreateForDaprHttpInterator();
|
||||
|
||||
var actorType = "ActorType_Test";
|
||||
var actorId = "ActorId_Test";
|
||||
var timerName = "TimerName";
|
||||
var payload = "JsonData";
|
||||
|
||||
var task = httpInteractor.RegisterTimerAsync(actorType, actorId, timerName, payload);
|
||||
var request = await client.CaptureHttpRequestAsync(async httpInteractor =>
|
||||
{
|
||||
await httpInteractor.RegisterTimerAsync(actorType, actorId, timerName, payload);
|
||||
});
|
||||
|
||||
handler.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var actualPath = entry.Request.RequestUri.LocalPath.TrimStart('/');
|
||||
request.Dismiss();
|
||||
|
||||
var actualPath = request.Request.RequestUri.LocalPath.TrimStart('/');
|
||||
var expectedPath = string.Format(CultureInfo.InvariantCulture, Constants.ActorTimerRelativeUrlFormat, actorType, actorId, timerName);
|
||||
|
||||
actualPath.Should().Be(expectedPath);
|
||||
entry.Request.Method.Should().Be(HttpMethod.Put);
|
||||
request.Request.Method.Should().Be(HttpMethod.Put);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UnregisterTimer_ValidateRequest()
|
||||
public async Task UnregisterTimer_ValidateRequest()
|
||||
{
|
||||
var handler = new TestHttpClientHandler();
|
||||
var httpInteractor = new DaprHttpInteractor(handler);
|
||||
await using var client = TestClient.CreateForDaprHttpInterator();
|
||||
|
||||
var actorType = "ActorType_Test";
|
||||
var actorId = "ActorId_Test";
|
||||
var timerName = "TimerName";
|
||||
|
||||
var task = httpInteractor.UnregisterTimerAsync(actorType, actorId, timerName);
|
||||
var request = await client.CaptureHttpRequestAsync(async httpInteractor =>
|
||||
{
|
||||
await httpInteractor.UnregisterTimerAsync(actorType, actorId, timerName);
|
||||
});
|
||||
|
||||
handler.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var actualPath = entry.Request.RequestUri.LocalPath.TrimStart('/');
|
||||
request.Dismiss();
|
||||
|
||||
var actualPath = request.Request.RequestUri.LocalPath.TrimStart('/');
|
||||
var expectedPath = string.Format(CultureInfo.InvariantCulture, Constants.ActorTimerRelativeUrlFormat, actorType, actorId, timerName);
|
||||
|
||||
actualPath.Should().Be(expectedPath);
|
||||
entry.Request.Method.Should().Be(HttpMethod.Delete);
|
||||
request.Request.Method.Should().Be(HttpMethod.Delete);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Call_WithApiTokenSet()
|
||||
public async Task Call_WithApiTokenSet()
|
||||
{
|
||||
var handler = new TestHttpClientHandler();
|
||||
var httpInteractor = new DaprHttpInteractor(handler, apiToken: "test_token");
|
||||
await using var client = TestClient.CreateForDaprHttpInterator(apiToken: "test_token");
|
||||
|
||||
var actorType = "ActorType_Test";
|
||||
var actorId = "ActorId_Test";
|
||||
var timerName = "TimerName";
|
||||
|
||||
var task = httpInteractor.UnregisterTimerAsync(actorType, actorId, timerName);
|
||||
var request = await client.CaptureHttpRequestAsync(async httpInteractor =>
|
||||
{
|
||||
await httpInteractor.UnregisterTimerAsync(actorType, actorId, timerName);
|
||||
});
|
||||
|
||||
handler.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
entry.Request.Headers.TryGetValues("dapr-api-token", out var headerValues);
|
||||
request.Dismiss();
|
||||
|
||||
request.Request.Headers.TryGetValues("dapr-api-token", out var headerValues);
|
||||
headerValues.Count().Should().Be(1);
|
||||
headerValues.First().Should().Be("test_token");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Call_WithoutApiToken()
|
||||
public async Task Call_WithoutApiToken()
|
||||
{
|
||||
var handler = new TestHttpClientHandler();
|
||||
var httpInteractor = new DaprHttpInteractor(handler);
|
||||
await using var client = TestClient.CreateForDaprHttpInterator();
|
||||
|
||||
var actorType = "ActorType_Test";
|
||||
var actorId = "ActorId_Test";
|
||||
var timerName = "TimerName";
|
||||
|
||||
var task = httpInteractor.UnregisterTimerAsync(actorType, actorId, timerName);
|
||||
var request = await client.CaptureHttpRequestAsync(async httpInteractor =>
|
||||
{
|
||||
await httpInteractor.UnregisterTimerAsync(actorType, actorId, timerName);
|
||||
});
|
||||
|
||||
handler.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
entry.Request.Headers.TryGetValues("dapr-api-token", out var headerValues);
|
||||
request.Dismiss();
|
||||
|
||||
request.Request.Headers.TryGetValues("dapr-api-token", out var headerValues);
|
||||
headerValues.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Call_ValidateUnsuccessfulResponse()
|
||||
{
|
||||
var handler = new TestHttpClientHandler();
|
||||
var httpInteractor = new DaprHttpInteractor(handler);
|
||||
await using var client = TestClient.CreateForDaprHttpInterator();
|
||||
|
||||
var actorType = "ActorType_Test";
|
||||
var actorId = "ActorId_Test";
|
||||
var timerName = "TimerName";
|
||||
|
||||
var task = httpInteractor.UnregisterTimerAsync(actorType, actorId, timerName);
|
||||
handler.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var request = await client.CaptureHttpRequestAsync(async httpInteractor =>
|
||||
{
|
||||
await httpInteractor.UnregisterTimerAsync(actorType, actorId, timerName);
|
||||
});
|
||||
|
||||
request.Dismiss();
|
||||
|
||||
var error = new DaprError()
|
||||
{
|
||||
|
@ -253,43 +253,54 @@ namespace Dapr.Actors.Test
|
|||
Content = new StringContent(JsonSerializer.Serialize(error))
|
||||
};
|
||||
|
||||
entry.Completion.SetResult(message);
|
||||
await FluentActions.Awaiting(async () => await task).Should().ThrowAsync<DaprApiException>();
|
||||
await Assert.ThrowsAsync<DaprApiException>(async () =>
|
||||
{
|
||||
await request.CompleteAsync(message);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Call_ValidateUnsuccessful404Response()
|
||||
{
|
||||
var handler = new TestHttpClientHandler();
|
||||
var httpInteractor = new DaprHttpInteractor(handler);
|
||||
await using var client = TestClient.CreateForDaprHttpInterator();
|
||||
|
||||
var actorType = "ActorType_Test";
|
||||
var actorId = "ActorId_Test";
|
||||
var timerName = "TimerName";
|
||||
|
||||
var task = httpInteractor.UnregisterTimerAsync(actorType, actorId, timerName);
|
||||
handler.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var request = await client.CaptureHttpRequestAsync(async httpInteractor =>
|
||||
{
|
||||
await httpInteractor.UnregisterTimerAsync(actorType, actorId, timerName);
|
||||
});
|
||||
|
||||
var message = new HttpResponseMessage(HttpStatusCode.NotFound);
|
||||
|
||||
entry.Completion.SetResult(message);
|
||||
await FluentActions.Awaiting(async () => await task).Should().ThrowAsync<DaprApiException>();
|
||||
await Assert.ThrowsAsync<DaprApiException>(async () =>
|
||||
{
|
||||
await request.CompleteAsync(message);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Call_ValidateUnauthorizedResponse()
|
||||
{
|
||||
var handler = new TestHttpClientHandler();
|
||||
var httpInteractor = new DaprHttpInteractor(handler);
|
||||
await using var client = TestClient.CreateForDaprHttpInterator();
|
||||
|
||||
var actorType = "ActorType_Test";
|
||||
var actorId = "ActorId_Test";
|
||||
var timerName = "TimerName";
|
||||
|
||||
var task = httpInteractor.UnregisterTimerAsync(actorType, actorId, timerName);
|
||||
handler.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var request = await client.CaptureHttpRequestAsync(async httpInteractor =>
|
||||
{
|
||||
await httpInteractor.UnregisterTimerAsync(actorType, actorId, timerName);
|
||||
});
|
||||
|
||||
var message = new HttpResponseMessage(HttpStatusCode.Unauthorized);
|
||||
entry.Completion.SetResult(message);
|
||||
await FluentActions.Awaiting(async () => await task).Should().ThrowAsync<AuthenticationException>();
|
||||
|
||||
await Assert.ThrowsAsync<AuthenticationException>(async () =>
|
||||
{
|
||||
await request.CompleteAsync(message);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,8 +23,4 @@
|
|||
<ProjectReference Include="..\Dapr.AspNetCore.IntegrationTest.App\Dapr.AspNetCore.IntegrationTest.App.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\Shared\TestHttpClient.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -18,8 +18,8 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\Shared\TestHttpClient.cs" />
|
||||
<Compile Include="..\Shared\GrpcUtils.cs" />
|
||||
<Compile Include="..\Shared\TestClient.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -37,9 +37,8 @@ namespace Dapr.AspNetCore.Test
|
|||
[Fact]
|
||||
public void DaprClientBuilder_DoesNotOverrideUserGrpcChannelOptions()
|
||||
{
|
||||
var httpClient = new TestHttpClient();
|
||||
var builder = new DaprClientBuilder();
|
||||
var daprClient = builder.UseGrpcChannelOptions(new GrpcChannelOptions { HttpClient = httpClient }).Build();
|
||||
var daprClient = builder.UseGrpcChannelOptions(new GrpcChannelOptions()).Build();
|
||||
Assert.False(builder.GrpcChannelOptions.ThrowOperationCanceledOnCancellation);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,13 +6,11 @@
|
|||
namespace Dapr.AspNetCore.Test
|
||||
{
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Dapr.Client;
|
||||
using Dapr.Client.Autogen.Grpc.v1;
|
||||
using FluentAssertions;
|
||||
using Grpc.Net.Client;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
@ -25,37 +23,41 @@ namespace Dapr.AspNetCore.Test
|
|||
[Fact]
|
||||
public async Task BindAsync_WithoutMatchingRouteValue_ReportsError()
|
||||
{
|
||||
var binder = new StateEntryModelBinder("testStore", "test", isStateEntry: false, typeof(Widget));
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var httpClient = new TestHttpClient();
|
||||
var context = CreateContext(CreateServices(httpClient));
|
||||
var binder = new StateEntryModelBinder("testStore", "test", isStateEntry: false, typeof(Widget));
|
||||
var context = CreateContext(CreateServices(client.InnerClient));
|
||||
|
||||
await binder.BindModelAsync(context);
|
||||
|
||||
context.Result.IsModelSet.Should().BeFalse();
|
||||
context.ModelState.ErrorCount.Should().Be(1);
|
||||
context.ModelState["testParameter"].Errors.Count.Should().Be(1);
|
||||
|
||||
httpClient.Requests.Count.Should().Be(0);
|
||||
// No request to state store, validated by disposing client
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BindAsync_CanBindValue()
|
||||
{
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var binder = new StateEntryModelBinder("testStore", "id", isStateEntry: false, typeof(Widget));
|
||||
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var context = CreateContext(CreateServices(httpClient));
|
||||
var context = CreateContext(CreateServices(client.InnerClient));
|
||||
context.HttpContext.Request.RouteValues["id"] = "test";
|
||||
var task = binder.BindModelAsync(context);
|
||||
|
||||
var request = await client.CaptureGrpcRequestAsync(async _ =>
|
||||
{
|
||||
await binder.BindModelAsync(context);
|
||||
});
|
||||
|
||||
// Create Response & Respond
|
||||
var state = new Widget() { Size = "small", Color = "yellow", };
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
await SendResponseWithState(state, entry);
|
||||
await SendResponseWithState(state, request);
|
||||
|
||||
// Get response and validate
|
||||
await task;
|
||||
context.Result.IsModelSet.Should().BeTrue();
|
||||
context.Result.Model.As<Widget>().Size.Should().Be("small");
|
||||
context.Result.Model.As<Widget>().Color.Should().Be("yellow");
|
||||
|
@ -67,21 +69,24 @@ namespace Dapr.AspNetCore.Test
|
|||
[Fact]
|
||||
public async Task BindAsync_CanBindStateEntry()
|
||||
{
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var binder = new StateEntryModelBinder("testStore", "id", isStateEntry: true, typeof(Widget));
|
||||
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var context = CreateContext(CreateServices(httpClient));
|
||||
var context = CreateContext(CreateServices(client.InnerClient));
|
||||
context.HttpContext.Request.RouteValues["id"] = "test";
|
||||
var task = binder.BindModelAsync(context);
|
||||
|
||||
var request = await client.CaptureGrpcRequestAsync(async _ =>
|
||||
{
|
||||
await binder.BindModelAsync(context);
|
||||
});
|
||||
|
||||
// Create Response & Respond
|
||||
var state = new Widget() { Size = "small", Color = "yellow", };
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
await SendResponseWithState(state, entry);
|
||||
await SendResponseWithState(state, request);
|
||||
|
||||
// Get response and validate
|
||||
await task;
|
||||
context.Result.IsModelSet.Should().BeTrue();
|
||||
context.Result.Model.As<StateEntry<Widget>>().Key.Should().Be("test");
|
||||
context.Result.Model.As<StateEntry<Widget>>().Value.Size.Should().Be("small");
|
||||
|
@ -94,18 +99,21 @@ namespace Dapr.AspNetCore.Test
|
|||
[Fact]
|
||||
public async Task BindAsync_ReturnsNullForNonExistentStateEntry()
|
||||
{
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var binder = new StateEntryModelBinder("testStore", "id", isStateEntry: false, typeof(Widget));
|
||||
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var context = CreateContext(CreateServices(httpClient));
|
||||
var context = CreateContext(CreateServices(client.InnerClient));
|
||||
context.HttpContext.Request.RouteValues["id"] = "test";
|
||||
var task = binder.BindModelAsync(context);
|
||||
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
await SendResponseWithState<string>(null, entry);
|
||||
var request = await client.CaptureGrpcRequestAsync(async _ =>
|
||||
{
|
||||
await binder.BindModelAsync(context);
|
||||
});
|
||||
|
||||
await SendResponseWithState<string>(null, request);
|
||||
|
||||
await task;
|
||||
context.ModelState.IsValid.Should().BeTrue();
|
||||
context.Result.IsModelSet.Should().BeFalse();
|
||||
context.Result.Should().Be(ModelBindingResult.Failed());
|
||||
|
@ -114,18 +122,21 @@ namespace Dapr.AspNetCore.Test
|
|||
[Fact]
|
||||
public async Task BindAsync_WithStateEntry_ForNonExistentStateEntry()
|
||||
{
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var binder = new StateEntryModelBinder("testStore", "id", isStateEntry: true, typeof(Widget));
|
||||
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var context = CreateContext(CreateServices(httpClient));
|
||||
var context = CreateContext(CreateServices(client.InnerClient));
|
||||
context.HttpContext.Request.RouteValues["id"] = "test";
|
||||
var task = binder.BindModelAsync(context);
|
||||
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
await SendResponseWithState<string>(null, entry);
|
||||
var request = await client.CaptureGrpcRequestAsync(async _ =>
|
||||
{
|
||||
await binder.BindModelAsync(context);
|
||||
});
|
||||
|
||||
await SendResponseWithState<string>(null, request);
|
||||
|
||||
await task;
|
||||
context.ModelState.IsValid.Should().BeTrue();
|
||||
context.Result.IsModelSet.Should().BeTrue();
|
||||
((StateEntry<Widget>)context.Result.Model).Value.Should().BeNull();
|
||||
|
@ -148,27 +159,21 @@ namespace Dapr.AspNetCore.Test
|
|||
};
|
||||
}
|
||||
|
||||
private async Task SendResponseWithState<T>(T state, TestHttpClient.Entry entry)
|
||||
private async Task SendResponseWithState<T>(T state, TestClient<DaprClient>.TestGrpcRequest request)
|
||||
{
|
||||
var stateData = TypeConverters.ToJsonByteString(state, new JsonSerializerOptions(JsonSerializerDefaults.Web));
|
||||
var stateResponse = new GetStateResponse
|
||||
var stateResponse = new GetStateResponse()
|
||||
{
|
||||
Data = stateData,
|
||||
Etag = "test",
|
||||
};
|
||||
|
||||
var streamContent = await GrpcUtils.CreateResponseContent(stateResponse);
|
||||
var response = GrpcUtils.CreateResponse(HttpStatusCode.OK, streamContent);
|
||||
entry.Completion.SetResult(response);
|
||||
await request.CompleteWithMessageAsync(stateResponse);
|
||||
}
|
||||
|
||||
private static IServiceProvider CreateServices(TestHttpClient httpClient)
|
||||
private static IServiceProvider CreateServices(DaprClient daprClient)
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions { HttpClient = httpClient })
|
||||
.Build();
|
||||
|
||||
services.AddSingleton(daprClient);
|
||||
return services.BuildServiceProvider();
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\Shared\AppCallbackClient.cs" />
|
||||
<Compile Include="..\Shared\TestHttpClient.cs" />
|
||||
<Compile Include="..\Shared\TestClient.cs" />
|
||||
<Compile Include="..\Shared\GrpcUtils.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -5,12 +5,9 @@
|
|||
|
||||
namespace Dapr.Client.Test
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using FluentAssertions;
|
||||
using Grpc.Net.Client;
|
||||
using Xunit;
|
||||
using Autogenerated = Dapr.Client.Autogen.Grpc.v1;
|
||||
|
||||
|
@ -20,19 +17,19 @@ namespace Dapr.Client.Test
|
|||
public async Task DaprCall_WithApiTokenSet()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions { HttpClient = httpClient })
|
||||
.UseDaprApiToken("test_token")
|
||||
.Build();
|
||||
await using var client = TestClient.CreateForDaprClient(c => c.UseDaprApiToken("test_token"));
|
||||
|
||||
var task = daprClient.GetSecretAsync("testStore", "test_key");
|
||||
var request = await client.CaptureGrpcRequestAsync(async daprClient =>
|
||||
{
|
||||
return await daprClient.GetSecretAsync("testStore", "test_key");
|
||||
});
|
||||
|
||||
request.Dismiss();
|
||||
|
||||
// Get Request and validate
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var request = await GrpcUtils.GetRequestFromRequestMessageAsync<Autogenerated.GetSecretRequest>(entry.Request);
|
||||
var envelope = await request.GetRequestEnvelopeAsync<Autogenerated.GetSecretRequest>();
|
||||
|
||||
entry.Request.Headers.TryGetValues("dapr-api-token", out var headerValues);
|
||||
request.Request.Headers.TryGetValues("dapr-api-token", out var headerValues);
|
||||
headerValues.Count().Should().Be(1);
|
||||
headerValues.First().Should().Be("test_token");
|
||||
}
|
||||
|
@ -41,18 +38,19 @@ namespace Dapr.Client.Test
|
|||
public async Task DaprCall_WithoutApiToken()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions { HttpClient = httpClient })
|
||||
.Build();
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var task = daprClient.GetSecretAsync("testStore", "test_key");
|
||||
var request = await client.CaptureGrpcRequestAsync(async daprClient =>
|
||||
{
|
||||
return await daprClient.GetSecretAsync("testStore", "test_key");
|
||||
});
|
||||
|
||||
request.Dismiss();
|
||||
|
||||
// Get Request and validate
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var request = await GrpcUtils.GetRequestFromRequestMessageAsync<Autogenerated.GetSecretRequest>(entry.Request);
|
||||
var envelope = await request.GetRequestEnvelopeAsync<Autogenerated.GetSecretRequest>();
|
||||
|
||||
entry.Request.Headers.TryGetValues("dapr-api-token", out var headerValues);
|
||||
request.Request.Headers.TryGetValues("dapr-api-token", out var headerValues);
|
||||
headerValues.Should().BeNull();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,14 +13,10 @@ namespace Dapr.Client.Test
|
|||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Dapr.Client;
|
||||
using FluentAssertions;
|
||||
using Grpc.Core;
|
||||
using Grpc.Net.Client;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
// Most of the InvokeMethodAsync functionality on DaprClient is non-abstract methods that
|
||||
// forward to a few different entry points to create a message, or send a message and process
|
||||
// forward to a few different request points to create a message, or send a message and process
|
||||
// its result.
|
||||
//
|
||||
// So we write basic tests for all of those that every parameter passing is correct, and then
|
||||
|
@ -37,270 +33,232 @@ namespace Dapr.Client.Test
|
|||
[Fact]
|
||||
public async Task InvokeMethodAsync_VoidVoidNoHttpMethod_Success()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var client = new DaprClientGrpc(
|
||||
GrpcChannel.ForAddress("http://localhost"),
|
||||
Mock.Of<global::Dapr.Client.Autogen.Grpc.v1.Dapr.DaprClient>(),
|
||||
httpClient,
|
||||
new Uri("https://test-endpoint:3501"),
|
||||
jsonSerializerOptions,
|
||||
default);
|
||||
await using var client = TestClient.CreateForDaprClient(c =>
|
||||
{
|
||||
c.UseGrpcEndpoint("http://localhost").UseHttpEndpoint("https://test-endpoint:3501").UseJsonSerializationOptions(this.jsonSerializerOptions);
|
||||
});
|
||||
|
||||
var task = client.InvokeMethodAsync("app1", "mymethod");
|
||||
var request = await client.CaptureHttpRequestAsync(async daprClient =>
|
||||
{
|
||||
await daprClient.InvokeMethodAsync("app1", "mymethod");
|
||||
});
|
||||
|
||||
// Get Request and validate
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
Assert.Equal(entry.Request.Method, HttpMethod.Post);
|
||||
Assert.Equal(new Uri("https://test-endpoint:3501/v1.0/invoke/app1/method/mymethod").AbsoluteUri, entry.Request.RequestUri.AbsoluteUri);
|
||||
Assert.Null(entry.Request.Content);
|
||||
Assert.Equal(request.Request.Method, HttpMethod.Post);
|
||||
Assert.Equal(new Uri("https://test-endpoint:3501/v1.0/invoke/app1/method/mymethod").AbsoluteUri, request.Request.RequestUri.AbsoluteUri);
|
||||
Assert.Null(request.Request.Content);
|
||||
|
||||
entry.Respond(new HttpResponseMessage());
|
||||
await task;
|
||||
await request.CompleteAsync(new HttpResponseMessage());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeMethodAsync_VoidVoidWithHttpMethod_Success()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var client = new DaprClientGrpc(
|
||||
GrpcChannel.ForAddress("http://localhost"),
|
||||
Mock.Of<global::Dapr.Client.Autogen.Grpc.v1.Dapr.DaprClient>(),
|
||||
httpClient,
|
||||
new Uri("https://test-endpoint:3501"),
|
||||
jsonSerializerOptions,
|
||||
default);
|
||||
await using var client = TestClient.CreateForDaprClient(c =>
|
||||
{
|
||||
c.UseGrpcEndpoint("http://localhost").UseHttpEndpoint("https://test-endpoint:3501").UseJsonSerializationOptions(this.jsonSerializerOptions);
|
||||
});
|
||||
|
||||
var task = client.InvokeMethodAsync(HttpMethod.Put, "app1", "mymethod");
|
||||
var request = await client.CaptureHttpRequestAsync(async daprClient =>
|
||||
{
|
||||
await daprClient.InvokeMethodAsync(HttpMethod.Put, "app1", "mymethod");
|
||||
});
|
||||
|
||||
// Get Request and validate
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
Assert.Equal(entry.Request.Method, HttpMethod.Put);
|
||||
Assert.Equal(new Uri("https://test-endpoint:3501/v1.0/invoke/app1/method/mymethod").AbsoluteUri, entry.Request.RequestUri.AbsoluteUri);
|
||||
Assert.Null(entry.Request.Content);
|
||||
Assert.Equal(request.Request.Method, HttpMethod.Put);
|
||||
Assert.Equal(new Uri("https://test-endpoint:3501/v1.0/invoke/app1/method/mymethod").AbsoluteUri, request.Request.RequestUri.AbsoluteUri);
|
||||
Assert.Null(request.Request.Content);
|
||||
|
||||
entry.Respond(new HttpResponseMessage());
|
||||
await task;
|
||||
await request.CompleteAsync(new HttpResponseMessage());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeMethodAsync_VoidResponseNoHttpMethod_Success()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var client = new DaprClientGrpc(
|
||||
GrpcChannel.ForAddress("http://localhost"),
|
||||
Mock.Of<global::Dapr.Client.Autogen.Grpc.v1.Dapr.DaprClient>(),
|
||||
httpClient,
|
||||
new Uri("https://test-endpoint:3501"),
|
||||
jsonSerializerOptions,
|
||||
default);
|
||||
await using var client = TestClient.CreateForDaprClient(c =>
|
||||
{
|
||||
c.UseGrpcEndpoint("http://localhost").UseHttpEndpoint("https://test-endpoint:3501").UseJsonSerializationOptions(this.jsonSerializerOptions);
|
||||
});
|
||||
|
||||
var task = client.InvokeMethodAsync<Widget>("app1", "mymethod");
|
||||
var request = await client.CaptureHttpRequestAsync(async daprClient =>
|
||||
{
|
||||
return await daprClient.InvokeMethodAsync<Widget>("app1", "mymethod");
|
||||
});
|
||||
|
||||
// Get Request and validate
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
Assert.Equal(entry.Request.Method, HttpMethod.Post);
|
||||
Assert.Equal(new Uri("https://test-endpoint:3501/v1.0/invoke/app1/method/mymethod").AbsoluteUri, entry.Request.RequestUri.AbsoluteUri);
|
||||
Assert.Null(entry.Request.Content);
|
||||
Assert.Equal(request.Request.Method, HttpMethod.Post);
|
||||
Assert.Equal(new Uri("https://test-endpoint:3501/v1.0/invoke/app1/method/mymethod").AbsoluteUri, request.Request.RequestUri.AbsoluteUri);
|
||||
Assert.Null(request.Request.Content);
|
||||
|
||||
var expected = new Widget()
|
||||
{
|
||||
Color = "red",
|
||||
};
|
||||
|
||||
entry.RespondWithJson(expected, jsonSerializerOptions);
|
||||
var actual = await task;
|
||||
var actual = await request.CompleteWithJsonAsync(expected, jsonSerializerOptions);
|
||||
Assert.Equal(expected.Color, actual.Color);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeMethodAsync_VoidResponseWithHttpMethod_Success()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var client = new DaprClientGrpc(
|
||||
GrpcChannel.ForAddress("http://localhost"),
|
||||
Mock.Of<global::Dapr.Client.Autogen.Grpc.v1.Dapr.DaprClient>(),
|
||||
httpClient,
|
||||
new Uri("https://test-endpoint:3501"),
|
||||
jsonSerializerOptions,
|
||||
default);
|
||||
await using var client = TestClient.CreateForDaprClient(c =>
|
||||
{
|
||||
c.UseGrpcEndpoint("http://localhost").UseHttpEndpoint("https://test-endpoint:3501").UseJsonSerializationOptions(this.jsonSerializerOptions);
|
||||
});
|
||||
|
||||
var task = client.InvokeMethodAsync<Widget>(HttpMethod.Put, "app1", "mymethod");
|
||||
var request = await client.CaptureHttpRequestAsync(async daprClient =>
|
||||
{
|
||||
return await daprClient.InvokeMethodAsync<Widget>(HttpMethod.Put, "app1", "mymethod");
|
||||
});
|
||||
|
||||
// Get Request and validate
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
Assert.Equal(entry.Request.Method, HttpMethod.Put);
|
||||
Assert.Equal(new Uri("https://test-endpoint:3501/v1.0/invoke/app1/method/mymethod").AbsoluteUri, entry.Request.RequestUri.AbsoluteUri);
|
||||
Assert.Null(entry.Request.Content);
|
||||
Assert.Equal(request.Request.Method, HttpMethod.Put);
|
||||
Assert.Equal(new Uri("https://test-endpoint:3501/v1.0/invoke/app1/method/mymethod").AbsoluteUri, request.Request.RequestUri.AbsoluteUri);
|
||||
Assert.Null(request.Request.Content);
|
||||
|
||||
var expected = new Widget()
|
||||
{
|
||||
Color = "red",
|
||||
};
|
||||
|
||||
entry.RespondWithJson(expected, jsonSerializerOptions);
|
||||
var actual = await task;
|
||||
var actual = await request.CompleteWithJsonAsync(expected, jsonSerializerOptions);
|
||||
Assert.Equal(expected.Color, actual.Color);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeMethodAsync_RequestVoidNoHttpMethod_Success()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var client = new DaprClientGrpc(
|
||||
GrpcChannel.ForAddress("http://localhost"),
|
||||
Mock.Of<global::Dapr.Client.Autogen.Grpc.v1.Dapr.DaprClient>(),
|
||||
httpClient,
|
||||
new Uri("https://test-endpoint:3501"),
|
||||
jsonSerializerOptions,
|
||||
default);
|
||||
await using var client = TestClient.CreateForDaprClient(c =>
|
||||
{
|
||||
c.UseGrpcEndpoint("http://localhost").UseHttpEndpoint("https://test-endpoint:3501").UseJsonSerializationOptions(this.jsonSerializerOptions);
|
||||
});
|
||||
|
||||
var data = new Widget()
|
||||
{
|
||||
Color = "red",
|
||||
};
|
||||
|
||||
var task = client.InvokeMethodAsync<Widget>("app1", "mymethod", data);
|
||||
var request = await client.CaptureHttpRequestAsync(async daprClient =>
|
||||
{
|
||||
await daprClient.InvokeMethodAsync<Widget>("app1", "mymethod", data);
|
||||
});
|
||||
|
||||
// Get Request and validate
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
Assert.Equal(entry.Request.Method, HttpMethod.Post);
|
||||
Assert.Equal(new Uri("https://test-endpoint:3501/v1.0/invoke/app1/method/mymethod").AbsoluteUri, entry.Request.RequestUri.AbsoluteUri);
|
||||
Assert.Equal(request.Request.Method, HttpMethod.Post);
|
||||
Assert.Equal(new Uri("https://test-endpoint:3501/v1.0/invoke/app1/method/mymethod").AbsoluteUri, request.Request.RequestUri.AbsoluteUri);
|
||||
|
||||
var content = Assert.IsType<JsonContent>(entry.Request.Content);
|
||||
var content = Assert.IsType<JsonContent>(request.Request.Content);
|
||||
Assert.Equal(data.GetType(), content.ObjectType);
|
||||
Assert.Same(data, content.Value);
|
||||
|
||||
entry.Respond(new HttpResponseMessage());
|
||||
await task;
|
||||
await request.CompleteAsync(new HttpResponseMessage());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeMethodAsync_RequestVoidWithHttpMethod_Success()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var client = new DaprClientGrpc(
|
||||
GrpcChannel.ForAddress("http://localhost"),
|
||||
Mock.Of<global::Dapr.Client.Autogen.Grpc.v1.Dapr.DaprClient>(),
|
||||
httpClient,
|
||||
new Uri("https://test-endpoint:3501"),
|
||||
jsonSerializerOptions,
|
||||
default);
|
||||
await using var client = TestClient.CreateForDaprClient(c =>
|
||||
{
|
||||
c.UseGrpcEndpoint("http://localhost").UseHttpEndpoint("https://test-endpoint:3501").UseJsonSerializationOptions(this.jsonSerializerOptions);
|
||||
});
|
||||
|
||||
var data = new Widget()
|
||||
{
|
||||
Color = "red",
|
||||
};
|
||||
|
||||
var task = client.InvokeMethodAsync<Widget>(HttpMethod.Put, "app1", "mymethod", data);
|
||||
var request = await client.CaptureHttpRequestAsync(async daprClient =>
|
||||
{
|
||||
await daprClient.InvokeMethodAsync<Widget>(HttpMethod.Put, "app1", "mymethod", data);
|
||||
});
|
||||
|
||||
// Get Request and validate
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
Assert.Equal(entry.Request.Method, HttpMethod.Put);
|
||||
Assert.Equal(new Uri("https://test-endpoint:3501/v1.0/invoke/app1/method/mymethod").AbsoluteUri, entry.Request.RequestUri.AbsoluteUri);
|
||||
Assert.Equal(request.Request.Method, HttpMethod.Put);
|
||||
Assert.Equal(new Uri("https://test-endpoint:3501/v1.0/invoke/app1/method/mymethod").AbsoluteUri, request.Request.RequestUri.AbsoluteUri);
|
||||
|
||||
var content = Assert.IsType<JsonContent>(entry.Request.Content);
|
||||
var content = Assert.IsType<JsonContent>(request.Request.Content);
|
||||
Assert.Equal(data.GetType(), content.ObjectType);
|
||||
Assert.Same(data, content.Value);
|
||||
|
||||
entry.Respond(new HttpResponseMessage());
|
||||
await task;
|
||||
await request.CompleteAsync(new HttpResponseMessage());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeMethodAsync_RequestResponseNoHttpMethod_Success()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var client = new DaprClientGrpc(
|
||||
GrpcChannel.ForAddress("http://localhost"),
|
||||
Mock.Of<global::Dapr.Client.Autogen.Grpc.v1.Dapr.DaprClient>(),
|
||||
httpClient,
|
||||
new Uri("https://test-endpoint:3501"),
|
||||
jsonSerializerOptions,
|
||||
default);
|
||||
await using var client = TestClient.CreateForDaprClient(c =>
|
||||
{
|
||||
c.UseGrpcEndpoint("http://localhost").UseHttpEndpoint("https://test-endpoint:3501").UseJsonSerializationOptions(this.jsonSerializerOptions);
|
||||
});
|
||||
|
||||
var data = new Widget()
|
||||
{
|
||||
Color = "red",
|
||||
};
|
||||
|
||||
var task = client.InvokeMethodAsync<Widget, Widget>("app1", "mymethod", data);
|
||||
var request = await client.CaptureHttpRequestAsync(async daprClient =>
|
||||
{
|
||||
return await daprClient.InvokeMethodAsync<Widget, Widget>("app1", "mymethod", data);
|
||||
});
|
||||
|
||||
// Get Request and validate
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
Assert.Equal(entry.Request.Method, HttpMethod.Post);
|
||||
Assert.Equal(new Uri("https://test-endpoint:3501/v1.0/invoke/app1/method/mymethod").AbsoluteUri, entry.Request.RequestUri.AbsoluteUri);
|
||||
Assert.Equal(request.Request.Method, HttpMethod.Post);
|
||||
Assert.Equal(new Uri("https://test-endpoint:3501/v1.0/invoke/app1/method/mymethod").AbsoluteUri, request.Request.RequestUri.AbsoluteUri);
|
||||
|
||||
var content = Assert.IsType<JsonContent>(entry.Request.Content);
|
||||
var content = Assert.IsType<JsonContent>(request.Request.Content);
|
||||
Assert.Equal(data.GetType(), content.ObjectType);
|
||||
Assert.Same(data, content.Value);
|
||||
|
||||
entry.RespondWithJson(data, jsonSerializerOptions);
|
||||
var actual = await task;
|
||||
var actual = await request.CompleteWithJsonAsync(data, jsonSerializerOptions);
|
||||
Assert.Equal(data.Color, actual.Color);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeMethodAsync_RequestResponseWithHttpMethod_Success()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var client = new DaprClientGrpc(
|
||||
GrpcChannel.ForAddress("http://localhost"),
|
||||
Mock.Of<global::Dapr.Client.Autogen.Grpc.v1.Dapr.DaprClient>(),
|
||||
httpClient,
|
||||
new Uri("https://test-endpoint:3501"),
|
||||
jsonSerializerOptions,
|
||||
default);
|
||||
await using var client = TestClient.CreateForDaprClient(c =>
|
||||
{
|
||||
c.UseGrpcEndpoint("http://localhost").UseHttpEndpoint("https://test-endpoint:3501").UseJsonSerializationOptions(this.jsonSerializerOptions);
|
||||
});
|
||||
|
||||
var data = new Widget()
|
||||
{
|
||||
Color = "red",
|
||||
};
|
||||
|
||||
var task = client.InvokeMethodAsync<Widget, Widget>(HttpMethod.Put, "app1", "mymethod", data);
|
||||
var request = await client.CaptureHttpRequestAsync(async daprClient =>
|
||||
{
|
||||
return await daprClient.InvokeMethodAsync<Widget, Widget>(HttpMethod.Put, "app1", "mymethod", data);
|
||||
});
|
||||
|
||||
// Get Request and validate
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
Assert.Equal(entry.Request.Method, HttpMethod.Put);
|
||||
Assert.Equal(new Uri("https://test-endpoint:3501/v1.0/invoke/app1/method/mymethod").AbsoluteUri, entry.Request.RequestUri.AbsoluteUri);
|
||||
Assert.Equal(request.Request.Method, HttpMethod.Put);
|
||||
Assert.Equal(new Uri("https://test-endpoint:3501/v1.0/invoke/app1/method/mymethod").AbsoluteUri, request.Request.RequestUri.AbsoluteUri);
|
||||
|
||||
var content = Assert.IsType<JsonContent>(entry.Request.Content);
|
||||
var content = Assert.IsType<JsonContent>(request.Request.Content);
|
||||
Assert.Equal(data.GetType(), content.ObjectType);
|
||||
Assert.Same(data, content.Value);
|
||||
|
||||
entry.RespondWithJson(data, jsonSerializerOptions);
|
||||
var actual = await task;
|
||||
var actual = await request.CompleteWithJsonAsync(data, jsonSerializerOptions);
|
||||
Assert.Equal(data.Color, actual.Color);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeMethodAsync_WrapsHttpRequestException()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var client = new DaprClientGrpc(
|
||||
GrpcChannel.ForAddress("http://localhost"),
|
||||
Mock.Of<global::Dapr.Client.Autogen.Grpc.v1.Dapr.DaprClient>(),
|
||||
httpClient,
|
||||
new Uri("https://test-endpoint:3501"),
|
||||
jsonSerializerOptions,
|
||||
default);
|
||||
await using var client = TestClient.CreateForDaprClient(c =>
|
||||
{
|
||||
c.UseGrpcEndpoint("http://localhost").UseHttpEndpoint("https://test-endpoint:3501").UseJsonSerializationOptions(this.jsonSerializerOptions);
|
||||
});
|
||||
|
||||
var request = client.CreateInvokeMethodRequest("test-app", "test");
|
||||
var task = client.InvokeMethodAsync(request);
|
||||
var request = await client.CaptureHttpRequestAsync(async daprClient =>
|
||||
{
|
||||
var request = daprClient.CreateInvokeMethodRequest("test-app", "test");
|
||||
await daprClient.InvokeMethodAsync(request);
|
||||
});
|
||||
|
||||
var exception = new HttpRequestException();
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
entry.Throw(exception);
|
||||
|
||||
var thrown = await Assert.ThrowsAsync<InvocationException>(async () => await task);
|
||||
var thrown = await Assert.ThrowsAsync<InvocationException>(async () => await request.CompleteWithExceptionAsync(exception));
|
||||
Assert.Equal("test-app", thrown.AppId);
|
||||
Assert.Equal("test", thrown.MethodName);
|
||||
Assert.Same(exception, thrown.InnerException);
|
||||
|
@ -310,24 +268,19 @@ namespace Dapr.Client.Test
|
|||
[Fact]
|
||||
public async Task InvokeMethodAsync_WrapsHttpRequestException_FromEnsureSuccessStatus()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var client = new DaprClientGrpc(
|
||||
GrpcChannel.ForAddress("http://localhost"),
|
||||
Mock.Of<global::Dapr.Client.Autogen.Grpc.v1.Dapr.DaprClient>(),
|
||||
httpClient,
|
||||
new Uri("https://test-endpoint:3501"),
|
||||
jsonSerializerOptions,
|
||||
default);
|
||||
await using var client = TestClient.CreateForDaprClient(c =>
|
||||
{
|
||||
c.UseGrpcEndpoint("http://localhost").UseHttpEndpoint("https://test-endpoint:3501").UseJsonSerializationOptions(this.jsonSerializerOptions);
|
||||
});
|
||||
|
||||
var request = client.CreateInvokeMethodRequest("test-app", "test");
|
||||
var task = client.InvokeMethodAsync(request);
|
||||
var request = await client.CaptureHttpRequestAsync(async daprClient =>
|
||||
{
|
||||
var request = daprClient.CreateInvokeMethodRequest("test-app", "test");
|
||||
await daprClient.InvokeMethodAsync(request);
|
||||
});
|
||||
|
||||
var response = new HttpResponseMessage(HttpStatusCode.NotFound);
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
entry.Respond(response);
|
||||
|
||||
var thrown = await Assert.ThrowsAsync<InvocationException>(async () => await task);
|
||||
var thrown = await Assert.ThrowsAsync<InvocationException>(async () => await request.CompleteAsync(response));
|
||||
Assert.Equal("test-app", thrown.AppId);
|
||||
Assert.Equal("test", thrown.MethodName);
|
||||
Assert.IsType<HttpRequestException>(thrown.InnerException);
|
||||
|
@ -337,24 +290,19 @@ namespace Dapr.Client.Test
|
|||
[Fact]
|
||||
public async Task InvokeMethodAsync_WithBody_WrapsHttpRequestException()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var client = new DaprClientGrpc(
|
||||
GrpcChannel.ForAddress("http://localhost"),
|
||||
Mock.Of<global::Dapr.Client.Autogen.Grpc.v1.Dapr.DaprClient>(),
|
||||
httpClient,
|
||||
new Uri("https://test-endpoint:3501"),
|
||||
jsonSerializerOptions,
|
||||
default);
|
||||
await using var client = TestClient.CreateForDaprClient(c =>
|
||||
{
|
||||
c.UseGrpcEndpoint("http://localhost").UseHttpEndpoint("https://test-endpoint:3501").UseJsonSerializationOptions(this.jsonSerializerOptions);
|
||||
});
|
||||
|
||||
var request = client.CreateInvokeMethodRequest("test-app", "test");
|
||||
var task = client.InvokeMethodAsync<Widget>(request);
|
||||
var request = await client.CaptureHttpRequestAsync(async daprClient =>
|
||||
{
|
||||
var request = daprClient.CreateInvokeMethodRequest("test-app", "test");
|
||||
return await daprClient.InvokeMethodAsync<Widget>(request);
|
||||
});
|
||||
|
||||
var exception = new HttpRequestException();
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
entry.Throw(exception);
|
||||
|
||||
var thrown = await Assert.ThrowsAsync<InvocationException>(async () => await task);
|
||||
var thrown = await Assert.ThrowsAsync<InvocationException>(async () => await request.CompleteWithExceptionAsync(exception));
|
||||
Assert.Equal("test-app", thrown.AppId);
|
||||
Assert.Equal("test", thrown.MethodName);
|
||||
Assert.Same(exception, thrown.InnerException);
|
||||
|
@ -364,24 +312,21 @@ namespace Dapr.Client.Test
|
|||
[Fact]
|
||||
public async Task InvokeMethodAsync_WithBody_WrapsHttpRequestException_FromEnsureSuccessStatus()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var client = new DaprClientGrpc(
|
||||
GrpcChannel.ForAddress("http://localhost"),
|
||||
Mock.Of<global::Dapr.Client.Autogen.Grpc.v1.Dapr.DaprClient>(),
|
||||
httpClient,
|
||||
new Uri("https://test-endpoint:3501"),
|
||||
jsonSerializerOptions,
|
||||
default);
|
||||
await using var client = TestClient.CreateForDaprClient(c =>
|
||||
{
|
||||
c.UseGrpcEndpoint("http://localhost").UseHttpEndpoint("https://test-endpoint:3501").UseJsonSerializationOptions(this.jsonSerializerOptions);
|
||||
});
|
||||
|
||||
var request = client.CreateInvokeMethodRequest("test-app", "test");
|
||||
var task = client.InvokeMethodAsync<Widget>(request);
|
||||
var request = await client.CaptureHttpRequestAsync(async daprClient =>
|
||||
{
|
||||
var request = daprClient.CreateInvokeMethodRequest("test-app", "test");
|
||||
return await daprClient.InvokeMethodAsync<Widget>(request);
|
||||
});
|
||||
|
||||
|
||||
|
||||
var response = new HttpResponseMessage(HttpStatusCode.NotFound);
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
entry.Respond(response);
|
||||
|
||||
var thrown = await Assert.ThrowsAsync<InvocationException>(async () => await task);
|
||||
var thrown = await Assert.ThrowsAsync<InvocationException>(async () => await request.CompleteAsync(response));
|
||||
Assert.Equal("test-app", thrown.AppId);
|
||||
Assert.Equal("test", thrown.MethodName);
|
||||
Assert.IsType<HttpRequestException>(thrown.InnerException);
|
||||
|
@ -391,28 +336,22 @@ namespace Dapr.Client.Test
|
|||
[Fact]
|
||||
public async Task InvokeMethodAsync_WrapsHttpRequestException_FromSerialization()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var client = new DaprClientGrpc(
|
||||
GrpcChannel.ForAddress("http://localhost"),
|
||||
Mock.Of<global::Dapr.Client.Autogen.Grpc.v1.Dapr.DaprClient>(),
|
||||
httpClient,
|
||||
new Uri("https://test-endpoint:3501"),
|
||||
jsonSerializerOptions,
|
||||
default);
|
||||
await using var client = TestClient.CreateForDaprClient(c =>
|
||||
{
|
||||
c.UseGrpcEndpoint("http://localhost").UseHttpEndpoint("https://test-endpoint:3501").UseJsonSerializationOptions(this.jsonSerializerOptions);
|
||||
});
|
||||
|
||||
var request = client.CreateInvokeMethodRequest("test-app", "test");
|
||||
var task = client.InvokeMethodAsync<Widget>(request);
|
||||
var request = await client.CaptureHttpRequestAsync(async daprClient =>
|
||||
{
|
||||
var request = daprClient.CreateInvokeMethodRequest("test-app", "test");
|
||||
return await daprClient.InvokeMethodAsync<Widget>(request);
|
||||
});
|
||||
|
||||
var response = new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new StringContent("{ \"invalid\": true", Encoding.UTF8, "application/json")
|
||||
};
|
||||
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
entry.Respond(response);
|
||||
|
||||
var thrown = await Assert.ThrowsAsync<InvocationException>(async () => await task);
|
||||
var thrown = await Assert.ThrowsAsync<InvocationException>(async () => await request.CompleteAsync(response));
|
||||
Assert.Equal("test-app", thrown.AppId);
|
||||
Assert.Equal("test", thrown.MethodName);
|
||||
Assert.IsType<JsonException>(thrown.InnerException);
|
||||
|
@ -428,41 +367,31 @@ namespace Dapr.Client.Test
|
|||
|
||||
// garbage in -> garbage out - we don't deeply inspect what you pass.
|
||||
[InlineData("http://example.com", "https://test-endpoint:3501/v1.0/invoke/test-app/method/http://example.com")]
|
||||
public void CreateInvokeMethodRequest_TransformsUrlCorrectly(string method, string expected)
|
||||
public async Task CreateInvokeMethodRequest_TransformsUrlCorrectly(string method, string expected)
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var client = new DaprClientGrpc(
|
||||
GrpcChannel.ForAddress("http://localhost"),
|
||||
Mock.Of<global::Dapr.Client.Autogen.Grpc.v1.Dapr.DaprClient>(),
|
||||
httpClient,
|
||||
new Uri("https://test-endpoint:3501"),
|
||||
jsonSerializerOptions,
|
||||
default);
|
||||
await using var client = TestClient.CreateForDaprClient(c =>
|
||||
{
|
||||
c.UseGrpcEndpoint("http://localhost").UseHttpEndpoint("https://test-endpoint:3501").UseJsonSerializationOptions(this.jsonSerializerOptions);
|
||||
});
|
||||
|
||||
var request = client.CreateInvokeMethodRequest("test-app", method);
|
||||
var request = client.InnerClient.CreateInvokeMethodRequest("test-app", method);
|
||||
Assert.Equal(new Uri(expected).AbsoluteUri, request.RequestUri.AbsoluteUri);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateInvokeMethodRequest_WithData_CreatesJsonContent()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var client = new DaprClientGrpc(
|
||||
GrpcChannel.ForAddress("http://localhost"),
|
||||
Mock.Of<global::Dapr.Client.Autogen.Grpc.v1.Dapr.DaprClient>(),
|
||||
httpClient,
|
||||
new Uri("https://test-endpoint:3501"),
|
||||
jsonSerializerOptions,
|
||||
default);
|
||||
await using var client = TestClient.CreateForDaprClient(c =>
|
||||
{
|
||||
c.UseGrpcEndpoint("http://localhost").UseHttpEndpoint("https://test-endpoint:3501").UseJsonSerializationOptions(this.jsonSerializerOptions);
|
||||
});
|
||||
|
||||
var data = new Widget
|
||||
{
|
||||
Color = "red",
|
||||
};
|
||||
|
||||
var request = client.CreateInvokeMethodRequest("test-app", "test", data);
|
||||
var request = client.InnerClient.CreateInvokeMethodRequest("test-app", "test", data);
|
||||
var content = Assert.IsType<JsonContent>(request.Content);
|
||||
Assert.Equal(typeof(Widget), content.ObjectType);
|
||||
Assert.Same(data, content.Value);
|
||||
|
@ -475,46 +404,37 @@ namespace Dapr.Client.Test
|
|||
[Fact]
|
||||
public async Task InvokeMethodWithResponseAsync_ReturnsMessageWithoutCheckingStatus()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var client = new DaprClientGrpc(
|
||||
GrpcChannel.ForAddress("http://localhost"),
|
||||
Mock.Of<global::Dapr.Client.Autogen.Grpc.v1.Dapr.DaprClient>(),
|
||||
httpClient,
|
||||
new Uri("https://test-endpoint:3501"),
|
||||
jsonSerializerOptions,
|
||||
default);
|
||||
await using var client = TestClient.CreateForDaprClient(c =>
|
||||
{
|
||||
c.UseGrpcEndpoint("http://localhost").UseHttpEndpoint("https://test-endpoint:3501").UseJsonSerializationOptions(this.jsonSerializerOptions);
|
||||
});
|
||||
|
||||
var request = client.CreateInvokeMethodRequest("test-app", "test");
|
||||
var task = client.InvokeMethodWithResponseAsync(request);
|
||||
var request = await client.CaptureHttpRequestAsync(async daprClient =>
|
||||
{
|
||||
var request = daprClient.CreateInvokeMethodRequest("test-app", "test");
|
||||
return await daprClient.InvokeMethodWithResponseAsync(request);
|
||||
});
|
||||
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
entry.Respond(new HttpResponseMessage(HttpStatusCode.BadRequest)); // Non-2xx response
|
||||
|
||||
var response = await task;
|
||||
var response = await request.CompleteAsync(new HttpResponseMessage(HttpStatusCode.BadRequest)); // Non-2xx response
|
||||
Assert.NotNull(response);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeMethodWithResponseAsync_WrapsHttpRequestException()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var client = new DaprClientGrpc(
|
||||
GrpcChannel.ForAddress("http://localhost"),
|
||||
Mock.Of<global::Dapr.Client.Autogen.Grpc.v1.Dapr.DaprClient>(),
|
||||
httpClient,
|
||||
new Uri("https://test-endpoint:3501"),
|
||||
jsonSerializerOptions,
|
||||
default);
|
||||
await using var client = TestClient.CreateForDaprClient(c =>
|
||||
{
|
||||
c.UseGrpcEndpoint("http://localhost").UseHttpEndpoint("https://test-endpoint:3501").UseJsonSerializationOptions(this.jsonSerializerOptions);
|
||||
});
|
||||
|
||||
var request = client.CreateInvokeMethodRequest("test-app", "test");
|
||||
var task = client.InvokeMethodWithResponseAsync(request);
|
||||
var request = await client.CaptureHttpRequestAsync(async daprClient =>
|
||||
{
|
||||
var request = daprClient.CreateInvokeMethodRequest("test-app", "test");
|
||||
return await daprClient.InvokeMethodWithResponseAsync(request);
|
||||
});
|
||||
|
||||
var exception = new HttpRequestException();
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
entry.Throw(exception);
|
||||
|
||||
var thrown = await Assert.ThrowsAsync<InvocationException>(async () => await task);
|
||||
var thrown = await Assert.ThrowsAsync<InvocationException>(async () => await request.CompleteWithExceptionAsync(exception));
|
||||
Assert.Equal("test-app", thrown.AppId);
|
||||
Assert.Equal("test", thrown.MethodName);
|
||||
Assert.Same(exception, thrown.InnerException);
|
||||
|
@ -524,20 +444,15 @@ namespace Dapr.Client.Test
|
|||
[Fact]
|
||||
public async Task InvokeMethodWithResponseAsync_PreventsNonDaprRequest()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var client = new DaprClientGrpc(
|
||||
GrpcChannel.ForAddress("http://localhost"),
|
||||
Mock.Of<global::Dapr.Client.Autogen.Grpc.v1.Dapr.DaprClient>(),
|
||||
httpClient,
|
||||
new Uri("https://test-endpoint:3501"),
|
||||
jsonSerializerOptions,
|
||||
default);
|
||||
await using var client = TestClient.CreateForDaprClient(c =>
|
||||
{
|
||||
c.UseGrpcEndpoint("http://localhost").UseHttpEndpoint("https://test-endpoint:3501").UseJsonSerializationOptions(this.jsonSerializerOptions);
|
||||
});
|
||||
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, "https://example.com");
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () =>
|
||||
{
|
||||
await client.InvokeMethodWithResponseAsync(request);
|
||||
await client.InnerClient.InvokeMethodWithResponseAsync(request);
|
||||
});
|
||||
|
||||
Assert.Equal("The provided request URI is not a Dapr service invocation URI.", ex.Message);
|
||||
|
|
|
@ -4,15 +4,11 @@
|
|||
// ------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Dapr.Client.Autogen.Grpc.v1;
|
||||
using Dapr.Client.Autogen.Test.Grpc.v1;
|
||||
using FluentAssertions;
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using Grpc.Core;
|
||||
using Grpc.Net.Client;
|
||||
|
@ -26,57 +22,51 @@ namespace Dapr.Client.Test
|
|||
{
|
||||
public partial class DaprClientTest
|
||||
{
|
||||
private DaprClient CreateTestClientGrpc(HttpClient httpClient)
|
||||
{
|
||||
return new DaprClientBuilder()
|
||||
.UseJsonSerializationOptions(this.jsonSerializerOptions)
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions
|
||||
{
|
||||
HttpClient = httpClient,
|
||||
ThrowOperationCanceledOnCancellation = true,
|
||||
})
|
||||
.Build();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeMethodGrpcAsync_WithCancelledToken()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = CreateTestClientGrpc(httpClient);
|
||||
|
||||
var ctSource = new CancellationTokenSource();
|
||||
CancellationToken ct = ctSource.Token;
|
||||
ctSource.Cancel();
|
||||
|
||||
await FluentActions.Awaiting(async () =>
|
||||
await using var client = TestClient.CreateForDaprClient(c =>
|
||||
{
|
||||
await daprClient.InvokeMethodGrpcAsync<Request, Response>("test", "test", new Request() { RequestParameter = "Hello " }, cancellationToken: ct);
|
||||
}).Should().ThrowAsync<OperationCanceledException>();
|
||||
c.UseJsonSerializationOptions(this.jsonSerializerOptions);
|
||||
});
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
cts.Cancel();
|
||||
|
||||
await Assert.ThrowsAsync<OperationCanceledException>(async () =>
|
||||
{
|
||||
await client.InnerClient.InvokeMethodGrpcAsync<Request, Response>("test", "test", new Request() { RequestParameter = "Hello " }, cancellationToken: cts.Token);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeMethodGrpcAsync_CanInvokeMethodWithReturnTypeAndData()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = CreateTestClientGrpc(httpClient);
|
||||
await using var client = TestClient.CreateForDaprClient(c =>
|
||||
{
|
||||
c.UseJsonSerializationOptions(this.jsonSerializerOptions);
|
||||
});
|
||||
|
||||
var task = daprClient.InvokeMethodGrpcAsync<Request, Response>("test", "test", new Request() { RequestParameter = "Hello " });
|
||||
var request = await client.CaptureGrpcRequestAsync(async daprClient =>
|
||||
{
|
||||
return await daprClient.InvokeMethodGrpcAsync<Request, Response>("test", "test", new Request() { RequestParameter = "Hello " });
|
||||
});
|
||||
|
||||
// Get Request and validate
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var envelope = await GrpcUtils.GetRequestFromRequestMessageAsync<InvokeServiceRequest>(entry.Request);
|
||||
var envelope = await request.GetRequestEnvelopeAsync<InvokeServiceRequest>();
|
||||
envelope.Id.Should().Be("test");
|
||||
envelope.Message.Method.Should().Be("test");
|
||||
envelope.Message.ContentType.Should().Be(Constants.ContentTypeApplicationGrpc);
|
||||
|
||||
// Create Response & Respond
|
||||
var data = new Response() { Name = "Look, I was invoked!" };
|
||||
await SendResponse(data, entry);
|
||||
var response = new Autogen.Grpc.v1.InvokeResponse()
|
||||
{
|
||||
Data = Any.Pack(data),
|
||||
};
|
||||
|
||||
// Validate Response
|
||||
var invokedResponse = await task;
|
||||
var invokedResponse = await request.CompleteWithMessageAsync(response);
|
||||
invokedResponse.Name.Should().Be("Look, I was invoked!");
|
||||
}
|
||||
|
||||
|
@ -117,25 +107,31 @@ namespace Dapr.Client.Test
|
|||
[Fact]
|
||||
public async Task InvokeMethodGrpcAsync_CanInvokeMethodWithReturnTypeNoData()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = CreateTestClientGrpc(httpClient);
|
||||
await using var client = TestClient.CreateForDaprClient(c =>
|
||||
{
|
||||
c.UseJsonSerializationOptions(this.jsonSerializerOptions);
|
||||
});
|
||||
|
||||
var task = daprClient.InvokeMethodGrpcAsync<Response>("test", "test");
|
||||
var request = await client.CaptureGrpcRequestAsync(async daprClient =>
|
||||
{
|
||||
return await daprClient.InvokeMethodGrpcAsync<Response>("test", "test");
|
||||
});
|
||||
|
||||
// Get Request and validate
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var envelope = await GrpcUtils.GetRequestFromRequestMessageAsync<InvokeServiceRequest>(entry.Request);
|
||||
var envelope = await request.GetRequestEnvelopeAsync<InvokeServiceRequest>();
|
||||
envelope.Id.Should().Be("test");
|
||||
envelope.Message.Method.Should().Be("test");
|
||||
envelope.Message.ContentType.Should().Be(string.Empty);
|
||||
|
||||
// Create Response & Respond
|
||||
var data = new Response() { Name = "Look, I was invoked!" };
|
||||
await SendResponse(data, entry);
|
||||
var response = new Autogen.Grpc.v1.InvokeResponse()
|
||||
{
|
||||
Data = Any.Pack(data),
|
||||
};
|
||||
|
||||
// Validate Response
|
||||
var invokedResponse = await task;
|
||||
var invokedResponse = await request.CompleteWithMessageAsync(response);
|
||||
invokedResponse.Name.Should().Be("Look, I was invoked!");
|
||||
}
|
||||
|
||||
|
@ -234,16 +230,21 @@ namespace Dapr.Client.Test
|
|||
[Fact]
|
||||
public async Task InvokeMethodGrpcAsync_WithNoReturnTypeAndData()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = CreateTestClientGrpc(httpClient);
|
||||
await using var client = TestClient.CreateForDaprClient(c =>
|
||||
{
|
||||
c.UseJsonSerializationOptions(this.jsonSerializerOptions);
|
||||
});
|
||||
|
||||
var invokeRequest = new Request() { RequestParameter = "Hello" };
|
||||
var task = daprClient.InvokeMethodGrpcAsync<Request, Response>("test", "test", invokeRequest);
|
||||
var request = await client.CaptureGrpcRequestAsync(async daprClient =>
|
||||
{
|
||||
return await daprClient.InvokeMethodGrpcAsync<Request, Response>("test", "test", invokeRequest);
|
||||
});
|
||||
|
||||
request.Dismiss();
|
||||
|
||||
// Get Request and validate
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var envelope = await GrpcUtils.GetRequestFromRequestMessageAsync<InvokeServiceRequest>(entry.Request);
|
||||
var envelope = await request.GetRequestEnvelopeAsync<InvokeServiceRequest>();
|
||||
envelope.Id.Should().Be("test");
|
||||
envelope.Message.Method.Should().Be("test");
|
||||
envelope.Message.ContentType.Should().Be(Constants.ContentTypeApplicationGrpc);
|
||||
|
@ -255,18 +256,20 @@ namespace Dapr.Client.Test
|
|||
[Fact]
|
||||
public async Task InvokeMethodGrpcAsync_WithReturnTypeAndData()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = CreateTestClientGrpc(httpClient);
|
||||
await using var client = TestClient.CreateForDaprClient(c =>
|
||||
{
|
||||
c.UseJsonSerializationOptions(this.jsonSerializerOptions);
|
||||
});
|
||||
|
||||
var invokeRequest = new Request() { RequestParameter = "Hello " };
|
||||
var invokedResponse = new Response { Name = "Look, I was invoked!" };
|
||||
|
||||
var task = daprClient.InvokeMethodGrpcAsync<Request, Response>("test", "test", invokeRequest);
|
||||
var invokeResponse = new Response { Name = "Look, I was invoked!" };
|
||||
var request = await client.CaptureGrpcRequestAsync(async daprClient =>
|
||||
{
|
||||
return await daprClient.InvokeMethodGrpcAsync<Request, Response>("test", "test", invokeRequest);
|
||||
});
|
||||
|
||||
// Get Request and validate
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var envelope = await GrpcUtils.GetRequestFromRequestMessageAsync<InvokeServiceRequest>(entry.Request);
|
||||
var envelope = await request.GetRequestEnvelopeAsync<InvokeServiceRequest>();
|
||||
envelope.Id.Should().Be("test");
|
||||
envelope.Message.Method.Should().Be("test");
|
||||
envelope.Message.ContentType.Should().Be(Constants.ContentTypeApplicationGrpc);
|
||||
|
@ -274,10 +277,16 @@ namespace Dapr.Client.Test
|
|||
var actual = envelope.Message.Data.Unpack<Request>();
|
||||
Assert.Equal(invokeRequest.RequestParameter, actual.RequestParameter);
|
||||
|
||||
await SendResponse(invokedResponse, entry);
|
||||
var response = await task;
|
||||
// Create Response & Respond
|
||||
var data = new Response() { Name = "Look, I was invoked!" };
|
||||
var response = new Autogen.Grpc.v1.InvokeResponse()
|
||||
{
|
||||
Data = Any.Pack(data),
|
||||
};
|
||||
|
||||
response.Name.Should().Be(invokedResponse.Name);
|
||||
// Validate Response
|
||||
var invokedResponse = await request.CompleteWithMessageAsync(response);
|
||||
invokeResponse.Name.Should().Be(invokeResponse.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -285,7 +294,10 @@ namespace Dapr.Client.Test
|
|||
{
|
||||
// Configure Client
|
||||
var httpClient = new AppCallbackClient(new DaprAppCallbackService());
|
||||
var daprClient = CreateTestClientGrpc(httpClient);
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions(){ HttpClient = httpClient, })
|
||||
.UseJsonSerializationOptions(this.jsonSerializerOptions)
|
||||
.Build();
|
||||
|
||||
var request = new Request() { RequestParameter = "Look, I was invoked!" };
|
||||
|
||||
|
@ -299,7 +311,10 @@ namespace Dapr.Client.Test
|
|||
{
|
||||
// Configure Client
|
||||
var httpClient = new AppCallbackClient(new DaprAppCallbackService());
|
||||
var daprClient = CreateTestClientGrpc(httpClient);
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions(){ HttpClient = httpClient, })
|
||||
.UseJsonSerializationOptions(this.jsonSerializerOptions)
|
||||
.Build();
|
||||
|
||||
var testRun = new TestRun();
|
||||
testRun.Tests.Add(new TestCase() { Name = "test1" });
|
||||
|
@ -319,7 +334,10 @@ namespace Dapr.Client.Test
|
|||
{
|
||||
// Configure Client
|
||||
var httpClient = new AppCallbackClient(new DaprAppCallbackService());
|
||||
var daprClient = CreateTestClientGrpc(httpClient);
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions(){ HttpClient = httpClient, })
|
||||
.UseJsonSerializationOptions(this.jsonSerializerOptions)
|
||||
.Build();
|
||||
|
||||
var request = new Request() { RequestParameter = "Look, I was invoked!" };
|
||||
|
||||
|
@ -328,19 +346,6 @@ namespace Dapr.Client.Test
|
|||
response.Name.Should().Be("unexpected");
|
||||
}
|
||||
|
||||
|
||||
private async Task SendResponse<T>(T data, TestHttpClient.Entry entry) where T : IMessage
|
||||
{
|
||||
var dataResponse = new InvokeResponse
|
||||
{
|
||||
Data = Any.Pack(data),
|
||||
};
|
||||
|
||||
var streamContent = await GrpcUtils.CreateResponseContent(dataResponse);
|
||||
var response = GrpcUtils.CreateResponse(HttpStatusCode.OK, streamContent);
|
||||
entry.Completion.SetResult(response);
|
||||
}
|
||||
|
||||
// Test implementation of the AppCallback.AppCallbackBase service
|
||||
private class DaprAppCallbackService : AppCallback.Autogen.Grpc.v1.AppCallback.AppCallbackBase
|
||||
{
|
||||
|
|
|
@ -8,7 +8,6 @@ namespace Dapr.Client.Test
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -16,7 +15,6 @@ namespace Dapr.Client.Test
|
|||
using FluentAssertions;
|
||||
using Google.Protobuf;
|
||||
using Grpc.Core;
|
||||
using Grpc.Net.Client;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
@ -25,33 +23,29 @@ namespace Dapr.Client.Test
|
|||
[Fact]
|
||||
public async Task InvokeBindingAsync_ValidateRequest()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions { HttpClient = httpClient })
|
||||
.Build();
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var invokeRequest = new InvokeRequest() { RequestParameter = "Hello " };
|
||||
var task = daprClient.InvokeBindingAsync<InvokeRequest>("test", "create", invokeRequest);
|
||||
var request = await client.CaptureGrpcRequestAsync(async daprClient =>
|
||||
{
|
||||
await daprClient.InvokeBindingAsync<InvokeRequest>("test", "create", invokeRequest);
|
||||
});
|
||||
|
||||
// Get Request and validate
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var request = await GrpcUtils.GetRequestFromRequestMessageAsync<InvokeBindingRequest>(entry.Request);
|
||||
request.Name.Should().Be("test");
|
||||
request.Metadata.Count.Should().Be(0);
|
||||
var json = request.Data.ToStringUtf8();
|
||||
var typeFromRequest = JsonSerializer.Deserialize<InvokeRequest>(json, daprClient.JsonSerializerOptions);
|
||||
request.Dismiss();
|
||||
|
||||
// Get Request and validate
|
||||
var envelope = await request.GetRequestEnvelopeAsync<InvokeBindingRequest>();
|
||||
envelope.Name.Should().Be("test");
|
||||
envelope.Metadata.Count.Should().Be(0);
|
||||
var json = envelope.Data.ToStringUtf8();
|
||||
var typeFromRequest = JsonSerializer.Deserialize<InvokeRequest>(json, client.InnerClient.JsonSerializerOptions);
|
||||
typeFromRequest.RequestParameter.Should().Be("Hello ");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeBindingAsync_ValidateRequest_WithMetadata()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions { HttpClient = httpClient })
|
||||
.Build();
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var metadata = new Dictionary<string, string>
|
||||
{
|
||||
|
@ -59,55 +53,55 @@ namespace Dapr.Client.Test
|
|||
{ "key2", "value2" }
|
||||
};
|
||||
var invokeRequest = new InvokeRequest() { RequestParameter = "Hello " };
|
||||
var task = daprClient.InvokeBindingAsync<InvokeRequest>("test", "create", invokeRequest, metadata);
|
||||
var request = await client.CaptureGrpcRequestAsync(async daprClient =>
|
||||
{
|
||||
await daprClient.InvokeBindingAsync<InvokeRequest>("test", "create", invokeRequest, metadata);
|
||||
});
|
||||
|
||||
request.Dismiss();
|
||||
|
||||
// Get Request and validate
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var request = await GrpcUtils.GetRequestFromRequestMessageAsync<InvokeBindingRequest>(entry.Request);
|
||||
request.Name.Should().Be("test");
|
||||
request.Metadata.Count.Should().Be(2);
|
||||
request.Metadata.Keys.Contains("key1").Should().BeTrue();
|
||||
request.Metadata.Keys.Contains("key2").Should().BeTrue();
|
||||
request.Metadata["key1"].Should().Be("value1");
|
||||
request.Metadata["key2"].Should().Be("value2");
|
||||
var json = request.Data.ToStringUtf8();
|
||||
var typeFromRequest = JsonSerializer.Deserialize<InvokeRequest>(json, daprClient.JsonSerializerOptions);
|
||||
var envelope = await request.GetRequestEnvelopeAsync<InvokeBindingRequest>();
|
||||
envelope.Name.Should().Be("test");
|
||||
envelope.Metadata.Count.Should().Be(2);
|
||||
envelope.Metadata.Keys.Contains("key1").Should().BeTrue();
|
||||
envelope.Metadata.Keys.Contains("key2").Should().BeTrue();
|
||||
envelope.Metadata["key1"].Should().Be("value1");
|
||||
envelope.Metadata["key2"].Should().Be("value2");
|
||||
var json = envelope.Data.ToStringUtf8();
|
||||
var typeFromRequest = JsonSerializer.Deserialize<InvokeRequest>(json, client.InnerClient.JsonSerializerOptions);
|
||||
typeFromRequest.RequestParameter.Should().Be("Hello ");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeBindingAsync_WithNullPayload_ValidateRequest()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions { HttpClient = httpClient })
|
||||
.Build();
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var task = daprClient.InvokeBindingAsync<InvokeRequest>("test", "create", null);
|
||||
var request = await client.CaptureGrpcRequestAsync(async daprClient =>
|
||||
{
|
||||
await daprClient.InvokeBindingAsync<InvokeRequest>("test", "create", null);
|
||||
});
|
||||
|
||||
// Get Request and validate
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var request = await GrpcUtils.GetRequestFromRequestMessageAsync<InvokeBindingRequest>(entry.Request);
|
||||
request.Name.Should().Be("test");
|
||||
request.Metadata.Count.Should().Be(0);
|
||||
var json = request.Data.ToStringUtf8();
|
||||
request.Dismiss();
|
||||
|
||||
// Get Request and validate
|
||||
var envelope = await request.GetRequestEnvelopeAsync<InvokeBindingRequest>();
|
||||
envelope.Name.Should().Be("test");
|
||||
envelope.Metadata.Count.Should().Be(0);
|
||||
var json = envelope.Data.ToStringUtf8();
|
||||
Assert.Equal("null", json);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeBindingAsync_WithRequest_ValidateRequest()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions { HttpClient = httpClient })
|
||||
.Build();
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var payload = new InvokeRequest() { RequestParameter = "Hello " };
|
||||
var request = new BindingRequest("test", "create")
|
||||
var bindingRequest = new BindingRequest("test", "create")
|
||||
{
|
||||
Data = JsonSerializer.SerializeToUtf8Bytes(payload, daprClient.JsonSerializerOptions),
|
||||
Data = JsonSerializer.SerializeToUtf8Bytes(payload, client.InnerClient.JsonSerializerOptions),
|
||||
Metadata =
|
||||
{
|
||||
{ "key1", "value1" },
|
||||
|
@ -115,37 +109,35 @@ namespace Dapr.Client.Test
|
|||
}
|
||||
};
|
||||
|
||||
var task = daprClient.InvokeBindingAsync(request);
|
||||
|
||||
// Get Request and validate
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
|
||||
var gRpcRequest = await GrpcUtils.GetRequestFromRequestMessageAsync<InvokeBindingRequest>(entry.Request);
|
||||
gRpcRequest.Name.Should().Be("test");
|
||||
gRpcRequest.Metadata.Count.Should().Be(2);
|
||||
gRpcRequest.Metadata.Keys.Contains("key1").Should().BeTrue();
|
||||
gRpcRequest.Metadata.Keys.Contains("key2").Should().BeTrue();
|
||||
gRpcRequest.Metadata["key1"].Should().Be("value1");
|
||||
gRpcRequest.Metadata["key2"].Should().Be("value2");
|
||||
|
||||
var json = gRpcRequest.Data.ToStringUtf8();
|
||||
var typeFromRequest = JsonSerializer.Deserialize<InvokeRequest>(json, daprClient.JsonSerializerOptions);
|
||||
typeFromRequest.RequestParameter.Should().Be("Hello ");
|
||||
var request = await client.CaptureGrpcRequestAsync(async daprClient =>
|
||||
{
|
||||
return await daprClient.InvokeBindingAsync(bindingRequest);
|
||||
});
|
||||
|
||||
var gRpcResponse = new Autogen.Grpc.v1.InvokeBindingResponse()
|
||||
{
|
||||
Data = ByteString.CopyFrom(JsonSerializer.SerializeToUtf8Bytes(new Widget() { Color = "red", }, daprClient.JsonSerializerOptions)),
|
||||
Data = ByteString.CopyFrom(JsonSerializer.SerializeToUtf8Bytes(new Widget() { Color = "red", }, client.InnerClient.JsonSerializerOptions)),
|
||||
Metadata =
|
||||
{
|
||||
{ "anotherkey", "anothervalue" },
|
||||
}
|
||||
};
|
||||
var streamContent = await GrpcUtils.CreateResponseContent(gRpcResponse);
|
||||
entry.Completion.SetResult(GrpcUtils.CreateResponse(HttpStatusCode.OK, streamContent));
|
||||
var response = await request.CompleteWithMessageAsync(gRpcResponse);
|
||||
|
||||
var response = await task;
|
||||
Assert.Same(request, response.Request);
|
||||
Assert.Equal("red", JsonSerializer.Deserialize<Widget>(response.Data.Span, daprClient.JsonSerializerOptions).Color);
|
||||
var envelope = await request.GetRequestEnvelopeAsync<InvokeBindingRequest>();
|
||||
envelope.Name.Should().Be("test");
|
||||
envelope.Metadata.Count.Should().Be(2);
|
||||
envelope.Metadata.Keys.Contains("key1").Should().BeTrue();
|
||||
envelope.Metadata.Keys.Contains("key2").Should().BeTrue();
|
||||
envelope.Metadata["key1"].Should().Be("value1");
|
||||
envelope.Metadata["key2"].Should().Be("value2");
|
||||
|
||||
var json = envelope.Data.ToStringUtf8();
|
||||
var typeFromRequest = JsonSerializer.Deserialize<InvokeRequest>(json, client.InnerClient.JsonSerializerOptions);
|
||||
typeFromRequest.RequestParameter.Should().Be("Hello ");
|
||||
|
||||
Assert.Same(bindingRequest, response.Request);
|
||||
Assert.Equal("red", JsonSerializer.Deserialize<Widget>(response.Data.Span, client.InnerClient.JsonSerializerOptions).Color);
|
||||
Assert.Collection(
|
||||
response.Metadata,
|
||||
kvp =>
|
||||
|
@ -159,15 +151,10 @@ namespace Dapr.Client.Test
|
|||
[Fact]
|
||||
public async Task InvokeBindingAsync_WithCancelledToken()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions { HttpClient = httpClient, ThrowOperationCanceledOnCancellation = true })
|
||||
.Build();
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var ctSource = new CancellationTokenSource();
|
||||
CancellationToken ct = ctSource.Token;
|
||||
ctSource.Cancel();
|
||||
var cts = new CancellationTokenSource();
|
||||
cts.Cancel();
|
||||
|
||||
var metadata = new Dictionary<string, string>
|
||||
{
|
||||
|
@ -175,10 +162,10 @@ namespace Dapr.Client.Test
|
|||
{ "key2", "value2" }
|
||||
};
|
||||
var invokeRequest = new InvokeRequest() { RequestParameter = "Hello " };
|
||||
var task = daprClient.InvokeBindingAsync<InvokeRequest>("test", "create", invokeRequest, metadata, ct);
|
||||
|
||||
await FluentActions.Awaiting(async () => await task)
|
||||
.Should().ThrowAsync<OperationCanceledException>();
|
||||
await Assert.ThrowsAsync<OperationCanceledException>(async () =>
|
||||
{
|
||||
await client.InnerClient.InvokeBindingAsync<InvokeRequest>("test", "create", invokeRequest, metadata, cts.Token);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -203,26 +190,21 @@ namespace Dapr.Client.Test
|
|||
[Fact]
|
||||
public async Task InvokeBindingAsync_WrapsJsonException()
|
||||
{
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions { HttpClient = httpClient })
|
||||
.Build();
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var response = new Autogen.Grpc.v1.InvokeBindingResponse();
|
||||
var bytes = JsonSerializer.SerializeToUtf8Bytes<Widget>(new Widget(){ Color = "red", }, new JsonSerializerOptions(JsonSerializerDefaults.Web));
|
||||
response.Data = ByteString.CopyFrom(bytes.Take(10).ToArray()); // trim it to make invalid JSON blog
|
||||
var bytes = JsonSerializer.SerializeToUtf8Bytes<Widget>(new Widget(){ Color = "red", }, client.InnerClient.JsonSerializerOptions);
|
||||
response.Data = ByteString.CopyFrom(bytes.Take(10).ToArray()); // trim it to make invalid JSON blob
|
||||
|
||||
var task = daprClient.InvokeBindingAsync<InvokeRequest, Widget>("test", "test", new InvokeRequest() { RequestParameter = "Hello " });
|
||||
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var request = await GrpcUtils.GetRequestFromRequestMessageAsync<InvokeBindingRequest>(entry.Request);
|
||||
|
||||
var streamContent = await GrpcUtils.CreateResponseContent(response);
|
||||
entry.Completion.SetResult(GrpcUtils.CreateResponse(HttpStatusCode.OK, streamContent));
|
||||
var request = await client.CaptureGrpcRequestAsync(async daprClient =>
|
||||
{
|
||||
return await daprClient.InvokeBindingAsync<InvokeRequest, Widget>("test", "test", new InvokeRequest() { RequestParameter = "Hello " });
|
||||
});
|
||||
|
||||
var envelope = await request.GetRequestEnvelopeAsync<InvokeBindingRequest>();
|
||||
var ex = await Assert.ThrowsAsync<DaprException>(async () =>
|
||||
{
|
||||
await task;
|
||||
await request.CompleteWithMessageAsync(response);
|
||||
});
|
||||
Assert.IsType<JsonException>(ex.InnerException);
|
||||
}
|
||||
|
|
|
@ -24,32 +24,30 @@ namespace Dapr.Client.Test
|
|||
[Fact]
|
||||
public async Task PublishEventAsync_CanPublishTopicWithData()
|
||||
{
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions{ HttpClient = httpClient })
|
||||
.Build();
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var publishData = new PublishData() { PublishObjectParameter = "testparam" };
|
||||
var task = daprClient.PublishEventAsync<PublishData>(TestPubsubName, "test", publishData);
|
||||
var request = await client.CaptureGrpcRequestAsync(async daprClient =>
|
||||
{
|
||||
await daprClient.PublishEventAsync<PublishData>(TestPubsubName, "test", publishData);
|
||||
});
|
||||
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var request = await GrpcUtils.GetRequestFromRequestMessageAsync<PublishEventRequest>(entry.Request);
|
||||
var jsonFromRequest = request.Data.ToStringUtf8();
|
||||
request.Dismiss();
|
||||
|
||||
request.DataContentType.Should().Be("application/json");
|
||||
request.PubsubName.Should().Be(TestPubsubName);
|
||||
request.Topic.Should().Be("test");
|
||||
jsonFromRequest.Should().Be(JsonSerializer.Serialize(publishData, daprClient.JsonSerializerOptions));
|
||||
request.Metadata.Count.Should().Be(0);
|
||||
var envelope = await request.GetRequestEnvelopeAsync<PublishEventRequest>();
|
||||
var jsonFromRequest = envelope.Data.ToStringUtf8();
|
||||
|
||||
envelope.DataContentType.Should().Be("application/json");
|
||||
envelope.PubsubName.Should().Be(TestPubsubName);
|
||||
envelope.Topic.Should().Be("test");
|
||||
jsonFromRequest.Should().Be(JsonSerializer.Serialize(publishData, client.InnerClient.JsonSerializerOptions));
|
||||
envelope.Metadata.Count.Should().Be(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PublishEventAsync_CanPublishTopicWithData_WithMetadata()
|
||||
{
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions{ HttpClient = httpClient })
|
||||
.Build();
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var metadata = new Dictionary<string, string>
|
||||
{
|
||||
|
@ -58,51 +56,53 @@ namespace Dapr.Client.Test
|
|||
};
|
||||
|
||||
var publishData = new PublishData() { PublishObjectParameter = "testparam" };
|
||||
var task = daprClient.PublishEventAsync<PublishData>(TestPubsubName, "test", publishData, metadata);
|
||||
var request = await client.CaptureGrpcRequestAsync(async daprClient =>
|
||||
{
|
||||
await daprClient.PublishEventAsync<PublishData>(TestPubsubName, "test", publishData, metadata);
|
||||
});
|
||||
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var request = await GrpcUtils.GetRequestFromRequestMessageAsync<PublishEventRequest>(entry.Request);
|
||||
var jsonFromRequest = request.Data.ToStringUtf8();
|
||||
request.Dismiss();
|
||||
|
||||
request.DataContentType.Should().Be("application/json");
|
||||
request.PubsubName.Should().Be(TestPubsubName);
|
||||
request.Topic.Should().Be("test");
|
||||
jsonFromRequest.Should().Be(JsonSerializer.Serialize(publishData, daprClient.JsonSerializerOptions));
|
||||
var envelope = await request.GetRequestEnvelopeAsync<PublishEventRequest>();
|
||||
var jsonFromRequest = envelope.Data.ToStringUtf8();
|
||||
|
||||
request.Metadata.Count.Should().Be(2);
|
||||
request.Metadata.Keys.Contains("key1").Should().BeTrue();
|
||||
request.Metadata.Keys.Contains("key2").Should().BeTrue();
|
||||
request.Metadata["key1"].Should().Be("value1");
|
||||
request.Metadata["key2"].Should().Be("value2");
|
||||
envelope.DataContentType.Should().Be("application/json");
|
||||
envelope.PubsubName.Should().Be(TestPubsubName);
|
||||
envelope.Topic.Should().Be("test");
|
||||
jsonFromRequest.Should().Be(JsonSerializer.Serialize(publishData, client.InnerClient.JsonSerializerOptions));
|
||||
|
||||
envelope.Metadata.Count.Should().Be(2);
|
||||
envelope.Metadata.Keys.Contains("key1").Should().BeTrue();
|
||||
envelope.Metadata.Keys.Contains("key2").Should().BeTrue();
|
||||
envelope.Metadata["key1"].Should().Be("value1");
|
||||
envelope.Metadata["key2"].Should().Be("value2");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PublishEventAsync_CanPublishTopicWithNoContent()
|
||||
{
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions { HttpClient = httpClient })
|
||||
.Build();
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var task = daprClient.PublishEventAsync(TestPubsubName, "test");
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var request = await GrpcUtils.GetRequestFromRequestMessageAsync<PublishEventRequest>(entry.Request);
|
||||
var jsonFromRequest = request.Data.ToStringUtf8();
|
||||
var request = await client.CaptureGrpcRequestAsync(async daprClient =>
|
||||
{
|
||||
await daprClient.PublishEventAsync(TestPubsubName, "test");
|
||||
});
|
||||
|
||||
request.PubsubName.Should().Be(TestPubsubName);
|
||||
request.Topic.Should().Be("test");
|
||||
request.Data.Length.Should().Be(0);
|
||||
request.Dismiss();
|
||||
|
||||
request.Metadata.Count.Should().Be(0);
|
||||
var envelope = await request.GetRequestEnvelopeAsync<PublishEventRequest>();
|
||||
var jsonFromRequest = envelope.Data.ToStringUtf8();
|
||||
|
||||
envelope.PubsubName.Should().Be(TestPubsubName);
|
||||
envelope.Topic.Should().Be("test");
|
||||
envelope.Data.Length.Should().Be(0);
|
||||
envelope.Metadata.Count.Should().Be(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PublishEventAsync_CanPublishTopicWithNoContent_WithMetadata()
|
||||
{
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions { HttpClient = httpClient })
|
||||
.Build();
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var metadata = new Dictionary<string, string>
|
||||
{
|
||||
|
@ -110,35 +110,37 @@ namespace Dapr.Client.Test
|
|||
{ "key2", "value2" }
|
||||
};
|
||||
|
||||
var task = daprClient.PublishEventAsync(TestPubsubName, "test", metadata);
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var request = await GrpcUtils.GetRequestFromRequestMessageAsync<PublishEventRequest>(entry.Request);
|
||||
var request = await client.CaptureGrpcRequestAsync(async daprClient =>
|
||||
{
|
||||
await daprClient.PublishEventAsync(TestPubsubName, "test", metadata);
|
||||
});
|
||||
|
||||
request.PubsubName.Should().Be(TestPubsubName);
|
||||
request.Topic.Should().Be("test");
|
||||
request.Data.Length.Should().Be(0);
|
||||
request.Dismiss();
|
||||
|
||||
request.Metadata.Count.Should().Be(2);
|
||||
request.Metadata.Keys.Contains("key1").Should().BeTrue();
|
||||
request.Metadata.Keys.Contains("key2").Should().BeTrue();
|
||||
request.Metadata["key1"].Should().Be("value1");
|
||||
request.Metadata["key2"].Should().Be("value2");
|
||||
var envelope = await request.GetRequestEnvelopeAsync<PublishEventRequest>();
|
||||
envelope.PubsubName.Should().Be(TestPubsubName);
|
||||
envelope.Topic.Should().Be("test");
|
||||
envelope.Data.Length.Should().Be(0);
|
||||
|
||||
envelope.Metadata.Count.Should().Be(2);
|
||||
envelope.Metadata.Keys.Contains("key1").Should().BeTrue();
|
||||
envelope.Metadata.Keys.Contains("key2").Should().BeTrue();
|
||||
envelope.Metadata["key1"].Should().Be("value1");
|
||||
envelope.Metadata["key2"].Should().Be("value2");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PublishEventAsync_WithCancelledToken()
|
||||
{
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions { HttpClient = httpClient, ThrowOperationCanceledOnCancellation = true })
|
||||
.Build();
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var ctSource = new CancellationTokenSource();
|
||||
CancellationToken ct = ctSource.Token;
|
||||
ctSource.Cancel();
|
||||
var cts = new CancellationTokenSource();
|
||||
cts.Cancel();
|
||||
|
||||
await FluentActions.Awaiting(async () => await daprClient.PublishEventAsync(TestPubsubName, "test", cancellationToken: ct))
|
||||
.Should().ThrowAsync<OperationCanceledException>();
|
||||
await Assert.ThrowsAsync<OperationCanceledException>(async () =>
|
||||
{
|
||||
await client.InnerClient.PublishEventAsync(TestPubsubName, "test", cancellationToken: cts.Token);
|
||||
});
|
||||
}
|
||||
|
||||
// All overloads call through a common path that does exception handling.
|
||||
|
|
|
@ -7,13 +7,10 @@ namespace Dapr.Client.Test
|
|||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using FluentAssertions;
|
||||
using Google.Rpc;
|
||||
using Grpc.Core;
|
||||
using Grpc.Net.Client;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
using Autogenerated = Dapr.Client.Autogen.Grpc.v1;
|
||||
|
@ -23,67 +20,66 @@ namespace Dapr.Client.Test
|
|||
[Fact]
|
||||
public async Task GetSecretAsync_ValidateRequest()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions { HttpClient = httpClient })
|
||||
.Build();
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var metadata = new Dictionary<string, string>
|
||||
{
|
||||
{ "key1", "value1" },
|
||||
{ "key2", "value2" }
|
||||
};
|
||||
var task = daprClient.GetSecretAsync("testStore", "test_key", metadata);
|
||||
var request = await client.CaptureGrpcRequestAsync(async daprClient =>
|
||||
{
|
||||
return await daprClient.GetSecretAsync("testStore", "test_key", metadata);
|
||||
});
|
||||
|
||||
request.Dismiss();
|
||||
|
||||
// Get Request and validate
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var request = await GrpcUtils.GetRequestFromRequestMessageAsync<Autogenerated.GetSecretRequest>(entry.Request);
|
||||
request.StoreName.Should().Be("testStore");
|
||||
request.Key.Should().Be("test_key");
|
||||
request.Metadata.Count.Should().Be(2);
|
||||
request.Metadata.Keys.Contains("key1").Should().BeTrue();
|
||||
request.Metadata.Keys.Contains("key2").Should().BeTrue();
|
||||
request.Metadata["key1"].Should().Be("value1");
|
||||
request.Metadata["key2"].Should().Be("value2");
|
||||
var envelope = await request.GetRequestEnvelopeAsync<Autogenerated.GetSecretRequest>();
|
||||
envelope.StoreName.Should().Be("testStore");
|
||||
envelope.Key.Should().Be("test_key");
|
||||
envelope.Metadata.Count.Should().Be(2);
|
||||
envelope.Metadata.Keys.Contains("key1").Should().BeTrue();
|
||||
envelope.Metadata.Keys.Contains("key2").Should().BeTrue();
|
||||
envelope.Metadata["key1"].Should().Be("value1");
|
||||
envelope.Metadata["key2"].Should().Be("value2");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetSecretAsync_ReturnSingleSecret()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions { HttpClient = httpClient })
|
||||
.Build();
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var metadata = new Dictionary<string, string>
|
||||
{
|
||||
{ "key1", "value1" },
|
||||
{ "key2", "value2" }
|
||||
};
|
||||
var task = daprClient.GetSecretAsync("testStore", "test_key", metadata);
|
||||
var request = await client.CaptureGrpcRequestAsync(async daprClient =>
|
||||
{
|
||||
return await daprClient.GetSecretAsync("testStore", "test_key", metadata);
|
||||
});
|
||||
|
||||
request.Dismiss();
|
||||
|
||||
// Get Request and validate
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var request = await GrpcUtils.GetRequestFromRequestMessageAsync<Autogenerated.GetSecretRequest>(entry.Request);
|
||||
request.StoreName.Should().Be("testStore");
|
||||
request.Key.Should().Be("test_key");
|
||||
request.Metadata.Count.Should().Be(2);
|
||||
request.Metadata.Keys.Contains("key1").Should().BeTrue();
|
||||
request.Metadata.Keys.Contains("key2").Should().BeTrue();
|
||||
request.Metadata["key1"].Should().Be("value1");
|
||||
request.Metadata["key2"].Should().Be("value2");
|
||||
var envelope = await request.GetRequestEnvelopeAsync<Autogenerated.GetSecretRequest>();
|
||||
envelope.StoreName.Should().Be("testStore");
|
||||
envelope.Key.Should().Be("test_key");
|
||||
envelope.Metadata.Count.Should().Be(2);
|
||||
envelope.Metadata.Keys.Contains("key1").Should().BeTrue();
|
||||
envelope.Metadata.Keys.Contains("key2").Should().BeTrue();
|
||||
envelope.Metadata["key1"].Should().Be("value1");
|
||||
envelope.Metadata["key2"].Should().Be("value2");
|
||||
|
||||
// Create Response & Respond
|
||||
var secrets = new Dictionary<string, string>
|
||||
{
|
||||
{ "redis_secret", "Guess_Redis" }
|
||||
};
|
||||
await SendResponseWithSecrets(secrets, entry);
|
||||
var secretsResponse = await SendResponseWithSecrets(secrets, request);
|
||||
|
||||
// Get response and validate
|
||||
var secretsResponse = await task;
|
||||
secretsResponse.Count.Should().Be(1);
|
||||
secretsResponse.ContainsKey("redis_secret").Should().BeTrue();
|
||||
secretsResponse["redis_secret"].Should().Be("Guess_Redis");
|
||||
|
@ -92,29 +88,29 @@ namespace Dapr.Client.Test
|
|||
[Fact]
|
||||
public async Task GetSecretAsync_ReturnMultipleSecrets()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions { HttpClient = httpClient })
|
||||
.Build();
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var metadata = new Dictionary<string, string>
|
||||
{
|
||||
{ "key1", "value1" },
|
||||
{ "key2", "value2" }
|
||||
};
|
||||
var task = daprClient.GetSecretAsync("testStore", "test_key", metadata);
|
||||
var request = await client.CaptureGrpcRequestAsync(async daprClient =>
|
||||
{
|
||||
return await daprClient.GetSecretAsync("testStore", "test_key", metadata);
|
||||
});
|
||||
|
||||
request.Dismiss();
|
||||
|
||||
// Get Request and validate
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var request = await GrpcUtils.GetRequestFromRequestMessageAsync<Autogenerated.GetSecretRequest>(entry.Request);
|
||||
request.StoreName.Should().Be("testStore");
|
||||
request.Key.Should().Be("test_key");
|
||||
request.Metadata.Count.Should().Be(2);
|
||||
request.Metadata.Keys.Contains("key1").Should().BeTrue();
|
||||
request.Metadata.Keys.Contains("key2").Should().BeTrue();
|
||||
request.Metadata["key1"].Should().Be("value1");
|
||||
request.Metadata["key2"].Should().Be("value2");
|
||||
var envelope = await request.GetRequestEnvelopeAsync<Autogenerated.GetSecretRequest>();
|
||||
envelope.StoreName.Should().Be("testStore");
|
||||
envelope.Key.Should().Be("test_key");
|
||||
envelope.Metadata.Count.Should().Be(2);
|
||||
envelope.Metadata.Keys.Contains("key1").Should().BeTrue();
|
||||
envelope.Metadata.Keys.Contains("key2").Should().BeTrue();
|
||||
envelope.Metadata["key1"].Should().Be("value1");
|
||||
envelope.Metadata["key2"].Should().Be("value2");
|
||||
|
||||
// Create Response & Respond
|
||||
var secrets = new Dictionary<string, string>
|
||||
|
@ -122,10 +118,9 @@ namespace Dapr.Client.Test
|
|||
{ "redis_secret", "Guess_Redis" },
|
||||
{ "kafka_secret", "Guess_Kafka" }
|
||||
};
|
||||
await SendResponseWithSecrets(secrets, entry);
|
||||
var secretsResponse = await SendResponseWithSecrets(secrets, request);
|
||||
|
||||
// Get response and validate
|
||||
var secretsResponse = await task;
|
||||
secretsResponse.Count.Should().Be(2);
|
||||
secretsResponse.ContainsKey("redis_secret").Should().BeTrue();
|
||||
secretsResponse["redis_secret"].Should().Be("Guess_Redis");
|
||||
|
@ -136,11 +131,7 @@ namespace Dapr.Client.Test
|
|||
[Fact]
|
||||
public async Task GetSecretAsync_WithCancelledToken()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions { HttpClient = httpClient, ThrowOperationCanceledOnCancellation = true })
|
||||
.Build();
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var metadata = new Dictionary<string, string>
|
||||
{
|
||||
|
@ -148,11 +139,13 @@ namespace Dapr.Client.Test
|
|||
{ "key2", "value2" }
|
||||
};
|
||||
|
||||
var ctSource = new CancellationTokenSource();
|
||||
CancellationToken ct = ctSource.Token;
|
||||
ctSource.Cancel();
|
||||
await FluentActions.Awaiting(async () => await daprClient.GetSecretAsync("testStore", "test_key", metadata, cancellationToken: ct))
|
||||
.Should().ThrowAsync<OperationCanceledException>();
|
||||
var cts = new CancellationTokenSource();
|
||||
cts.Cancel();
|
||||
|
||||
await Assert.ThrowsAsync<OperationCanceledException>(async () =>
|
||||
{
|
||||
await client.InnerClient.GetSecretAsync("testStore", "test_key", metadata, cancellationToken: cts.Token);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -178,59 +171,58 @@ namespace Dapr.Client.Test
|
|||
[Fact]
|
||||
public async Task GetBulkSecretAsync_ValidateRequest()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions { HttpClient = httpClient })
|
||||
.Build();
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var metadata = new Dictionary<string, string>();
|
||||
metadata.Add("key1", "value1");
|
||||
metadata.Add("key2", "value2");
|
||||
var task = daprClient.GetBulkSecretAsync("testStore", metadata);
|
||||
|
||||
var request = await client.CaptureGrpcRequestAsync(async daprClient =>
|
||||
{
|
||||
return await daprClient.GetBulkSecretAsync("testStore", metadata);
|
||||
});
|
||||
|
||||
request.Dismiss();
|
||||
|
||||
// Get Request and validate
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var request = await GrpcUtils.GetRequestFromRequestMessageAsync<Autogenerated.GetBulkSecretRequest>(entry.Request);
|
||||
request.StoreName.Should().Be("testStore");
|
||||
request.Metadata.Count.Should().Be(2);
|
||||
request.Metadata.Keys.Contains("key1").Should().BeTrue();
|
||||
request.Metadata.Keys.Contains("key2").Should().BeTrue();
|
||||
request.Metadata["key1"].Should().Be("value1");
|
||||
request.Metadata["key2"].Should().Be("value2");
|
||||
var envelope = await request.GetRequestEnvelopeAsync<Autogenerated.GetBulkSecretRequest>();
|
||||
envelope.StoreName.Should().Be("testStore");
|
||||
envelope.Metadata.Count.Should().Be(2);
|
||||
envelope.Metadata.Keys.Contains("key1").Should().BeTrue();
|
||||
envelope.Metadata.Keys.Contains("key2").Should().BeTrue();
|
||||
envelope.Metadata["key1"].Should().Be("value1");
|
||||
envelope.Metadata["key2"].Should().Be("value2");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetBulkSecretAsync_ReturnSingleSecret()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions { HttpClient = httpClient })
|
||||
.Build();
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var metadata = new Dictionary<string, string>();
|
||||
metadata.Add("key1", "value1");
|
||||
metadata.Add("key2", "value2");
|
||||
var task = daprClient.GetBulkSecretAsync("testStore", metadata);
|
||||
|
||||
var request = await client.CaptureGrpcRequestAsync(async daprClient =>
|
||||
{
|
||||
return await daprClient.GetBulkSecretAsync("testStore", metadata);
|
||||
});
|
||||
|
||||
// Get Request and validate
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var request = await GrpcUtils.GetRequestFromRequestMessageAsync<Autogenerated.GetBulkSecretRequest>(entry.Request);
|
||||
request.StoreName.Should().Be("testStore");
|
||||
request.Metadata.Count.Should().Be(2);
|
||||
request.Metadata.Keys.Contains("key1").Should().BeTrue();
|
||||
request.Metadata.Keys.Contains("key2").Should().BeTrue();
|
||||
request.Metadata["key1"].Should().Be("value1");
|
||||
request.Metadata["key2"].Should().Be("value2");
|
||||
var envelope = await request.GetRequestEnvelopeAsync<Autogenerated.GetBulkSecretRequest>();
|
||||
envelope.StoreName.Should().Be("testStore");
|
||||
envelope.Metadata.Count.Should().Be(2);
|
||||
envelope.Metadata.Keys.Contains("key1").Should().BeTrue();
|
||||
envelope.Metadata.Keys.Contains("key2").Should().BeTrue();
|
||||
envelope.Metadata["key1"].Should().Be("value1");
|
||||
envelope.Metadata["key2"].Should().Be("value2");
|
||||
|
||||
// Create Response & Respond
|
||||
var secrets = new Dictionary<string, string>();
|
||||
secrets.Add("redis_secret", "Guess_Redis");
|
||||
await SendBulkResponseWithSecrets(secrets, entry);
|
||||
var secretsResponse = await SendBulkResponseWithSecrets(secrets, request);
|
||||
|
||||
// Get response and validate
|
||||
var secretsResponse = await task;
|
||||
secretsResponse.Count.Should().Be(1);
|
||||
secretsResponse.ContainsKey("redis_secret").Should().BeTrue();
|
||||
secretsResponse["redis_secret"]["redis_secret"].Should().Be("Guess_Redis");
|
||||
|
@ -239,35 +231,34 @@ namespace Dapr.Client.Test
|
|||
[Fact]
|
||||
public async Task GetBulkSecretAsync_ReturnMultipleSecrets()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions { HttpClient = httpClient })
|
||||
.Build();
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var metadata = new Dictionary<string, string>();
|
||||
metadata.Add("key1", "value1");
|
||||
metadata.Add("key2", "value2");
|
||||
var task = daprClient.GetBulkSecretAsync("testStore", metadata);
|
||||
|
||||
var request = await client.CaptureGrpcRequestAsync(async daprClient =>
|
||||
{
|
||||
return await daprClient.GetBulkSecretAsync("testStore", metadata);
|
||||
});
|
||||
|
||||
|
||||
// Get Request and validate
|
||||
httpClient.Requests.TryDequeue(out var entry).Should().BeTrue();
|
||||
var request = await GrpcUtils.GetRequestFromRequestMessageAsync<Autogenerated.GetBulkSecretRequest>(entry.Request);
|
||||
request.StoreName.Should().Be("testStore");
|
||||
request.Metadata.Count.Should().Be(2);
|
||||
request.Metadata.Keys.Contains("key1").Should().BeTrue();
|
||||
request.Metadata.Keys.Contains("key2").Should().BeTrue();
|
||||
request.Metadata["key1"].Should().Be("value1");
|
||||
request.Metadata["key2"].Should().Be("value2");
|
||||
var envelope = await request.GetRequestEnvelopeAsync<Autogenerated.GetBulkSecretRequest>();
|
||||
envelope.StoreName.Should().Be("testStore");
|
||||
envelope.Metadata.Count.Should().Be(2);
|
||||
envelope.Metadata.Keys.Contains("key1").Should().BeTrue();
|
||||
envelope.Metadata.Keys.Contains("key2").Should().BeTrue();
|
||||
envelope.Metadata["key1"].Should().Be("value1");
|
||||
envelope.Metadata["key2"].Should().Be("value2");
|
||||
|
||||
// Create Response & Respond
|
||||
var secrets = new Dictionary<string, string>();
|
||||
secrets.Add("redis_secret", "Guess_Redis");
|
||||
secrets.Add("kafka_secret", "Guess_Kafka");
|
||||
await SendBulkResponseWithSecrets(secrets, entry);
|
||||
var secretsResponse = await SendBulkResponseWithSecrets(secrets, request);
|
||||
|
||||
// Get response and validate
|
||||
var secretsResponse = await task;
|
||||
secretsResponse.Count.Should().Be(2);
|
||||
secretsResponse.ContainsKey("redis_secret").Should().BeTrue();
|
||||
secretsResponse["redis_secret"]["redis_secret"].Should().Be("Guess_Redis");
|
||||
|
@ -278,21 +269,19 @@ namespace Dapr.Client.Test
|
|||
[Fact]
|
||||
public async Task GetBulkSecretAsync_WithCancelledToken()
|
||||
{
|
||||
// Configure Client
|
||||
var httpClient = new TestHttpClient();
|
||||
var daprClient = new DaprClientBuilder()
|
||||
.UseGrpcChannelOptions(new GrpcChannelOptions { HttpClient = httpClient, ThrowOperationCanceledOnCancellation = true })
|
||||
.Build();
|
||||
await using var client = TestClient.CreateForDaprClient();
|
||||
|
||||
var metadata = new Dictionary<string, string>();
|
||||
metadata.Add("key1", "value1");
|
||||
metadata.Add("key2", "value2");
|
||||
|
||||
var ctSource = new CancellationTokenSource();
|
||||
CancellationToken ct = ctSource.Token;
|
||||
ctSource.Cancel();
|
||||
await FluentActions.Awaiting(async () => await daprClient.GetBulkSecretAsync("testStore", metadata, cancellationToken: ct))
|
||||
.Should().ThrowAsync<OperationCanceledException>();
|
||||
var cts = new CancellationTokenSource();
|
||||
cts.Cancel();
|
||||
|
||||
await Assert.ThrowsAsync<OperationCanceledException>(async () =>
|
||||
{
|
||||
await client.InnerClient.GetBulkSecretAsync("testStore", metadata, cancellationToken: cts.Token);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -315,17 +304,15 @@ namespace Dapr.Client.Test
|
|||
Assert.Same(rpcException, ex.InnerException);
|
||||
}
|
||||
|
||||
private async Task SendResponseWithSecrets(Dictionary<string, string> secrets, TestHttpClient.Entry entry)
|
||||
private async Task<TResponse> SendResponseWithSecrets<TResponse>(Dictionary<string, string> secrets, TestClient<DaprClient>.TestGrpcRequest<TResponse> request)
|
||||
{
|
||||
var secretResponse = new Autogenerated.GetSecretResponse();
|
||||
secretResponse.Data.Add(secrets);
|
||||
|
||||
var streamContent = await GrpcUtils.CreateResponseContent(secretResponse);
|
||||
var response = GrpcUtils.CreateResponse(HttpStatusCode.OK, streamContent);
|
||||
entry.Completion.SetResult(response);
|
||||
return await request.CompleteWithMessageAsync(secretResponse);
|
||||
}
|
||||
|
||||
private async Task SendBulkResponseWithSecrets(Dictionary<string, string> secrets, TestHttpClient.Entry entry)
|
||||
private async Task<TResponse> SendBulkResponseWithSecrets<TResponse>(Dictionary<string, string> secrets, TestClient<DaprClient>.TestGrpcRequest<TResponse> request)
|
||||
{
|
||||
var getBulkSecretResponse = new Autogenerated.GetBulkSecretResponse();
|
||||
foreach (var secret in secrets)
|
||||
|
@ -335,9 +322,7 @@ namespace Dapr.Client.Test
|
|||
getBulkSecretResponse.Data.Add(secret.Key, secretsResponse);
|
||||
}
|
||||
|
||||
var streamContent = await GrpcUtils.CreateResponseContent(getBulkSecretResponse);
|
||||
var response = GrpcUtils.CreateResponse(HttpStatusCode.OK, streamContent);
|
||||
entry.Completion.SetResult(response);
|
||||
return await request.CompleteWithMessageAsync(getBulkSecretResponse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -14,8 +14,8 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\Shared\TestHttpClient.cs" />
|
||||
<Compile Include="..\Shared\GrpcUtils.cs" />
|
||||
<Compile Include="..\Shared\TestClient.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -16,6 +16,10 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace Dapr.Extensions.Configuration.Test
|
||||
{
|
||||
// These tests use the outdated TestHttpClient infrastructure because they need to
|
||||
// support testing with synchronous HTTP requests.
|
||||
//
|
||||
// Don't copy this pattern elsewhere.
|
||||
public class DaprSecretStoreConfigurationProviderTest
|
||||
{
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace Dapr
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
// This client will capture all requests, and put them in .Requests for you to inspect.
|
||||
// This is an old piece of infrastructure with some limitations, don't use it in new places.
|
||||
public class TestHttpClient : HttpClient
|
||||
{
|
||||
private readonly TestHttpClientHandler handler;
|
|
@ -21,20 +21,15 @@ namespace Dapr
|
|||
public class AppCallbackClient : HttpClient
|
||||
{
|
||||
public AppCallbackClient(AppCallbackBase callbackService)
|
||||
: this(new TestHttpClientHandler(callbackService))
|
||||
: base(new Handler(callbackService))
|
||||
{
|
||||
}
|
||||
|
||||
private AppCallbackClient(TestHttpClientHandler handler)
|
||||
: base(handler)
|
||||
{
|
||||
}
|
||||
|
||||
private class TestHttpClientHandler : HttpMessageHandler
|
||||
private class Handler : HttpMessageHandler
|
||||
{
|
||||
private readonly AppCallbackBase callbackService;
|
||||
|
||||
public TestHttpClientHandler(AppCallbackBase callbackService)
|
||||
public Handler(AppCallbackBase callbackService)
|
||||
{
|
||||
this.callbackService = callbackService;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,420 @@
|
|||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
#if ACTORS
|
||||
using Dapr.Actors;
|
||||
#endif
|
||||
using Dapr.Client;
|
||||
using Google.Protobuf;
|
||||
using Grpc.Net.Client;
|
||||
|
||||
namespace Dapr
|
||||
{
|
||||
public abstract class TestClient
|
||||
{
|
||||
#if ACTORS
|
||||
internal static TestClient<DaprHttpInteractor> CreateForDaprHttpInterator(string? apiToken = null)
|
||||
{
|
||||
var handler = new CapturingHandler();
|
||||
return new TestClient<DaprHttpInteractor>(new DaprHttpInteractor(handler, apiToken), handler);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static TestClient<HttpMessageHandler> CreateForMessageHandler()
|
||||
{
|
||||
var handler = new CapturingHandler();
|
||||
return new TestClient<HttpMessageHandler>(handler, handler);
|
||||
}
|
||||
|
||||
public static TestClient<DaprClient> CreateForDaprClient(Action<DaprClientBuilder>? configure = default)
|
||||
{
|
||||
var handler = new CapturingHandler();
|
||||
var httpClient = new HttpClient(handler);
|
||||
|
||||
var builder = new DaprClientBuilder();
|
||||
configure?.Invoke(builder);
|
||||
|
||||
builder.UseHttpClientFactory(() => httpClient);
|
||||
builder.UseGrpcChannelOptions(new GrpcChannelOptions()
|
||||
{
|
||||
HttpClient = httpClient,
|
||||
ThrowOperationCanceledOnCancellation = true,
|
||||
});
|
||||
|
||||
return new TestClient<DaprClient>(builder.Build(), handler);
|
||||
}
|
||||
|
||||
private static async Task WithTimeout(Task task, TimeSpan timeout, string message)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<object>();
|
||||
|
||||
using var cts = new CancellationTokenSource(timeout);
|
||||
using (cts.Token.Register((obj) =>
|
||||
{
|
||||
var tcs = (TaskCompletionSource<object>)obj!;
|
||||
tcs.SetException(new TimeoutException());
|
||||
}, tcs))
|
||||
{
|
||||
await (await Task.WhenAny(task, tcs.Task));
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<T> WithTimeout<T>(Task<T> task, TimeSpan timeout, string message)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<T>();
|
||||
|
||||
using var cts = new CancellationTokenSource(timeout);
|
||||
using (cts.Token.Register((obj) =>
|
||||
{
|
||||
var tcs = (TaskCompletionSource<T>)obj!;
|
||||
tcs.SetException(new TimeoutException());
|
||||
}, tcs))
|
||||
{
|
||||
return await (await Task.WhenAny<T>(task, tcs.Task));
|
||||
}
|
||||
}
|
||||
|
||||
public class TestHttpRequest
|
||||
{
|
||||
public TestHttpRequest(HttpRequestMessage request, CaptureToken capture, Task task)
|
||||
{
|
||||
this.Request = request;
|
||||
this.Capture = capture;
|
||||
this.Task = task;
|
||||
}
|
||||
|
||||
public HttpRequestMessage Request { get; }
|
||||
|
||||
private CaptureToken Capture { get; }
|
||||
|
||||
private Task Task { get; }
|
||||
|
||||
public async Task CompleteAsync(HttpResponseMessage response)
|
||||
{
|
||||
this.Capture.Response.SetResult(response);
|
||||
await WithTimeout(this.Task, TimeSpan.FromSeconds(10), "Waiting for response to be completed timed out.");
|
||||
}
|
||||
|
||||
public async Task CompleteWithExceptionAsync(Exception ex)
|
||||
{
|
||||
this.Capture.Response.SetException(ex);
|
||||
await WithTimeout(this.Task, TimeSpan.FromSeconds(10), "Waiting for response to be completed timed out.");
|
||||
}
|
||||
|
||||
public void Dismiss()
|
||||
{
|
||||
this.Capture.IsDismissed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public class TestHttpRequest<T>
|
||||
{
|
||||
public TestHttpRequest(HttpRequestMessage request, CaptureToken capture, Task<T> task)
|
||||
{
|
||||
this.Request = request;
|
||||
this.Capture = capture;
|
||||
this.Task = task;
|
||||
}
|
||||
|
||||
public HttpRequestMessage Request { get; }
|
||||
|
||||
private CaptureToken Capture { get; }
|
||||
|
||||
private Task<T> Task { get; }
|
||||
|
||||
public async Task<T> CompleteWithJsonAsync<TData>(TData value, JsonSerializerOptions options)
|
||||
{
|
||||
var bytes = JsonSerializer.SerializeToUtf8Bytes(value, options);
|
||||
var response = new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new ByteArrayContent(bytes)
|
||||
};
|
||||
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json") { CharSet = "UTF-8", };
|
||||
return await CompleteAsync(response);
|
||||
}
|
||||
|
||||
public async Task<T> CompleteAsync(HttpResponseMessage response)
|
||||
{
|
||||
this.Capture.Response.SetResult(response);
|
||||
return await WithTimeout<T>(this.Task, TimeSpan.FromSeconds(10), "Waiting for response to be completed timed out.");
|
||||
}
|
||||
|
||||
public async Task CompleteWithExceptionAsync(Exception ex)
|
||||
{
|
||||
this.Capture.Response.SetException(ex);
|
||||
await WithTimeout(this.Task, TimeSpan.FromSeconds(10), "Waiting for response to be completed timed out.");
|
||||
}
|
||||
|
||||
public void Dismiss()
|
||||
{
|
||||
this.Capture.IsDismissed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public class TestGrpcRequest
|
||||
{
|
||||
public TestGrpcRequest(HttpRequestMessage request, CaptureToken capture, Task task)
|
||||
{
|
||||
this.Request = request;
|
||||
this.Capture = capture;
|
||||
this.Task = task;
|
||||
}
|
||||
|
||||
public HttpRequestMessage Request { get; }
|
||||
|
||||
private CaptureToken Capture { get; }
|
||||
|
||||
private Task Task { get; }
|
||||
|
||||
public async Task<TRequestEnvelope> GetRequestEnvelopeAsync<TRequestEnvelope>()
|
||||
where TRequestEnvelope : IMessage<TRequestEnvelope>, new()
|
||||
{
|
||||
return await GrpcUtils.GetRequestFromRequestMessageAsync<TRequestEnvelope>(this.Request);
|
||||
}
|
||||
|
||||
public async Task CompleteWithMessageAsync<TResponseEnvelope>(TResponseEnvelope value)
|
||||
where TResponseEnvelope : IMessage<TResponseEnvelope>
|
||||
{
|
||||
var content = await GrpcUtils.CreateResponseContent<TResponseEnvelope>(value);
|
||||
var response = GrpcUtils.CreateResponse(HttpStatusCode.OK, content);
|
||||
await CompleteAsync(response);
|
||||
}
|
||||
|
||||
public async Task CompleteAsync(HttpResponseMessage response)
|
||||
{
|
||||
this.Capture.Response.SetResult(response);
|
||||
await WithTimeout(this.Task, TimeSpan.FromSeconds(10), "Waiting for response to be completed timed out.");
|
||||
}
|
||||
|
||||
public async Task CompleteWithExceptionAsync(Exception ex)
|
||||
{
|
||||
this.Capture.Response.SetException(ex);
|
||||
await WithTimeout(this.Task, TimeSpan.FromSeconds(10), "Waiting for response to be completed timed out.");
|
||||
}
|
||||
|
||||
public void Dismiss()
|
||||
{
|
||||
this.Capture.IsDismissed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public class TestGrpcRequest<TResponse>
|
||||
{
|
||||
public TestGrpcRequest(HttpRequestMessage request, CaptureToken capture, Task<TResponse> task)
|
||||
{
|
||||
this.Request = request;
|
||||
this.Capture = capture;
|
||||
this.Task = task;
|
||||
}
|
||||
|
||||
public HttpRequestMessage Request { get; }
|
||||
|
||||
private CaptureToken Capture { get; }
|
||||
|
||||
private Task<TResponse> Task { get; }
|
||||
|
||||
public async Task<TRequestEnvelope> GetRequestEnvelopeAsync<TRequestEnvelope>()
|
||||
where TRequestEnvelope : IMessage<TRequestEnvelope>, new()
|
||||
{
|
||||
return await GrpcUtils.GetRequestFromRequestMessageAsync<TRequestEnvelope>(this.Request);
|
||||
}
|
||||
|
||||
public async Task<TResponse> CompleteWithMessageAsync<TResponseEnvelope>(TResponseEnvelope value)
|
||||
where TResponseEnvelope : IMessage<TResponseEnvelope>
|
||||
{
|
||||
var content = await GrpcUtils.CreateResponseContent<TResponseEnvelope>(value);
|
||||
var response = GrpcUtils.CreateResponse(HttpStatusCode.OK, content);
|
||||
return await CompleteAsync(response);
|
||||
}
|
||||
|
||||
public async Task<TResponse> CompleteAsync(HttpResponseMessage response)
|
||||
{
|
||||
this.Capture.Response.SetResult(response);
|
||||
return await WithTimeout<TResponse>(this.Task, TimeSpan.FromSeconds(10), "Waiting for response to be completed timed out.");
|
||||
}
|
||||
|
||||
public async Task CompleteWithExceptionAsync(Exception ex)
|
||||
{
|
||||
this.Capture.Response.SetException(ex);
|
||||
await WithTimeout(this.Task, TimeSpan.FromSeconds(10), "Waiting for response to be completed timed out.");
|
||||
}
|
||||
|
||||
public void Dismiss()
|
||||
{
|
||||
this.Capture.IsDismissed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public class CapturingHandler : HttpMessageHandler
|
||||
{
|
||||
private readonly ConcurrentQueue<CaptureToken> requests = new ConcurrentQueue<CaptureToken>();
|
||||
private readonly object @lock = new object();
|
||||
private CaptureToken? current;
|
||||
public CaptureToken Capture()
|
||||
{
|
||||
lock (this.@lock)
|
||||
{
|
||||
if (this.current is CaptureToken)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Capture operation started while already capturing. " +
|
||||
"Concurrent use of the test client is not supported.");
|
||||
}
|
||||
|
||||
return (this.current = new CaptureToken());
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<CaptureToken> GetOutstandingRequests()
|
||||
{
|
||||
foreach (var request in this.requests)
|
||||
{
|
||||
if (request.IsComplete)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return request;
|
||||
}
|
||||
}
|
||||
|
||||
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
CaptureToken? capture;
|
||||
lock (this.@lock)
|
||||
{
|
||||
if ((capture = this.current) is CaptureToken)
|
||||
{
|
||||
this.current = default;
|
||||
}
|
||||
}
|
||||
|
||||
capture ??= new CaptureToken();
|
||||
this.requests.Enqueue(capture);
|
||||
capture.Request.SetResult(request);
|
||||
|
||||
return capture.Response.Task;
|
||||
}
|
||||
}
|
||||
|
||||
public class CaptureToken
|
||||
{
|
||||
public TaskCompletionSource<HttpRequestMessage> Request { get; } = new TaskCompletionSource<HttpRequestMessage>();
|
||||
|
||||
public TaskCompletionSource<HttpResponseMessage> Response { get; } = new TaskCompletionSource<HttpResponseMessage>();
|
||||
|
||||
public bool IsDismissed { get; set; }
|
||||
|
||||
public bool IsComplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return
|
||||
IsDismissed ||
|
||||
// We assume that whomever started the work observed exceptions making the request.
|
||||
!Request.Task.IsCompletedSuccessfully ||
|
||||
Response.Task.IsCompleted;
|
||||
}
|
||||
}
|
||||
|
||||
public Task<HttpRequestMessage> GetRequestAsync(TimeSpan timeout)
|
||||
{
|
||||
return WithTimeout(Request.Task, timeout, "Waiting for request to be queued timed out.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TestClient<TClient> : TestClient, IAsyncDisposable
|
||||
{
|
||||
public TestClient(TClient innerClient, CapturingHandler handler)
|
||||
{
|
||||
this.InnerClient = innerClient;
|
||||
this.Handler = handler;
|
||||
}
|
||||
|
||||
public TClient InnerClient { get; }
|
||||
|
||||
private CapturingHandler Handler { get; }
|
||||
|
||||
public async Task<TestHttpRequest> CaptureHttpRequestAsync(Func<TClient, Task> operation)
|
||||
{
|
||||
var (request, capture, task) = await CaptureHttpRequestMessageAsync(operation);
|
||||
return new TestHttpRequest(request, capture, task);
|
||||
}
|
||||
|
||||
public async Task<TestHttpRequest<T>> CaptureHttpRequestAsync<T>(Func<TClient, Task<T>> operation)
|
||||
{
|
||||
var (request, capture, task) = await CaptureHttpRequestMessageAsync(operation);
|
||||
return new TestHttpRequest<T>(request, capture, (Task<T>)task);
|
||||
}
|
||||
|
||||
public async Task<TestGrpcRequest> CaptureGrpcRequestAsync(Func<TClient, Task> operation)
|
||||
{
|
||||
var (request, capture, task) = await CaptureHttpRequestMessageAsync(operation);
|
||||
return new TestGrpcRequest(request, capture, task);
|
||||
}
|
||||
|
||||
public async Task<TestGrpcRequest<T>> CaptureGrpcRequestAsync<T>(Func<TClient, Task<T>> operation)
|
||||
{
|
||||
var (request, capture, task) = await CaptureHttpRequestMessageAsync(operation);
|
||||
return new TestGrpcRequest<T>(request, capture, (Task<T>)task);
|
||||
}
|
||||
|
||||
private async Task<(HttpRequestMessage, CaptureToken, Task)> CaptureHttpRequestMessageAsync(Func<TClient, Task> operation)
|
||||
{
|
||||
var capture = this.Handler.Capture();
|
||||
var task = operation(this.InnerClient);
|
||||
if (task.IsFaulted)
|
||||
{
|
||||
// If the task throws, we want to bubble that up eaglerly.
|
||||
await task;
|
||||
}
|
||||
|
||||
HttpRequestMessage request;
|
||||
try
|
||||
{
|
||||
// Apply a 10 second timeout to waiting for the task to be queued. This is a very
|
||||
// generous timeout so if we hit it then it's likely a bug.
|
||||
request = await capture.GetRequestAsync(TimeSpan.FromSeconds(10));
|
||||
}
|
||||
|
||||
// If the original operation threw, report that instead of the timeout
|
||||
catch (TimeoutException) when (task.IsFaulted)
|
||||
{
|
||||
await task;
|
||||
throw; // unreachable
|
||||
}
|
||||
|
||||
return (request, capture, task);
|
||||
}
|
||||
|
||||
public ValueTask DisposeAsync()
|
||||
{
|
||||
(this.InnerClient as IDisposable)?.Dispose();
|
||||
|
||||
var requests = this.Handler.GetOutstandingRequests().ToArray();
|
||||
if (requests.Length > 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"The client has 1 or more incomplete requests. " +
|
||||
"Use 'request.Dismiss()' if the test is uninterested in the response.");
|
||||
}
|
||||
|
||||
return new ValueTask();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue