Skip to content

Commit

Permalink
Multiplexer tests for payload-based stream channels (apple#225)
Browse files Browse the repository at this point in the history
Motivation:

As part of apple#214 we added a stream channel which deals with
`HTTP2Frame.FramePayload` as well as the relevant entry points in
`HTTP2StreamMultiplexer` to create these streams. We didn't add a
corresponding set of tests.

Modifications:

- Duplicate `HTTP2StreamMultiplexerTests`
- Refactor to make use of new stream creation function and new inbound
  stream initializer
- Fix up a couple of bugs in `HTTP2StreamMultiplexer`:
  - activate pending streams on `channelActive`
  - deactivate pending streams on `channelInactive`
  - change stream writability for pending streams on `channelWritabilityChanged`
  - add implementation for `childChannelClosed(channelID:)`

Result:

- Tests for payload-based stream creation via `HTTP2StreamMultiplexer`
  • Loading branch information
glbrntt authored Aug 3, 2020
1 parent 98a86c5 commit b03b4e8
Show file tree
Hide file tree
Showing 5 changed files with 1,840 additions and 8 deletions.
21 changes: 17 additions & 4 deletions Sources/NIOHTTP2/HTTP2StreamMultiplexer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public final class HTTP2StreamMultiplexer: ChannelInboundHandler, ChannelOutboun
return
}

if let channel = streams[streamID] {
if let channel = self.streams[streamID] {
channel.receiveInboundFrame(frame)
if !channel.inList {
self.didReadChannels.append(channel)
Expand Down Expand Up @@ -136,20 +136,30 @@ public final class HTTP2StreamMultiplexer: ChannelInboundHandler, ChannelOutboun

public func channelActive(context: ChannelHandlerContext) {
// We just got channelActive. Any previously existing channels may be marked active.
for channel in self.streams.values {
self.activateChannels(self.streams.values, context: context)
self.activateChannels(self.pendingStreams.values, context: context)

context.fireChannelActive()
}

private func activateChannels<Channels: Sequence>(_ channels: Channels, context: ChannelHandlerContext) where Channels.Element == MultiplexerAbstractChannel {
for channel in channels {
// We double-check the channel activity here, because it's possible action taken during
// the activation of one of the child channels will cause the parent to close!
if context.channel.isActive {
channel.performActivation()
}
}
context.fireChannelActive()
}

public func channelInactive(context: ChannelHandlerContext) {
for channel in self.streams.values {
channel.receiveStreamClosed(nil)
}
for channel in self.pendingStreams.values {
channel.receiveStreamClosed(nil)
}

context.fireChannelInactive()
}

Expand Down Expand Up @@ -188,6 +198,9 @@ public final class HTTP2StreamMultiplexer: ChannelInboundHandler, ChannelOutboun
for channel in self.streams.values {
channel.parentChannelWritabilityChanged(newValue: context.channel.isWritable)
}
for channel in self.pendingStreams.values {
channel.parentChannelWritabilityChanged(newValue: context.channel.isWritable)
}

context.fireChannelWritabilityChanged()
}
Expand Down Expand Up @@ -409,7 +422,7 @@ extension HTTP2StreamMultiplexer {
}

internal func childChannelClosed(channelID: ObjectIdentifier) {
preconditionFailure("We don't currently support closing channels by 'channelID'")
self.pendingStreams.removeValue(forKey: channelID)
}

internal func childChannelWrite(_ frame: HTTP2Frame, promise: EventLoopPromise<Void>?) {
Expand Down
1 change: 1 addition & 0 deletions Tests/LinuxMain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class LinuxMainRunnerImpl: LinuxMainRunner {
testCase(HPACKRegressionTests.allTests),
testCase(HTTP2FrameConvertibleTests.allTests),
testCase(HTTP2FrameParserTests.allTests),
testCase(HTTP2FramePayloadStreamMultiplexerTests.allTests),
testCase(HTTP2FramePayloadToHTTP1CodecTests.allTests),
testCase(HTTP2StreamMultiplexerTests.allTests),
testCase(HTTP2ToHTTP1CodecTests.allTests),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftNIO open source project
//
// Copyright (c) 2017-2018 Apple Inc. and the SwiftNIO project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
//
// HTTP2FramePayloadStreamMultiplexerTests+XCTest.swift
//
import XCTest

///
/// NOTE: This file was generated by generate_linux_tests.rb
///
/// Do NOT edit this file directly as it will be regenerated automatically when needed.
///

extension HTTP2FramePayloadStreamMultiplexerTests {

@available(*, deprecated, message: "not actually deprecated. Just deprecated to allow deprecated tests (which test deprecated functionality) without warnings")
static var allTests : [(String, (HTTP2FramePayloadStreamMultiplexerTests) -> () throws -> Void)] {
return [
("testMultiplexerIgnoresFramesOnStream0", testMultiplexerIgnoresFramesOnStream0),
("testHeadersFramesCreateNewChannels", testHeadersFramesCreateNewChannels),
("testChannelsCloseThemselvesWhenToldTo", testChannelsCloseThemselvesWhenToldTo),
("testChannelsCloseAfterResetStreamFrameFirstThenEvent", testChannelsCloseAfterResetStreamFrameFirstThenEvent),
("testChannelsCloseAfterGoawayFrameFirstThenEvent", testChannelsCloseAfterGoawayFrameFirstThenEvent),
("testFramesForUnknownStreamsAreReported", testFramesForUnknownStreamsAreReported),
("testFramesForClosedStreamsAreReported", testFramesForClosedStreamsAreReported),
("testClosingIdleChannels", testClosingIdleChannels),
("testClosingActiveChannels", testClosingActiveChannels),
("testClosePromiseIsSatisfiedWithTheEvent", testClosePromiseIsSatisfiedWithTheEvent),
("testMultipleClosePromisesAreSatisfied", testMultipleClosePromisesAreSatisfied),
("testClosePromiseFailsWithError", testClosePromiseFailsWithError),
("testFramesAreNotDeliveredUntilStreamIsSetUp", testFramesAreNotDeliveredUntilStreamIsSetUp),
("testFramesAreNotDeliveredIfSetUpFails", testFramesAreNotDeliveredIfSetUpFails),
("testFlushingOneChannelDoesntFlushThemAll", testFlushingOneChannelDoesntFlushThemAll),
("testUnflushedWritesFailOnClose", testUnflushedWritesFailOnClose),
("testUnflushedWritesFailOnError", testUnflushedWritesFailOnError),
("testWritesFailOnClosedStreamChannels", testWritesFailOnClosedStreamChannels),
("testReadPullsInAllFrames", testReadPullsInAllFrames),
("testReadIsPerChannel", testReadIsPerChannel),
("testReadWillCauseAutomaticFrameDelivery", testReadWillCauseAutomaticFrameDelivery),
("testReadWithNoPendingDataCausesReadOnParentChannel", testReadWithNoPendingDataCausesReadOnParentChannel),
("testHandlersAreRemovedOnClosure", testHandlersAreRemovedOnClosure),
("testHandlersAreRemovedOnClosureWithError", testHandlersAreRemovedOnClosureWithError),
("testCreatingOutboundChannel", testCreatingOutboundChannel),
("testCreatingOutboundChannelClient", testCreatingOutboundChannelClient),
("testWritesOnCreatedChannelAreDelayed", testWritesOnCreatedChannelAreDelayed),
("testWritesAreCancelledOnFailingInitializer", testWritesAreCancelledOnFailingInitializer),
("testFailingInitializerDoesNotWrite", testFailingInitializerDoesNotWrite),
("testCreatedChildChannelDoesNotActivateEarly", testCreatedChildChannelDoesNotActivateEarly),
("testCreatedChildChannelActivatesIfParentIsActive", testCreatedChildChannelActivatesIfParentIsActive),
("testInitiatedChildChannelActivates", testInitiatedChildChannelActivates),
("testMultiplexerIgnoresPriorityFrames", testMultiplexerIgnoresPriorityFrames),
("testMultiplexerForwardsActiveToParent", testMultiplexerForwardsActiveToParent),
("testCreatedChildChannelCanBeClosedImmediately", testCreatedChildChannelCanBeClosedImmediately),
("testCreatedChildChannelCanBeClosedBeforeWritingHeaders", testCreatedChildChannelCanBeClosedBeforeWritingHeaders),
("testCreatedChildChannelCanBeClosedImmediatelyWhenBaseIsActive", testCreatedChildChannelCanBeClosedImmediatelyWhenBaseIsActive),
("testCreatedChildChannelCanBeClosedBeforeWritingHeadersWhenBaseIsActive", testCreatedChildChannelCanBeClosedBeforeWritingHeadersWhenBaseIsActive),
("testMultiplexerCoalescesFlushCallsDuringChannelRead", testMultiplexerCoalescesFlushCallsDuringChannelRead),
("testMultiplexerDoesntFireReadCompleteForEachFrame", testMultiplexerDoesntFireReadCompleteForEachFrame),
("testMultiplexerCorrectlyTellsAllStreamsAboutReadComplete", testMultiplexerCorrectlyTellsAllStreamsAboutReadComplete),
("testMultiplexerModifiesStreamChannelWritabilityBasedOnFixedSizeTokens", testMultiplexerModifiesStreamChannelWritabilityBasedOnFixedSizeTokens),
("testMultiplexerModifiesStreamChannelWritabilityBasedOnParentChannelWritability", testMultiplexerModifiesStreamChannelWritabilityBasedOnParentChannelWritability),
("testMultiplexerModifiesStreamChannelWritabilityBasedOnFixedSizeTokensAndChannelWritability", testMultiplexerModifiesStreamChannelWritabilityBasedOnFixedSizeTokensAndChannelWritability),
("testStreamChannelToleratesFailingInitializer", testStreamChannelToleratesFailingInitializer),
("testInboundChannelWindowSizeIsCustomisable", testInboundChannelWindowSizeIsCustomisable),
]
}
}

Loading

0 comments on commit b03b4e8

Please sign in to comment.