5
5
using System . Net ;
6
6
using System . Net . Http ;
7
7
using System . Net . Http . Headers ;
8
+ using System . Net . Sockets ;
8
9
using System . Security . Authentication ;
9
10
using Microsoft . AspNetCore . Hosting ;
10
11
using Microsoft . AspNetCore . Http ;
11
12
using Microsoft . AspNetCore . Internal ;
13
+ using Microsoft . AspNetCore . InternalTesting ;
12
14
using Microsoft . AspNetCore . Server . Kestrel . Core ;
13
15
using Microsoft . AspNetCore . Server . Kestrel . Core . Features ;
14
- using Microsoft . AspNetCore . InternalTesting ;
15
16
using Microsoft . Extensions . DependencyInjection ;
16
- using Microsoft . Extensions . Diagnostics . Metrics ;
17
17
using Microsoft . Extensions . Diagnostics . Metrics . Testing ;
18
18
using Microsoft . Extensions . Hosting ;
19
19
using Microsoft . Extensions . Logging ;
@@ -23,6 +23,72 @@ namespace Interop.FunctionalTests.Http2;
23
23
[ Collection ( nameof ( NoParallelCollection ) ) ]
24
24
public class Http2RequestTests : LoggedTest
25
25
{
26
+ [ Fact ]
27
+ public async Task InvalidHandshake_MetricsHasErrorType ( )
28
+ {
29
+ // Arrange
30
+ var builder = CreateHostBuilder (
31
+ c =>
32
+ {
33
+ return Task . CompletedTask ;
34
+ } ,
35
+ protocol : HttpProtocols . Http2 ,
36
+ plaintext : true ) ;
37
+
38
+ using ( var host = builder . Build ( ) )
39
+ {
40
+ var meterFactory = host . Services . GetRequiredService < IMeterFactory > ( ) ;
41
+
42
+ // Use MeterListener for this test because we want to check that a single error.type tag is added.
43
+ // MetricCollector can't be used for this because it stores tags in a dictionary and overwrites values.
44
+ var measurementTcs = new TaskCompletionSource < Measurement < double > > ( ) ;
45
+ var meterListener = new MeterListener ( ) ;
46
+ meterListener . InstrumentPublished = ( instrument , meterListener ) =>
47
+ {
48
+ if ( instrument . Meter . Scope == meterFactory &&
49
+ instrument . Meter . Name == "Microsoft.AspNetCore.Server.Kestrel" &&
50
+ instrument . Name == "kestrel.connection.duration" )
51
+ {
52
+ meterListener . EnableMeasurementEvents ( instrument ) ;
53
+ meterListener . SetMeasurementEventCallback < double > ( ( Instrument instrument , double measurement , ReadOnlySpan < KeyValuePair < string , object > > tags , object state ) =>
54
+ {
55
+ measurementTcs . SetResult ( new Measurement < double > ( measurement , tags ) ) ;
56
+ } ) ;
57
+ }
58
+ } ;
59
+ meterListener . Start ( ) ;
60
+
61
+ await host . StartAsync ( ) ;
62
+ var client = HttpHelpers . CreateClient ( maxResponseHeadersLength : 1024 ) ;
63
+
64
+ // Act
65
+ using var socket = new Socket ( SocketType . Stream , ProtocolType . Tcp ) ;
66
+ socket . LingerState = new LingerOption ( false , 0 ) ;
67
+
68
+ socket . Connect ( IPAddress . Loopback , host . GetPort ( ) ) ;
69
+ socket . Send ( new byte [ 1024 * 16 ] ) ;
70
+
71
+ // Wait for measurement to be available.
72
+ var measurement = await measurementTcs . Task . DefaultTimeout ( ) ;
73
+
74
+ // Assert
75
+ Assert . True ( measurement . Value > 0 ) ;
76
+
77
+ var tags = measurement . Tags . ToArray ( ) ;
78
+ Assert . Equal ( "http" , ( string ) tags . Single ( t => t . Key == "network.protocol.name" ) . Value ) ;
79
+ Assert . Equal ( "2" , ( string ) tags . Single ( t => t . Key == "network.protocol.version" ) . Value ) ;
80
+ Assert . Equal ( "tcp" , ( string ) tags . Single ( t => t . Key == "network.transport" ) . Value ) ;
81
+ Assert . Equal ( "ipv4" , ( string ) tags . Single ( t => t . Key == "network.type" ) . Value ) ;
82
+ Assert . Equal ( "127.0.0.1" , ( string ) tags . Single ( t => t . Key == "server.address" ) . Value ) ;
83
+ Assert . Equal ( host . GetPort ( ) , ( int ) tags . Single ( t => t . Key == "server.port" ) . Value ) ;
84
+ Assert . Equal ( "invalid_handshake" , ( string ) tags . Single ( t => t . Key == "error.type" ) . Value ) ;
85
+
86
+ socket . Close ( ) ;
87
+
88
+ await host . StopAsync ( ) ;
89
+ }
90
+ }
91
+
26
92
[ Fact ]
27
93
public async Task GET_Metrics_HttpProtocolAndTlsSet ( )
28
94
{
0 commit comments