Migrate to GitHub Actions (#44)

Migrate CI to use GitHub Actions.

### Motivation:

To migrate to GitHub actions and centralised infrastructure.

### Modifications:

Changes of note:
* Bump minimum Swift version to 5.9 in line with CI coverage.
* Adopt NIO formatting rules
* Remove scripts and docker files which are no longer needed.
* Fixup minor changes in `NIOAsyncChannel` API usage

### Result:

Feature parity with old CI plus additional soundness checks.
This commit is contained in:
Rick Newton-Rogers
2024-11-12 16:03:17 +00:00
committed by GitHub
parent c63219e40b
commit 5b9db4ad3b
34 changed files with 430 additions and 381 deletions
+8
View File
@@ -0,0 +1,8 @@
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
+14
View File
@@ -0,0 +1,14 @@
changelog:
categories:
- title: SemVer Major
labels:
- ⚠️ semver/major
- title: SemVer Minor
labels:
- semver/minor
- title: SemVer Patch
labels:
- semver/patch
- title: Other Changes
labels:
- semver/none
+18
View File
@@ -0,0 +1,18 @@
name: Main
on:
push:
branches: [main]
schedule:
- cron: "0 8,20 * * *"
jobs:
unit-tests:
name: Unit tests
uses: ./.github/workflows/unit_tests.yml
with:
linux_5_9_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -strict-concurrency=complete"
linux_5_10_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -strict-concurrency=complete"
linux_6_0_arguments_override: "--explicit-target-dependency-import-check error"
linux_nightly_6_0_arguments_override: "--explicit-target-dependency-import-check error"
linux_nightly_main_arguments_override: "--explicit-target-dependency-import-check error"
+26
View File
@@ -0,0 +1,26 @@
name: PR
on:
pull_request:
types: [opened, reopened, synchronize]
jobs:
soundness:
name: Soundness
uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main
with:
license_header_check_project_name: "swift-memcache-gsoc"
unit-tests:
name: Unit tests
uses: ./.github/workflows/unit_tests.yml
with:
linux_5_9_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -strict-concurrency=complete"
linux_5_10_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -strict-concurrency=complete"
linux_6_0_arguments_override: "--explicit-target-dependency-import-check error"
linux_nightly_6_0_arguments_override: "--explicit-target-dependency-import-check error"
linux_nightly_main_arguments_override: "--explicit-target-dependency-import-check error"
cxx-interop:
name: Cxx interop
uses: apple/swift-nio/.github/workflows/cxx_interop.yml@main
+18
View File
@@ -0,0 +1,18 @@
name: PR label
on:
pull_request:
types: [labeled, unlabeled, opened, reopened, synchronize]
jobs:
semver-label-check:
name: Semantic version label check
runs-on: ubuntu-latest
timeout-minutes: 1
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Check for Semantic Version label
uses: apple/swift-nio/.github/actions/pull_request_semver_label_checker@main
+99
View File
@@ -0,0 +1,99 @@
name: Unit tests
on:
workflow_call:
inputs:
linux_5_9_enabled:
type: boolean
description: "Boolean to enable the Linux 5.9 Swift version matrix job. Defaults to true."
default: true
linux_5_9_arguments_override:
type: string
description: "The arguments passed to swift test in the Linux 5.9 Swift version matrix job."
default: ""
linux_5_10_enabled:
type: boolean
description: "Boolean to enable the Linux 5.10 Swift version matrix job. Defaults to true."
default: true
linux_5_10_arguments_override:
type: string
description: "The arguments passed to swift test in the Linux 5.10 Swift version matrix job."
default: ""
linux_6_0_enabled:
type: boolean
description: "Boolean to enable the Linux 6.0 Swift version matrix job. Defaults to true."
default: true
linux_6_0_arguments_override:
type: string
description: "The arguments passed to swift test in the Linux 6.0 Swift version matrix job."
default: ""
linux_nightly_6_0_enabled:
type: boolean
description: "Boolean to enable the Linux nightly 6.0 Swift version matrix job. Defaults to true."
default: true
linux_nightly_6_0_arguments_override:
type: string
description: "The arguments passed to swift test in the Linux nightly 6.0 Swift version matrix job."
default: ""
linux_nightly_main_enabled:
type: boolean
description: "Boolean to enable the Linux nightly main Swift version matrix job. Defaults to true."
default: true
linux_nightly_main_arguments_override:
type: string
description: "The arguments passed to swift test in the Linux nightly main Swift version matrix job."
default: ""
jobs:
unit-tests:
name: Unit tests
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# We are specifying only the major and minor of the docker images to automatically pick up the latest patch release
swift:
- image: "swift:5.9-jammy"
swift_version: "5.9"
enabled: ${{ inputs.linux_5_9_enabled }}
- image: "swift:5.10-jammy"
swift_version: "5.10"
enabled: ${{ inputs.linux_5_10_enabled }}
- image: "swift:6.0-jammy"
swift_version: "6.0"
enabled: ${{ inputs.linux_6_0_enabled }}
- image: "swiftlang/swift:nightly-6.0-jammy"
swift_version: "nightly-6.0"
enabled: ${{ inputs.linux_nightly_6_0_enabled }}
- image: "swiftlang/swift:nightly-main-jammy"
swift_version: "nightly-main"
enabled: ${{ inputs.linux_nightly_main_enabled }}
steps:
- name: Checkout repository
if: ${{ matrix.swift.enabled }}
uses: actions/checkout@v4
with:
persist-credentials: false
submodules: true
- name: Mark the workspace as safe
if: ${{ matrix.swift.enabled }}
# https://github.com/actions/checkout/issues/766
run: git config --global --add safe.directory ${GITHUB_WORKSPACE}
- name: Run matrix job
if: ${{ matrix.swift.enabled }}
env:
SWIFT_VERSION: ${{ matrix.swift.swift_version }}
COMMAND: "swift test"
COMMAND_OVERRIDE_5_9: "swift test ${{ inputs.linux_5_9_arguments_override }}"
COMMAND_OVERRIDE_5_10: "swift test ${{ inputs.linux_5_10_arguments_override }}"
COMMAND_OVERRIDE_6_0: "swift test ${{ inputs.linux_6_0_arguments_override }}"
COMMAND_OVERRIDE_NIGHTLY_6_0: "swift test ${{ inputs.linux_nightly_6_0_arguments_override }}"
COMMAND_OVERRIDE_NIGHTLY_MAIN: "swift test ${{ inputs.linux_nightly_main_arguments_override }}"
run: |
apt-get -qq update && apt-get -qq -y install curl
curl -s https://raw.githubusercontent.com/apple/swift-nio/main/scripts/check-matrix-job.sh | bash
container:
image: ${{ matrix.swift.image }}
services:
memcached:
image: memcached:latest
+36
View File
@@ -0,0 +1,36 @@
.gitignore
**/.gitignore
.licenseignore
.gitattributes
.git-blame-ignore-revs
.mailfilter
.mailmap
.spi.yml
.swift-format
.swiftformatignore
.editorconfig
.github/*
*.md
*.txt
*.yml
*.yaml
*.json
Package.swift
**/Package.swift
Package@-*.swift
**/Package@-*.swift
Package.resolved
**/Package.resolved
Makefile
*.modulemap
**/*.modulemap
**/*.docc/*
*.xcprivacy
**/*.xcprivacy
*.symlink
**/*.symlink
Dockerfile
**/Dockerfile
Snippets/*
dev/git.commit.template
.unacceptablelanguageignore
+68
View File
@@ -0,0 +1,68 @@
{
"version" : 1,
"indentation" : {
"spaces" : 4
},
"tabWidth" : 4,
"fileScopedDeclarationPrivacy" : {
"accessLevel" : "private"
},
"spacesAroundRangeFormationOperators" : false,
"indentConditionalCompilationBlocks" : false,
"indentSwitchCaseLabels" : false,
"lineBreakAroundMultilineExpressionChainComponents" : false,
"lineBreakBeforeControlFlowKeywords" : false,
"lineBreakBeforeEachArgument" : true,
"lineBreakBeforeEachGenericRequirement" : true,
"lineLength" : 120,
"maximumBlankLines" : 1,
"respectsExistingLineBreaks" : true,
"prioritizeKeepingFunctionOutputTogether" : true,
"noAssignmentInExpressions" : {
"allowedFunctions" : [
"XCTAssertNoThrow",
"XCTAssertThrowsError"
]
},
"rules" : {
"AllPublicDeclarationsHaveDocumentation" : false,
"AlwaysUseLiteralForEmptyCollectionInit" : false,
"AlwaysUseLowerCamelCase" : false,
"AmbiguousTrailingClosureOverload" : true,
"BeginDocumentationCommentWithOneLineSummary" : false,
"DoNotUseSemicolons" : true,
"DontRepeatTypeInStaticProperties" : true,
"FileScopedDeclarationPrivacy" : true,
"FullyIndirectEnum" : true,
"GroupNumericLiterals" : true,
"IdentifiersMustBeASCII" : true,
"NeverForceUnwrap" : false,
"NeverUseForceTry" : false,
"NeverUseImplicitlyUnwrappedOptionals" : false,
"NoAccessLevelOnExtensionDeclaration" : true,
"NoAssignmentInExpressions" : true,
"NoBlockComments" : true,
"NoCasesWithOnlyFallthrough" : true,
"NoEmptyTrailingClosureParentheses" : true,
"NoLabelsInCasePatterns" : true,
"NoLeadingUnderscores" : false,
"NoParensAroundConditions" : true,
"NoVoidReturnOnFunctionSignature" : true,
"OmitExplicitReturns" : true,
"OneCasePerLine" : true,
"OneVariableDeclarationPerLine" : true,
"OnlyOneTrailingClosureArgument" : true,
"OrderedImports" : true,
"ReplaceForEachWithForLoop" : true,
"ReturnVoidInsteadOfEmptyTuple" : true,
"UseEarlyExits" : false,
"UseExplicitNilCheckInConditions" : false,
"UseLetInEveryBoundCaseVariable" : false,
"UseShorthandTypeNames" : true,
"UseSingleLinePropertyGetter" : false,
"UseSynthesizedInitializer" : false,
"UseTripleSlashForDocumentationComments" : true,
"UseWhereClausesInForLoops" : false,
"ValidateDocumentationComments" : false
}
}
-25
View File
@@ -1,25 +0,0 @@
# file options
--swiftversion 5.7
--exclude .build
# format options
--self insert
--patternlet inline
--ranges nospace
--stripunusedargs unnamed-only
--ifdef no-indent
--extensionacl on-declarations
--disable typeSugar # https://github.com/nicklockwood/SwiftFormat/issues/636
--disable andOperator
--disable wrapMultilineStatementBraces
--disable enumNamespaces
--disable redundantExtensionACL
--disable redundantReturn
--disable preferKeyPath
--disable sortedSwitchCases
--disable hoistTry
--disable hoistAwait
# rules
@@ -21,7 +21,7 @@ private let eventLoopGroup = MultiThreadedEventLoopGroup.singleton.next()
let benchmarks = {
let defaultMetrics: [BenchmarkMetric] = [
.mallocCountTotal,
.mallocCountTotal
]
Benchmark(
@@ -41,7 +41,10 @@ let benchmarks = {
timeUnits: .milliseconds
)
) { benchmark in
try await runSetWithTTLRequest(iterations: benchmark.scaledIterations.upperBound, eventLoopGroup: eventLoopGroup)
try await runSetWithTTLRequest(
iterations: benchmark.scaledIterations.upperBound,
eventLoopGroup: eventLoopGroup
)
}
Benchmark(
"Delete Request",
+4 -4
View File
@@ -1,4 +1,4 @@
// swift-tools-version: 5.7
// swift-tools-version: 5.9
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftCertificates open source project
@@ -18,7 +18,7 @@ import PackageDescription
let package = Package(
name: "Benchmarks",
platforms: [
.macOS(.v13),
.macOS(.v13)
],
dependencies: [
.package(name: "swift-memcache-gsoc", path: "../"),
@@ -36,8 +36,8 @@ let package = Package(
],
path: "Benchmarks/MemcacheBenchmarks",
plugins: [
.plugin(name: "BenchmarkPlugin", package: "package-benchmark"),
.plugin(name: "BenchmarkPlugin", package: "package-benchmark")
]
),
)
]
)
+4 -4
View File
@@ -1,4 +1,4 @@
// swift-tools-version: 5.7
// swift-tools-version: 5.9
//===----------------------------------------------------------------------===//
//
// This source file is part of the swift-memcache-gsoc open source project
@@ -27,10 +27,10 @@ let package = Package(
.library(
name: "Memcache",
targets: ["Memcache"]
),
)
],
dependencies: [
.package(url: "https://github.com/apple/swift-nio.git", from: "2.56.0"),
.package(url: "https://github.com/apple/swift-nio.git", from: "2.76.1"),
.package(url: "https://github.com/apple/swift-log.git", from: "1.0.0"),
.package(url: "https://github.com/swift-server/swift-service-lifecycle.git", from: "2.0.0"),
],
@@ -52,7 +52,7 @@ let package = Package(
.executableTarget(
name: "MemcacheExample",
dependencies: [
.target(name: "Memcache"),
.target(name: "Memcache")
]
),
]
@@ -12,12 +12,13 @@
//
//===----------------------------------------------------------------------===//
import NIOCore
#if os(Linux)
import Glibc
#else
import Darwin
#endif
import NIOCore
extension ByteBuffer {
/// Write `integer` into this `ByteBuffer` as ASCII digits, without leading zeros, moving the writer index forward appropriately.
@@ -40,7 +41,8 @@ extension ByteBuffer {
mutating func readIntegerFromASCII<T: FixedWidthInteger>() -> T? {
var value: T = 0
while self.readableBytes > 0, let currentByte = self.readInteger(as: UInt8.self),
currentByte >= UInt8.zero && currentByte <= UInt8.nine {
currentByte >= UInt8.zero && currentByte <= UInt8.nine
{
value = (value * 10) + T(currentByte - UInt8.zero)
}
return value > 0 ? value : nil
@@ -58,7 +60,10 @@ extension ByteBuffer {
/// - flags: An instance of MemcacheFlags that holds the flags intended to be serialized and written to the ByteBuffer.
mutating func writeMemcacheFlags(flags: MemcacheFlags) {
// Ensure that both storageMode and arithmeticMode aren't set at the same time.
precondition(!(flags.storageMode != nil && flags.arithmeticMode != nil), "Cannot specify both a storage and arithmetic mode.")
precondition(
!(flags.storageMode != nil && flags.arithmeticMode != nil),
"Cannot specify both a storage and arithmetic mode."
)
if let shouldReturnValue = flags.shouldReturnValue, shouldReturnValue {
self.writeInteger(UInt8.whitespace)
+32 -27
View File
@@ -11,9 +11,7 @@
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
@_spi(AsyncChannel)
import NIOCore
@_spi(AsyncChannel) import NIOCore
import NIOPosix
import ServiceLifecycle
@@ -92,7 +90,7 @@ public actor MemcacheConnection: Service {
let channel = try await ClientBootstrap(group: eventLoopGroup)
.connect(host: self.host, port: self.port)
.flatMap { channel in
return channel.eventLoop.makeCompletedFuture {
channel.eventLoop.makeCompletedFuture {
try channel.pipeline.syncOperations.addHandler(MessageToByteHandler(MemcacheRequestEncoder()))
try channel.pipeline.syncOperations.addHandler(ByteToMessageHandler(MemcacheResponseDecoder()))
return try NIOAsyncChannel<MemcacheResponse, MemcacheRequest>(synchronouslyWrapping: channel)
@@ -106,12 +104,12 @@ public actor MemcacheConnection: Service {
requestContinuation: continuation
)
var iterator = channel.inboundStream.makeAsyncIterator()
var iterator = channel.inbound.makeAsyncIterator()
switch self.state {
case .running(_, let channel, let requestStream, let requestContinuation):
for await (request, continuation) in requestStream {
do {
try await channel.outboundWriter.write(request)
try await channel.outbound.write(request)
let responseBuffer = try await iterator.next()
if let response = responseBuffer {
@@ -119,24 +117,29 @@ public actor MemcacheConnection: Service {
} else {
self.state = .finished
requestContinuation.finish()
continuation.resume(throwing: MemcacheError(
code: .connectionShutdown,
message: "The connection to the Memcache server was unexpectedly closed.",
cause: nil,
location: .here()
))
continuation.resume(
throwing: MemcacheError(
code: .connectionShutdown,
message: "The connection to the Memcache server was unexpectedly closed.",
cause: nil,
location: .here()
)
)
}
} catch {
switch self.state {
case .running:
self.state = .finished
requestContinuation.finish()
continuation.resume(throwing: MemcacheError(
code: .connectionShutdown,
message: "The connection to the Memcache server has shut down while processing a request.",
cause: error,
location: .here()
))
continuation.resume(
throwing: MemcacheError(
code: .connectionShutdown,
message:
"The connection to the Memcache server has shut down while processing a request.",
cause: error,
location: .here()
)
)
case .initial, .finished:
break
}
@@ -152,19 +155,21 @@ public actor MemcacheConnection: Service {
private func sendRequest(_ request: MemcacheRequest) async throws -> MemcacheResponse {
switch self.state {
case .initial(_, _, _, let requestContinuation),
.running(_, _, _, let requestContinuation):
.running(_, _, _, let requestContinuation):
return try await withCheckedThrowingContinuation { continuation in
switch requestContinuation.yield((request, continuation)) {
case .enqueued:
break
case .dropped, .terminated:
continuation.resume(throwing: MemcacheError(
code: .connectionShutdown,
message: "Unable to enqueue request due to the connection being shutdown.",
cause: nil,
location: .here()
))
continuation.resume(
throwing: MemcacheError(
code: .connectionShutdown,
message: "Unable to enqueue request due to the connection being shutdown.",
cause: nil,
location: .here()
)
)
default:
break
}
@@ -190,7 +195,7 @@ public actor MemcacheConnection: Service {
private func getBufferAllocator() throws -> ByteBufferAllocator {
switch self.state {
case .initial(_, let bufferAllocator, _, _),
.running(let bufferAllocator, _, _, _):
.running(let bufferAllocator, _, _, _):
return bufferAllocator
case .finished:
throw MemcacheError(
@@ -264,7 +269,7 @@ public actor MemcacheConnection: Service {
public func set(_ key: String, value: some MemcacheValue, timeToLive: TimeToLive = .indefinitely) async throws {
switch self.state {
case .initial(_, let bufferAllocator, _, _),
.running(let bufferAllocator, _, _, _):
.running(let bufferAllocator, _, _, _):
var buffer = bufferAllocator.buffer(capacity: 0)
value.writeToBuffer(&buffer)
+5 -4
View File
@@ -37,7 +37,7 @@ public struct MemcacheError: Error, @unchecked Sendable {
}
func copy() -> Self {
return Self(
Self(
code: self.code,
message: self.message,
cause: self.cause,
@@ -111,7 +111,8 @@ extension MemcacheError: CustomStringConvertible {
extension MemcacheError: CustomDebugStringConvertible {
public var debugDescription: String {
if let cause = self.cause {
return "\(String(reflecting: self.code)): \(String(reflecting: self.message)) (\(String(reflecting: cause)))"
return
"\(String(reflecting: self.code)): \(String(reflecting: self.message)) (\(String(reflecting: cause)))"
} else {
return "\(String(reflecting: self.code)): \(String(reflecting: self.message))"
}
@@ -146,7 +147,7 @@ extension MemcacheError {
///
/// - Returns: A multi-line description of the error.
public func detailedDescription() -> String {
return self.detailedDescriptionLines().joined(separator: "\n")
self.detailedDescriptionLines().joined(separator: "\n")
}
}
@@ -229,7 +230,7 @@ extension MemcacheError {
file: String = #fileID,
line: Int = #line
) -> Self {
return SourceLocation(function: function, file: file, line: line)
SourceLocation(function: function, file: file, line: line)
}
}
}
+1
View File
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
import NIOCore
enum MemcacheRequest: Sendable {
struct SetCommand: Sendable {
let key: String
+21 -9
View File
@@ -109,8 +109,10 @@ struct MemcacheResponseDecoder: NIOSingleStepByteToMessageDecoder {
mutating func next(buffer: inout ByteBuffer) throws -> NextDecodeAction {
// Check if the buffer contains "\r\n"
let bytesView = buffer.readableBytesView
guard let crIndex = bytesView.firstIndex(of: UInt8.carriageReturn), bytesView.index(after: crIndex) < bytesView.endIndex,
bytesView[bytesView.index(after: crIndex)] == UInt8.newline else {
guard let crIndex = bytesView.firstIndex(of: UInt8.carriageReturn),
bytesView.index(after: crIndex) < bytesView.endIndex,
bytesView[bytesView.index(after: crIndex)] == UInt8.newline
else {
return .waitForMoreBytes
}
switch self.nextStep {
@@ -130,7 +132,9 @@ struct MemcacheResponseDecoder: NIOSingleStepByteToMessageDecoder {
return .waitForMoreBytes
}
if let currentByte = buffer.getInteger(at: buffer.readerIndex, as: UInt8.self), currentByte == UInt8.whitespace {
if let currentByte = buffer.getInteger(at: buffer.readerIndex, as: UInt8.self),
currentByte == UInt8.whitespace
{
buffer.moveReaderIndex(forwardBy: 1)
}
@@ -152,7 +156,9 @@ struct MemcacheResponseDecoder: NIOSingleStepByteToMessageDecoder {
return .continueDecodeLoop
}
if let currentByte = buffer.getInteger(at: buffer.readerIndex, as: UInt8.self), currentByte == UInt8.whitespace {
if let currentByte = buffer.getInteger(at: buffer.readerIndex, as: UInt8.self),
currentByte == UInt8.whitespace
{
buffer.moveReaderIndex(forwardBy: 1)
}
@@ -162,7 +168,12 @@ struct MemcacheResponseDecoder: NIOSingleStepByteToMessageDecoder {
self.nextStep = .decodeValue(returnCode, dataLength!, flags)
return .continueDecodeLoop
} else {
let response = MemcacheResponse(returnCode: returnCode, dataLength: dataLength, flags: flags, value: nil)
let response = MemcacheResponse(
returnCode: returnCode,
dataLength: dataLength,
flags: flags,
value: nil
)
self.nextStep = .returnCode
return .returnDecodedResponse(response)
}
@@ -177,10 +188,11 @@ struct MemcacheResponseDecoder: NIOSingleStepByteToMessageDecoder {
}
guard buffer.readableBytes >= 2,
let nextByte = buffer.readInteger(as: UInt8.self),
nextByte == UInt8.carriageReturn,
let nextNextByte = buffer.readInteger(as: UInt8.self),
nextNextByte == UInt8.newline else {
let nextByte = buffer.readInteger(as: UInt8.self),
nextByte == UInt8.carriageReturn,
let nextNextByte = buffer.readInteger(as: UInt8.self),
nextNextByte == UInt8.newline
else {
preconditionFailure("Expected to find CRLF at end of response")
}
+2 -2
View File
@@ -40,7 +40,7 @@ extension MemcacheValue where Self: FixedWidthInteger {
///
/// - Parameter buffer: The ByteBuffer from which the value should be read.
public static func readFromBuffer(_ buffer: inout ByteBuffer) -> Self? {
return buffer.readIntegerFromASCII()
buffer.readIntegerFromASCII()
}
}
@@ -57,7 +57,7 @@ extension MemcacheValue where Self: StringProtocol {
///
/// - Parameter buffer: The ByteBuffer from which the value should be read.
public static func readFromBuffer(_ buffer: inout ByteBuffer) -> Self? {
return buffer.readString(length: buffer.readableBytes) as? Self
buffer.readString(length: buffer.readableBytes) as? Self
}
}
@@ -12,11 +12,12 @@
//
//===----------------------------------------------------------------------===//
@testable import Memcache
import NIOCore
import NIOPosix
import XCTest
@testable import Memcache
final class MemcacheIntegrationTest: XCTestCase {
var channel: ClientBootstrap!
var group: EventLoopGroup!
@@ -27,7 +28,9 @@ final class MemcacheIntegrationTest: XCTestCase {
self.channel = ClientBootstrap(group: self.group)
.channelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
.channelInitializer { channel in
return channel.pipeline.addHandlers([MessageToByteHandler(MemcacheRequestEncoder()), ByteToMessageHandler(MemcacheResponseDecoder())])
channel.pipeline.addHandlers([
MessageToByteHandler(MemcacheRequestEncoder()), ByteToMessageHandler(MemcacheResponseDecoder()),
])
}
}
@@ -274,7 +277,11 @@ final class MemcacheIntegrationTest: XCTestCase {
// Get value for key after prepend operation
let updatedValue: String? = try await memcacheConnection.get("greet")
XCTAssertEqual(updatedValue, prependValue + initialValue, "Received value should be the same as the concatenation of prependValue and initialValue")
XCTAssertEqual(
updatedValue,
prependValue + initialValue,
"Received value should be the same as the concatenation of prependValue and initialValue"
)
group.cancelAll()
}
@@ -300,7 +307,11 @@ final class MemcacheIntegrationTest: XCTestCase {
// Get value for key after append operation
let updatedValue: String? = try await memcacheConnection.get("greet")
XCTAssertEqual(updatedValue, initialValue + appendValue, "Received value should be the same as the concatenation of initialValue and appendValue")
XCTAssertEqual(
updatedValue,
initialValue + appendValue,
"Received value should be the same as the concatenation of initialValue and appendValue"
)
group.cancelAll()
}
@@ -12,9 +12,10 @@
//
//===----------------------------------------------------------------------===//
@testable import Memcache
import XCTest
@testable import Memcache
final class MemcacheErrorTests: XCTestCase {
func testInitialization() {
let location = MemcacheError.SourceLocation(function: "testFunction", file: "testFile.swift", line: 8)
@@ -31,7 +32,12 @@ final class MemcacheErrorTests: XCTestCase {
func testCustomStringConvertible() {
let location = MemcacheError.SourceLocation.here()
let causeError = MemcacheError(code: .protocolError, message: "No response", cause: nil, location: location)
let mainError = MemcacheError(code: .connectionShutdown, message: "Connection lost", cause: causeError, location: location)
let mainError = MemcacheError(
code: .connectionShutdown,
message: "Connection lost",
cause: causeError,
location: location
)
let description = mainError.description
@@ -53,7 +59,12 @@ final class MemcacheErrorTests: XCTestCase {
func testDetailedDescription() {
let location = MemcacheError.SourceLocation.here()
let causeError = MemcacheError(code: .protocolError, message: "No response", cause: nil, location: location)
let mainError = MemcacheError(code: .connectionShutdown, message: "Connection lost", cause: causeError, location: location)
let mainError = MemcacheError(
code: .connectionShutdown,
message: "Connection lost",
cause: causeError,
location: location
)
let detailedDesc = mainError.detailedDescription()
@@ -12,9 +12,10 @@
//
//===----------------------------------------------------------------------===//
@testable import Memcache
import XCTest
@testable import Memcache
final class MemcacheFlagsTests: XCTestCase {
func testVFlag() {
var flags = MemcacheFlags()
@@ -12,10 +12,11 @@
//
//===----------------------------------------------------------------------===//
@testable import Memcache
import NIOCore
import XCTest
@testable import Memcache
final class MemcacheRequestEncoderTests: XCTestCase {
var encoder: MemcacheRequestEncoder!
@@ -120,7 +121,11 @@ final class MemcacheRequestEncoderTests: XCTestCase {
// Extract the encoded Time-To-Live
let encodedString = outBuffer.getString(at: 0, length: outBuffer.readableBytes)!
let regex = try! NSRegularExpression(pattern: "T(\\d+)", options: .caseInsensitive)
let match = regex.firstMatch(in: encodedString, options: [], range: NSRange(location: 0, length: encodedString.utf16.count))
let match = regex.firstMatch(
in: encodedString,
options: [],
range: NSRange(location: 0, length: encodedString.utf16.count)
)
let encodedTTLRange = Range(match!.range(at: 1), in: encodedString)!
let encodedTTL = Int32(encodedString[encodedTTLRange])!
@@ -12,11 +12,12 @@
//
//===----------------------------------------------------------------------===//
@testable import Memcache
import NIOCore
import NIOEmbedded
import XCTest
@testable import Memcache
final class MemcacheResponseDecoderTests: XCTestCase {
var decoder: MemcacheResponseDecoder!
@@ -155,7 +156,10 @@ final class MemcacheResponseDecoderTests: XCTestCase {
// VA 2
var firstPartBuffer = buffer.getSlice(at: buffer.readerIndex, length: splitIndex)!
// \r\nhi\r\n
var secondPartBuffer = buffer.getSlice(at: buffer.readerIndex + splitIndex, length: buffer.readableBytes - splitIndex)!
var secondPartBuffer = buffer.getSlice(
at: buffer.readerIndex + splitIndex,
length: buffer.readableBytes - splitIndex
)!
// Try to decode the first part, which should return .waitForMoreBytes
switch try self.decoder.next(buffer: &firstPartBuffer) {
@@ -12,10 +12,11 @@
//
//===----------------------------------------------------------------------===//
@testable import Memcache
import NIOCore
import XCTest
@testable import Memcache
final class MemcacheTimeToLiveTests: XCTestCase {
let clock = ContinuousClock()
@@ -12,10 +12,11 @@
//
//===----------------------------------------------------------------------===//
@testable import Memcache
import NIOCore
import XCTest
@testable import Memcache
final class MemcacheValueTests: XCTestCase {
func testMemcacheValueConformance() {
var buffer = ByteBufferAllocator().buffer(capacity: 0)
+2 -2
View File
@@ -45,10 +45,10 @@ set -o pipefail
here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
target_repo=${2-"$here/.."}
for f in 57 58 59 510 -nightly; do
for f in 59 510 -nightly; do
echo "swift$f"
docker_file=$(if [[ "$f" == "-nightly" ]]; then f=main; fi && ls "$target_repo/docker/docker-compose."*"$f"*".yaml")
docker-compose -f docker/docker-compose.yaml -f $docker_file run update-benchmark-baseline
docker-compose -f docker/docker-compose.yaml -f "$docker_file" run update-benchmark-baseline
done
+2 -8
View File
@@ -1,4 +1,4 @@
ARG swift_version=5.7
ARG swift_version=5.9
ARG ubuntu_version=jammy
ARG base_image=swift:$swift_version-$ubuntu_version
FROM $base_image
@@ -16,11 +16,5 @@ ENV LANGUAGE en_US.UTF-8
RUN mkdir -p $HOME/.tools
RUN echo 'export PATH="$HOME/.tools:$PATH"' >> $HOME/.profile
# swiftformat (until part of the toolchain)
ARG swiftformat_version=0.51.8
RUN git clone --branch $swiftformat_version --depth 1 https://github.com/nicklockwood/SwiftFormat $HOME/.tools/swift-format
RUN cd $HOME/.tools/swift-format && swift build -c release
RUN ln -s $HOME/.tools/swift-format/.build/release/swiftformat $HOME/.tools/swiftformat
# install jemalloc for running allocation benchmarks
RUN apt-get update & apt-get install -y libjemalloc-dev
RUN apt-get update & apt-get install -y libjemalloc-dev
+1 -2
View File
@@ -17,9 +17,8 @@ services:
shell:
image: swift-memcache-gsoc:22.04-5.10
update-benchmark-baseline:
image: swift-memcache-gsoc:22.04-5.10
environment:
- SWIFT_VERSION=5.10
-24
View File
@@ -1,24 +0,0 @@
version: "3"
services:
runtime-setup:
image: swift-memcache-gsoc:22.04-5.7
build:
args:
ubuntu_version: "jammy"
swift_version: "5.7"
test:
image: swift-memcache-gsoc:22.04-5.7
environment:
- WARN_AS_ERROR_ARG=-Xswiftc -warnings-as-errors
# - SANITIZER_ARG=--sanitize=thread # TSan broken still
shell:
image: swift-memcache-gsoc:22.04-5.7
update-benchmark-baseline:
image: swift-memcache-gsoc:22.04-5.7
environment:
- SWIFT_VERSION=5.7
-25
View File
@@ -1,25 +0,0 @@
version: "3"
services:
runtime-setup:
image: swift-memcache-gsoc:22.04-5.8
build:
args:
ubuntu_version: "jammy"
swift_version: "5.8"
test:
image: swift-memcache-gsoc:22.04-5.8
environment:
- WARN_AS_ERROR_ARG=-Xswiftc -warnings-as-errors
- IMPORT_CHECK_ARG=--explicit-target-dependency-import-check error
# - SANITIZER_ARG=--sanitize=thread # TSan broken still
shell:
image: swift-memcache-gsoc:22.04-5.8
update-benchmark-baseline:
image: swift-memcache-gsoc:22.04-5.8
environment:
- SWIFT_VERSION=5.8
+1 -1
View File
@@ -21,4 +21,4 @@ services:
update-benchmark-baseline:
image: swift-memcache-gsoc:22.04-main
environment:
- SWIFT_VERSION=main
- SWIFT_VERSION=main
+7 -7
View File
@@ -3,14 +3,14 @@ version: "3.9"
services:
# Swift on Server CI
# e.g. docker-compose -f docker/docker-compose.yaml -f docker/docker-compose.2204.57.yaml run test
memcached:
image: memcached:latest
networks:
- memcached
ports:
- 11211
- 11211
runtime-setup:
image: swift-memcache-gsoc:default
build:
@@ -32,8 +32,8 @@ services:
test:
<<: *common
depends_on:
- runtime-setup
- memcached
- runtime-setup
- memcached
command: /bin/bash -xcl "swift $${SWIFT_TEST_VERB-test} $${WARN_AS_ERROR_ARG-} $${SANITIZER_ARG-} $${IMPORT_CHECK_ARG-} && cd Benchmarks && swift package --disable-sandbox benchmark baseline check --check-absolute-path Thresholds/$${SWIFT_VERSION-}/"
networks:
- memcached
@@ -47,8 +47,8 @@ services:
update-benchmark-baseline:
<<: *common
depends_on:
- runtime-setup
- memcached
- runtime-setup
- memcached
command: /bin/bash -xcl "cd Benchmarks && swift package --disable-sandbox --scratch-path .build/$${SWIFT_VERSION-}/ --allow-writing-to-package-directory benchmark --format metricP90AbsoluteThresholds --path Thresholds/$${SWIFT_VERSION-}/"
# dedicated network
-39
View File
@@ -1,39 +0,0 @@
#!/bin/bash
##===----------------------------------------------------------------------===##
##
## This source file is part of the swift-memcache-gsoc open source project
##
## Copyright (c) 2023 Apple Inc. and the swift-memcache-gsoc project authors
## Licensed under Apache License v2.0
##
## See LICENSE.txt for license information
## See CONTRIBUTORS.txt for the list of swift-memcache-gsoc project authors
##
## SPDX-License-Identifier: Apache-2.0
##
##===----------------------------------------------------------------------===##
set -eu
here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
contributors=$( cd "$here"/.. && git shortlog -es | cut -f2 | sed 's/^/- /' )
cat > "$here/../CONTRIBUTORS.txt" <<- EOF
For the purpose of tracking copyright, this is the list of individuals and
organizations who have contributed source code to swift-memcache-gsoc.
For employees of an organization/company where the copyright of work done
by employees of that company is held by the company itself, only the company
needs to be listed here.
## COPYRIGHT HOLDERS
- Apple Inc. (all contributors with '@apple.com')
### Contributors
$contributors
**Updating this list**
Please do not edit this file manually. It is generated using \`./scripts/generate_contributors_list.sh\`. If a name is misspelled or appearing multiple times: add an entry in \`./.mailmap\`
EOF
-179
View File
@@ -1,179 +0,0 @@
#!/bin/bash
##===----------------------------------------------------------------------===##
##
## This source file is part of the swift-memcache-gsoc open source project
##
## Copyright (c) 2023 Apple Inc. and the swift-memcache-gsoc project authors
## Licensed under Apache License v2.0
##
## See LICENSE.txt for license information
## See CONTRIBUTORS.txt for the list of swift-memcache-gsoc project authors
##
## SPDX-License-Identifier: Apache-2.0
##
##===----------------------------------------------------------------------===##
set -eu
here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
function replace_acceptable_years() {
# this needs to replace all acceptable forms with 'YEARS'
sed -e 's/20[12][7890123]-20[12][890123]/YEARS/' -e 's/20[12][890123]/YEARS/'
}
printf "=> Checking for unacceptable language... "
# This greps for unacceptable terminology. The square bracket[s] are so that
# "git grep" doesn't find the lines that greps :).
unacceptable_terms=(
-e blacklis[t]
-e whitelis[t]
-e slav[e]
-e sanit[y]
)
# We have to exclude the code of conduct because it gives examples of unacceptable language.
exclude_files=(
CODE_OF_CONDUCT.md
)
for word in "${exclude_files[@]}"; do
exclude_files+=(":(exclude)$word")
done
exclude_files_str=$(printf " %s" "${exclude_files[@]}")
if git grep --color=never -i "${unacceptable_terms[@]}" -- . $exclude_files_str > /dev/null; then
printf "\033[0;31mUnacceptable language found.\033[0m\n"
git grep -i "${unacceptable_terms[@]}" -- . $exclude_files_str
exit 1
fi
printf "\033[0;32mokay.\033[0m\n"
printf "=> Checking format... "
FIRST_OUT="$(git status --porcelain)"
swiftformat . > /dev/null 2>&1
SECOND_OUT="$(git status --porcelain)"
if [[ "$FIRST_OUT" != "$SECOND_OUT" ]]; then
printf "\033[0;31mformatting issues!\033[0m\n"
git --no-pager diff
exit 1
else
printf "\033[0;32mokay.\033[0m\n"
fi
printf "=> Checking license headers... "
tmp=$(mktemp /tmp/.swift-memcache-gsoc-soundness_XXXXXX)
for language in swift-or-c bash dtrace python; do
declare -a matching_files
declare -a exceptions
expections=( )
matching_files=( -name '*' )
case "$language" in
swift-or-c)
exceptions=( -name Package.swift )
matching_files=( -name '*.swift' -o -name '*.c' -o -name '*.h' )
cat > "$tmp" <<"EOF"
//===----------------------------------------------------------------------===//
//
// This source file is part of the swift-memcache-gsoc open source project
//
// Copyright (c) YEARS Apple Inc. and the swift-memcache-gsoc project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of swift-memcache-gsoc project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
EOF
;;
bash)
matching_files=( -name '*.sh' )
cat > "$tmp" <<"EOF"
#!/bin/bash
##===----------------------------------------------------------------------===##
##
## This source file is part of the swift-memcache-gsoc open source project
##
## Copyright (c) YEARS Apple Inc. and the swift-memcache-gsoc project authors
## Licensed under Apache License v2.0
##
## See LICENSE.txt for license information
## See CONTRIBUTORS.txt for the list of swift-memcache-gsoc project authors
##
## SPDX-License-Identifier: Apache-2.0
##
##===----------------------------------------------------------------------===##
EOF
;;
python)
matching_files=( -name '*.py' )
cat > "$tmp" <<"EOF"
#!/usr/bin/env python3
##===----------------------------------------------------------------------===##
##
## This source file is part of the swift-memcache-gsoc open source project
##
## Copyright (c) YEARS Apple Inc. and the swift-memcache-gsoc project authors
## Licensed under Apache License v2.0
##
## See LICENSE.txt for license information
## See CONTRIBUTORS.txt for the list of swift-memcache-gsoc project authors
##
## SPDX-License-Identifier: Apache-2.0
##
##===----------------------------------------------------------------------===##
EOF
;;
dtrace)
matching_files=( -name '*.d' )
cat > "$tmp" <<"EOF"
#!/usr/sbin/dtrace -q -s
/*===----------------------------------------------------------------------===*
*
* This source file is part of the swift-memcache-gsoc open source project
*
* Copyright (c) YEARS Apple Inc. and the swift-memcache-gsoc project authors
* Licensed under Apache License v2.0
*
* See LICENSE.txt for license information
* See CONTRIBUTORS.txt for the list of swift-memcache-gsoc project authors
*
* SPDX-License-Identifier: Apache-2.0
*
*===----------------------------------------------------------------------===*/
EOF
;;
*)
echo >&2 "ERROR: unknown language '$language'"
;;
esac
expected_lines=$(cat "$tmp" | wc -l)
expected_sha=$(cat "$tmp" | shasum)
(
cd "$here/.."
{
find . \
\( \! -path '*/.build/*' -a \
\( "${matching_files[@]}" \) -a \
\( \! \( "${exceptions[@]}" \) \) \)
if [[ "$language" = bash ]]; then
# add everything with a shell shebang too
git grep --full-name -l '#!/bin/bash'
git grep --full-name -l '#!/bin/sh'
fi
} | while read line; do
if [[ "$(cat "$line" | replace_acceptable_years | head -n $expected_lines | shasum)" != "$expected_sha" ]]; then
printf "\033[0;31mmissing headers in file '$line'!\033[0m\n"
diff -u <(cat "$line" | replace_acceptable_years | head -n $expected_lines) "$tmp"
exit 1
fi
done
printf "\033[0;32mokay.\033[0m\n"
)
done
rm "$tmp"