@@ -33,12 +33,25 @@ final class GRPCServerStreamHandlerTests: XCTestCase {
33
33
descriptorPromise: EventLoopPromise < MethodDescriptor > ? = nil ,
34
34
disableAssertions: Bool = false
35
35
) -> GRPCServerStreamHandler {
36
+ let serverConnectionManagementHandler = ServerConnectionManagementHandler (
37
+ eventLoop: channel. eventLoop,
38
+ maxIdleTime: nil ,
39
+ maxAge: nil ,
40
+ maxGraceTime: nil ,
41
+ keepaliveTime: nil ,
42
+ keepaliveTimeout: nil ,
43
+ allowKeepaliveWithoutCalls: false ,
44
+ minPingIntervalWithoutCalls: . minutes( 5 ) ,
45
+ requireALPN: false
46
+ )
47
+
36
48
return GRPCServerStreamHandler (
37
49
scheme: scheme,
38
50
acceptedEncodings: acceptedEncodings,
39
51
maxPayloadSize: maxPayloadSize,
40
52
methodDescriptorPromise: descriptorPromise ?? channel. eventLoop. makePromise ( ) ,
41
53
eventLoop: channel. eventLoop,
54
+ connectionManagementHandler: serverConnectionManagementHandler. syncView,
42
55
skipStateMachineAssertions: disableAssertions
43
56
)
44
57
}
@@ -974,28 +987,50 @@ final class GRPCServerStreamHandlerTests: XCTestCase {
974
987
}
975
988
976
989
struct ServerStreamHandlerTests {
977
- private func makeServerStreamHandler(
990
+ struct ConnectionAndStreamHandlers {
991
+ let streamHandler : GRPCServerStreamHandler
992
+ let connectionHandler : ServerConnectionManagementHandler
993
+ }
994
+
995
+ private func makeServerConnectionAndStreamHandlers(
978
996
channel: any Channel ,
979
997
scheme: Scheme = . http,
980
998
acceptedEncodings: CompressionAlgorithmSet = [ ] ,
981
999
maxPayloadSize: Int = . max,
982
1000
descriptorPromise: EventLoopPromise < MethodDescriptor > ? = nil ,
983
1001
disableAssertions: Bool = false
984
- ) -> GRPCServerStreamHandler {
985
- return GRPCServerStreamHandler (
1002
+ ) -> ConnectionAndStreamHandlers {
1003
+ let connectionManagementHandler = ServerConnectionManagementHandler (
1004
+ eventLoop: channel. eventLoop,
1005
+ maxIdleTime: nil ,
1006
+ maxAge: nil ,
1007
+ maxGraceTime: nil ,
1008
+ keepaliveTime: nil ,
1009
+ keepaliveTimeout: nil ,
1010
+ allowKeepaliveWithoutCalls: false ,
1011
+ minPingIntervalWithoutCalls: . minutes( 5 ) ,
1012
+ requireALPN: false
1013
+ )
1014
+ let streamHandler = GRPCServerStreamHandler (
986
1015
scheme: scheme,
987
1016
acceptedEncodings: acceptedEncodings,
988
1017
maxPayloadSize: maxPayloadSize,
989
1018
methodDescriptorPromise: descriptorPromise ?? channel. eventLoop. makePromise ( ) ,
990
1019
eventLoop: channel. eventLoop,
1020
+ connectionManagementHandler: connectionManagementHandler. syncView,
991
1021
skipStateMachineAssertions: disableAssertions
992
1022
)
1023
+
1024
+ return ConnectionAndStreamHandlers (
1025
+ streamHandler: streamHandler,
1026
+ connectionHandler: connectionManagementHandler
1027
+ )
993
1028
}
994
1029
995
1030
@Test ( " ChannelShouldQuiesceEvent is buffered and turns into RPC cancellation " )
996
1031
func shouldQuiesceEventIsBufferedBeforeHandleIsSet( ) async throws {
997
1032
let channel = EmbeddedChannel ( )
998
- let handler = self . makeServerStreamHandler ( channel: channel)
1033
+ let handler = self . makeServerConnectionAndStreamHandlers ( channel: channel) . streamHandler
999
1034
try channel. pipeline. syncOperations. addHandler ( handler)
1000
1035
channel. pipeline. fireUserInboundEventTriggered ( ChannelShouldQuiesceEvent ( ) )
1001
1036
@@ -1011,7 +1046,7 @@ struct ServerStreamHandlerTests {
1011
1046
@Test ( " ChannelShouldQuiesceEvent turns into RPC cancellation " )
1012
1047
func shouldQuiesceEventTriggersCancellation( ) async throws {
1013
1048
let channel = EmbeddedChannel ( )
1014
- let handler = self . makeServerStreamHandler ( channel: channel)
1049
+ let handler = self . makeServerConnectionAndStreamHandlers ( channel: channel) . streamHandler
1015
1050
try channel. pipeline. syncOperations. addHandler ( handler)
1016
1051
1017
1052
await withServerContextRPCCancellationHandle { handle in
@@ -1028,7 +1063,7 @@ struct ServerStreamHandlerTests {
1028
1063
@Test ( " RST_STREAM turns into RPC cancellation " )
1029
1064
func rstStreamTriggersCancellation( ) async throws {
1030
1065
let channel = EmbeddedChannel ( )
1031
- let handler = self . makeServerStreamHandler ( channel: channel)
1066
+ let handler = self . makeServerConnectionAndStreamHandlers ( channel: channel) . streamHandler
1032
1067
try channel. pipeline. syncOperations. addHandler ( handler)
1033
1068
1034
1069
await withServerContextRPCCancellationHandle { handle in
@@ -1045,6 +1080,51 @@ struct ServerStreamHandlerTests {
1045
1080
_ = try ? channel. finish ( )
1046
1081
}
1047
1082
1083
+ @Test ( " Connection FrameStats are updated when writing headers or data frames " )
1084
+ func connectionFrameStatsAreUpdatedAccordingly( ) async throws {
1085
+ let channel = EmbeddedChannel ( )
1086
+ let handlers = self . makeServerConnectionAndStreamHandlers ( channel: channel)
1087
+ try channel. pipeline. syncOperations. addHandler ( handlers. streamHandler)
1088
+
1089
+ // We have written nothing yet, so expect FrameStats/didWriteHeadersOrData to be false
1090
+ #expect( !handlers. connectionHandler. frameStats. didWriteHeadersOrData)
1091
+
1092
+ // FrameStats aren't affected by pings received
1093
+ channel. pipeline. fireChannelRead (
1094
+ NIOAny ( HTTP2Frame . FramePayload. ping ( . init( withInteger: 42 ) , ack: false ) )
1095
+ )
1096
+ #expect( !handlers. connectionHandler. frameStats. didWriteHeadersOrData)
1097
+
1098
+ // Now write back headers and make sure FrameStats are updated accordingly:
1099
+ // To do that, we first need to receive client's initial metadata...
1100
+ let clientInitialMetadata : HPACKHeaders = [
1101
+ GRPCHTTP2Keys . path. rawValue: " /SomeService/SomeMethod " ,
1102
+ GRPCHTTP2Keys . scheme. rawValue: " http " ,
1103
+ GRPCHTTP2Keys . method. rawValue: " POST " ,
1104
+ GRPCHTTP2Keys . contentType. rawValue: " application/grpc " ,
1105
+ GRPCHTTP2Keys . te. rawValue: " trailers " ,
1106
+ ]
1107
+ try channel. writeInbound (
1108
+ HTTP2Frame . FramePayload. headers ( . init( headers: clientInitialMetadata) )
1109
+ )
1110
+
1111
+ // Now we write back server's initial metadata...
1112
+ let serverInitialMetadata = RPCResponsePart . metadata ( [ : ] )
1113
+ try channel. writeOutbound ( serverInitialMetadata)
1114
+
1115
+ // And this should have updated the FrameStats
1116
+ #expect( handlers. connectionHandler. frameStats. didWriteHeadersOrData)
1117
+
1118
+ // Manually reset the FrameStats to make sure that writing data also updates it correctly.
1119
+ handlers. connectionHandler. frameStats. reset ( )
1120
+ #expect( !handlers. connectionHandler. frameStats. didWriteHeadersOrData)
1121
+ try channel. writeOutbound ( RPCResponsePart . message ( [ 42 ] ) )
1122
+ #expect( handlers. connectionHandler. frameStats. didWriteHeadersOrData)
1123
+
1124
+ // Clean up.
1125
+ // Throwing is fine: the channel is closed abruptly, errors are expected.
1126
+ _ = try ? channel. finish ( )
1127
+ }
1048
1128
}
1049
1129
1050
1130
extension EmbeddedChannel {
0 commit comments