Files
ccn/Packages/Persistence/Tests/Cases/Public/Methods/ServiceTests.swift
T

172 lines
4.7 KiB
Swift
Raw Normal View History

import Foundation
import Logging
import SQLKit
import Testing
@testable import Persistence
@Suite(
"Service method",
.tags(.method)
)
struct ServiceTests {
// MARK: Methods tests
@Test
func `registers an SQLite database as the default for the in-memory driver`() async throws {
let service = Service(
driver: .inMemory,
logger: Logger(label: "test")
)
let fluent = service()
let database = fluent.db() as? any SQLDatabase
try await fluent.shutdown()
let dialect = try #require(database?.dialect)
#expect(dialect.name == "sqlite")
}
@Test
func `registers a MySQL database as the default for the mysql driver`() async throws {
// Resolving the default database opens no connection — pooling is lazy — so no server
// needs to be listening on the configured host and port.
let service = Service(
driver: .mysql(
.init(
host: "127.0.0.1",
port: 3306,
name: "loud",
username: "loud",
password: "loud",
tls: .off,
maxConnectionsPerEventLoop: 1
)
),
logger: Logger(label: "test")
)
let fluent = service()
let database = fluent.db() as? any SQLDatabase
try await fluent.shutdown()
let dialect = try #require(database?.dialect)
#expect(dialect.name == "mysql")
}
@Test
func `builds a usable in-memory database`() async throws {
let service = Service(
driver: .inMemory,
logger: Logger(label: "test")
)
let fluent = service()
do {
let database = try #require(fluent.db() as? any SQLDatabase)
try await database.raw("SELECT 1").run()
} catch {
try? await fluent.shutdown()
throw error
}
try await fluent.shutdown()
}
@Test("in-memory: migrate, insert, read back")
func inMemoryRoundTrip() async throws {
try await roundTrip(driver: .inMemory)
}
@Test(
"mysql: migrate, insert, read back",
.enabled(if: mysqlDriver != nil)
)
func mysqlRoundTrip() async throws {
try await roundTrip(
driver: mysqlDriver!,
revertAfter: true
)
}
}
// MARK: - Helpers
private extension ServiceTests {
/// Migrates, inserts, and reads back a record against the given driver, shutting the pool down after.
///
/// The `Fluent` service normally owns pool shutdown via its `run()` in the service group; outside that,
/// the test must shut it down explicitly — even on failure — or the pool asserts on `deinit`.
/// - Parameters:
/// - driver: the persistence backend to exercise.
/// - revertAfter: whether to revert the migrations afterwards; set for a shared database (the
/// in-memory database is discarded on shutdown, so it needs no revert).
func roundTrip(
driver: Persistence.Driver,
revertAfter: Bool = false
) async throws {
let prepareDB = PrepareDB()
let service = Service(
driver: driver,
logger: Logger(label: "test")
)
let fluent = service()
do {
await prepareDB(for: fluent)
try await fluent.migrate()
let repository = ExampleRepository(fluent: fluent)
let created = try await repository.create(name: "loud")
#expect(try await repository.all().contains(created))
if revertAfter {
try await fluent.revert()
}
} catch {
try? await fluent.shutdown()
throw error
}
try await fluent.shutdown()
}
}
/// The MySQL/MariaDB driver built from the `MYSQL_TEST_*` environment variables, or `nil` when the gate
/// variable `MYSQL_TEST_HOST` is unset — in which case the MySQL integration test is skipped, so the suite
/// stays runnable with no database available.
private let mysqlDriver: Persistence.Driver? = {
let environment = ProcessInfo.processInfo.environment
guard let host = environment["MYSQL_TEST_HOST"] else {
return nil
}
return .mysql(
.init(
host: host,
port: environment["MYSQL_TEST_PORT"].flatMap(Int.init) ?? 3306,
name: environment["MYSQL_TEST_NAME"] ?? "loud",
username: environment["MYSQL_TEST_USERNAME"] ?? "loud",
password: environment["MYSQL_TEST_PASSWORD"] ?? "loud",
tls: .off,
maxConnectionsPerEventLoop: 2
)
)
}()