-
Notifications
You must be signed in to change notification settings - Fork 48
Expand file tree
/
Copy pathSecureClientFixture.cs
More file actions
108 lines (96 loc) · 4.84 KB
/
Copy pathSecureClientFixture.cs
File metadata and controls
108 lines (96 loc) · 4.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using FluentAssertions;
using Halibut.Diagnostics;
using Halibut.Diagnostics.LogCreators;
using Halibut.Logging;
using Halibut.ServiceModel;
using Halibut.Tests.Support;
using Halibut.Tests.Support.Logging;
using Halibut.Tests.TestServices;
using Halibut.TestUtils.Contracts;
using Halibut.Transport;
using Halibut.Transport.Observability;
using Halibut.Transport.Protocol;
using Halibut.Transport.Streams;
using NSubstitute;
using NUnit.Framework;
using ILog = Halibut.Diagnostics.ILog;
namespace Halibut.Tests.Transport
{
public class SecureClientFixture : IAsyncDisposable
{
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
ServiceEndPoint endpoint;
HalibutRuntime tentacle;
ILog log;
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
[SetUp]
public void SetUp()
{
var services = new DelegateServiceFactory();
services.Register<IEchoService, IAsyncEchoService>(() => new AsyncEchoService());
tentacle = new HalibutRuntimeBuilder()
.WithServerCertificate(Certificates.TentacleListening)
.WithServiceFactory(services)
.WithHalibutTimeoutsAndLimits(new HalibutTimeoutsAndLimitsForTestsBuilder().Build())
.Build();
var tentaclePort = tentacle.Listen();
tentacle.Trust(Certificates.OctopusPublicThumbprint);
endpoint = new ServiceEndPoint("https://localhost:" + tentaclePort, Certificates.TentacleListeningPublicThumbprint, tentacle.TimeoutsAndLimits)
{
ConnectionErrorRetryTimeout = TimeSpan.MaxValue
};
log = new TestContextLogCreator("Client", LogLevel.Info).ToCachingLogFactory().ForEndpoint(endpoint.BaseUri);
}
public async ValueTask DisposeAsync()
{
await tentacle.DisposeAsync();
}
[Test]
public async Task SecureClientClearsPoolWhenAllConnectionsCorrupt()
{
var halibutTimeoutsAndLimits = new HalibutTimeoutsAndLimitsForTestsBuilder().Build();
await using var connectionManager = new ConnectionManagerAsync();
var stream = Substitute.For<IMessageExchangeStream>();
stream.IdentifyAsClientAsync(Arg.Any<CancellationToken>()).Returns(Task.FromException(new ConnectionInitializationFailedException("")));
for (int i = 0; i < halibutTimeoutsAndLimits.RetryCountLimit; i++)
{
var connection = Substitute.For<IConnection>();
var limits = new HalibutTimeoutsAndLimitsForTestsBuilder().Build();
var activeConnectionLimiter = new ActiveTcpConnectionsLimiter(limits);
connection.Protocol.Returns(new MessageExchangeProtocol(stream, limits, activeConnectionLimiter, log, new NullSubscriberObserver()));
await connectionManager.ReleaseConnectionAsync(endpoint, connection, CancellationToken.None);
}
var request = new RequestMessage
{
Destination = endpoint,
ServiceName = "IEchoService",
MethodName = "SayHello",
Params = new object[] { "Fred" }
};
var tcpConnectionFactory = new TcpConnectionFactory(
Certificates.Octopus,
halibutTimeoutsAndLimits,
new StreamFactory(),
NoOpSecureConnectionObserver.Instance,
SslConfiguration.Default
);
var secureClient = new SecureListeningClient(GetProtocol, endpoint, Certificates.Octopus, log, connectionManager, tcpConnectionFactory);
ResponseMessage response = null!;
await secureClient.ExecuteTransactionAsync(async (mep, ct) => response = await mep.ExchangeAsClientAsync(request, ct), CancellationToken.None);
// The pool should be cleared after the second failure
await stream.Received(2).IdentifyAsClientAsync(Arg.Any<CancellationToken>());
// And a new valid connection should then be made
response.Result.Should().Be("Fred...");
}
static MessageExchangeProtocol GetProtocol(Stream stream, ILog logger)
{
var limits = new HalibutTimeoutsAndLimitsForTestsBuilder().Build();
var activeConnectionLimiter = new ActiveTcpConnectionsLimiter(limits);
return new MessageExchangeProtocol(new MessageExchangeStream(stream, new MessageSerializerBuilder(new LogFactory()).Build(), new NoOpControlMessageObserver(), limits, logger), limits, activeConnectionLimiter, logger, new NullSubscriberObserver());
}
}
}