feat: Moved cli client tests to XCTest to work in docker
Some checks failed
CI / Run Tests (push) Has been cancelled

This commit is contained in:
2024-11-18 15:53:23 -05:00
parent ce18c44363
commit 24f2ad63a7
14 changed files with 227 additions and 486 deletions

2
.gitignore vendored
View File

@@ -5,7 +5,7 @@
xcuserdata/
DerivedData/
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.dewPoint-env
.dewPoint-env*
.topics
mqtt_password.txt
.env

View File

@@ -1,2 +1,9 @@
disabled_rules:
- closing_brace
- fuction_body_length
included:
- Sources
- Tests
ignore_multiline_statement_conditions: true

View File

@@ -1,67 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1610"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "MQTTConnectionService"
BuildableName = "MQTTConnectionService"
BlueprintName = "MQTTConnectionService"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "MQTTConnectionService"
BuildableName = "MQTTConnectionService"
BlueprintName = "MQTTConnectionService"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -1,67 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1610"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "MQTTManager"
BuildableName = "MQTTManager"
BlueprintName = "MQTTManager"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "MQTTManager"
BuildableName = "MQTTManager"
BlueprintName = "MQTTManager"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -1,67 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1330"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Models"
BuildableName = "Models"
BlueprintName = "Models"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Models"
BuildableName = "Models"
BlueprintName = "Models"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -1,67 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1610"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "SensorsService"
BuildableName = "SensorsService"
BlueprintName = "SensorsService"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "SensorsService"
BuildableName = "SensorsService"
BlueprintName = "SensorsService"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -7,6 +7,20 @@
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CliClient"
BuildableName = "CliClient"
BlueprintName = "CliClient"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
@@ -77,48 +91,25 @@
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "IntegrationTests"
BuildableName = "IntegrationTests"
BlueprintName = "IntegrationTests"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CliClient"
BuildableName = "CliClient"
BlueprintName = "CliClient"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<TestPlans>
<TestPlanReference
reference = "container:.swiftpm/dewpoint-controller-Package.xctestplan"
default = "YES">
</TestPlanReference>
</TestPlans>
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CliClientTests"
BuildableName = "CliClientTests"
BlueprintName = "CliClientTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference

View File

@@ -1,78 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1610"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "dewpoint-controller"
BuildableName = "dewpoint-controller"
BlueprintName = "dewpoint-controller"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "dewpoint-controller"
BuildableName = "dewpoint-controller"
BlueprintName = "dewpoint-controller"
ReferencedContainer = "container:">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "dewpoint-controller"
BuildableName = "dewpoint-controller"
BlueprintName = "dewpoint-controller"
ReferencedContainer = "container:">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -48,7 +48,8 @@ let package = Package(
"CliClient"
],
resources: [
.copy("test.env")
.copy("test.env"),
.copy("test-env.json")
]
),
.executableTarget(

View File

@@ -67,6 +67,7 @@ public struct CliClient {
self.logger = logger
self.mqttClientVersion = mqttClientVersion
}
}
}
@@ -121,8 +122,8 @@ extension EnvVars {
@Dependency(\.environment) var environment
let defaultEnvVars = EnvVars()
let encoder = JSONEncoder()
let decoder = JSONDecoder()
let encoder = environment.jsonEncoder()
let decoder = environment.jsonDecoder()
let defaultEnvDict = (try? encoder.encode(defaultEnvVars))
.flatMap { try? decoder.decode([String: String].self, from: $0) }

View File

@@ -6,6 +6,11 @@ import Models
@_spi(Internal)
public extension DependencyValues {
/// A dependecy responsible for loding environment variables.
///
/// This is just used internally of this module, but is useful to
/// override for testing purposes, so import using `@_spi(Internal)`.
var environment: EnvironmentDependency {
get { self[EnvironmentDependency.self] }
set { self[EnvironmentDependency.self] = newValue }
@@ -19,16 +24,27 @@ public extension DependencyValues {
@DependencyClient
public struct EnvironmentDependency: Sendable {
/// A json decoder to use to decode files and environment variables.
public var jsonDecoder: @Sendable () -> JSONDecoder = { JSONDecoder() }
/// A json encoder to use to encode files and environment variables.
public var jsonEncoder: @Sendable () -> JSONEncoder = { JSONEncoder() }
/// Load the variables based on the request.
public var load: @Sendable (FileType) async throws -> [String: String] = { _ in [:] }
/// Load the environment variables based on the current process environment.
///
/// You can override this to use an empty environment, which is useful for testing purposes.
public var processInfo: @Sendable () -> [String: String] = { [:] }
/// Represents the types of files that can be loaded and decoded into
/// the environment.
public enum FileType: Equatable {
case dotEnv(path: String)
case json(path: String)
init?(path: String) {
public init?(path: String) {
let strings = path.split(separator: ".")
guard let ext = strings.last else {
return nil
@@ -50,7 +66,13 @@ extension EnvironmentDependency: DependencyKey {
public static let testValue: EnvironmentDependency = Self()
public static let liveValue: EnvironmentDependency = Self(
public static func live(
decoder: JSONDecoder = .init(),
encoder: JSONEncoder = .init()
) -> Self {
Self(
jsonDecoder: { decoder },
jsonEncoder: { encoder },
load: { file in
switch file {
case let .dotEnv(path: path):
@@ -59,8 +81,8 @@ extension EnvironmentDependency: DependencyKey {
partialResult[line.key] = line.value
}
case let .json(path: path):
let url = URL(filePath: path)
return try JSONDecoder().decode(
let url = url(for: path)
return try decoder.decode(
[String: String].self,
from: Data(contentsOf: url)
)
@@ -68,4 +90,15 @@ extension EnvironmentDependency: DependencyKey {
},
processInfo: { ProcessInfo.processInfo.environment }
)
}
public static let liveValue: EnvironmentDependency = .live()
}
private func url(for path: String) -> URL {
#if os(Linux)
return URL(fileURLWithPath: path)
#else
return URL(filePath: path)
#endif
}

View File

@@ -4,37 +4,40 @@ import Foundation
import Logging
import Models
import MQTTNIO
import Testing
import XCTest
@Test
func checkTesting() {
#expect(Bool(true))
}
final class CliClientTests: XCTestCase {
@Test(
arguments: [
override func invokeTest() {
withDependencies {
$0.cliClient = .liveValue
$0.environment = .liveValue
$0.environment.processInfo = { [:] }
} operation: {
super.invokeTest()
}
}
func testParsingMQTTVersion() {
@Dependency(\.cliClient) var cliClient
let arguments = [
(MQTTClient.Version.v3_1_1, ["3", "3.1", "3.1.1", "00367894"]),
(MQTTClient.Version.v5_0, ["5", "5.1", "5.1.1", "00000500012"]),
(nil, ["0", "0.1", "0.1.1", "0000000001267894", "blob"])
]
)
func checkParseMQTTVersion(
version: MQTTClient.Version?,
strings: [String]
) {
withDependencies {
$0.cliClient = .liveValue
} operation: {
@Dependency(\.cliClient) var cliClient
for string in strings {
#expect(cliClient.parseMqttClientVersion(string) == version)
#expect(cliClient.parseMqttClientVersion("v\(string)") == version)
}
}
}
@Test(
arguments: [
for (version, strings) in arguments {
for string in strings {
XCTAssertEqual(cliClient.parseMqttClientVersion(string), version)
}
}
}
func testLogLevelFromEnvironment() {
@Dependency(\.cliClient) var cliClient
let arguments = [
(Logger.Level.debug, EnvVars(appEnv: .staging, logLevel: nil)),
(Logger.Level.debug, EnvVars(appEnv: .development, logLevel: nil)),
(Logger.Level.info, EnvVars(appEnv: .production, logLevel: nil)),
@@ -44,18 +47,17 @@ func checkParseMQTTVersion(
(Logger.Level.warning, EnvVars(appEnv: .production, logLevel: .warning)),
(Logger.Level.debug, EnvVars(appEnv: .testing, logLevel: .debug))
]
)
func logLevelFromEnvVars(expectedLevel: Logger.Level, environment: EnvVars) {
withDependencies {
$0.cliClient = .liveValue
} operation: {
@Dependency(\.cliClient) var cliClient
#expect(cliClient.logLevel(environment) == expectedLevel)
}
}
@Test(
arguments: [
for (expected, envVars) in arguments {
XCTAssertEqual(expected, cliClient.logLevel(envVars))
}
}
func testMakeEnvVars() async throws {
@Dependency(\.cliClient) var cliClient
@Dependency(\.environment) var environment
let arguments = [
(
CliClient.EnvVarsRequest(envFilePath: nil, logger: nil, version: nil),
EnvVars()
@@ -66,11 +68,68 @@ func logLevelFromEnvVars(expectedLevel: Logger.Level, environment: EnvVars) {
),
(
CliClient.EnvVarsRequest(
envFilePath: "Tests/CliClientTests/test.env",
envFilePath: "test.env", // Needs to be a bundled resource.
logger: nil,
version: nil
),
EnvVars(
EnvVars.test
),
(
CliClient.EnvVarsRequest(
envFilePath: "test-env.json", // Needs to be a bundled resource.
logger: nil,
version: nil
),
EnvVars.test
)
]
for (request, expectedEnvVars) in arguments {
var request = request
if let file = request.envFilePath {
request = .init(
envFilePath: cleanFilePath(file),
logger: request.logger,
version: request.mqttClientVersion
)
}
let result = try await cliClient.makeEnvVars(request)
XCTAssertEqual(result, expectedEnvVars)
}
}
func testFileType() {
let arguments = [
(EnvironmentDependency.FileType.dotEnv(path: "test.env"), "test.env"),
(EnvironmentDependency.FileType.json(path: "test.json"), "test.json"),
(nil, "test"),
(nil, "")
]
for (expected, file) in arguments {
XCTAssertEqual(EnvironmentDependency.FileType(path: file), expected)
}
}
func testEnvironmentLiveValueProcessInfo() {
let environment = EnvironmentDependency.liveValue
XCTAssertEqual(environment.processInfo(), ProcessInfo.processInfo.environment)
}
}
// - MARK: Helper
private func cleanFilePath(_ path: String) -> String {
let split = path.split(separator: ".")
let fileName = split.first!
let ext = split.last!
let url = Bundle.module.url(forResource: String(fileName), withExtension: String(ext))!.absoluteString
let cleaned = url.split(separator: "file://").last!
return String(cleaned)
}
extension EnvVars {
static let test = EnvVars(
appEnv: .testing,
host: "test.mqtt",
port: "1234",
@@ -80,20 +139,4 @@ func logLevelFromEnvVars(expectedLevel: Logger.Level, environment: EnvVars) {
logLevel: .debug,
version: "5.0"
)
)
]
)
func checkMakeEnvVars(
request: CliClient.EnvVarsRequest,
expectedEnvVars: EnvVars
) async throws {
try await withDependencies {
$0.cliClient = .liveValue
$0.environment = .liveValue
$0.environment.processInfo = { [:] }
} operation: {
@Dependency(\.cliClient) var cliClient
let result = try await cliClient.makeEnvVars(request)
#expect(result == expectedEnvVars)
}
}

View File

@@ -0,0 +1,10 @@
{
"APP_ENV": "testing",
"MQTT_HOST": "test.mqtt",
"MQTT_PORT": "1234",
"MQTT_IDENTIFIER": "testing-mqtt",
"MQTT_USERNAME": "test-user",
"MQTT_PASSWORD": "super-secret",
"LOG_LEVEL": "debug",
"MQTT_VERSION": "5.0"
}

View File

@@ -1,5 +1,6 @@
# Used to build a test image.
FROM swift:5.10
ARG SWIFT_IMAGE_VERSION="5.10"
FROM swift:${SWIFT_IMAGE_VERSION}
WORKDIR /app
COPY ./Package.* ./
RUN swift package resolve