Move EmbeddedChannel to its own library. (#1933)
Motivation: EmbeddedChannel is an important testing tool, and we want to use it without needing to bring along the POSIX layer. They are not tightly coupled. However, it also doesn't belong naturally in NIOCore, so we should probably put it in its own place. Modifications: - Moved EmbeddedChannel and EmbeddedEventLoop to NIOEmbedded. - Moved the tests to NIOEmbeddedTests - Duplicated some test helpers Result: Easy to use EmbeddedChannel without the POSIX layer.
This commit is contained in:
parent
d62c733653
commit
f2ab9ab422
|
@ -19,13 +19,15 @@ var targets: [PackageDescription.Target] = [
|
|||
.target(name: "NIOCore",
|
||||
dependencies: ["NIOConcurrencyHelpers", "CNIOLinux"]),
|
||||
.target(name: "_NIODataStructures"),
|
||||
.target(name: "NIOEmbedded", dependencies: ["NIOCore", "_NIODataStructures"]),
|
||||
.target(name: "NIO",
|
||||
dependencies: ["CNIOLinux",
|
||||
"CNIODarwin",
|
||||
"CNIOWindows",
|
||||
"NIOConcurrencyHelpers",
|
||||
"NIOCore",
|
||||
"_NIODataStructures"]),
|
||||
"_NIODataStructures",
|
||||
"NIOEmbedded"]),
|
||||
.target(name: "_NIOConcurrency",
|
||||
dependencies: ["NIO"]),
|
||||
.target(name: "NIOFoundationCompat", dependencies: ["NIO"]),
|
||||
|
@ -72,8 +74,10 @@ var targets: [PackageDescription.Target] = [
|
|||
dependencies: ["NIO", "NIOHTTP1", "NIOWebSocket", "NIOFoundationCompat"]),
|
||||
.target(name: "NIOAsyncAwaitDemo",
|
||||
dependencies: ["NIO", "NIOHTTP1", "_NIOConcurrency"]),
|
||||
.testTarget(name: "NIOEmbeddedTests",
|
||||
dependencies: ["NIOConcurrencyHelpers", "NIOCore", "NIOEmbedded"]),
|
||||
.testTarget(name: "NIOTests",
|
||||
dependencies: ["NIO", "NIOFoundationCompat", "NIOTestUtils", "NIOConcurrencyHelpers"]),
|
||||
dependencies: ["NIO", "NIOFoundationCompat", "NIOTestUtils", "NIOConcurrencyHelpers", "NIOEmbedded"]),
|
||||
.testTarget(name: "NIOConcurrencyHelpersTests",
|
||||
dependencies: ["NIOConcurrencyHelpers", "NIO"]),
|
||||
.testTarget(name: "NIODataStructuresTests",
|
||||
|
@ -95,6 +99,7 @@ let package = Package(
|
|||
products: [
|
||||
.library(name: "NIOCore", targets: ["NIOCore"]),
|
||||
.library(name: "NIO", targets: ["NIO"]),
|
||||
.library(name: "NIOEmbedded", targets: ["NIOEmbedded"]),
|
||||
.library(name: "_NIOConcurrency", targets: ["_NIOConcurrency"]),
|
||||
.library(name: "NIOTLS", targets: ["NIOTLS"]),
|
||||
.library(name: "NIOHTTP1", targets: ["NIOHTTP1"]),
|
||||
|
|
|
@ -12,3 +12,4 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
@_exported import NIOCore
|
||||
@_exported import NIOEmbedded
|
|
@ -2,7 +2,7 @@
|
|||
//
|
||||
// This source file is part of the SwiftNIO open source project
|
||||
//
|
||||
// Copyright (c) 2017-2020 Apple Inc. and the SwiftNIO project authors
|
||||
// Copyright (c) 2017-2021 Apple Inc. and the SwiftNIO project authors
|
||||
// Licensed under Apache License v2.0
|
||||
//
|
||||
// See LICENSE.txt for license information
|
||||
|
@ -14,6 +14,7 @@
|
|||
|
||||
import Dispatch
|
||||
import _NIODataStructures
|
||||
import NIOCore
|
||||
|
||||
private final class EmbeddedScheduledTask {
|
||||
let task: () -> Void
|
|
@ -25,6 +25,7 @@ import XCTest
|
|||
#if os(Linux) || os(FreeBSD) || os(Android)
|
||||
@testable import NIOConcurrencyHelpersTests
|
||||
@testable import NIODataStructuresTests
|
||||
@testable import NIOEmbeddedTests
|
||||
@testable import NIOFoundationCompatTests
|
||||
@testable import NIOHTTP1Tests
|
||||
@testable import NIOTLSTests
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
//
|
||||
// This source file is part of the SwiftNIO open source project
|
||||
//
|
||||
// Copyright (c) 2017-2019 Apple Inc. and the SwiftNIO project authors
|
||||
// Copyright (c) 2017-2021 Apple Inc. and the SwiftNIO project authors
|
||||
// Licensed under Apache License v2.0
|
||||
//
|
||||
// See LICENSE.txt for license information
|
||||
|
@ -13,7 +13,60 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import XCTest
|
||||
@testable import NIO
|
||||
import NIOCore
|
||||
@testable import NIOEmbedded
|
||||
|
||||
class ChannelLifecycleHandler: ChannelInboundHandler {
|
||||
public typealias InboundIn = Any
|
||||
|
||||
public enum ChannelState {
|
||||
case unregistered
|
||||
case registered
|
||||
case inactive
|
||||
case active
|
||||
}
|
||||
|
||||
public var currentState: ChannelState
|
||||
public var stateHistory: [ChannelState]
|
||||
|
||||
public init() {
|
||||
currentState = .unregistered
|
||||
stateHistory = [.unregistered]
|
||||
}
|
||||
|
||||
private func updateState(_ state: ChannelState) {
|
||||
currentState = state
|
||||
stateHistory.append(state)
|
||||
}
|
||||
|
||||
public func channelRegistered(context: ChannelHandlerContext) {
|
||||
XCTAssertEqual(currentState, .unregistered)
|
||||
XCTAssertFalse(context.channel.isActive)
|
||||
updateState(.registered)
|
||||
context.fireChannelRegistered()
|
||||
}
|
||||
|
||||
public func channelActive(context: ChannelHandlerContext) {
|
||||
XCTAssertEqual(currentState, .registered)
|
||||
XCTAssertTrue(context.channel.isActive)
|
||||
updateState(.active)
|
||||
context.fireChannelActive()
|
||||
}
|
||||
|
||||
public func channelInactive(context: ChannelHandlerContext) {
|
||||
XCTAssertEqual(currentState, .active)
|
||||
XCTAssertFalse(context.channel.isActive)
|
||||
updateState(.inactive)
|
||||
context.fireChannelInactive()
|
||||
}
|
||||
|
||||
public func channelUnregistered(context: ChannelHandlerContext) {
|
||||
XCTAssertEqual(currentState, .inactive)
|
||||
XCTAssertFalse(context.channel.isActive)
|
||||
updateState(.unregistered)
|
||||
context.fireChannelUnregistered()
|
||||
}
|
||||
}
|
||||
|
||||
class EmbeddedChannelTest: XCTestCase {
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
//
|
||||
// This source file is part of the SwiftNIO open source project
|
||||
//
|
||||
// Copyright (c) 2017-2018 Apple Inc. and the SwiftNIO project authors
|
||||
// Copyright (c) 2017-2021 Apple Inc. and the SwiftNIO project authors
|
||||
// Licensed under Apache License v2.0
|
||||
//
|
||||
// See LICENSE.txt for license information
|
||||
|
@ -12,7 +12,8 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@testable import NIO
|
||||
import NIOCore
|
||||
@testable import NIOEmbedded
|
||||
import XCTest
|
||||
|
||||
private class EmbeddedTestError: Error { }
|
|
@ -0,0 +1,61 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the SwiftNIO open source project
|
||||
//
|
||||
// Copyright (c) 2021 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
import Foundation
|
||||
import XCTest
|
||||
import NIOCore
|
||||
import NIOConcurrencyHelpers
|
||||
|
||||
// FIXME: Duplicated with NIO
|
||||
func assert(_ condition: @autoclosure () -> Bool, within time: TimeAmount, testInterval: TimeAmount? = nil, _ message: String = "condition not satisfied in time", file: StaticString = #file, line: UInt = #line) {
|
||||
let testInterval = testInterval ?? TimeAmount.nanoseconds(time.nanoseconds / 5)
|
||||
let endTime = NIODeadline.now() + time
|
||||
|
||||
repeat {
|
||||
if condition() { return }
|
||||
usleep(UInt32(testInterval.nanoseconds / 1000))
|
||||
} while (NIODeadline.now() < endTime)
|
||||
|
||||
if !condition() {
|
||||
XCTFail(message, file: (file), line: line)
|
||||
}
|
||||
}
|
||||
|
||||
extension EventLoopFuture {
|
||||
var isFulfilled: Bool {
|
||||
if self.eventLoop.inEventLoop {
|
||||
// Easy, we're on the EventLoop. Let's just use our knowledge that we run completed future callbacks
|
||||
// immediately.
|
||||
var fulfilled = false
|
||||
self.whenComplete { _ in
|
||||
fulfilled = true
|
||||
}
|
||||
return fulfilled
|
||||
} else {
|
||||
let lock = Lock()
|
||||
let group = DispatchGroup()
|
||||
var fulfilled = false // protected by lock
|
||||
|
||||
group.enter()
|
||||
self.eventLoop.execute {
|
||||
let isFulfilled = self.isFulfilled // This will now enter the above branch.
|
||||
lock.withLock {
|
||||
fulfilled = isFulfilled
|
||||
}
|
||||
group.leave()
|
||||
}
|
||||
group.wait() // this is very nasty but this is for tests only, so...
|
||||
return lock.withLock { fulfilled }
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue