Skip to content

Commit 58db57b

Browse files
Plumb a clock interface through SignalR for testing (#19311)
1 parent d1d9b97 commit 58db57b

13 files changed

+224
-109
lines changed

src/SignalR/common/Http.Connections/src/Internal/HttpConnectionContext.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,6 @@ public HttpConnectionContext(string connectionId, string connectionToken, ILogge
8484
Features.Set<IConnectionInherentKeepAliveFeature>(this);
8585
}
8686

87-
internal HttpConnectionContext(string id, IDuplexPipe transport, IDuplexPipe application, ILogger logger = null)
88-
: this(id, null, logger)
89-
{
90-
Transport = transport;
91-
Application = application;
92-
}
93-
9487
public CancellationTokenSource Cancellation { get; set; }
9588

9689
public HttpTransportType TransportType { get; set; }

src/SignalR/common/Http.Connections/src/Internal/HttpConnectionManager.cs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
using System.Net.WebSockets;
1111
using System.Security.Cryptography;
1212
using System.Threading.Tasks;
13-
using Microsoft.AspNetCore.Hosting;
1413
using Microsoft.AspNetCore.Internal;
1514
using Microsoft.Extensions.Hosting;
1615
using Microsoft.Extensions.Internal;
@@ -31,24 +30,14 @@ internal partial class HttpConnectionManager
3130
private readonly TimerAwaitable _nextHeartbeat;
3231
private readonly ILogger<HttpConnectionManager> _logger;
3332
private readonly ILogger<HttpConnectionContext> _connectionLogger;
34-
private readonly bool _useSendTimeout = true;
3533
private readonly TimeSpan _disconnectTimeout;
3634

37-
public HttpConnectionManager(ILoggerFactory loggerFactory, IHostApplicationLifetime appLifetime)
38-
: this(loggerFactory, appLifetime, Options.Create(new ConnectionOptions() { DisconnectTimeout = ConnectionOptionsSetup.DefaultDisconectTimeout }))
39-
{
40-
}
41-
4235
public HttpConnectionManager(ILoggerFactory loggerFactory, IHostApplicationLifetime appLifetime, IOptions<ConnectionOptions> connectionOptions)
4336
{
4437
_logger = loggerFactory.CreateLogger<HttpConnectionManager>();
4538
_connectionLogger = loggerFactory.CreateLogger<HttpConnectionContext>();
4639
_nextHeartbeat = new TimerAwaitable(_heartbeatTickRate, _heartbeatTickRate);
4740
_disconnectTimeout = connectionOptions.Value.DisconnectTimeout ?? ConnectionOptionsSetup.DefaultDisconectTimeout;
48-
if (AppContext.TryGetSwitch("Microsoft.AspNetCore.Http.Connections.DoNotUseSendTimeout", out var timeoutDisabled))
49-
{
50-
_useSendTimeout = !timeoutDisabled;
51-
}
5241

5342
// Register these last as the callbacks could run immediately
5443
appLifetime.ApplicationStarted.Register(() => Start());
@@ -176,7 +165,7 @@ public void Scan()
176165
}
177166
else
178167
{
179-
if (!Debugger.IsAttached && _useSendTimeout)
168+
if (!Debugger.IsAttached)
180169
{
181170
connection.TryCancelSend(utcNow.Ticks);
182171
}

src/SignalR/common/Http.Connections/test/HttpConnectionDispatcherTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2347,10 +2347,10 @@ private static void SetTransport(HttpContext context, HttpTransportType transpor
23472347

23482348
private static HttpConnectionManager CreateConnectionManager(ILoggerFactory loggerFactory)
23492349
{
2350-
return new HttpConnectionManager(loggerFactory ?? new LoggerFactory(), new EmptyApplicationLifetime());
2350+
return CreateConnectionManager(loggerFactory, null);
23512351
}
23522352

2353-
private static HttpConnectionManager CreateConnectionManager(ILoggerFactory loggerFactory, TimeSpan disconnectTimeout)
2353+
private static HttpConnectionManager CreateConnectionManager(ILoggerFactory loggerFactory, TimeSpan? disconnectTimeout)
23542354
{
23552355
var connectionOptions = new ConnectionOptions();
23562356
connectionOptions.DisconnectTimeout = disconnectTimeout;

src/SignalR/common/Http.Connections/test/HttpConnectionManagerTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Threading.Tasks;
88
using Microsoft.AspNetCore.Hosting;
99
using Microsoft.AspNetCore.Http.Connections.Internal;
10+
using Microsoft.AspNetCore.Internal;
1011
using Microsoft.AspNetCore.SignalR.Tests;
1112
using Microsoft.Extensions.Hosting;
1213
using Microsoft.Extensions.Logging;
@@ -411,7 +412,7 @@ public async Task ApplicationLifetimeCanStartBeforeHttpConnectionManagerInitiali
411412
private static HttpConnectionManager CreateConnectionManager(ILoggerFactory loggerFactory, IHostApplicationLifetime lifetime = null)
412413
{
413414
lifetime = lifetime ?? new EmptyApplicationLifetime();
414-
return new HttpConnectionManager(loggerFactory, lifetime);
415+
return new HttpConnectionManager(loggerFactory, lifetime, Options.Create(new ConnectionOptions()));
415416
}
416417

417418
[Flags]

src/SignalR/common/Http.Connections/test/WebSocketsTests.cs

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,15 @@ public async Task ReceivedFramesAreWrittenToChannel(string webSocketMessageType)
3131
using (StartVerifiableLog())
3232
{
3333
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
34-
var connection = new HttpConnectionContext("foo", pair.Transport, pair.Application, LoggerFactory.CreateLogger("HttpConnectionContext1"));
34+
var connection = new HttpConnectionContext("foo", connectionToken: null, LoggerFactory.CreateLogger("HttpConnectionContext1"))
35+
{
36+
Transport = pair.Transport,
37+
Application = pair.Application,
38+
};
3539

3640
using (var feature = new TestWebSocketConnectionFeature())
3741
{
38-
var connectionContext = new HttpConnectionContext(string.Empty, null, null, LoggerFactory.CreateLogger("HttpConnectionContext2"));
42+
var connectionContext = new HttpConnectionContext(string.Empty, connectionToken: null, LoggerFactory.CreateLogger("HttpConnectionContext2"));
3943
var ws = new WebSocketsServerTransport(new WebSocketOptions(), connection.Application, connectionContext, LoggerFactory);
4044

4145
// Give the server socket to the transport and run it
@@ -79,11 +83,15 @@ public async Task WebSocketTransportSetsMessageTypeBasedOnTransferFormatFeature(
7983
using (StartVerifiableLog())
8084
{
8185
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
82-
var connection = new HttpConnectionContext("foo", pair.Transport, pair.Application, LoggerFactory.CreateLogger("HttpConnectionContext1"));
86+
var connection = new HttpConnectionContext("foo", connectionToken: null, LoggerFactory.CreateLogger("HttpConnectionContext1"))
87+
{
88+
Transport = pair.Transport,
89+
Application = pair.Application,
90+
};
8391

8492
using (var feature = new TestWebSocketConnectionFeature())
8593
{
86-
var connectionContext = new HttpConnectionContext(string.Empty, null, null, LoggerFactory.CreateLogger("HttpConnectionContext2"));
94+
var connectionContext = new HttpConnectionContext(string.Empty, connectionToken: null, LoggerFactory.CreateLogger("HttpConnectionContext2"));
8795
connectionContext.ActiveFormat = transferFormat;
8896
var ws = new WebSocketsServerTransport(new WebSocketOptions(), connection.Application, connectionContext, LoggerFactory);
8997

@@ -116,7 +124,11 @@ public async Task TransportCommunicatesErrorToApplicationWhenClientDisconnectsAb
116124
using (StartVerifiableLog())
117125
{
118126
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
119-
var connection = new HttpConnectionContext("foo", pair.Transport, pair.Application, LoggerFactory.CreateLogger("HttpConnectionContext1"));
127+
var connection = new HttpConnectionContext("foo", connectionToken: null, LoggerFactory.CreateLogger("HttpConnectionContext1"))
128+
{
129+
Transport = pair.Transport,
130+
Application = pair.Application,
131+
};
120132

121133
using (var feature = new TestWebSocketConnectionFeature())
122134
{
@@ -139,7 +151,7 @@ async Task CompleteApplicationAfterTransportCompletes()
139151
}
140152
}
141153

142-
var connectionContext = new HttpConnectionContext(string.Empty, null, null, LoggerFactory.CreateLogger("HttpConnectionContext2"));
154+
var connectionContext = new HttpConnectionContext(string.Empty, connectionToken: null, LoggerFactory.CreateLogger("HttpConnectionContext2"));
143155
var ws = new WebSocketsServerTransport(new WebSocketOptions(), connection.Application, connectionContext, LoggerFactory);
144156

145157
// Give the server socket to the transport and run it
@@ -169,7 +181,11 @@ public async Task ClientReceivesInternalServerErrorWhenTheApplicationFails()
169181
using (StartVerifiableLog())
170182
{
171183
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
172-
var connection = new HttpConnectionContext("foo", pair.Transport, pair.Application);
184+
var connection = new HttpConnectionContext("foo", connectionToken: null, LoggerFactory.CreateLogger(nameof(HttpConnectionContext)))
185+
{
186+
Transport = pair.Transport,
187+
Application = pair.Application,
188+
};
173189

174190
using (var feature = new TestWebSocketConnectionFeature())
175191
{
@@ -201,7 +217,11 @@ public async Task TransportClosesOnCloseTimeoutIfClientDoesNotSendCloseFrame()
201217
using (StartVerifiableLog())
202218
{
203219
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
204-
var connection = new HttpConnectionContext("foo", pair.Transport, pair.Application);
220+
var connection = new HttpConnectionContext("foo", connectionToken: null, LoggerFactory.CreateLogger(nameof(HttpConnectionContext)))
221+
{
222+
Transport = pair.Transport,
223+
Application = pair.Application,
224+
};
205225

206226
using (var feature = new TestWebSocketConnectionFeature())
207227
{
@@ -236,7 +256,11 @@ public async Task TransportFailsOnTimeoutWithErrorWhenApplicationFailsAndClientD
236256
using (StartVerifiableLog())
237257
{
238258
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
239-
var connection = new HttpConnectionContext("foo", pair.Transport, pair.Application);
259+
var connection = new HttpConnectionContext("foo", connectionToken: null, LoggerFactory.CreateLogger(nameof(HttpConnectionContext)))
260+
{
261+
Transport = pair.Transport,
262+
Application = pair.Application,
263+
};
240264

241265
using (var feature = new TestWebSocketConnectionFeature())
242266
{
@@ -271,7 +295,11 @@ public async Task ServerGracefullyClosesWhenApplicationEndsThenClientSendsCloseF
271295
using (StartVerifiableLog())
272296
{
273297
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
274-
var connection = new HttpConnectionContext("foo", pair.Transport, pair.Application);
298+
var connection = new HttpConnectionContext("foo", connectionToken: null, LoggerFactory.CreateLogger(nameof(HttpConnectionContext)))
299+
{
300+
Transport = pair.Transport,
301+
Application = pair.Application,
302+
};
275303

276304
using (var feature = new TestWebSocketConnectionFeature())
277305
{
@@ -311,7 +339,11 @@ public async Task ServerGracefullyClosesWhenClientSendsCloseFrameThenApplication
311339
using (StartVerifiableLog())
312340
{
313341
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
314-
var connection = new HttpConnectionContext("foo", pair.Transport, pair.Application);
342+
var connection = new HttpConnectionContext("foo", connectionToken: null, LoggerFactory.CreateLogger(nameof(HttpConnectionContext)))
343+
{
344+
Transport = pair.Transport,
345+
Application = pair.Application,
346+
};
315347

316348
using (var feature = new TestWebSocketConnectionFeature())
317349
{
@@ -354,7 +386,11 @@ public async Task SubProtocolSelectorIsUsedToSelectSubProtocol()
354386
using (StartVerifiableLog())
355387
{
356388
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
357-
var connection = new HttpConnectionContext("foo", pair.Transport, pair.Application);
389+
var connection = new HttpConnectionContext("foo", connectionToken: null, LoggerFactory.CreateLogger(nameof(HttpConnectionContext)))
390+
{
391+
Transport = pair.Transport,
392+
Application = pair.Application,
393+
};
358394

359395
using (var feature = new TestWebSocketConnectionFeature())
360396
{
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
6+
namespace Microsoft.AspNetCore.Internal
7+
{
8+
internal interface ISystemClock
9+
{
10+
/// <summary>
11+
/// Retrieves the current UTC system time.
12+
/// </summary>
13+
DateTimeOffset UtcNow { get; }
14+
15+
/// <summary>
16+
/// Retrieves ticks for the current UTC system time.
17+
/// </summary>
18+
long UtcNowTicks { get; }
19+
20+
/// <summary>
21+
/// Retrieves the current UTC system time.
22+
/// This is only safe to use from code called by the Heartbeat.
23+
/// </summary>
24+
DateTimeOffset UtcNowUnsynchronized { get; }
25+
}
26+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
6+
namespace Microsoft.AspNetCore.Internal
7+
{
8+
/// <summary>
9+
/// Provides access to the normal system clock.
10+
/// </summary>
11+
internal class SystemClock : ISystemClock
12+
{
13+
/// <summary>
14+
/// Retrieves the current UTC system time.
15+
/// </summary>
16+
public DateTimeOffset UtcNow => DateTimeOffset.UtcNow;
17+
18+
/// <summary>
19+
/// Retrieves ticks for the current UTC system time.
20+
/// </summary>
21+
public long UtcNowTicks => DateTimeOffset.UtcNow.Ticks;
22+
23+
/// <summary>
24+
/// Retrieves the current UTC system time.
25+
/// </summary>
26+
public DateTimeOffset UtcNowUnsynchronized => DateTimeOffset.UtcNow;
27+
}
28+
}

0 commit comments

Comments
 (0)