Files
swift-hpa/Tests/PlaybookClientTests/PlaybookClientTests.swift

277 lines
8.3 KiB
Swift

import CodersClient
@_spi(Internal) import CommandClient
@_spi(Internal) import ConfigurationClient
import Dependencies
import FileClient
import Foundation
@_spi(Internal) import PlaybookClient
import ShellClient
import Testing
import TestSupport
@Suite("PlaybookClientTests")
struct PlaybookClientTests: TestCase {
static var sharedRunOptions: PlaybookClient.RunPlaybook.SharedRunOptions {
.init(loggingOptions: loggingOptions)
}
@Test(.tags(.repository))
func repositoryInstallation() async throws {
try await withDependencies {
$0.fileClient = .liveValue
$0.asyncShellClient = .liveValue
$0.commandClient = .liveValue
} operation: {
try await withTemporaryDirectory { tempDirectory in
let pathUrl = tempDirectory.appending(path: "playbook")
let playbookClient = PlaybookClient.liveValue
let configuration = Configuration(playbook: .init(directory: pathUrl.cleanFilePath))
try? FileManager.default.removeItem(at: pathUrl)
try await playbookClient.repository.install(configuration)
let exists = FileManager.default.fileExists(atPath: pathUrl.cleanFilePath)
#expect(exists)
}
}
}
@Test(
.tags(.repository),
arguments: [
(Configuration(), PlaybookClient.Constants.defaultInstallationPath),
(Configuration(playbook: .init(directory: "playbook")), "playbook")
]
)
func repositoryDirectory(configuration: Configuration, expected: String) async throws {
let client = PlaybookClient.liveValue
let result = try await client.repository.directory(configuration)
#expect(result == expected)
}
@Test(.tags(.run))
func runBuildProject() async throws {
let captured = CommandClient.CapturingClient()
try await withMockConfiguration(captured, key: "runBuildProject") {
@Dependency(\.playbookClient) var playbookClient
let configuration = Configuration.mock
try await playbookClient.run.buildProject(.init(projectDirectory: "/foo", shared: Self.sharedRunOptions))
let arguments = await captured.options!.arguments
print(arguments)
#expect(arguments == [
"ansible-playbook", "~/.local/share/hpa/playbook/main.yml",
"--inventory", "~/.local/share/hpa/playbook/inventory.ini",
configuration.vault.args!.first!,
"--tags", "build-project",
"--extra-vars", "project_dir=/foo"
])
}
}
@Test(
.tags(.run),
arguments: [
(true, "\'{\"template\":{\"path\":\"\(Configuration.mock.template.directory!)\"}}\'"),
(false, "\'{\"template\":{\"repo\":{\"url\":\"\(Configuration.mock.template.url!)\",\"version\":\"\(Configuration.mock.template.version!)\"}}}\'")
]
)
func runCreateProject(useLocalTemplateDirectory: Bool, json: String) async throws {
let captured = CommandClient.CapturingClient()
try await withMockConfiguration(captured, key: "runBuildProject") {
@Dependency(\.logger) var logger
@Dependency(\.playbookClient) var playbookClient
let configuration = Configuration.mock
try await playbookClient.run.createProject(
.init(
projectDirectory: "/project",
shared: Self.sharedRunOptions,
useLocalTemplateDirectory: useLocalTemplateDirectory
)
)
let arguments = await captured.options!.arguments
logger.debug("\(arguments)")
#expect(arguments == [
"ansible-playbook", "~/.local/share/hpa/playbook/main.yml",
"--inventory", "~/.local/share/hpa/playbook/inventory.ini",
configuration.vault.args!.first!,
"--tags", "setup-project",
"--extra-vars", "project_dir=/project",
"--extra-vars", json
])
}
}
@Test(arguments: CreateJsonTestOption.testCases)
func createJson(input: CreateJsonTestOption) {
withTestLogger(key: "generateJson") {
$0.coders.jsonEncoder = { jsonEncoder }
$0.configurationClient = .mock(input.configuration)
} operation: {
@Dependency(\.coders) var coders
let jsonData = try? input.options.createJSONData(
configuration: input.configuration,
encoder: coders.jsonEncoder()
)
switch input.expectation {
case let .success(expected):
let json = String(data: jsonData!, encoding: .utf8)!
if json != expected {
print("json:", json)
print("expected:", expected)
}
#expect(json == expected)
case .failure:
#expect(jsonData == nil)
}
}
}
func withMockConfiguration(
_ capturing: CommandClient.CapturingClient,
configuration: Configuration = .mock,
key: String,
logLevel: Logger.Level = .trace,
depednencies setupDependencies: @escaping (inout DependencyValues) -> Void = { _ in },
operation: @Sendable @escaping () async throws -> Void
) async rethrows {
try await withDependencies {
$0.configurationClient = .mock(configuration)
$0.commandClient = .capturing(capturing)
$0.playbookClient = .liveValue
setupDependencies(&$0)
} operation: {
try await operation()
}
}
}
struct CreateJsonTestOption: Sendable {
let options: PlaybookClient.RunPlaybook.CreateOptions
let configuration: Configuration
let expectation: Result<String, TestError>
static let testCases: [Self] = [
CreateJsonTestOption(
options: .init(
projectDirectory: "/project",
shared: PlaybookClientTests.sharedRunOptions,
template: .init(url: nil, version: nil, directory: nil),
useLocalTemplateDirectory: true
),
configuration: .init(),
expectation: .failing
),
CreateJsonTestOption(
options: .init(
projectDirectory: "/project",
shared: PlaybookClientTests.sharedRunOptions,
template: .init(url: nil, version: nil, directory: nil),
useLocalTemplateDirectory: false
),
configuration: .init(),
expectation: .failing
),
CreateJsonTestOption(
options: .init(
projectDirectory: "/project",
shared: PlaybookClientTests.sharedRunOptions,
template: .init(url: nil, version: nil, directory: "/template"),
useLocalTemplateDirectory: true
),
configuration: .init(template: .init(directory: "/template")),
expectation: .success("""
{
"template" : {
"path" : "/template"
}
}
""")
),
CreateJsonTestOption(
options: .init(
projectDirectory: "/project",
shared: PlaybookClientTests.sharedRunOptions,
template: .init(url: nil, version: nil, directory: "/template"),
useLocalTemplateDirectory: true
),
configuration: .init(template: .init(directory: "/template")),
expectation: .success("""
{
"template" : {
"path" : "/template"
}
}
""")
),
CreateJsonTestOption(
options: .init(
projectDirectory: "/project",
shared: PlaybookClientTests.sharedRunOptions,
template: .init(url: "https://git.example.com/template.git", version: "main", directory: nil),
useLocalTemplateDirectory: false
),
configuration: .init(),
expectation: .success("""
{
"template" : {
"repo" : {
"url" : "https://git.example.com/template.git",
"version" : "main"
}
}
}
""")
),
CreateJsonTestOption(
options: .init(
projectDirectory: "/project",
shared: PlaybookClientTests.sharedRunOptions,
template: .init(url: "https://git.example.com/template.git", version: "v0.1.0", directory: nil),
useLocalTemplateDirectory: false
),
configuration: .init(template: .init(url: "https://git.example.com/template.git", version: "v0.1.0")),
expectation: .success("""
{
"template" : {
"repo" : {
"url" : "https://git.example.com/template.git",
"version" : "v0.1.0"
}
}
}
""")
)
]
}
extension Result where Failure == TestError {
static var failing: Self { .failure(TestError()) }
}
struct TestError: Error {}
extension Tag {
@Tag static var repository: Self
@Tag static var run: Self
}
let jsonEncoder: JSONEncoder = {
let encoder = JSONEncoder()
encoder.outputFormatting = [.prettyPrinted, .withoutEscapingSlashes, .sortedKeys]
return encoder
}()