Skip to content

Commit

Permalink
Make own application type TodosApp, add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
adam-fowler committed Dec 28, 2023
1 parent 9df82dc commit ef116d4
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 95 deletions.
4 changes: 4 additions & 0 deletions todos-dynamodb/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ let package = Package(
name: "AppTests",
dependencies: [
.byName(name: "App"),
.product(name: "Hummingbird", package: "hummingbird"),
.product(name: "HummingbirdFoundation", package: "hummingbird"),
.product(name: "ArgumentParser", package: "swift-argument-parser"),
.product(name: "SotoDynamoDB", package: "soto"),
.product(name: "HummingbirdXCT", package: "hummingbird"),
]
),
Expand Down
1 change: 0 additions & 1 deletion todos-dynamodb/Packages/hummingbird

This file was deleted.

50 changes: 0 additions & 50 deletions todos-dynamodb/Sources/App/Application+build.swift

This file was deleted.

55 changes: 55 additions & 0 deletions todos-dynamodb/Sources/App/TodosApp.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import Hummingbird
import HummingbirdFoundation
import NIOCore
import NIOPosix
import ServiceLifecycle
import SotoDynamoDB

struct TodosApp: HBApplicationProtocol {
/// Request context which default to using JSONDecoder/Encoder
struct Context: HBRequestContext {
init(eventLoop: EventLoop, allocator: ByteBufferAllocator, logger: Logger) {
self.coreContext = .init(
requestDecoder: JSONDecoder(),
responseEncoder: JSONEncoder(),
eventLoop: eventLoop,
allocator: allocator,
logger: logger
)
}

var coreContext: HBCoreRequestContext
}

init(configuration: HBApplicationConfiguration, eventLoopGroupProvider: EventLoopGroupProvider = .singleton) {
self.configuration = configuration
self.eventLoopGroup = eventLoopGroupProvider.eventLoopGroup
self.awsClient = AWSClient(httpClientProvider: .createNewWithEventLoopGroup(self.eventLoopGroup))
}

var responder: some HBResponder<Context> {
let router = HBRouter(context: Context.self)
// middleware
router.middlewares.add(HBLogRequestsMiddleware(.debug))
router.middlewares.add(HBCORSMiddleware(
allowOrigin: .originBased,
allowHeaders: [.contentType],
allowMethods: [.get, .options, .post, .delete, .patch]
))
router.get("/") { _, _ in
return "Hello"
}

let dynamoDB = DynamoDB(client: awsClient, region: .euwest1)

let todoController = TodoController(dynamoDB: dynamoDB)
todoController.addRoutes(to: router.group("todos"))

return router.buildResponder()
}

let awsClient: AWSClient
let configuration: HBApplicationConfiguration
let eventLoopGroup: EventLoopGroup
var services: [any Service] { [self.awsClient] }
}
2 changes: 1 addition & 1 deletion todos-dynamodb/Sources/App/app.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ struct HummingbirdArguments: AsyncParsableCommand {
var port: Int = 8080

func run() async throws {
let app = buildApplication(configuration: .init(
let app = TodosApp(configuration: .init(
address: .hostname(self.hostname, port: self.port),
serverName: "Hummingbird"
))
Expand Down
163 changes: 120 additions & 43 deletions todos-dynamodb/Tests/AppTests/AppTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,60 +4,137 @@ import HummingbirdXCT
import XCTest

final class AppTests: XCTestCase {
func createTodo(title: String, client: some HBXCTClientProtocol) async throws -> UUID {
let json = "{\"title\": \"\(title)\"}"
let todo = try await client.XCTExecute(
uri: "/todos",
method: .post,
body: ByteBufferAllocator().buffer(string: json)
) { response in
XCTAssertEqual(response.status, .created)
let body = try XCTUnwrap(response.body)
return try JSONDecoder().decode(Todo.self, from: body)
}
return try XCTUnwrap(todo.id)
}

func getTodo(id: UUID, client: some HBXCTClientProtocol) async throws -> Todo {
return try await client.XCTExecute(
uri: "/todos/\(id)",
method: .get
) { response in
XCTAssertEqual(response.status, .ok)
let body = try XCTUnwrap(response.body)
return try JSONDecoder().decode(Todo.self, from: body)
}
}

func listTodos(client: some HBXCTClientProtocol) async throws -> [Todo] {
return try await client.XCTExecute(
uri: "/todos/",
method: .get
) { response in
XCTAssertEqual(response.status, .ok)
let body = try XCTUnwrap(response.body)
return try JSONDecoder().decode([Todo].self, from: body)
}
}

func updateTodo(editedTodo: EditTodo, id: UUID, client: some HBXCTClientProtocol) async throws -> Todo {
let buffer = try JSONEncoder().encodeAsByteBuffer(editedTodo, allocator: ByteBufferAllocator())
return try await client.XCTExecute(
uri: "/todos/\(id)",
method: .patch,
body: buffer
) { response in
XCTAssertEqual(response.status, .ok)
let body = try XCTUnwrap(response.body)
return try JSONDecoder().decode(Todo.self, from: body)
}
}

func deleteTodo(id: UUID, client: some HBXCTClientProtocol) async throws {
try await client.XCTExecute(
uri: "/todos/\(id)",
method: .delete
) { response in
XCTAssertEqual(response.status, .ok)
}
}

func deleteAllTodos(client: some HBXCTClientProtocol) async throws {
try await client.XCTExecute(
uri: "/todos/",
method: .delete
) { response in
XCTAssertEqual(response.status, .ok)
}
}

// MARK: Tests

func testCreate() async throws {
try XCTSkipIf(HBEnvironment().get("CI") != nil)

let app = buildApplication(configuration: .init())
let app = TodosApp(configuration: .init())
try await app.test(.live) { client in
let todo = try await client.XCTExecute(
uri: "/todos",
method: .post,
body: ByteBufferAllocator().buffer(string: #"{"title":"add more tests"}"#)
) { response in
XCTAssertEqual(response.status, .created)
let body = try XCTUnwrap(response.body)
return try JSONDecoder().decode(Todo.self, from: body)
}
let todoId = try XCTUnwrap(todo.id)
try await client.XCTExecute(
uri: "/todos/\(todoId)",
method: .get
) { response in
XCTAssertEqual(response.status, .ok)
let body = try XCTUnwrap(response.body)
let todo = try JSONDecoder().decode(Todo.self, from: body)
XCTAssertEqual(todo.id, todoId)
XCTAssertEqual(todo.title, "add more tests")
}
let todoId = try await self.createTodo(title: "Add more tests", client: client)
let todo = try await self.getTodo(id: todoId, client: client)
XCTAssertEqual(todo.id, todoId)
XCTAssertEqual(todo.title, "Add more tests")
}
}

func testList() async throws {
try XCTSkipIf(HBEnvironment().get("CI") != nil)

let app = buildApplication(configuration: .init())
let app = TodosApp(configuration: .init())
try await app.test(.live) { client in
let todoId = try await self.createTodo(title: "Test listing tests", client: client)
let todos = try await self.listTodos(client: client)
let todo = try XCTUnwrap(todos.first { $0.id == todoId })
XCTAssertEqual(todo.id, todoId)
XCTAssertEqual(todo.title, "Test listing tests")
}
}

func testUpdate() async throws {
try XCTSkipIf(HBEnvironment().get("CI") != nil)

let app = TodosApp(configuration: .init())
try await app.test(.live) { client in
let todoId = try await self.createTodo(title: "Update tests", client: client)
let updatedTodo = try await self.updateTodo(editedTodo: .init(completed: true), id: todoId, client: client)
XCTAssertEqual(updatedTodo.id, todoId)
XCTAssertEqual(updatedTodo.completed, true)
let getTodo = try await self.getTodo(id: todoId, client: client)
XCTAssertEqual(getTodo.id, todoId)
XCTAssertEqual(getTodo.title, "Update tests")
XCTAssertEqual(getTodo.completed, true)
}
}

func testDelete() async throws {
try XCTSkipIf(HBEnvironment().get("CI") != nil)

let app = TodosApp(configuration: .init())
try await app.test(.live) { client in
let todoId = try await self.createTodo(title: "Delete tests", client: client)
try await self.deleteTodo(id: todoId, client: client)
let todos = try await self.listTodos(client: client)
XCTAssertNil(todos.first { $0.id == todoId })
}
}

func testDeleteAll() async throws {
try XCTSkipIf(HBEnvironment().get("CI") != nil)

let app = TodosApp(configuration: .init())
try await app.test(.live) { client in
let todo = try await client.XCTExecute(
uri: "/todos",
method: .post,
body: ByteBufferAllocator().buffer(string: #"{"title":"add more tests"}"#)
) { response in
XCTAssertEqual(response.status, .created)
let body = try XCTUnwrap(response.body)
return try JSONDecoder().decode(Todo.self, from: body)
}
let todoId = try XCTUnwrap(todo.id)
try await client.XCTExecute(
uri: "/todos/",
method: .get
) { response in
XCTAssertEqual(response.status, .ok)
let body = try XCTUnwrap(response.body)
let todos = try JSONDecoder().decode([Todo].self, from: body)
let todo = try XCTUnwrap(todos.first { $0.id == todoId })
XCTAssertEqual(todo.id, todoId)
XCTAssertEqual(todo.title, "add more tests")
}
_ = try await self.createTodo(title: "Delete all tests", client: client)
try await self.deleteAllTodos(client: client)
let todos = try await self.listTodos(client: client)
XCTAssertEqual(todos.count, 0)
}
}
}

0 comments on commit ef116d4

Please sign in to comment.