Skip to content

Commit

Permalink
Initial set up of tests
Browse files Browse the repository at this point in the history
  • Loading branch information
fpseverino committed Jul 22, 2024
1 parent a0dbb52 commit 436520c
Show file tree
Hide file tree
Showing 7 changed files with 402 additions and 10 deletions.
4 changes: 4 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ let package = Package(
.package(url: "https://github.com/vapor/vapor.git", from: "4.102.0"),
.package(url: "https://github.com/vapor/fluent.git", from: "4.11.0"),
.package(url: "https://github.com/vapor/apns.git", from: "4.1.0"),
// used in tests
.package(url: "https://github.com/vapor/fluent-sqlite-driver.git", from: "4.7.4"),
],
targets: [
.target(
Expand Down Expand Up @@ -44,6 +46,7 @@ let package = Package(
dependencies: [
.target(name: "Passes"),
.product(name: "XCTVapor", package: "vapor"),
.product(name: "FluentSQLiteDriver", package: "fluent-sqlite-driver"),
],
swiftSettings: swiftSettings
),
Expand All @@ -52,6 +55,7 @@ let package = Package(
dependencies: [
.target(name: "Orders"),
.product(name: "XCTVapor", package: "vapor"),
.product(name: "FluentSQLiteDriver", package: "fluent-sqlite-driver"),
],
swiftSettings: swiftSettings
),
Expand Down
126 changes: 126 additions & 0 deletions Tests/OrdersTests/OrderData.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import Fluent
import struct Foundation.UUID
import Orders
import Vapor

final class OrderData: OrderDataModel, @unchecked Sendable {
static let schema = OrderData.vddMMyyyy.schemaName

@ID(key: .id)
var id: UUID?

@Field(key: OrderData.vddMMyyyy.title)
var title: String

@Parent(key: OrderData.vddMMyyyy.orderID)
var order: Order

init() { }

init(id: UUID? = nil, title: String) {
self.id = id
self.title = title
}

func toDTO() -> OrderDataDTO {
.init(
id: self.id,
title: self.$title.value
)
}
}

struct OrderDataDTO: Content {
var id: UUID?
var title: String?

func toModel() -> OrderData {
let model = OrderData()

model.id = self.id
if let title = self.title {
model.title = title
}
return model
}
}

struct CreateOrderData: AsyncMigration {
func prepare(on database: any Database) async throws {
try await database.schema(OrderData.vddMMyyyy.schemaName)
.id()
.field(OrderData.vddMMyyyy.title, .string, .required)
.field(OrderData.vddMMyyyy.orderID, .uuid, .required, .references(Order.schema, .id, onDelete: .cascade))
.create()
}

func revert(on database: any Database) async throws {
try await database.schema(OrderData.vddMMyyyy.schemaName).delete()
}
}

extension OrderData {
enum vddMMyyyy {
static let schemaName = "order_data"
static let title = FieldKey(stringLiteral: "title")
static let orderID = FieldKey(stringLiteral: "order_id")
}
}

struct OrderJSONData: OrderJSON.Properties {
let schemaVersion = OrderJSON.SchemaVersion.v1
let orderTypeIdentifier = "order.com.example.pet-store"
let orderIdentifier: String
let orderType = OrderJSON.OrderType.ecommerce
let orderNumber = "HM090772020864"
let createdAt: String
let updatedAt: String
let status = OrderJSON.OrderStatus.open
let merchant: MerchantData
let orderManagementURL = "https://www.example.com/"
let authenticationToken: String

private let webServiceURL = "https://www.example.com/api/orders/"

struct MerchantData: OrderJSON.Merchant {
let merchantIdentifier = "com.example.pet-store"
let displayName: String
let url = "https://www.example.com/"
let logo = "pet_store_logo.png"
}

init(data: OrderData, order: Order) {
self.orderIdentifier = order.id!.uuidString
self.authenticationToken = order.authenticationToken
self.merchant = MerchantData(displayName: data.title)
let dateFormatter = ISO8601DateFormatter()
dateFormatter.formatOptions = .withInternetDateTime
self.createdAt = dateFormatter.string(from: order.createdAt!)
self.updatedAt = dateFormatter.string(from: order.updatedAt!)
}
}

struct OrderDataMiddleware: AsyncModelMiddleware {
private unowned let service: OrdersService

init(service: OrdersService) {
self.service = service
}

func create(model: OrderData, on db: any Database, next: any AnyAsyncModelResponder) async throws {
let order = Order(
orderTypeIdentifier: "order.com.example.pet-store",
authenticationToken: Data([UInt8].random(count: 12)).base64EncodedString())
try await order.save(on: db)
model.$order.id = try order.requireID()
try await next.create(model, on: db)
}

func update(model: OrderData, on db: any Database, next: any AnyAsyncModelResponder) async throws {
let order = try await model.$order.get(on: db)
order.updatedAt = Date()
try await order.save(on: db)
try await next.update(model, on: db)
try await service.sendPushNotifications(for: order, on: db)
}
}
27 changes: 27 additions & 0 deletions Tests/OrdersTests/OrderDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import Vapor
import Fluent
import Orders

final class OrderDelegate: OrdersDelegate {
let sslSigningFilesDirectory = URL(fileURLWithPath: "Certificates/Orders/", isDirectory: true)

let pemPrivateKeyPassword: String? = "password"

func encode<O: OrderModel>(order: O, db: any Database, encoder: JSONEncoder) async throws -> Data {
guard let orderData = try await OrderData.query(on: db)
.filter(\.$order.$id == order.requireID())
.with(\.$order)
.first()
else {
throw Abort(.internalServerError)
}
guard let data = try? encoder.encode(OrderJSONData(data: orderData, order: orderData.order)) else {
throw Abort(.internalServerError)
}
return data
}

func template<O: OrderModel>(for: O, db: any Database) async throws -> URL {
return URL(fileURLWithPath: "Templates/Orders/", isDirectory: true)
}
}
26 changes: 21 additions & 5 deletions Tests/OrdersTests/OrdersTests.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
import XCTVapor
import Fluent
import FluentSQLiteDriver
@testable import Orders

final class OrdersTests: XCTestCase {
func testExample() {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct
// results.
//XCTAssertEqual(OrdersService().text, "Hello, World!")
var app: Application!
let orderDelegate = OrderDelegate()

override func setUp() async throws {
self.app = try await Application.make(.testing)

app.databases.use(.sqlite(.memory), as: .sqlite)
OrdersService.register(migrations: app.migrations)
app.migrations.add(CreateOrderData())
let ordersService = try OrdersService(app: app, delegate: orderDelegate)
app.databases.middleware.use(OrderDataMiddleware(service: ordersService), on: .sqlite)

try await app.autoMigrate()
}

override func tearDown() async throws {
try await app.autoRevert()
try await self.app.asyncShutdown()
self.app = nil
}
}
157 changes: 157 additions & 0 deletions Tests/PassesTests/PassData.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import Fluent
import struct Foundation.UUID
import Passes
import Vapor

final class PassData: PassDataModel, @unchecked Sendable {
static let schema = PassData.vddMMyyyy.schemaName

@ID(key: .id)
var id: UUID?

@Field(key: PassData.vddMMyyyy.title)
var title: String

@Parent(key: PassData.vddMMyyyy.passID)
var pass: PKPass

init() { }

init(id: UUID? = nil, title: String) {
self.id = id
self.title = title
}

func toDTO() -> PassDataDTO {
.init(
id: self.id,
title: self.$title.value
)
}
}

struct PassDataDTO: Content {
var id: UUID?
var title: String?

func toModel() -> PassData {
let model = PassData()

model.id = self.id
if let title = self.title {
model.title = title
}
return model
}
}

struct CreatePassData: AsyncMigration {
func prepare(on database: any Database) async throws {
try await database.schema(PassData.vddMMyyyy.schemaName)
.id()
.field(PassData.vddMMyyyy.title, .string, .required)
.field(PassData.vddMMyyyy.passID, .uuid, .required, .references(PKPass.schema, .id, onDelete: .cascade))
.create()
}

func revert(on database: any Database) async throws {
try await database.schema(PassData.vddMMyyyy.schemaName).delete()
}
}

extension PassData {
enum vddMMyyyy {
static let schemaName = "pass_data"
static let title = FieldKey(stringLiteral: "title")
static let passID = FieldKey(stringLiteral: "pass_id")
}
}

struct PassJSONData: PassJSON.Properties {
let description: String
let formatVersion = PassJSON.FormatVersion.v1
let organizationName = "vapor-community"
let passTypeIdentifier = "pass.com.vapor-community.pass"
let serialNumber: String
let teamIdentifier = "ABCD1234"

private let webServiceURL = "https://www.example.com/api/passes/"
private let authenticationToken: String
private let logoText = "Vapor"
private let sharingProhibited = true
let backgroundColor = "rgb(207, 77, 243)"
let foregroundColor = "rgb(255, 255, 255)"

let barcodes = Barcode(message: "test")
struct Barcode: PassJSON.Barcodes {
let format = PassJSON.BarcodeFormat.qr
let message: String
let messageEncoding = "iso-8859-1"
}

let boardingPass = Boarding(transitType: .air)
struct Boarding: PassJSON.BoardingPass {
let transitType: PassJSON.TransitType
let headerFields: [PassField]
let primaryFields: [PassField]
let secondaryFields: [PassField]
let auxiliaryFields: [PassField]
let backFields: [PassField]

struct PassField: PassJSON.PassFieldContent {
let key: String
let label: String
let value: String
}

init(transitType: PassJSON.TransitType) {
self.headerFields = [.init(key: "header", label: "Header", value: "Header")]
self.primaryFields = [.init(key: "primary", label: "Primary", value: "Primary")]
self.secondaryFields = [.init(key: "secondary", label: "Secondary", value: "Secondary")]
self.auxiliaryFields = [.init(key: "auxiliary", label: "Auxiliary", value: "Auxiliary")]
self.backFields = [.init(key: "back", label: "Back", value: "Back")]
self.transitType = transitType
}
}

init(data: PassData, pass: PKPass) {
self.description = data.title
self.serialNumber = pass.id!.uuidString
self.authenticationToken = pass.authenticationToken
}
}

struct PersonalizationJSONData: PersonalizationJSON.Properties {
var requiredPersonalizationFields = [
PersonalizationJSON.PersonalizationField.name,
PersonalizationJSON.PersonalizationField.postalCode,
PersonalizationJSON.PersonalizationField.emailAddress,
PersonalizationJSON.PersonalizationField.phoneNumber
]
var description = "Hello, World!"
}

struct PassDataMiddleware: AsyncModelMiddleware {
private unowned let service: PassesService

init(service: PassesService) {
self.service = service
}

func create(model: PassData, on db: any Database, next: any AnyAsyncModelResponder) async throws {
let pkPass = PKPass(
passTypeIdentifier: "pass.com.vapor-community.pass",
authenticationToken: Data([UInt8].random(count: 12)).base64EncodedString())
try await pkPass.save(on: db)
model.$pass.id = try pkPass.requireID()
try await next.create(model, on: db)
}

func update(model: PassData, on db: any Database, next: any AnyAsyncModelResponder) async throws {
let pkPass = try await model.$pass.get(on: db)
pkPass.updatedAt = Date()
try await pkPass.save(on: db)
try await next.update(model, on: db)
try await service.sendPushNotifications(for: pkPass, on: db)
}
}
Loading

0 comments on commit 436520c

Please sign in to comment.