Skip to content

[core] Remove swift 6 concurrency errors (WIP do not merge) #466

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 16 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -22,56 +22,58 @@ import AWSLambdaRuntime
// This code is shown for the example only and is not used in this demo.
// This code doesn't perform any type of token validation. It should be used as a reference only.
let policyAuthorizerHandler:
(APIGatewayLambdaAuthorizerRequest, LambdaContext) async throws -> APIGatewayLambdaAuthorizerPolicyResponse = {
(request: APIGatewayLambdaAuthorizerRequest, context: LambdaContext) in
@Sendable (APIGatewayLambdaAuthorizerRequest, LambdaContext) async throws ->
APIGatewayLambdaAuthorizerPolicyResponse = {
(request: APIGatewayLambdaAuthorizerRequest, context: LambdaContext) in

context.logger.debug("+++ Policy Authorizer called +++")
context.logger.debug("+++ Policy Authorizer called +++")

// typically, this function will check the validity of the incoming token received in the request
// typically, this function will check the validity of the incoming token received in the request

// then it creates and returns a response
return APIGatewayLambdaAuthorizerPolicyResponse(
principalId: "John Appleseed",
// then it creates and returns a response
return APIGatewayLambdaAuthorizerPolicyResponse(
principalId: "John Appleseed",

// this policy allows the caller to invoke any API Gateway endpoint
policyDocument: .init(statement: [
.init(
action: "execute-api:Invoke",
effect: .allow,
resource: "*"
)
// this policy allows the caller to invoke any API Gateway endpoint
policyDocument: .init(statement: [
.init(
action: "execute-api:Invoke",
effect: .allow,
resource: "*"
)

]),
]),

// this is additional context we want to return to the caller
context: [
"abc1": "xyz1",
"abc2": "xyz2",
]
)
}
// this is additional context we want to return to the caller
context: [
"abc1": "xyz1",
"abc2": "xyz2",
]
)
}

//
// This is an example of a simple authorizer that always authorizes the request.
// A simple authorizer returns a yes/no decision and optional context key-value pairs
//
// This code doesn't perform any type of token validation. It should be used as a reference only.
let simpleAuthorizerHandler:
(APIGatewayLambdaAuthorizerRequest, LambdaContext) async throws -> APIGatewayLambdaAuthorizerSimpleResponse = {
(_: APIGatewayLambdaAuthorizerRequest, context: LambdaContext) in
@Sendable (APIGatewayLambdaAuthorizerRequest, LambdaContext) async throws ->
APIGatewayLambdaAuthorizerSimpleResponse = {
(_: APIGatewayLambdaAuthorizerRequest, context: LambdaContext) in

context.logger.debug("+++ Simple Authorizer called +++")
context.logger.debug("+++ Simple Authorizer called +++")

// typically, this function will check the validity of the incoming token received in the request
// typically, this function will check the validity of the incoming token received in the request

return APIGatewayLambdaAuthorizerSimpleResponse(
// this is the authorization decision: yes or no
isAuthorized: true,
return APIGatewayLambdaAuthorizerSimpleResponse(
// this is the authorization decision: yes or no
isAuthorized: true,

// this is additional context we want to return to the caller
context: ["abc1": "xyz1"]
)
}
// this is additional context we want to return to the caller
context: ["abc1": "xyz1"]
)
}

// create the runtime and start polling for new events.
// in this demo we use the simple authorizer handler
10 changes: 5 additions & 5 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ let package = Package(
.library(name: "AWSLambdaTesting", targets: ["AWSLambdaTesting"]),
],
dependencies: [
.package(url: "https://github.com/apple/swift-nio.git", from: "2.76.0"),
.package(url: "https://github.com/apple/swift-nio.git", from: "2.77.0"),
.package(url: "https://github.com/apple/swift-log.git", from: "1.5.4"),
],
targets: [
@@ -36,8 +36,8 @@ let package = Package(
.product(name: "NIOCore", package: "swift-nio"),
.product(name: "NIOConcurrencyHelpers", package: "swift-nio"),
.product(name: "NIOPosix", package: "swift-nio"),
],
swiftSettings: [.swiftLanguageMode(.v5)]
]
// swiftSettings: [.swiftLanguageMode(.v5)]
),
.plugin(
name: "AWSLambdaPackager",
@@ -89,11 +89,11 @@ let package = Package(
.executableTarget(
name: "MockServer",
dependencies: [
.product(name: "Logging", package: "swift-log"),
.product(name: "NIOHTTP1", package: "swift-nio"),
.product(name: "NIOCore", package: "swift-nio"),
.product(name: "NIOPosix", package: "swift-nio"),
],
swiftSettings: [.swiftLanguageMode(.v5)]
]
),
]
)
4 changes: 2 additions & 2 deletions Sources/AWSLambdaRuntime/Lambda+Codable.swift
Original file line number Diff line number Diff line change
@@ -91,7 +91,7 @@ extension LambdaRuntime {
public convenience init<Event: Decodable, Output>(
decoder: JSONDecoder = JSONDecoder(),
encoder: JSONEncoder = JSONEncoder(),
body: sending @escaping (Event, LambdaContext) async throws -> Output
body: @Sendable @escaping (Event, LambdaContext) async throws -> Output
)
where
Handler == LambdaCodableAdapter<
@@ -116,7 +116,7 @@ extension LambdaRuntime {
/// - Parameter decoder: The decoder object that will be used to decode the incoming `ByteBuffer` event into the generic `Event` type. `JSONDecoder()` used as default.
public convenience init<Event: Decodable>(
decoder: JSONDecoder = JSONDecoder(),
body: sending @escaping (Event, LambdaContext) async throws -> Void
body: @Sendable @escaping (Event, LambdaContext) async throws -> Void
)
where
Handler == LambdaCodableAdapter<
11 changes: 6 additions & 5 deletions Sources/AWSLambdaRuntimeCore/Lambda+Codable.swift
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ import NIOCore

/// The protocol a decoder must conform to so that it can be used with ``LambdaCodableAdapter`` to decode incoming
/// `ByteBuffer` events.
public protocol LambdaEventDecoder {
public protocol LambdaEventDecoder: Sendable {
/// Decode the `ByteBuffer` representing the received event into the generic `Event` type
/// the handler will receive.
/// - Parameters:
@@ -28,7 +28,7 @@ public protocol LambdaEventDecoder {

/// The protocol an encoder must conform to so that it can be used with ``LambdaCodableAdapter`` to encode the generic
/// ``LambdaOutputEncoder/Output`` object into a `ByteBuffer`.
public protocol LambdaOutputEncoder {
public protocol LambdaOutputEncoder: Sendable {
associatedtype Output

/// Encode the generic type `Output` the handler has returned into a `ByteBuffer`.
@@ -52,7 +52,7 @@ public struct LambdaHandlerAdapter<
Event: Decodable,
Output,
Handler: LambdaHandler
>: LambdaWithBackgroundProcessingHandler where Handler.Event == Event, Handler.Output == Output {
>: Sendable, LambdaWithBackgroundProcessingHandler where Handler.Event == Event, Handler.Output == Output {
@usableFromInline let handler: Handler

/// Initializes an instance given a concrete handler.
@@ -86,7 +86,8 @@ public struct LambdaCodableAdapter<
Output,
Decoder: LambdaEventDecoder,
Encoder: LambdaOutputEncoder
>: StreamingLambdaHandler where Handler.Event == Event, Handler.Output == Output, Encoder.Output == Output {
>: Sendable, StreamingLambdaHandler
where Handler.Event == Event, Handler.Output == Output, Encoder.Output == Output, Encoder: Sendable, Decoder: Sendable {
@usableFromInline let handler: Handler
@usableFromInline let encoder: Encoder
@usableFromInline let decoder: Decoder
@@ -139,7 +140,7 @@ public struct LambdaCodableAdapter<
/// A ``LambdaResponseStreamWriter`` wrapper that conforms to ``LambdaResponseWriter``.
public struct LambdaCodableResponseWriter<Output, Encoder: LambdaOutputEncoder, Base: LambdaResponseStreamWriter>:
LambdaResponseWriter
where Output == Encoder.Output {
where Output == Encoder.Output, Encoder: Sendable {
@usableFromInline let underlyingStreamWriter: Base
@usableFromInline let encoder: Encoder

588 changes: 345 additions & 243 deletions Sources/AWSLambdaRuntimeCore/Lambda+LocalServer.swift

Large diffs are not rendered by default.

20 changes: 10 additions & 10 deletions Sources/AWSLambdaRuntimeCore/LambdaHandlers.swift
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ import NIOCore
/// Background work can also be executed after returning the response. After closing the response stream by calling
/// ``LambdaResponseStreamWriter/finish()`` or ``LambdaResponseStreamWriter/writeAndFinish(_:)``,
/// the ``handle(_:responseWriter:context:)`` function is free to execute any background work.
public protocol StreamingLambdaHandler {
public protocol StreamingLambdaHandler: Sendable {
/// The handler function -- implement the business logic of the Lambda function here.
/// - Parameters:
/// - event: The invocation's input data.
@@ -45,7 +45,7 @@ public protocol StreamingLambdaHandler {

/// A writer object to write the Lambda response stream into. The HTTP response is started lazily.
/// before the first call to ``write(_:)`` or ``writeAndFinish(_:)``.
public protocol LambdaResponseStreamWriter {
public protocol LambdaResponseStreamWriter: Sendable {
/// Write a response part into the stream. Bytes written are streamed continually.
/// - Parameter buffer: The buffer to write.
func write(_ buffer: ByteBuffer) async throws
@@ -64,7 +64,7 @@ public protocol LambdaResponseStreamWriter {
///
/// - note: This handler protocol does not support response streaming because the output has to be encoded prior to it being sent, e.g. it is not possible to encode a partial/incomplete JSON string.
/// This protocol also does not support the execution of background work after the response has been returned -- the ``LambdaWithBackgroundProcessingHandler`` protocol caters for such use-cases.
public protocol LambdaHandler {
public protocol LambdaHandler: Sendable {
/// Generic input type.
/// The body of the request sent to Lambda will be decoded into this type for the handler to consume.
associatedtype Event: Decodable
@@ -86,7 +86,7 @@ public protocol LambdaHandler {
/// ``LambdaResponseWriter``that is passed in as an argument, meaning that the
/// ``LambdaWithBackgroundProcessingHandler/handle(_:outputWriter:context:)`` function is then
/// free to implement any background work after the result has been sent to the AWS Lambda control plane.
public protocol LambdaWithBackgroundProcessingHandler {
public protocol LambdaWithBackgroundProcessingHandler: Sendable {
/// Generic input type.
/// The body of the request sent to Lambda will be decoded into this type for the handler to consume.
associatedtype Event: Decodable
@@ -110,7 +110,7 @@ public protocol LambdaWithBackgroundProcessingHandler {
/// Used with ``LambdaWithBackgroundProcessingHandler``.
/// A mechanism to "return" an output from ``LambdaWithBackgroundProcessingHandler/handle(_:outputWriter:context:)`` without the function needing to
/// have a return type and exit at that point. This allows for background work to be executed _after_ a response has been sent to the AWS Lambda response endpoint.
public protocol LambdaResponseWriter<Output> {
public protocol LambdaResponseWriter<Output>: Sendable {
associatedtype Output
/// Sends the generic ``LambdaResponseWriter/Output`` object (representing the computed result of the handler)
/// to the AWS Lambda response endpoint.
@@ -150,17 +150,17 @@ public struct StreamingClosureHandler: StreamingLambdaHandler {
/// A ``LambdaHandler`` conforming handler object that can be constructed with a closure.
/// Allows for a handler to be defined in a clean manner, leveraging Swift's trailing closure syntax.
public struct ClosureHandler<Event: Decodable, Output>: LambdaHandler {
let body: (Event, LambdaContext) async throws -> Output
let body: @Sendable (Event, LambdaContext) async throws -> Output

/// Initialize with a closure handler over generic `Input` and `Output` types.
/// - Parameter body: The handler function written as a closure.
public init(body: @escaping (Event, LambdaContext) async throws -> Output) where Output: Encodable {
public init(body: @Sendable @escaping (Event, LambdaContext) async throws -> Output) where Output: Encodable {
self.body = body
}

/// Initialize with a closure handler over a generic `Input` type, and a `Void` `Output`.
/// - Parameter body: The handler function written as a closure.
public init(body: @escaping (Event, LambdaContext) async throws -> Void) where Output == Void {
public init(body: @Sendable @escaping (Event, LambdaContext) async throws -> Void) where Output == Void {
self.body = body
}

@@ -194,7 +194,7 @@ extension LambdaRuntime {
>(
encoder: Encoder,
decoder: Decoder,
body: sending @escaping (Event, LambdaContext) async throws -> Output
body: @Sendable @escaping (Event, LambdaContext) async throws -> Output
)
where
Handler == LambdaCodableAdapter<
@@ -220,7 +220,7 @@ extension LambdaRuntime {
/// - body: The handler in the form of a closure.
public convenience init<Event: Decodable, Decoder: LambdaEventDecoder>(
decoder: Decoder,
body: sending @escaping (Event, LambdaContext) async throws -> Void
body: @Sendable @escaping (Event, LambdaContext) async throws -> Void
)
where
Handler == LambdaCodableAdapter<
14 changes: 10 additions & 4 deletions Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift
Original file line number Diff line number Diff line change
@@ -12,6 +12,8 @@
//
//===----------------------------------------------------------------------===//

// TODO: rewrite for Swift 6 concurrency

import Logging
import NIOCore
import NIOHTTP1
@@ -140,6 +142,7 @@ final actor LambdaRuntimeClient: LambdaRuntimeClientProtocol {
}
}

// FIXME: add support for graceful shutdown
func nextInvocation() async throws -> (Invocation, Writer) {
switch self.lambdaState {
case .idle:
@@ -336,12 +339,15 @@ final actor LambdaRuntimeClient: LambdaRuntimeClientProtocol {
case .disconnected, .connected:
fatalError("Unexpected state: \(self.connectionState)")

case .connecting(let array):
// case .connecting(let array):
case .connecting:
self.connectionState = .connected(channel, handler)
defer {
for continuation in array {
continuation.resume(returning: handler)
}
// for continuation in array {
// // This causes an error in Swift 6
// // 'self'-isolated 'handler' is passed as a 'sending' parameter; Uses in callee may race with later 'self'-isolated uses
// continuation.resume(returning: handler)
// }
}
return handler
}
303 changes: 303 additions & 0 deletions Sources/MockServer/MockHTTPServer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,303 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftAWSLambdaRuntime open source project
//
// Copyright (c) 2017-2025 Apple Inc. and the SwiftAWSLambdaRuntime project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

import Logging
import NIOCore
import NIOHTTP1
import NIOPosix
import Synchronization

// for UUID and Date
#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif

@main
struct HttpServer {
/// The server's host. (default: 127.0.0.1)
private let host: String
/// The server's port. (default: 7000)
private let port: Int
/// The server's event loop group. (default: MultiThreadedEventLoopGroup.singleton)
private let eventLoopGroup: MultiThreadedEventLoopGroup
/// the mode. Are we mocking a server for a Lambda function that expects a String or a JSON document? (default: string)
private let mode: Mode
/// the number of connections this server must accept before shutting down (default: 1)
private let maxInvocations: Int
/// the logger (control verbosity with LOG_LEVEL environment variable)
private let logger: Logger

static func main() async throws {
var log = Logger(label: "MockServer")
log.logLevel = env("LOG_LEVEL").flatMap(Logger.Level.init) ?? .info

let server = HttpServer(
host: env("HOST") ?? "127.0.0.1",
port: env("PORT").flatMap(Int.init) ?? 7000,
eventLoopGroup: .singleton,
mode: env("MODE").flatMap(Mode.init) ?? .string,
maxInvocations: env("MAX_INVOCATIONS").flatMap(Int.init) ?? 1,
logger: log
)
try await server.run()
}

/// This method starts the server and handles one unique incoming connections
/// The Lambda function will send two HTTP requests over this connection: one for the next invocation and one for the response.
private func run() async throws {
let channel = try await ServerBootstrap(group: self.eventLoopGroup)
.serverChannelOption(.backlog, value: 256)
.serverChannelOption(.socketOption(.so_reuseaddr), value: 1)
.childChannelOption(.maxMessagesPerRead, value: 1)
.bind(
host: self.host,
port: self.port
) { channel in
channel.eventLoop.makeCompletedFuture {

try channel.pipeline.syncOperations.configureHTTPServerPipeline(
withErrorHandling: true
)

return try NIOAsyncChannel(
wrappingChannelSynchronously: channel,
configuration: NIOAsyncChannel.Configuration(
inboundType: HTTPServerRequestPart.self,
outboundType: HTTPServerResponsePart.self
)
)
}
}

logger.info(
"Server started and listening",
metadata: [
"host": "\(channel.channel.localAddress?.ipAddress?.debugDescription ?? "")",
"port": "\(channel.channel.localAddress?.port ?? 0)",
"maxInvocations": "\(self.maxInvocations)",
]
)

// This counter is used to track the number of incoming connections.
// This mock servers accepts n TCP connection then shutdowns
let connectionCounter = SharedCounter(maxValue: self.maxInvocations)

// We are handling each incoming connection in a separate child task. It is important
// to use a discarding task group here which automatically discards finished child tasks.
// A normal task group retains all child tasks and their outputs in memory until they are
// consumed by iterating the group or by exiting the group. Since, we are never consuming
// the results of the group we need the group to automatically discard them; otherwise, this
// would result in a memory leak over time.
try await withThrowingDiscardingTaskGroup { group in
try await channel.executeThenClose { inbound in
for try await connectionChannel in inbound {

let counter = connectionCounter.current()
logger.trace("Handling new connection", metadata: ["connectionNumber": "\(counter)"])

group.addTask {
await self.handleConnection(channel: connectionChannel)
logger.trace("Done handling connection", metadata: ["connectionNumber": "\(counter)"])
}

if connectionCounter.increment() {
logger.info(
"Maximum number of connections reached, shutting down after current connection",
metadata: ["maxConnections": "\(self.maxInvocations)"]
)
break // this causes the server to shutdown after handling the connection
}
}
}
}
logger.info("Server shutting down")
}

/// This method handles a single connection by responsing hard coded value to a Lambda function request.
/// It handles two requests: one for the next invocation and one for the response.
/// when the maximum number of requests is reached, it closes the connection.
private func handleConnection(
channel: NIOAsyncChannel<HTTPServerRequestPart, HTTPServerResponsePart>
) async {

var requestHead: HTTPRequestHead!
var requestBody: ByteBuffer?

// each Lambda invocation results in TWO HTTP requests (next and response)
let requestCount = SharedCounter(maxValue: 2)

// Note that this method is non-throwing and we are catching any error.
// We do this since we don't want to tear down the whole server when a single connection
// encounters an error.
do {
try await channel.executeThenClose { inbound, outbound in
for try await inboundData in inbound {
let requestNumber = requestCount.current()
logger.trace("Handling request", metadata: ["requestNumber": "\(requestNumber)"])

if case .head(let head) = inboundData {
logger.trace("Received request head", metadata: ["head": "\(head)"])
requestHead = head
}
if case .body(let body) = inboundData {
logger.trace("Received request body", metadata: ["body": "\(body)"])
requestBody = body
}
if case .end(let end) = inboundData {
logger.trace("Received request end", metadata: ["end": "\(String(describing: end))"])

precondition(requestHead != nil, "Received .end without .head")
let (responseStatus, responseHeaders, responseBody) = self.processRequest(
requestHead: requestHead,
requestBody: requestBody
)

try await self.sendResponse(
responseStatus: responseStatus,
responseHeaders: responseHeaders,
responseBody: responseBody,
outbound: outbound
)

requestHead = nil

if requestCount.increment() {
logger.info(
"Maximum number of requests reached, closing this connection",
metadata: ["maxRequest": "2"]
)
break // this finishes handiling request on this connection
}
}
}
}
} catch {
logger.error("Hit error: \(error)")
}
}
/// This function process the requests and return an hard-coded response (string or JSON depending on the mode).
/// We ignore the requestBody.
private func processRequest(
requestHead: HTTPRequestHead,
requestBody: ByteBuffer?
) -> (HTTPResponseStatus, [(String, String)], String) {
var responseStatus: HTTPResponseStatus = .ok
var responseBody: String = ""
var responseHeaders: [(String, String)] = []

logger.trace(
"Processing request",
metadata: ["VERB": "\(requestHead.method)", "URI": "\(requestHead.uri)"]
)

if requestHead.uri.hasSuffix("/next") {
responseStatus = .accepted

let requestId = UUID().uuidString
switch self.mode {
case .string:
responseBody = "\"Seb\"" // must be a valid JSON document
case .json:
responseBody = "{ \"name\": \"Seb\", \"age\" : 52 }"
}
let deadline = Int64(Date(timeIntervalSinceNow: 60).timeIntervalSince1970 * 1000)
responseHeaders = [
(AmazonHeaders.requestID, requestId),
(AmazonHeaders.invokedFunctionARN, "arn:aws:lambda:us-east-1:123456789012:function:custom-runtime"),
(AmazonHeaders.traceID, "Root=1-5bef4de7-ad49b0e87f6ef6c87fc2e700;Parent=9a9197af755a6419;Sampled=1"),
(AmazonHeaders.deadline, String(deadline)),
]
} else if requestHead.uri.hasSuffix("/response") {
responseStatus = .accepted
} else if requestHead.uri.hasSuffix("/error") {
responseStatus = .ok
} else {
responseStatus = .notFound
}
logger.trace("Returning response: \(responseStatus), \(responseHeaders), \(responseBody)")
return (responseStatus, responseHeaders, responseBody)
}

private func sendResponse(
responseStatus: HTTPResponseStatus,
responseHeaders: [(String, String)],
responseBody: String,
outbound: NIOAsyncChannelOutboundWriter<HTTPServerResponsePart>
) async throws {
var headers = HTTPHeaders(responseHeaders)
headers.add(name: "Content-Length", value: "\(responseBody.utf8.count)")
headers.add(name: "KeepAlive", value: "timeout=1, max=2")

logger.trace("Writing response head")
try await outbound.write(
HTTPServerResponsePart.head(
HTTPResponseHead(
version: .init(major: 1, minor: 1), // use HTTP 1.1 it keeps connection alive between requests
status: responseStatus,
headers: headers
)
)
)
logger.trace("Writing response body")
try await outbound.write(HTTPServerResponsePart.body(.byteBuffer(ByteBuffer(string: responseBody))))
logger.trace("Writing response end")
try await outbound.write(HTTPServerResponsePart.end(nil))
}

private enum Mode: String {
case string
case json
}

private static func env(_ name: String) -> String? {
guard let value = getenv(name) else {
return nil
}
return String(cString: value)
}

private enum ServerError: Error {
case notReady
case cantBind
}

private enum AmazonHeaders {
static let requestID = "Lambda-Runtime-Aws-Request-Id"
static let traceID = "Lambda-Runtime-Trace-Id"
static let clientContext = "X-Amz-Client-Context"
static let cognitoIdentity = "X-Amz-Cognito-Identity"
static let deadline = "Lambda-Runtime-Deadline-Ms"
static let invokedFunctionARN = "Lambda-Runtime-Invoked-Function-Arn"
}

private final class SharedCounter: Sendable {
private let counterMutex = Mutex<Int>(0)
private let maxValue: Int

init(maxValue: Int) {
self.maxValue = maxValue
}
func current() -> Int {
counterMutex.withLock { $0 }
}
func increment() -> Bool {
counterMutex.withLock {
$0 += 1
return $0 >= maxValue
}
}
}
}
177 changes: 0 additions & 177 deletions Sources/MockServer/main.swift

This file was deleted.