Skip to content

Commit 523321a

Browse files
authored
Created a encoder handler to serializing a MemcachedRequest (#8)
* Created a encoder handler that is capable of serializing a MemcachedRequest * no need to return anything here * fixed test case for consistency * clean up comments * rename extension * cleaned up imports and avoided writing Strings * pr comment fixes, i.e precond on key * consistency removings accessor * rename meta and set to m s * soundess ci failure fixes
1 parent ce04105 commit 523321a

File tree

8 files changed

+211
-2
lines changed

8 files changed

+211
-2
lines changed

Package.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ let package = Package(
3838
name: "SwiftMemcache",
3939
dependencies: [
4040
.product(name: "NIOCore", package: "swift-nio"),
41+
.product(name: "NIOPosix", package: "swift-nio"),
4142
.product(name: "Logging", package: "swift-log"),
4243
]
4344
),
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the swift-memcache-gsoc open source project
4+
//
5+
// Copyright (c) 2023 Apple Inc. and the swift-memcache-gsoc project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of swift-memcache-gsoc project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import NIOCore
16+
17+
extension ByteBuffer {
18+
/// Write `integer` into this `ByteBuffer` as ASCII digits, without leading zeros, moving the writer index forward appropriately.
19+
///
20+
/// - parameters:
21+
/// - integer: The integer to serialize.
22+
@inlinable
23+
mutating func writeIntegerAsASCII(_ integer: some FixedWidthInteger) {
24+
let string = String(integer)
25+
self.writeString(string)
26+
}
27+
}

Tests/SwiftMemcacheTests/empty.swift renamed to Sources/SwiftMemcache/Extensions/UInt8+Characters.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,11 @@
1111
// SPDX-License-Identifier: Apache-2.0
1212
//
1313
//===----------------------------------------------------------------------===//
14+
15+
extension UInt8 {
16+
static var whitespace: UInt8 = .init(ascii: " ")
17+
static var newline: UInt8 = .init(ascii: "\n")
18+
static var carriageReturn: UInt8 = .init(ascii: "\r")
19+
static var m: UInt8 = .init(ascii: "m")
20+
static var s: UInt8 = .init(ascii: "s")
21+
}

Sources/SwiftMemcache/empty.swift renamed to Sources/SwiftMemcache/MemcachedRequest.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,14 @@
1111
// SPDX-License-Identifier: Apache-2.0
1212
//
1313
//===----------------------------------------------------------------------===//
14+
15+
import NIOCore
16+
17+
enum MemcachedRequest {
18+
struct SetCommand {
19+
let key: String
20+
var value: ByteBuffer
21+
}
22+
23+
case set(SetCommand)
24+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the swift-memcache-gsoc open source project
4+
//
5+
// Copyright (c) 2023 Apple Inc. and the swift-memcache-gsoc project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of swift-memcache-gsoc project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import NIOCore
16+
import NIOPosix
17+
18+
struct MemcachedRequestEncoder: MessageToByteEncoder {
19+
typealias OutboundIn = MemcachedRequest
20+
21+
func encode(data: MemcachedRequest, out: inout ByteBuffer) throws {
22+
switch data {
23+
case .set(var command):
24+
precondition(!command.key.isEmpty, "Key must not be empty")
25+
26+
// write command and key
27+
out.writeInteger(UInt8.m)
28+
out.writeInteger(UInt8.s)
29+
out.writeInteger(UInt8.whitespace)
30+
out.writeBytes(command.key.utf8)
31+
out.writeInteger(UInt8.whitespace)
32+
33+
// write value length
34+
let length = command.value.readableBytes
35+
out.writeIntegerAsASCII(length)
36+
37+
// write separator
38+
out.writeInteger(UInt8.carriageReturn)
39+
out.writeInteger(UInt8.newline)
40+
41+
// write value and end line
42+
out.writeBuffer(&command.value)
43+
out.writeInteger(UInt8.carriageReturn)
44+
out.writeInteger(UInt8.newline)
45+
}
46+
}
47+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the swift-memcache-gsoc open source project
4+
//
5+
// Copyright (c) 2023 Apple Inc. and the swift-memcache-gsoc project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of swift-memcache-gsoc project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import NIOCore
16+
import NIOPosix
17+
@testable import SwiftMemcache
18+
import XCTest
19+
20+
final class MemcachedIntegrationTest: XCTestCase {
21+
var channel: ClientBootstrap!
22+
var group: EventLoopGroup!
23+
24+
override func setUp() {
25+
super.setUp()
26+
self.group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
27+
self.channel = ClientBootstrap(group: self.group)
28+
.channelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
29+
.channelInitializer { channel in
30+
channel.pipeline.addHandler(MessageToByteHandler(MemcachedRequestEncoder()))
31+
}
32+
}
33+
34+
override func tearDown() {
35+
XCTAssertNoThrow(try self.group.syncShutdownGracefully())
36+
super.tearDown()
37+
}
38+
39+
func testConnectionToMemcachedServer() throws {
40+
do {
41+
let connection = try channel.connect(host: "memcached", port: 11211).wait()
42+
XCTAssertNotNil(connection)
43+
44+
// Prepare a MemcachedRequest
45+
var buffer = ByteBufferAllocator().buffer(capacity: 3)
46+
buffer.writeString("hi")
47+
let command = MemcachedRequest.SetCommand(key: "foo", value: buffer)
48+
let request = MemcachedRequest.set(command)
49+
50+
// Write the request to the connection and wait for the result
51+
connection.writeAndFlush(request).whenComplete { result in
52+
switch result {
53+
case .success:
54+
print("Request successfully sent to the server.")
55+
case .failure(let error):
56+
XCTFail("Failed to send request: \(error)")
57+
}
58+
}
59+
} catch {
60+
XCTFail("Failed to connect to Memcached server: \(error)")
61+
}
62+
}
63+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the swift-memcache-gsoc open source project
4+
//
5+
// Copyright (c) 2023 Apple Inc. and the swift-memcache-gsoc project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of swift-memcache-gsoc project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import NIOCore
16+
@testable import SwiftMemcache
17+
import XCTest
18+
19+
final class MemcachedRequestEncoderTests: XCTestCase {
20+
var encoder: MemcachedRequestEncoder!
21+
22+
override func setUp() {
23+
super.setUp()
24+
self.encoder = MemcachedRequestEncoder()
25+
}
26+
27+
func testEncodeSetRequest() {
28+
// Prepare a MemcachedRequest
29+
var buffer = ByteBufferAllocator().buffer(capacity: 2)
30+
buffer.writeString("hi")
31+
let command = MemcachedRequest.SetCommand(key: "foo", value: buffer)
32+
let request = MemcachedRequest.set(command)
33+
34+
// pass our request through the encoder
35+
var outBuffer = ByteBufferAllocator().buffer(capacity: 0)
36+
do {
37+
try self.encoder.encode(data: request, out: &outBuffer)
38+
} catch {
39+
XCTFail("Encoding failed with error: \(error)")
40+
}
41+
42+
let expectedEncodedData = "ms foo 2\r\nhi\r\n"
43+
XCTAssertEqual(outBuffer.getString(at: 0, length: outBuffer.readableBytes), expectedEncodedData)
44+
}
45+
}

docker/docker-compose.yaml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@ version: "3.9"
33
services:
44
# Swift on Server CI
55
# e.g. docker-compose -f docker/docker-compose.yaml -f docker/docker-compose.2204.57.yaml run test
6-
6+
7+
memcached:
8+
image: memcached:latest
9+
ports:
10+
- "11211:11211"
11+
712
runtime-setup:
813
image: swift-memcache-gsoc:default
914
build:
@@ -24,7 +29,9 @@ services:
2429

2530
test:
2631
<<: *common
27-
depends_on: [runtime-setup]
32+
depends_on:
33+
- runtime-setup
34+
- memcached
2835
command: /bin/bash -xcl "swift $${SWIFT_TEST_VERB-test} $${WARN_AS_ERROR_ARG-} $${SANITIZER_ARG-} $${IMPORT_CHECK_ARG-}"
2936

3037
# util

0 commit comments

Comments
 (0)