292 lines
8.7 KiB
Swift
292 lines
8.7 KiB
Swift
import CodersClient
|
|
@_spi(Internal) import CommandClient
|
|
import ConfigurationClient
|
|
import Dependencies
|
|
import FileClient
|
|
import Foundation
|
|
@_spi(Internal) import PlaybookClient
|
|
import ShellClient
|
|
import Testing
|
|
import TestSupport
|
|
|
|
@Suite("PlaybookClientTests")
|
|
struct PlaybookClientTests: TestCase {
|
|
|
|
static let loggingOptions: LoggingOptions = {
|
|
let levelString = ProcessInfo.processInfo.environment["LOG_LEVEL"] ?? "debug"
|
|
let logLevel = Logger.Level(rawValue: levelString) ?? .debug
|
|
return .init(commandName: "PlaybookClientTests", logLevel: logLevel)
|
|
}()
|
|
|
|
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()) }
|
|
}
|
|
|
|
extension ConfigurationClient {
|
|
static func mock(_ configuration: Configuration) -> Self {
|
|
var mock = Self.testValue
|
|
mock.find = { throw TestError() }
|
|
mock.load = { _ in configuration }
|
|
return mock
|
|
}
|
|
}
|
|
|
|
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
|
|
}()
|