diff --git a/Makefile b/Makefile index c2bc38e9..ca8e0c41 100644 --- a/Makefile +++ b/Makefile @@ -12,3 +12,6 @@ build: test: bash make.sh test + +package: + bash make.sh package diff --git a/Package.resolved b/Package.resolved index fdef4f7d..3de71b02 100644 --- a/Package.resolved +++ b/Package.resolved @@ -6,8 +6,8 @@ "repositoryURL": "https://github.com/IBM-Swift/BlueSignals.git", "state": { "branch": null, - "revision": "23f62ec7a38a837e1c14acffc2e963b667a88b46", - "version": "1.0.16" + "revision": "b7331c8bef913f5f8b3cffa6ecfcce679f7c2531", + "version": "1.0.21" } }, { @@ -20,21 +20,21 @@ } }, { - "package": "CountedSet", - "repositoryURL": "https://github.com/0x7fs/CountedSet", + "package": "CommandLineToolkit", + "repositoryURL": "https://github.com/avito-tech/CommandLineToolkit.git", "state": { "branch": "master", - "revision": "5bdaf31e6f71dcb430e40a0da3ff10ff61bf5368", + "revision": "1da04bca1f31d05c4d5bad5c384af2c09d8e28b9", "version": null } }, { - "package": "GraphiteClient", - "repositoryURL": "https://github.com/avito-tech/GraphiteClient.git", + "package": "CountedSet", + "repositoryURL": "https://github.com/0x7fs/CountedSet", "state": { - "branch": null, - "revision": "2333d2c4a73c19db636939033cbe2b5ba3fc9f8c", - "version": "0.1.1" + "branch": "master", + "revision": "5bdaf31e6f71dcb430e40a0da3ff10ff61bf5368", + "version": null } }, { diff --git a/Package.swift b/Package.swift index 1cf35559..0996f24d 100644 --- a/Package.swift +++ b/Package.swift @@ -1,88 +1,38 @@ -// swift-tools-version:5.0 - +// swift-tools-version:5.2 import PackageDescription - let package = Package( name: "EmceeTestRunner", platforms: [ - .macOS(.v10_14), + .macOS(.v10_15), ], products: [ - .executable( - name: "Emcee", - targets: [ - "EmceeBinary", - ] - ), - .library( - name: "EmceePlugin", - targets: [ - "Logging", - "Plugin", - ] - ), - .library( - name: "EmceeCommunications", - targets: [ - "PortDeterminer", - "QueueClient", - "QueueCommunication", - "RemotePortDeterminer", - "RequestSender", - ] - ), - .library( - name: "EmceeInterfaces", - targets: [ - "BuildArtifacts", - "DeveloperDirModels", - "EmceeVersion", - "FileSystem", - "PathLib", - "PluginSupport", - "QueueModels", - "ResourceLocation", - "ResourceLocationResolver", - "RunnerModels", - "SimulatorPoolModels", - "SimulatorVideoRecorder", - "SocketModels", - "TestArgFile", - "TestDiscovery", - "TestsWorkingDirectorySupport", - "TypedResourceLocation", - "WorkerAlivenessModels", - "WorkerCapabilitiesModels", - ] - ), - .executable( - name: "testing_plugin", - targets: ["TestingPlugin"] - ) + .executable(name: "Emcee", targets: ["EmceeBinary"]), + .executable(name: "testing_plugin", targets: ["TestingPlugin"]), + .library(name: "EmceePlugin", targets: ["Logging", "Plugin"]), + .library(name: "EmceeCommunications", targets: ["PortDeterminer", "QueueClient", "QueueCommunication", "RemotePortDeterminer", "RequestSender"]), + .library(name: "EmceeInterfaces", targets: ["BuildArtifacts", "DeveloperDirModels", "EmceeVersion", "PluginSupport", "QueueModels", "ResourceLocation", "ResourceLocationResolver", "RunnerModels", "SimulatorPoolModels", "SimulatorVideoRecorder", "TestArgFile", "TestDiscovery", "TestsWorkingDirectorySupport", "TypedResourceLocation", "WorkerAlivenessModels", "WorkerCapabilitiesModels"]), ], dependencies: [ - .package(url: "https://github.com/0x7fs/CountedSet", .branch("master")), - .package(url: "https://github.com/IBM-Swift/BlueSignals.git", .exact("1.0.16")), - .package(url: "https://github.com/Weebly/OrderedSet", .exact("5.0.0")), - .package(url: "https://github.com/avito-tech/GraphiteClient.git", .exact("0.1.1")), - .package(url: "https://github.com/daltoniam/Starscream.git", .exact("3.0.6")), - .package(url: "https://github.com/httpswift/swifter.git", .exact("1.4.6")), - .package(url: "https://github.com/jakeheis/Shout.git", .exact("0.5.4")), + .package(name: "CommandLineToolkit", url: "https://github.com/avito-tech/CommandLineToolkit.git", .branch("master")), + .package(name: "CountedSet", url: "https://github.com/0x7fs/CountedSet", .branch("master")), + .package(name: "OrderedSet", url: "https://github.com/Weebly/OrderedSet", .exact("5.0.0")), + .package(name: "Shout", url: "https://github.com/jakeheis/Shout.git", .exact("0.5.4")), + .package(name: "Starscream", url: "https://github.com/daltoniam/Starscream.git", .exact("3.0.6")), + .package(name: "Swifter", url: "https://github.com/httpswift/swifter.git", .exact("1.4.6")), ], targets: [ .target( - // MARK: AppleTools name: "AppleTools", dependencies: [ - "AtomicModels", + .product(name: "AtomicModels", package: "CommandLineToolkit"), "BuildArtifacts", - "DateProvider", + .product(name: "DateProvider", package: "CommandLineToolkit"), "DeveloperDirLocator", "Logging", "ObservableFileReader", - "PathLib", - "PlistLib", - "ProcessController", + .product(name: "PathLib", package: "CommandLineToolkit"), + .product(name: "PlistLib", package: "CommandLineToolkit"), + .product(name: "ProcessController", package: "CommandLineToolkit"), "ResourceLocation", "ResourceLocationResolver", "ResultStream", @@ -90,27 +40,26 @@ let package = Package( "RunnerModels", "SimulatorPool", "SimulatorPoolModels", - "TemporaryStuff", + .product(name: "Tmp", package: "CommandLineToolkit"), "XCTestJsonCodable", ], path: "Sources/AppleTools" ), .testTarget( - // MARK: AppleToolsTests name: "AppleToolsTests", dependencies: [ "AppleTools", "BuildArtifacts", "BuildArtifactsTestHelpers", - "DateProvider", - "DateProviderTestHelpers", + .product(name: "DateProvider", package: "CommandLineToolkit"), + .product(name: "DateProviderTestHelpers", package: "CommandLineToolkit"), "DeveloperDirLocator", "DeveloperDirLocatorTestHelpers", "DeveloperDirModels", "FileCache", - "PathLib", - "ProcessController", - "ProcessControllerTestHelpers", + .product(name: "PathLib", package: "CommandLineToolkit"), + .product(name: "ProcessController", package: "CommandLineToolkit"), + .product(name: "ProcessControllerTestHelpers", package: "CommandLineToolkit"), "QueueModelsTestHelpers", "ResourceLocationResolver", "ResourceLocationResolverTestHelpers", @@ -121,22 +70,20 @@ let package = Package( "RunnerTestHelpers", "SimulatorPoolModels", "SimulatorPoolTestHelpers", - "TemporaryStuff", - "TestHelpers", + .product(name: "TestHelpers", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), "URLResource", ], path: "Tests/AppleToolsTests" ), .target( - // MARK: ArgLib name: "ArgLib", dependencies: [ - "OrderedSet", + .product(name: "OrderedSet", package: "OrderedSet"), ], path: "Sources/ArgLib" ), .testTarget( - // MARK: ArgLibTests name: "ArgLibTests", dependencies: [ "ArgLib", @@ -144,17 +91,15 @@ let package = Package( path: "Tests/ArgLibTests" ), .target( - // MARK: AutomaticTermination name: "AutomaticTermination", dependencies: [ - "DateProvider", + .product(name: "DateProvider", package: "CommandLineToolkit"), "Logging", - "Timer", + .product(name: "Timer", package: "CommandLineToolkit"), ], path: "Sources/AutomaticTermination" ), .target( - // MARK: AutomaticTerminationTestHelpers name: "AutomaticTerminationTestHelpers", dependencies: [ "AutomaticTermination", @@ -162,35 +107,32 @@ let package = Package( path: "Tests/AutomaticTerminationTestHelpers" ), .testTarget( - // MARK: AutomaticTerminationTests name: "AutomaticTerminationTests", dependencies: [ "AutomaticTermination", - "DateProvider", + .product(name: "DateProvider", package: "CommandLineToolkit"), ], path: "Tests/AutomaticTerminationTests" ), .target( - // MARK: BalancingBucketQueue name: "BalancingBucketQueue", dependencies: [ "BucketQueue", "BucketQueueModels", - "CountedSet", - "DateProvider", + .product(name: "CountedSet", package: "CountedSet"), + .product(name: "DateProvider", package: "CommandLineToolkit"), "LocalHostDeterminer", "Logging", - "Metrics", + .product(name: "Metrics", package: "CommandLineToolkit"), "QueueModels", "RunnerModels", - "Statsd", - "Types", + .product(name: "Statsd", package: "CommandLineToolkit"), + .product(name: "Types", package: "CommandLineToolkit"), "WorkerCapabilitiesModels", ], path: "Sources/BalancingBucketQueue" ), .testTarget( - // MARK: BalancingBucketQueueTests name: "BalancingBucketQueueTests", dependencies: [ "BalancingBucketQueue", @@ -199,16 +141,16 @@ let package = Package( "BucketQueueTestHelpers", "BuildArtifacts", "BuildArtifactsTestHelpers", - "DateProvider", - "DateProviderTestHelpers", - "MetricsTestHelpers", + .product(name: "DateProvider", package: "CommandLineToolkit"), + .product(name: "DateProviderTestHelpers", package: "CommandLineToolkit"), + .product(name: "MetricsTestHelpers", package: "CommandLineToolkit"), "QueueCommunication", "QueueCommunicationTestHelpers", "QueueModels", "QueueModelsTestHelpers", "RunnerModels", "RunnerTestHelpers", - "TestHelpers", + .product(name: "TestHelpers", package: "CommandLineToolkit"), "TestHistoryTestHelpers", "UniqueIdentifierGenerator", "UniqueIdentifierGeneratorTestHelpers", @@ -219,17 +161,16 @@ let package = Package( path: "Tests/BalancingBucketQueueTests" ), .target( - // MARK: BucketQueue name: "BucketQueue", dependencies: [ "BucketQueueModels", - "DateProvider", + .product(name: "DateProvider", package: "CommandLineToolkit"), "Logging", "QueueModels", "RunnerModels", "TestHistoryModels", "TestHistoryTracker", - "Types", + .product(name: "Types", package: "CommandLineToolkit"), "UniqueIdentifierGenerator", "WorkerAlivenessProvider", "WorkerCapabilities", @@ -238,7 +179,6 @@ let package = Package( path: "Sources/BucketQueue" ), .target( - // MARK: BucketQueueModels name: "BucketQueueModels", dependencies: [ "Logging", @@ -247,13 +187,12 @@ let package = Package( path: "Sources/BucketQueueModels" ), .target( - // MARK: BucketQueueTestHelpers name: "BucketQueueTestHelpers", dependencies: [ "BucketQueue", "BucketQueueModels", - "DateProvider", - "DateProviderTestHelpers", + .product(name: "DateProvider", package: "CommandLineToolkit"), + .product(name: "DateProviderTestHelpers", package: "CommandLineToolkit"), "QueueModels", "QueueModelsTestHelpers", "TestHistoryTestHelpers", @@ -267,13 +206,12 @@ let package = Package( path: "Tests/BucketQueueTestHelpers" ), .testTarget( - // MARK: BucketQueueTests name: "BucketQueueTests", dependencies: [ "BucketQueue", "BucketQueueModels", "BucketQueueTestHelpers", - "DateProviderTestHelpers", + .product(name: "DateProviderTestHelpers", package: "CommandLineToolkit"), "DistWorkerModels", "QueueCommunication", "QueueCommunicationTestHelpers", @@ -281,7 +219,7 @@ let package = Package( "QueueModelsTestHelpers", "RunnerModels", "RunnerTestHelpers", - "TestHelpers", + .product(name: "TestHelpers", package: "CommandLineToolkit"), "TestHistoryTestHelpers", "TestHistoryTracker", "UniqueIdentifierGenerator", @@ -293,7 +231,6 @@ let package = Package( path: "Tests/BucketQueueTests" ), .target( - // MARK: BuildArtifacts name: "BuildArtifacts", dependencies: [ "TypedResourceLocation", @@ -301,7 +238,6 @@ let package = Package( path: "Sources/BuildArtifacts" ), .target( - // MARK: BuildArtifactsTestHelpers name: "BuildArtifactsTestHelpers", dependencies: [ "BuildArtifacts", @@ -310,59 +246,39 @@ let package = Package( path: "Tests/BuildArtifactsTestHelpers" ), .target( - // MARK: ChromeTracing name: "ChromeTracing", dependencies: [ ], path: "Sources/ChromeTracing" ), .target( - // MARK: DI name: "DI", dependencies: [ - "AtomicModels", + .product(name: "AtomicModels", package: "CommandLineToolkit"), ], path: "Sources/DI" ), .testTarget( - // MARK: DITests name: "DITests", dependencies: [ "DI", - "TestHelpers", + .product(name: "TestHelpers", package: "CommandLineToolkit"), ], path: "Tests/DITests" ), .target( - // MARK: DateProvider - name: "DateProvider", - dependencies: [ - ], - path: "Sources/DateProvider" - ), - .target( - // MARK: DateProviderTestHelpers - name: "DateProviderTestHelpers", - dependencies: [ - "DateProvider", - ], - path: "Tests/DateProviderTestHelpers" - ), - .target( - // MARK: Deployer name: "Deployer", dependencies: [ "Logging", - "PathLib", - "ProcessController", + .product(name: "PathLib", package: "CommandLineToolkit"), + .product(name: "ProcessController", package: "CommandLineToolkit"), "QueueModels", - "TemporaryStuff", + .product(name: "Tmp", package: "CommandLineToolkit"), "UniqueIdentifierGenerator", ], path: "Sources/Deployer" ), .target( - // MARK: DeployerTestHelpers name: "DeployerTestHelpers", dependencies: [ "Deployer", @@ -370,110 +286,102 @@ let package = Package( path: "Tests/DeployerTestHelpers" ), .testTarget( - // MARK: DeployerTests name: "DeployerTests", dependencies: [ "Deployer", - "PathLib", - "ProcessController", - "ProcessControllerTestHelpers", - "TemporaryStuff", - "TestHelpers", + .product(name: "PathLib", package: "CommandLineToolkit"), + .product(name: "ProcessController", package: "CommandLineToolkit"), + .product(name: "ProcessControllerTestHelpers", package: "CommandLineToolkit"), + .product(name: "TestHelpers", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), "UniqueIdentifierGeneratorTestHelpers", ], path: "Tests/DeployerTests" ), .target( - // MARK: DeveloperDirLocator name: "DeveloperDirLocator", dependencies: [ "DeveloperDirModels", - "PathLib", - "ProcessController", + .product(name: "PathLib", package: "CommandLineToolkit"), + .product(name: "ProcessController", package: "CommandLineToolkit"), ], path: "Sources/DeveloperDirLocator" ), .target( - // MARK: DeveloperDirLocatorTestHelpers name: "DeveloperDirLocatorTestHelpers", dependencies: [ "DeveloperDirLocator", "DeveloperDirModels", - "PathLib", + .product(name: "PathLib", package: "CommandLineToolkit"), ], path: "Tests/DeveloperDirLocatorTestHelpers" ), .testTarget( - // MARK: DeveloperDirLocatorTests name: "DeveloperDirLocatorTests", dependencies: [ "DeveloperDirLocator", - "PathLib", - "ProcessController", - "ProcessControllerTestHelpers", - "TemporaryStuff", - "TestHelpers", + .product(name: "PathLib", package: "CommandLineToolkit"), + .product(name: "ProcessController", package: "CommandLineToolkit"), + .product(name: "ProcessControllerTestHelpers", package: "CommandLineToolkit"), + .product(name: "TestHelpers", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), ], path: "Tests/DeveloperDirLocatorTests" ), .target( - // MARK: DeveloperDirModels name: "DeveloperDirModels", dependencies: [ ], path: "Sources/DeveloperDirModels" ), .target( - // MARK: DistDeployer name: "DistDeployer", dependencies: [ "Deployer", "LaunchdUtils", "Logging", - "PathLib", - "ProcessController", + .product(name: "PathLib", package: "CommandLineToolkit"), + .product(name: "ProcessController", package: "CommandLineToolkit"), "QueueModels", "SSHDeployer", - "SocketModels", - "TemporaryStuff", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), "TypedResourceLocation", "UniqueIdentifierGenerator", ], path: "Sources/DistDeployer" ), .testTarget( - // MARK: DistDeployerTests name: "DistDeployerTests", dependencies: [ "Deployer", "DeployerTestHelpers", "DistDeployer", - "PathLib", + .product(name: "PathLib", package: "CommandLineToolkit"), "QueueModels", "ResourceLocationResolver", - "SocketModels", - "TemporaryStuff", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), ], path: "Tests/DistDeployerTests" ), .target( - // MARK: DistWorker name: "DistWorker", dependencies: [ - "AtomicModels", + .product(name: "AtomicModels", package: "CommandLineToolkit"), "AutomaticTermination", - "CountedSet", + .product(name: "CountedSet", package: "CountedSet"), "DI", - "DateProvider", + .product(name: "DateProvider", package: "CommandLineToolkit"), "DeveloperDirLocator", "DistWorkerModels", "EventBus", - "FileSystem", + .product(name: "FileSystem", package: "CommandLineToolkit"), "LocalHostDeterminer", "Logging", "LoggingSetup", - "Metrics", - "PathLib", + .product(name: "Metrics", package: "CommandLineToolkit"), + .product(name: "PathLib", package: "CommandLineToolkit"), "PluginManager", "QueueClient", "QueueModels", @@ -486,18 +394,17 @@ let package = Package( "RunnerModels", "Scheduler", "SimulatorPool", - "SocketModels", - "SynchronousWaiter", - "TemporaryStuff", - "Timer", - "Types", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "SynchronousWaiter", package: "CommandLineToolkit"), + .product(name: "Timer", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), + .product(name: "Types", package: "CommandLineToolkit"), "UniqueIdentifierGenerator", "WorkerCapabilities", ], path: "Sources/DistWorker" ), .target( - // MARK: DistWorkerModels name: "DistWorkerModels", dependencies: [ "LoggingSetup", @@ -507,7 +414,6 @@ let package = Package( path: "Sources/DistWorkerModels" ), .target( - // MARK: DistWorkerModelsTestHelpers name: "DistWorkerModelsTestHelpers", dependencies: [ "DistWorkerModels", @@ -517,7 +423,6 @@ let package = Package( path: "Tests/DistWorkerModelsTestHelpers" ), .testTarget( - // MARK: DistWorkerModelsTests name: "DistWorkerModelsTests", dependencies: [ "DistWorkerModels", @@ -526,7 +431,6 @@ let package = Package( path: "Tests/DistWorkerModelsTests" ), .testTarget( - // MARK: DistWorkerTests name: "DistWorkerTests", dependencies: [ "BuildArtifactsTestHelpers", @@ -541,7 +445,6 @@ let package = Package( path: "Tests/DistWorkerTests" ), .target( - // MARK: EmceeBinary name: "EmceeBinary", dependencies: [ "EmceeLib", @@ -549,18 +452,17 @@ let package = Package( path: "Sources/EmceeBinary" ), .target( - // MARK: EmceeLib name: "EmceeLib", dependencies: [ "AppleTools", "ArgLib", - "AtomicModels", + .product(name: "AtomicModels", package: "CommandLineToolkit"), "AutomaticTermination", "BucketQueue", "BuildArtifacts", "ChromeTracing", "DI", - "DateProvider", + .product(name: "DateProvider", package: "CommandLineToolkit"), "Deployer", "DeveloperDirLocator", "DeveloperDirModels", @@ -570,17 +472,17 @@ let package = Package( "EmceeVersion", "EventBus", "FileCache", - "FileSystem", + .product(name: "FileSystem", package: "CommandLineToolkit"), "JunitReporting", "LocalHostDeterminer", "LocalQueueServerRunner", "Logging", "LoggingSetup", - "Metrics", - "PathLib", + .product(name: "Metrics", package: "CommandLineToolkit"), + .product(name: "PathLib", package: "CommandLineToolkit"), "PluginManager", "PortDeterminer", - "ProcessController", + .product(name: "ProcessController", package: "CommandLineToolkit"), "QueueClient", "QueueCommunication", "QueueModels", @@ -594,17 +496,17 @@ let package = Package( "RunnerModels", "ScheduleStrategy", "Scheduler", - "SignalHandling", + .product(name: "SignalHandling", package: "CommandLineToolkit"), "SimulatorPool", "SimulatorPoolModels", - "SocketModels", - "Statsd", - "SynchronousWaiter", - "TemporaryStuff", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "Statsd", package: "CommandLineToolkit"), + .product(name: "SynchronousWaiter", package: "CommandLineToolkit"), "TestArgFile", "TestDiscovery", + .product(name: "Tmp", package: "CommandLineToolkit"), "TypedResourceLocation", - "Types", + .product(name: "Types", package: "CommandLineToolkit"), "URLResource", "UniqueIdentifierGenerator", "WorkerAlivenessProvider", @@ -615,21 +517,20 @@ let package = Package( path: "Sources/EmceeLib" ), .testTarget( - // MARK: EmceeLibTests name: "EmceeLibTests", dependencies: [ "AppleTools", - "AtomicModels", + .product(name: "AtomicModels", package: "CommandLineToolkit"), "BuildArtifacts", "BuildArtifactsTestHelpers", - "DateProviderTestHelpers", + .product(name: "DateProviderTestHelpers", package: "CommandLineToolkit"), "EmceeLib", - "FileSystem", - "FileSystemTestHelpers", + .product(name: "FileSystem", package: "CommandLineToolkit"), + .product(name: "FileSystemTestHelpers", package: "CommandLineToolkit"), "LoggingSetup", - "MetricsTestHelpers", - "PathLib", - "ProcessControllerTestHelpers", + .product(name: "MetricsTestHelpers", package: "CommandLineToolkit"), + .product(name: "PathLib", package: "CommandLineToolkit"), + .product(name: "ProcessControllerTestHelpers", package: "CommandLineToolkit"), "QueueModels", "QueueModelsTestHelpers", "ResourceLocationResolverTestHelpers", @@ -638,10 +539,10 @@ let package = Package( "SimulatorPool", "SimulatorPoolModels", "SimulatorPoolTestHelpers", - "TemporaryStuff", "TestArgFile", "TestDiscovery", - "TestHelpers", + .product(name: "TestHelpers", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), "URLResource", "UniqueIdentifierGeneratorTestHelpers", "fbxctest", @@ -649,7 +550,6 @@ let package = Package( path: "Tests/EmceeLibTests" ), .target( - // MARK: EmceeVersion name: "EmceeVersion", dependencies: [ "QueueModels", @@ -657,7 +557,6 @@ let package = Package( path: "Sources/EmceeVersion" ), .target( - // MARK: EventBus name: "EventBus", dependencies: [ "Logging", @@ -666,67 +565,60 @@ let package = Package( path: "Sources/EventBus" ), .testTarget( - // MARK: EventBusTests name: "EventBusTests", dependencies: [ "EventBus", - "SynchronousWaiter", + .product(name: "SynchronousWaiter", package: "CommandLineToolkit"), ], path: "Tests/EventBusTests" ), .target( - // MARK: Extensions name: "Extensions", dependencies: [ ], path: "Sources/Extensions" ), .testTarget( - // MARK: ExtensionsTests name: "ExtensionsTests", dependencies: [ "Extensions", - "TemporaryStuff", + .product(name: "Tmp", package: "CommandLineToolkit"), ], path: "Tests/ExtensionsTests" ), .target( - // MARK: FileCache name: "FileCache", dependencies: [ - "DateProvider", + .product(name: "DateProvider", package: "CommandLineToolkit"), "Extensions", "FileLock", - "FileSystem", - "PathLib", + .product(name: "FileSystem", package: "CommandLineToolkit"), + .product(name: "PathLib", package: "CommandLineToolkit"), "UniqueIdentifierGenerator", ], path: "Sources/FileCache" ), .testTarget( - // MARK: FileCacheTests name: "FileCacheTests", dependencies: [ - "DateProvider", + .product(name: "DateProvider", package: "CommandLineToolkit"), "FileCache", - "FileSystem", - "PathLib", - "TemporaryStuff", - "TestHelpers", + .product(name: "FileSystem", package: "CommandLineToolkit"), + .product(name: "PathLib", package: "CommandLineToolkit"), + .product(name: "TestHelpers", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), "UniqueIdentifierGenerator", "UniqueIdentifierGeneratorTestHelpers", ], path: "Tests/FileCacheTests" ), .target( - // MARK: FileLock name: "FileLock", dependencies: [ ], path: "Sources/FileLock" ), .testTarget( - // MARK: FileLockTests name: "FileLockTests", dependencies: [ "FileLock", @@ -734,56 +626,13 @@ let package = Package( path: "Tests/FileLockTests" ), .target( - // MARK: FileSystem - name: "FileSystem", - dependencies: [ - "PathLib", - ], - path: "Sources/FileSystem" - ), - .target( - // MARK: FileSystemTestHelpers - name: "FileSystemTestHelpers", - dependencies: [ - "FileSystem", - "PathLib", - ], - path: "Tests/FileSystemTestHelpers" - ), - .testTarget( - // MARK: FileSystemTests - name: "FileSystemTests", - dependencies: [ - "DateProvider", - "FileSystem", - "PathLib", - "TemporaryStuff", - "TestHelpers", - ], - path: "Tests/FileSystemTests" - ), - .target( - // MARK: Graphite - name: "Graphite", - dependencies: [ - "GraphiteClient", - "IO", - "Logging", - "MetricsUtils", - "SocketModels", - ], - path: "Sources/Graphite" - ), - .target( - // MARK: JSONStream name: "JSONStream", dependencies: [ - "AtomicModels", + .product(name: "AtomicModels", package: "CommandLineToolkit"), ], path: "Sources/JSONStream" ), .testTarget( - // MARK: JSONStreamTests name: "JSONStreamTests", dependencies: [ "JSONStream", @@ -791,14 +640,12 @@ let package = Package( path: "Tests/JSONStreamTests" ), .target( - // MARK: JunitReporting name: "JunitReporting", dependencies: [ ], path: "Sources/JunitReporting" ), .testTarget( - // MARK: JunitReportingTests name: "JunitReportingTests", dependencies: [ "Extensions", @@ -807,14 +654,12 @@ let package = Package( path: "Tests/JunitReportingTests" ), .target( - // MARK: LaunchdUtils name: "LaunchdUtils", dependencies: [ ], path: "Sources/LaunchdUtils" ), .testTarget( - // MARK: LaunchdUtilsTests name: "LaunchdUtilsTests", dependencies: [ "LaunchdUtils", @@ -822,14 +667,12 @@ let package = Package( path: "Tests/LaunchdUtilsTests" ), .target( - // MARK: ListeningSemaphore name: "ListeningSemaphore", dependencies: [ ], path: "Sources/ListeningSemaphore" ), .testTarget( - // MARK: ListeningSemaphoreTests name: "ListeningSemaphoreTests", dependencies: [ "ListeningSemaphore", @@ -837,7 +680,6 @@ let package = Package( path: "Tests/ListeningSemaphoreTests" ), .target( - // MARK: LocalHostDeterminer name: "LocalHostDeterminer", dependencies: [ "Logging", @@ -845,7 +687,6 @@ let package = Package( path: "Sources/LocalHostDeterminer" ), .target( - // MARK: LocalQueueServerRunner name: "LocalQueueServerRunner", dependencies: [ "AutomaticTermination", @@ -856,20 +697,19 @@ let package = Package( "LocalHostDeterminer", "Logging", "LoggingSetup", - "ProcessController", + .product(name: "ProcessController", package: "CommandLineToolkit"), "QueueCommunication", "QueueModels", "QueueServer", "RemotePortDeterminer", - "SocketModels", - "SynchronousWaiter", - "TemporaryStuff", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "SynchronousWaiter", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), "UniqueIdentifierGenerator", ], path: "Sources/LocalQueueServerRunner" ), .testTarget( - // MARK: LocalQueueServerRunnerTests name: "LocalQueueServerRunnerTests", dependencies: [ "AutomaticTermination", @@ -878,7 +718,7 @@ let package = Package( "DistDeployer", "LocalQueueServerRunner", "LoggingSetup", - "ProcessControllerTestHelpers", + .product(name: "ProcessControllerTestHelpers", package: "CommandLineToolkit"), "QueueCommunicationTestHelpers", "QueueModels", "QueueServer", @@ -887,213 +727,131 @@ let package = Package( "RemotePortDeterminerTestHelpers", "ScheduleStrategy", "Sentry", - "SocketModels", - "TemporaryStuff", - "TestHelpers", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "TestHelpers", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), "UniqueIdentifierGenerator", ], path: "Tests/LocalQueueServerRunnerTests" ), .target( - // MARK: Logging name: "Logging", dependencies: [ - "AtomicModels", + .product(name: "AtomicModels", package: "CommandLineToolkit"), "Extensions", ], path: "Sources/Logging" ), .target( - // MARK: LoggingSetup name: "LoggingSetup", dependencies: [ - "DateProvider", - "FileSystem", - "Graphite", + .product(name: "DateProvider", package: "CommandLineToolkit"), + .product(name: "FileSystem", package: "CommandLineToolkit"), + .product(name: "Graphite", package: "CommandLineToolkit"), "LocalHostDeterminer", "Logging", - "Metrics", - "PathLib", + .product(name: "Metrics", package: "CommandLineToolkit"), + .product(name: "PathLib", package: "CommandLineToolkit"), "QueueModels", "Sentry", - "SocketModels", - "Statsd", - "TemporaryStuff", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "Statsd", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), ], path: "Sources/LoggingSetup" ), .testTarget( - // MARK: LoggingTests name: "LoggingTests", dependencies: [ "Logging", - "TemporaryStuff", + .product(name: "Tmp", package: "CommandLineToolkit"), ], path: "Tests/LoggingTests" ), .target( - // MARK: Metrics - name: "Metrics", - dependencies: [ - "DateProvider", - "Graphite", - "Statsd", - ], - path: "Sources/Metrics" - ), - .target( - // MARK: MetricsTestHelpers - name: "MetricsTestHelpers", - dependencies: [ - "Graphite", - "Metrics", - "Statsd", - ], - path: "Tests/MetricsTestHelpers" - ), - .testTarget( - // MARK: MetricsTests - name: "MetricsTests", - dependencies: [ - "DateProviderTestHelpers", - "Graphite", - "Metrics", - "MetricsTestHelpers", - "Statsd", - "TestHelpers", - ], - path: "Tests/MetricsTests" - ), - .target( - // MARK: MetricsUtils - name: "MetricsUtils", - dependencies: [ - "IO", - "Logging", - ], - path: "Sources/MetricsUtils" - ), - .target( - // MARK: ObservableFileReader name: "ObservableFileReader", dependencies: [ - "PathLib", - "ProcessController", + .product(name: "PathLib", package: "CommandLineToolkit"), + .product(name: "ProcessController", package: "CommandLineToolkit"), ], path: "Sources/ObservableFileReader" ), .testTarget( - // MARK: ObservableFileReaderTests name: "ObservableFileReaderTests", dependencies: [ - "DateProvider", - "FileSystem", + .product(name: "DateProvider", package: "CommandLineToolkit"), + .product(name: "FileSystem", package: "CommandLineToolkit"), "ObservableFileReader", - "PathLib", - "ProcessController", - "ProcessControllerTestHelpers", - "TemporaryStuff", - "TestHelpers", + .product(name: "PathLib", package: "CommandLineToolkit"), + .product(name: "ProcessController", package: "CommandLineToolkit"), + .product(name: "ProcessControllerTestHelpers", package: "CommandLineToolkit"), + .product(name: "TestHelpers", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), ], path: "Tests/ObservableFileReaderTests" ), .target( - // MARK: PathLib - name: "PathLib", - dependencies: [ - ], - path: "Sources/PathLib" - ), - .testTarget( - // MARK: PathLibTests - name: "PathLibTests", - dependencies: [ - "PathLib", - ], - path: "Tests/PathLibTests" - ), - .target( - // MARK: PlistLib - name: "PlistLib", - dependencies: [ - ], - path: "Sources/PlistLib" - ), - .testTarget( - // MARK: PlistLibTests - name: "PlistLibTests", - dependencies: [ - "PlistLib", - "TestHelpers", - ], - path: "Tests/PlistLibTests" - ), - .target( - // MARK: Plugin name: "Plugin", dependencies: [ - "DateProvider", + .product(name: "DateProvider", package: "CommandLineToolkit"), "EventBus", - "FileSystem", + .product(name: "FileSystem", package: "CommandLineToolkit"), "JSONStream", "Logging", "LoggingSetup", "PluginSupport", - "Starscream", - "SynchronousWaiter", + .product(name: "Starscream", package: "Starscream"), + .product(name: "SynchronousWaiter", package: "CommandLineToolkit"), ], path: "Sources/Plugin" ), .target( - // MARK: PluginManager name: "PluginManager", dependencies: [ "EventBus", - "FileSystem", + .product(name: "FileSystem", package: "CommandLineToolkit"), "LocalHostDeterminer", "Logging", - "PathLib", + .product(name: "PathLib", package: "CommandLineToolkit"), "PluginSupport", - "ProcessController", + .product(name: "ProcessController", package: "CommandLineToolkit"), "ResourceLocationResolver", - "Swifter", - "SynchronousWaiter", + .product(name: "Swifter", package: "Swifter"), + .product(name: "SynchronousWaiter", package: "CommandLineToolkit"), ], path: "Sources/PluginManager" ), .target( - // MARK: PluginManagerTestHelpers name: "PluginManagerTestHelpers", dependencies: [ "EventBus", - "FileSystem", + .product(name: "FileSystem", package: "CommandLineToolkit"), "PluginManager", "PluginSupport", ], path: "Tests/PluginManagerTestHelpers" ), .testTarget( - // MARK: PluginManagerTests name: "PluginManagerTests", dependencies: [ - "DateProvider", + .product(name: "DateProvider", package: "CommandLineToolkit"), "EventBus", - "FileSystem", - "PathLib", + "Extensions", + .product(name: "FileSystem", package: "CommandLineToolkit"), + .product(name: "PathLib", package: "CommandLineToolkit"), "PluginManager", "PluginSupport", - "ProcessController", - "ProcessControllerTestHelpers", + .product(name: "ProcessController", package: "CommandLineToolkit"), + .product(name: "ProcessControllerTestHelpers", package: "CommandLineToolkit"), "ResourceLocation", "ResourceLocationResolverTestHelpers", "RunnerTestHelpers", - "TemporaryStuff", - "TestHelpers", + .product(name: "TestHelpers", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), ], path: "Tests/PluginManagerTests" ), .target( - // MARK: PluginSupport name: "PluginSupport", dependencies: [ "TypedResourceLocation", @@ -1101,85 +859,42 @@ let package = Package( path: "Sources/PluginSupport" ), .target( - // MARK: PortDeterminer name: "PortDeterminer", dependencies: [ "Logging", - "SocketModels", - "Swifter", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "Swifter", package: "Swifter"), ], path: "Sources/PortDeterminer" ), .testTarget( - // MARK: PortDeterminerTests name: "PortDeterminerTests", dependencies: [ "PortDeterminer", - "SocketModels", - "Swifter", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "Swifter", package: "Swifter"), ], path: "Tests/PortDeterminerTests" ), .target( - // MARK: ProcessController - name: "ProcessController", - dependencies: [ - "AtomicModels", - "DateProvider", - "FileSystem", - "Logging", - "LoggingSetup", - "PathLib", - "SignalHandling", - "Timer", - ], - path: "Sources/ProcessController" - ), - .target( - // MARK: ProcessControllerTestHelpers - name: "ProcessControllerTestHelpers", - dependencies: [ - "ProcessController", - "SynchronousWaiter", - "TemporaryStuff", - ], - path: "Tests/ProcessControllerTestHelpers" - ), - .testTarget( - // MARK: ProcessControllerTests - name: "ProcessControllerTests", - dependencies: [ - "DateProvider", - "FileSystem", - "PathLib", - "ProcessController", - "SignalHandling", - "TemporaryStuff", - "TestHelpers", - ], - path: "Tests/ProcessControllerTests" - ), - .target( - // MARK: QueueClient name: "QueueClient", dependencies: [ - "AtomicModels", + .product(name: "AtomicModels", package: "CommandLineToolkit"), "DistWorkerModels", "Logging", "QueueModels", "RESTMethods", "RequestSender", "ScheduleStrategy", - "SocketModels", - "SynchronousWaiter", - "Types", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "SynchronousWaiter", package: "CommandLineToolkit"), + .product(name: "Types", package: "CommandLineToolkit"), "WorkerAlivenessModels", "WorkerCapabilitiesModels", ], path: "Sources/QueueClient" ), .testTarget( - // MARK: QueueClientTests name: "QueueClientTests", dependencies: [ "DistWorkerModels", @@ -1190,44 +905,41 @@ let package = Package( "RESTMethods", "RequestSender", "RequestSenderTestHelpers", - "SocketModels", - "TestHelpers", - "Types", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "TestHelpers", package: "CommandLineToolkit"), + .product(name: "Types", package: "CommandLineToolkit"), "WorkerAlivenessModels", ], path: "Tests/QueueClientTests" ), .target( - // MARK: QueueCommunication name: "QueueCommunication", dependencies: [ - "AtomicModels", - "DateProvider", + .product(name: "AtomicModels", package: "CommandLineToolkit"), + .product(name: "DateProvider", package: "CommandLineToolkit"), "Deployer", - "Graphite", + .product(name: "Graphite", package: "CommandLineToolkit"), "LocalHostDeterminer", "Logging", - "Metrics", + .product(name: "Metrics", package: "CommandLineToolkit"), "QueueCommunicationModels", "QueueModels", "RESTMethods", "RemotePortDeterminer", "RequestSender", - "SocketModels", - "Timer", - "Types", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "Timer", package: "CommandLineToolkit"), + .product(name: "Types", package: "CommandLineToolkit"), ], path: "Sources/QueueCommunication" ), .target( - // MARK: QueueCommunicationModels name: "QueueCommunicationModels", dependencies: [ ], path: "Sources/QueueCommunicationModels" ), .target( - // MARK: QueueCommunicationTestHelpers name: "QueueCommunicationTestHelpers", dependencies: [ "Deployer", @@ -1235,23 +947,22 @@ let package = Package( "QueueCommunication", "QueueCommunicationModels", "QueueModels", - "SocketModels", - "TestHelpers", - "Types", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "TestHelpers", package: "CommandLineToolkit"), + .product(name: "Types", package: "CommandLineToolkit"), ], path: "Tests/QueueCommunicationTestHelpers" ), .testTarget( - // MARK: QueueCommunicationTests name: "QueueCommunicationTests", dependencies: [ - "DateProvider", - "DateProviderTestHelpers", + .product(name: "DateProvider", package: "CommandLineToolkit"), + .product(name: "DateProviderTestHelpers", package: "CommandLineToolkit"), "Deployer", "DeployerTestHelpers", - "Graphite", - "Metrics", - "MetricsTestHelpers", + .product(name: "Graphite", package: "CommandLineToolkit"), + .product(name: "Metrics", package: "CommandLineToolkit"), + .product(name: "MetricsTestHelpers", package: "CommandLineToolkit"), "QueueCommunication", "QueueCommunicationTestHelpers", "QueueModels", @@ -1259,13 +970,12 @@ let package = Package( "RemotePortDeterminer", "RemotePortDeterminerTestHelpers", "RequestSenderTestHelpers", - "SocketModels", - "TestHelpers", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "TestHelpers", package: "CommandLineToolkit"), ], path: "Tests/QueueCommunicationTests" ), .target( - // MARK: QueueModels name: "QueueModels", dependencies: [ "BuildArtifacts", @@ -1273,14 +983,13 @@ let package = Package( "PluginSupport", "RunnerModels", "SimulatorPoolModels", - "SocketModels", - "Types", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "Types", package: "CommandLineToolkit"), "WorkerCapabilitiesModels", ], path: "Sources/QueueModels" ), .target( - // MARK: QueueModelsTestHelpers name: "QueueModelsTestHelpers", dependencies: [ "BuildArtifacts", @@ -1292,13 +1001,12 @@ let package = Package( "RunnerTestHelpers", "SimulatorPoolModels", "SimulatorPoolTestHelpers", - "Types", + .product(name: "Types", package: "CommandLineToolkit"), "WorkerCapabilitiesModels", ], path: "Tests/QueueModelsTestHelpers" ), .testTarget( - // MARK: QueueModelsTests name: "QueueModelsTests", dependencies: [ "QueueModels", @@ -1309,22 +1017,21 @@ let package = Package( path: "Tests/QueueModelsTests" ), .target( - // MARK: QueueServer name: "QueueServer", dependencies: [ - "AtomicModels", + .product(name: "AtomicModels", package: "CommandLineToolkit"), "AutomaticTermination", "BalancingBucketQueue", "BucketQueue", "BucketQueueModels", - "DateProvider", + .product(name: "DateProvider", package: "CommandLineToolkit"), "Deployer", "DistWorkerModels", "EventBus", - "Graphite", + .product(name: "Graphite", package: "CommandLineToolkit"), "LocalHostDeterminer", "Logging", - "Metrics", + .product(name: "Metrics", package: "CommandLineToolkit"), "PortDeterminer", "QueueCommunication", "QueueModels", @@ -1334,14 +1041,14 @@ let package = Package( "RequestSender", "RunnerModels", "ScheduleStrategy", - "SocketModels", - "Statsd", - "Swifter", - "SynchronousWaiter", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "Statsd", package: "CommandLineToolkit"), + .product(name: "Swifter", package: "Swifter"), + .product(name: "SynchronousWaiter", package: "CommandLineToolkit"), "TestHistoryStorage", "TestHistoryTracker", - "Timer", - "Types", + .product(name: "Timer", package: "CommandLineToolkit"), + .product(name: "Types", package: "CommandLineToolkit"), "UniqueIdentifierGenerator", "WorkerAlivenessModels", "WorkerAlivenessProvider", @@ -1351,34 +1058,32 @@ let package = Package( path: "Sources/QueueServer" ), .target( - // MARK: QueueServerTestHelpers name: "QueueServerTestHelpers", dependencies: [ "QueueModels", "QueueServer", "ScheduleStrategy", - "SocketModels", + .product(name: "SocketModels", package: "CommandLineToolkit"), ], path: "Tests/QueueServerTestHelpers" ), .testTarget( - // MARK: QueueServerTests name: "QueueServerTests", dependencies: [ - "AtomicModels", + .product(name: "AtomicModels", package: "CommandLineToolkit"), "AutomaticTermination", "AutomaticTerminationTestHelpers", "BalancingBucketQueue", "BucketQueue", "BucketQueueModels", "BucketQueueTestHelpers", - "DateProviderTestHelpers", + .product(name: "DateProviderTestHelpers", package: "CommandLineToolkit"), "DeployerTestHelpers", "DistWorkerModels", "DistWorkerModelsTestHelpers", - "Graphite", - "Metrics", - "MetricsTestHelpers", + .product(name: "Graphite", package: "CommandLineToolkit"), + .product(name: "Metrics", package: "CommandLineToolkit"), + .product(name: "MetricsTestHelpers", package: "CommandLineToolkit"), "PortDeterminer", "QueueClient", "QueueCommunication", @@ -1395,11 +1100,11 @@ let package = Package( "RunnerTestHelpers", "ScheduleStrategy", "SimulatorPoolTestHelpers", - "SocketModels", - "Swifter", - "SynchronousWaiter", - "TestHelpers", - "Types", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "Swifter", package: "Swifter"), + .product(name: "SynchronousWaiter", package: "CommandLineToolkit"), + .product(name: "TestHelpers", package: "CommandLineToolkit"), + .product(name: "Types", package: "CommandLineToolkit"), "UniqueIdentifierGeneratorTestHelpers", "WorkerAlivenessModels", "WorkerAlivenessProvider", @@ -1409,7 +1114,6 @@ let package = Package( path: "Tests/QueueServerTests" ), .target( - // MARK: RESTInterfaces name: "RESTInterfaces", dependencies: [ "QueueModels", @@ -1417,7 +1121,6 @@ let package = Package( path: "Sources/RESTInterfaces" ), .target( - // MARK: RESTMethods name: "RESTMethods", dependencies: [ "Deployer", @@ -1426,14 +1129,13 @@ let package = Package( "RESTInterfaces", "RequestSender", "ScheduleStrategy", - "SocketModels", + .product(name: "SocketModels", package: "CommandLineToolkit"), "WorkerAlivenessModels", "WorkerCapabilitiesModels", ], path: "Sources/RESTMethods" ), .target( - // MARK: RESTServer name: "RESTServer", dependencies: [ "AutomaticTermination", @@ -1441,13 +1143,12 @@ let package = Package( "QueueModels", "RESTInterfaces", "RESTMethods", - "SocketModels", - "Swifter", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "Swifter", package: "Swifter"), ], path: "Sources/RESTServer" ), .testTarget( - // MARK: RESTServerTests name: "RESTServerTests", dependencies: [ "AutomaticTerminationTestHelpers", @@ -1455,39 +1156,36 @@ let package = Package( "RESTInterfaces", "RESTMethods", "RESTServer", - "SocketModels", - "Swifter", - "TestHelpers", - "Types", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "Swifter", package: "Swifter"), + .product(name: "TestHelpers", package: "CommandLineToolkit"), + .product(name: "Types", package: "CommandLineToolkit"), ], path: "Tests/RESTServerTests" ), .target( - // MARK: RemotePortDeterminer name: "RemotePortDeterminer", dependencies: [ - "AtomicModels", + .product(name: "AtomicModels", package: "CommandLineToolkit"), "Logging", "QueueClient", "QueueModels", "RequestSender", - "SocketModels", - "Types", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "Types", package: "CommandLineToolkit"), ], path: "Sources/RemotePortDeterminer" ), .target( - // MARK: RemotePortDeterminerTestHelpers name: "RemotePortDeterminerTestHelpers", dependencies: [ "QueueModels", "RemotePortDeterminer", - "SocketModels", + .product(name: "SocketModels", package: "CommandLineToolkit"), ], path: "Tests/RemotePortDeterminerTestHelpers" ), .testTarget( - // MARK: RemotePortDeterminerTests name: "RemotePortDeterminerTests", dependencies: [ "PortDeterminer", @@ -1497,115 +1195,106 @@ let package = Package( "RemotePortDeterminer", "RequestSender", "RequestSenderTestHelpers", - "SocketModels", - "Swifter", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "Swifter", package: "Swifter"), ], path: "Tests/RemotePortDeterminerTests" ), .target( - // MARK: RequestSender name: "RequestSender", dependencies: [ "Logging", - "SocketModels", - "Types", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "Types", package: "CommandLineToolkit"), ], path: "Sources/RequestSender" ), .target( - // MARK: RequestSenderTestHelpers name: "RequestSenderTestHelpers", dependencies: [ "RequestSender", - "SocketModels", - "Types", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "Types", package: "CommandLineToolkit"), ], path: "Tests/RequestSenderTestHelpers" ), .testTarget( - // MARK: RequestSenderTests name: "RequestSenderTests", dependencies: [ "RequestSender", "RequestSenderTestHelpers", - "SocketModels", - "Swifter", - "Types", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "Swifter", package: "Swifter"), + .product(name: "Types", package: "CommandLineToolkit"), ], path: "Tests/RequestSenderTests" ), .target( - // MARK: ResourceLocation name: "ResourceLocation", dependencies: [ - "PathLib", + .product(name: "PathLib", package: "CommandLineToolkit"), ], path: "Sources/ResourceLocation" ), .target( - // MARK: ResourceLocationResolver name: "ResourceLocationResolver", dependencies: [ - "AtomicModels", + .product(name: "AtomicModels", package: "CommandLineToolkit"), "FileCache", - "FileSystem", + .product(name: "FileSystem", package: "CommandLineToolkit"), "Logging", - "PathLib", - "ProcessController", + .product(name: "PathLib", package: "CommandLineToolkit"), + .product(name: "ProcessController", package: "CommandLineToolkit"), "ResourceLocation", - "SynchronousWaiter", + .product(name: "SynchronousWaiter", package: "CommandLineToolkit"), "TypedResourceLocation", "URLResource", ], path: "Sources/ResourceLocationResolver" ), .target( - // MARK: ResourceLocationResolverTestHelpers name: "ResourceLocationResolverTestHelpers", dependencies: [ - "PathLib", + .product(name: "PathLib", package: "CommandLineToolkit"), "ResourceLocation", "ResourceLocationResolver", ], path: "Tests/ResourceLocationResolverTestHelpers" ), .testTarget( - // MARK: ResourceLocationResolverTests name: "ResourceLocationResolverTests", dependencies: [ - "DateProvider", + .product(name: "DateProvider", package: "CommandLineToolkit"), "FileCache", - "FileSystem", + .product(name: "FileSystem", package: "CommandLineToolkit"), "Logging", - "PathLib", - "ProcessController", + .product(name: "PathLib", package: "CommandLineToolkit"), + .product(name: "ProcessController", package: "CommandLineToolkit"), "ResourceLocation", "ResourceLocationResolver", - "Swifter", - "SynchronousWaiter", - "TemporaryStuff", - "TestHelpers", + .product(name: "Swifter", package: "Swifter"), + .product(name: "SynchronousWaiter", package: "CommandLineToolkit"), + .product(name: "TestHelpers", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), "URLResource", ], path: "Tests/ResourceLocationResolverTests" ), .testTarget( - // MARK: ResourceLocationTests name: "ResourceLocationTests", dependencies: [ "ResourceLocation", - "TemporaryStuff", + .product(name: "Tmp", package: "CommandLineToolkit"), ], path: "Tests/ResourceLocationTests" ), .target( - // MARK: ResultStream name: "ResultStream", dependencies: [ - "DateProvider", + .product(name: "DateProvider", package: "CommandLineToolkit"), "JSONStream", "Logging", - "PathLib", + .product(name: "PathLib", package: "CommandLineToolkit"), "ResultStreamModels", "Runner", "RunnerModels", @@ -1613,7 +1302,6 @@ let package = Package( path: "Sources/ResultStream" ), .target( - // MARK: ResultStreamModels name: "ResultStreamModels", dependencies: [ "RunnerModels", @@ -1621,7 +1309,6 @@ let package = Package( path: "Sources/ResultStreamModels" ), .target( - // MARK: ResultStreamModelsTestHelpers name: "ResultStreamModelsTestHelpers", dependencies: [ "RunnerModels", @@ -1629,62 +1316,58 @@ let package = Package( path: "Tests/ResultStreamModelsTestHelpers" ), .testTarget( - // MARK: ResultStreamModelsTests name: "ResultStreamModelsTests", dependencies: [ "ResultStreamModels", "ResultStreamModelsTestHelpers", "RunnerModels", - "TestHelpers", + .product(name: "TestHelpers", package: "CommandLineToolkit"), ], path: "Tests/ResultStreamModelsTests" ), .testTarget( - // MARK: ResultStreamTests name: "ResultStreamTests", dependencies: [ - "DateProviderTestHelpers", + .product(name: "DateProviderTestHelpers", package: "CommandLineToolkit"), "ResultStream", "ResultStreamModels", "RunnerModels", "RunnerTestHelpers", - "SynchronousWaiter", - "TestHelpers", + .product(name: "SynchronousWaiter", package: "CommandLineToolkit"), + .product(name: "TestHelpers", package: "CommandLineToolkit"), ], path: "Tests/ResultStreamTests" ), .target( - // MARK: Runner name: "Runner", dependencies: [ - "AtomicModels", + .product(name: "AtomicModels", package: "CommandLineToolkit"), "BuildArtifacts", - "DateProvider", + .product(name: "DateProvider", package: "CommandLineToolkit"), "DeveloperDirLocator", "DeveloperDirModels", "EventBus", - "FileSystem", - "Graphite", + .product(name: "FileSystem", package: "CommandLineToolkit"), + .product(name: "Graphite", package: "CommandLineToolkit"), "LocalHostDeterminer", "Logging", - "Metrics", - "PathLib", + .product(name: "Metrics", package: "CommandLineToolkit"), + .product(name: "PathLib", package: "CommandLineToolkit"), "PluginManager", - "ProcessController", + .product(name: "ProcessController", package: "CommandLineToolkit"), "QueueModels", "ResourceLocationResolver", "RunnerModels", "SimulatorPoolModels", - "Statsd", - "SynchronousWaiter", - "TemporaryStuff", + .product(name: "Statsd", package: "CommandLineToolkit"), + .product(name: "SynchronousWaiter", package: "CommandLineToolkit"), "TestsWorkingDirectorySupport", - "Timer", + .product(name: "Timer", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), ], path: "Sources/Runner" ), .target( - // MARK: RunnerModels name: "RunnerModels", dependencies: [ "BuildArtifacts", @@ -1696,40 +1379,37 @@ let package = Package( path: "Sources/RunnerModels" ), .target( - // MARK: RunnerTestHelpers name: "RunnerTestHelpers", dependencies: [ "BuildArtifacts", "DeveloperDirLocator", "DeveloperDirModels", "Logging", - "ProcessController", + .product(name: "ProcessController", package: "CommandLineToolkit"), "Runner", "RunnerModels", "SimulatorPoolModels", "SimulatorPoolTestHelpers", - "TemporaryStuff", + .product(name: "Tmp", package: "CommandLineToolkit"), ], path: "Tests/RunnerTestHelpers" ), .testTarget( - // MARK: RunnerTests name: "RunnerTests", dependencies: [ "BuildArtifacts", "BuildArtifactsTestHelpers", - "DateProviderTestHelpers", + .product(name: "DateProviderTestHelpers", package: "CommandLineToolkit"), "DeveloperDirLocatorTestHelpers", "EventBus", - "FileSystemTestHelpers", - "Graphite", + .product(name: "FileSystemTestHelpers", package: "CommandLineToolkit"), + .product(name: "Graphite", package: "CommandLineToolkit"), "Logging", - "Metrics", - "MetricsTestHelpers", - "PathLib", + .product(name: "Metrics", package: "CommandLineToolkit"), + .product(name: "MetricsTestHelpers", package: "CommandLineToolkit"), "PluginManagerTestHelpers", - "ProcessController", - "ProcessControllerTestHelpers", + .product(name: "ProcessController", package: "CommandLineToolkit"), + .product(name: "ProcessControllerTestHelpers", package: "CommandLineToolkit"), "QueueModels", "ResourceLocationResolverTestHelpers", "Runner", @@ -1737,42 +1417,39 @@ let package = Package( "RunnerTestHelpers", "SimulatorPoolModels", "SimulatorPoolTestHelpers", - "SynchronousWaiter", - "TemporaryStuff", - "TestHelpers", + .product(name: "SynchronousWaiter", package: "CommandLineToolkit"), + .product(name: "TestHelpers", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), ], path: "Tests/RunnerTests" ), .target( - // MARK: SSHDeployer name: "SSHDeployer", dependencies: [ "Deployer", "Logging", - "PathLib", - "ProcessController", - "Shout", - "TemporaryStuff", + .product(name: "PathLib", package: "CommandLineToolkit"), + .product(name: "ProcessController", package: "CommandLineToolkit"), + .product(name: "Shout", package: "Shout"), + .product(name: "Tmp", package: "CommandLineToolkit"), "UniqueIdentifierGenerator", ], path: "Sources/SSHDeployer" ), .testTarget( - // MARK: SSHDeployerTests name: "SSHDeployerTests", dependencies: [ "Deployer", - "PathLib", - "ProcessControllerTestHelpers", + .product(name: "PathLib", package: "CommandLineToolkit"), + .product(name: "ProcessControllerTestHelpers", package: "CommandLineToolkit"), "SSHDeployer", - "TemporaryStuff", - "TestHelpers", + .product(name: "TestHelpers", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), "UniqueIdentifierGeneratorTestHelpers", ], path: "Tests/SSHDeployerTests" ), .target( - // MARK: ScheduleStrategy name: "ScheduleStrategy", dependencies: [ "BuildArtifacts", @@ -1782,14 +1459,13 @@ let package = Package( "QueueModels", "RunnerModels", "SimulatorPoolModels", - "Types", + .product(name: "Types", package: "CommandLineToolkit"), "UniqueIdentifierGenerator", "WorkerCapabilitiesModels", ], path: "Sources/ScheduleStrategy" ), .testTarget( - // MARK: ScheduleStrategyTests name: "ScheduleStrategyTests", dependencies: [ "BuildArtifacts", @@ -1802,29 +1478,28 @@ let package = Package( "ScheduleStrategy", "SimulatorPoolModels", "SimulatorPoolTestHelpers", - "TestHelpers", + .product(name: "TestHelpers", package: "CommandLineToolkit"), "UniqueIdentifierGenerator", "UniqueIdentifierGeneratorTestHelpers", ], path: "Tests/ScheduleStrategyTests" ), .target( - // MARK: Scheduler name: "Scheduler", dependencies: [ "BuildArtifacts", "DI", - "DateProvider", + .product(name: "DateProvider", package: "CommandLineToolkit"), "DeveloperDirLocator", "DeveloperDirModels", - "FileSystem", + .product(name: "FileSystem", package: "CommandLineToolkit"), "ListeningSemaphore", "LocalHostDeterminer", "Logging", - "Metrics", + .product(name: "Metrics", package: "CommandLineToolkit"), "PluginManager", "PluginSupport", - "ProcessController", + .product(name: "ProcessController", package: "CommandLineToolkit"), "QueueModels", "ResourceLocationResolver", "Runner", @@ -1832,21 +1507,19 @@ let package = Package( "ScheduleStrategy", "SimulatorPool", "SimulatorPoolModels", - "SynchronousWaiter", - "TemporaryStuff", + .product(name: "SynchronousWaiter", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), "UniqueIdentifierGenerator", ], path: "Sources/Scheduler" ), .target( - // MARK: Sentry name: "Sentry", dependencies: [ ], path: "Sources/Sentry" ), .testTarget( - // MARK: SentryTests name: "SentryTests", dependencies: [ "Sentry", @@ -1854,187 +1527,99 @@ let package = Package( path: "Tests/SentryTests" ), .target( - // MARK: SignalHandling - name: "SignalHandling", - dependencies: [ - "Signals", - "Types", - ], - path: "Sources/SignalHandling" - ), - .testTarget( - // MARK: SignalHandlingTests - name: "SignalHandlingTests", - dependencies: [ - "SignalHandling", - "Signals", - ], - path: "Tests/SignalHandlingTests" - ), - .target( - // MARK: SimulatorPool name: "SimulatorPool", dependencies: [ - "AtomicModels", + .product(name: "AtomicModels", package: "CommandLineToolkit"), "AutomaticTermination", - "DateProvider", + .product(name: "DateProvider", package: "CommandLineToolkit"), "DeveloperDirLocator", "DeveloperDirModels", - "Graphite", + .product(name: "Graphite", package: "CommandLineToolkit"), "LocalHostDeterminer", "Logging", - "Metrics", - "PathLib", - "PlistLib", - "ProcessController", + .product(name: "Metrics", package: "CommandLineToolkit"), + .product(name: "PathLib", package: "CommandLineToolkit"), + .product(name: "PlistLib", package: "CommandLineToolkit"), + .product(name: "ProcessController", package: "CommandLineToolkit"), "QueueModels", "ResourceLocationResolver", "RunnerModels", "SimulatorPoolModels", - "SynchronousWaiter", - "TemporaryStuff", - "Types", + .product(name: "SynchronousWaiter", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), + .product(name: "Types", package: "CommandLineToolkit"), "UniqueIdentifierGenerator", ], path: "Sources/SimulatorPool" ), .target( - // MARK: SimulatorPoolModels name: "SimulatorPoolModels", dependencies: [ - "PathLib", + .product(name: "PathLib", package: "CommandLineToolkit"), "ResourceLocation", "TypedResourceLocation", - "Types", + .product(name: "Types", package: "CommandLineToolkit"), ], path: "Sources/SimulatorPoolModels" ), .target( - // MARK: SimulatorPoolTestHelpers name: "SimulatorPoolTestHelpers", dependencies: [ "DeveloperDirLocator", "DeveloperDirLocatorTestHelpers", "DeveloperDirModels", - "PathLib", + .product(name: "PathLib", package: "CommandLineToolkit"), "RunnerModels", "SimulatorPool", "SimulatorPoolModels", - "TemporaryStuff", - "Types", + .product(name: "Tmp", package: "CommandLineToolkit"), + .product(name: "Types", package: "CommandLineToolkit"), ], path: "Tests/SimulatorPoolTestHelpers" ), .testTarget( - // MARK: SimulatorPoolTests name: "SimulatorPoolTests", dependencies: [ - "DateProviderTestHelpers", + .product(name: "DateProviderTestHelpers", package: "CommandLineToolkit"), "DeveloperDirLocator", "DeveloperDirLocatorTestHelpers", "DeveloperDirModels", - "MetricsTestHelpers", - "PathLib", - "PlistLib", - "ProcessController", - "ProcessControllerTestHelpers", + .product(name: "MetricsTestHelpers", package: "CommandLineToolkit"), + .product(name: "PathLib", package: "CommandLineToolkit"), + .product(name: "PlistLib", package: "CommandLineToolkit"), + .product(name: "ProcessController", package: "CommandLineToolkit"), + .product(name: "ProcessControllerTestHelpers", package: "CommandLineToolkit"), "QueueModels", "ResourceLocationResolver", "SimulatorPool", "SimulatorPoolModels", "SimulatorPoolTestHelpers", - "SynchronousWaiter", - "TemporaryStuff", - "TestHelpers", + .product(name: "SynchronousWaiter", package: "CommandLineToolkit"), + .product(name: "TestHelpers", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), "UniqueIdentifierGenerator", "UniqueIdentifierGeneratorTestHelpers", ], path: "Tests/SimulatorPoolTests" ), .target( - // MARK: SimulatorVideoRecorder name: "SimulatorVideoRecorder", dependencies: [ "Logging", - "PathLib", - "ProcessController", + .product(name: "PathLib", package: "CommandLineToolkit"), + .product(name: "ProcessController", package: "CommandLineToolkit"), "SimulatorPoolModels", ], path: "Sources/SimulatorVideoRecorder" ), - .target( - // MARK: SocketModels - name: "SocketModels", - dependencies: [ - "Types", - ], - path: "Sources/SocketModels" - ), .testTarget( - // MARK: SocketModelsTests name: "SocketModelsTests", dependencies: [ - "SocketModels", + .product(name: "SocketModels", package: "CommandLineToolkit"), ], path: "Tests/SocketModelsTests" ), .target( - // MARK: Statsd - name: "Statsd", - dependencies: [ - "IO", - "Logging", - "MetricsUtils", - "SocketModels", - ], - path: "Sources/Statsd" - ), - .testTarget( - // MARK: StatsdTests - name: "StatsdTests", - dependencies: [ - "Metrics", - "Statsd", - ], - path: "Tests/StatsdTests" - ), - .target( - // MARK: SynchronousWaiter - name: "SynchronousWaiter", - dependencies: [ - "AtomicModels", - "Logging", - ], - path: "Sources/SynchronousWaiter" - ), - .testTarget( - // MARK: SynchronousWaiterTests - name: "SynchronousWaiterTests", - dependencies: [ - "SynchronousWaiter", - "TestHelpers", - ], - path: "Tests/SynchronousWaiterTests" - ), - .target( - // MARK: TemporaryStuff - name: "TemporaryStuff", - dependencies: [ - "PathLib", - ], - path: "Sources/TemporaryStuff" - ), - .testTarget( - // MARK: TemporaryStuffTests - name: "TemporaryStuffTests", - dependencies: [ - "PathLib", - "TemporaryStuff", - ], - path: "Tests/TemporaryStuffTests" - ), - .target( - // MARK: TestArgFile name: "TestArgFile", dependencies: [ "BuildArtifacts", @@ -2050,7 +1635,6 @@ let package = Package( path: "Sources/TestArgFile" ), .testTarget( - // MARK: TestArgFileTests name: "TestArgFileTests", dependencies: [ "BuildArtifacts", @@ -2064,31 +1648,30 @@ let package = Package( "Sentry", "SimulatorPoolModels", "SimulatorPoolTestHelpers", - "SocketModels", + .product(name: "SocketModels", package: "CommandLineToolkit"), "TestArgFile", - "TestHelpers", + .product(name: "TestHelpers", package: "CommandLineToolkit"), ], path: "Tests/TestArgFileTests" ), .target( - // MARK: TestDiscovery name: "TestDiscovery", dependencies: [ "AppleTools", - "AtomicModels", + .product(name: "AtomicModels", package: "CommandLineToolkit"), "BuildArtifacts", - "DateProvider", + .product(name: "DateProvider", package: "CommandLineToolkit"), "DeveloperDirLocator", "DeveloperDirModels", - "FileSystem", - "Graphite", + .product(name: "FileSystem", package: "CommandLineToolkit"), + .product(name: "Graphite", package: "CommandLineToolkit"), "LocalHostDeterminer", "Logging", - "Metrics", - "PathLib", + .product(name: "Metrics", package: "CommandLineToolkit"), + .product(name: "PathLib", package: "CommandLineToolkit"), "PluginManager", "PluginSupport", - "ProcessController", + .product(name: "ProcessController", package: "CommandLineToolkit"), "QueueModels", "RequestSender", "ResourceLocationResolver", @@ -2096,37 +1679,36 @@ let package = Package( "RunnerModels", "SimulatorPool", "SimulatorPoolModels", - "SocketModels", - "Statsd", - "SynchronousWaiter", - "TemporaryStuff", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "Statsd", package: "CommandLineToolkit"), + .product(name: "SynchronousWaiter", package: "CommandLineToolkit"), "TestArgFile", - "Types", + .product(name: "Tmp", package: "CommandLineToolkit"), + .product(name: "Types", package: "CommandLineToolkit"), "UniqueIdentifierGenerator", ], path: "Sources/TestDiscovery" ), .testTarget( - // MARK: TestDiscoveryTests name: "TestDiscoveryTests", dependencies: [ "AppleTools", "BuildArtifacts", "BuildArtifactsTestHelpers", - "DateProvider", - "DateProviderTestHelpers", + .product(name: "DateProvider", package: "CommandLineToolkit"), + .product(name: "DateProviderTestHelpers", package: "CommandLineToolkit"), "DeveloperDirLocator", "DeveloperDirLocatorTestHelpers", "DeveloperDirModels", "FileCache", - "FileSystem", - "FileSystemTestHelpers", + .product(name: "FileSystem", package: "CommandLineToolkit"), + .product(name: "FileSystemTestHelpers", package: "CommandLineToolkit"), "Logging", - "MetricsTestHelpers", - "PathLib", + .product(name: "MetricsTestHelpers", package: "CommandLineToolkit"), + .product(name: "PathLib", package: "CommandLineToolkit"), "PluginManagerTestHelpers", - "ProcessController", - "ProcessControllerTestHelpers", + .product(name: "ProcessController", package: "CommandLineToolkit"), + .product(name: "ProcessControllerTestHelpers", package: "CommandLineToolkit"), "QueueModels", "RequestSender", "RequestSenderTestHelpers", @@ -2136,12 +1718,12 @@ let package = Package( "RunnerModels", "RunnerTestHelpers", "SimulatorPoolTestHelpers", - "SocketModels", - "SynchronousWaiter", - "TemporaryStuff", + .product(name: "SocketModels", package: "CommandLineToolkit"), + .product(name: "SynchronousWaiter", package: "CommandLineToolkit"), "TestArgFile", "TestDiscovery", - "TestHelpers", + .product(name: "TestHelpers", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), "URLResource", "UniqueIdentifierGenerator", "UniqueIdentifierGeneratorTestHelpers", @@ -2149,14 +1731,6 @@ let package = Package( path: "Tests/TestDiscoveryTests" ), .target( - // MARK: TestHelpers - name: "TestHelpers", - dependencies: [ - ], - path: "Tests/TestHelpers" - ), - .target( - // MARK: TestHistoryModels name: "TestHistoryModels", dependencies: [ "BuildArtifacts", @@ -2166,7 +1740,6 @@ let package = Package( path: "Sources/TestHistoryModels" ), .target( - // MARK: TestHistoryStorage name: "TestHistoryStorage", dependencies: [ "QueueModels", @@ -2176,7 +1749,6 @@ let package = Package( path: "Sources/TestHistoryStorage" ), .target( - // MARK: TestHistoryTestHelpers name: "TestHistoryTestHelpers", dependencies: [ "BucketQueue", @@ -2194,7 +1766,6 @@ let package = Package( path: "Tests/TestHistoryTestHelpers" ), .target( - // MARK: TestHistoryTracker name: "TestHistoryTracker", dependencies: [ "BucketQueueModels", @@ -2207,7 +1778,6 @@ let package = Package( path: "Sources/TestHistoryTracker" ), .testTarget( - // MARK: TestHistoryTrackerTests name: "TestHistoryTrackerTests", dependencies: [ "BucketQueue", @@ -2224,7 +1794,6 @@ let package = Package( path: "Tests/TestHistoryTrackerTests" ), .target( - // MARK: TestingFakeFbxctest name: "TestingFakeFbxctest", dependencies: [ "Extensions", @@ -2232,12 +1801,11 @@ let package = Package( path: "Sources/TestingFakeFbxctest" ), .target( - // MARK: TestingPlugin name: "TestingPlugin", dependencies: [ - "DateProvider", + .product(name: "DateProvider", package: "CommandLineToolkit"), "EventBus", - "FileSystem", + .product(name: "FileSystem", package: "CommandLineToolkit"), "Logging", "LoggingSetup", "Plugin", @@ -2245,23 +1813,14 @@ let package = Package( path: "Sources/TestingPlugin" ), .target( - // MARK: TestsWorkingDirectorySupport name: "TestsWorkingDirectorySupport", dependencies: [ - "PathLib", + .product(name: "PathLib", package: "CommandLineToolkit"), "RunnerModels", ], path: "Sources/TestsWorkingDirectorySupport" ), .target( - // MARK: Timer - name: "Timer", - dependencies: [ - ], - path: "Sources/Timer" - ), - .target( - // MARK: TypedResourceLocation name: "TypedResourceLocation", dependencies: [ "ResourceLocation", @@ -2269,58 +1828,39 @@ let package = Package( path: "Sources/TypedResourceLocation" ), .target( - // MARK: Types - name: "Types", - dependencies: [ - ], - path: "Sources/Types" - ), - .testTarget( - // MARK: TypesTests - name: "TypesTests", - dependencies: [ - "Types", - ], - path: "Tests/TypesTests" - ), - .target( - // MARK: URLResource name: "URLResource", dependencies: [ - "AtomicModels", + .product(name: "AtomicModels", package: "CommandLineToolkit"), "FileCache", "Logging", - "PathLib", - "SynchronousWaiter", - "Types", + .product(name: "PathLib", package: "CommandLineToolkit"), + .product(name: "SynchronousWaiter", package: "CommandLineToolkit"), + .product(name: "Types", package: "CommandLineToolkit"), ], path: "Sources/URLResource" ), .testTarget( - // MARK: URLResourceTests name: "URLResourceTests", dependencies: [ - "DateProviderTestHelpers", + .product(name: "DateProviderTestHelpers", package: "CommandLineToolkit"), "FileCache", - "FileSystem", - "PathLib", - "Swifter", - "SynchronousWaiter", - "TemporaryStuff", - "TestHelpers", + .product(name: "FileSystem", package: "CommandLineToolkit"), + .product(name: "PathLib", package: "CommandLineToolkit"), + .product(name: "Swifter", package: "Swifter"), + .product(name: "SynchronousWaiter", package: "CommandLineToolkit"), + .product(name: "TestHelpers", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), "URLResource", ], path: "Tests/URLResourceTests" ), .target( - // MARK: UniqueIdentifierGenerator name: "UniqueIdentifierGenerator", dependencies: [ ], path: "Sources/UniqueIdentifierGenerator" ), .target( - // MARK: UniqueIdentifierGeneratorTestHelpers name: "UniqueIdentifierGeneratorTestHelpers", dependencies: [ "UniqueIdentifierGenerator", @@ -2328,7 +1868,6 @@ let package = Package( path: "Tests/UniqueIdentifierGeneratorTestHelpers" ), .target( - // MARK: WorkerAlivenessModels name: "WorkerAlivenessModels", dependencies: [ "QueueCommunicationModels", @@ -2337,7 +1876,6 @@ let package = Package( path: "Sources/WorkerAlivenessModels" ), .target( - // MARK: WorkerAlivenessProvider name: "WorkerAlivenessProvider", dependencies: [ "Logging", @@ -2349,7 +1887,6 @@ let package = Package( path: "Sources/WorkerAlivenessProvider" ), .testTarget( - // MARK: WorkerAlivenessProviderTests name: "WorkerAlivenessProviderTests", dependencies: [ "QueueCommunicationTestHelpers", @@ -2360,88 +1897,82 @@ let package = Package( path: "Tests/WorkerAlivenessProviderTests" ), .target( - // MARK: WorkerCapabilities name: "WorkerCapabilities", dependencies: [ - "AtomicModels", - "FileSystem", + .product(name: "AtomicModels", package: "CommandLineToolkit"), + .product(name: "FileSystem", package: "CommandLineToolkit"), "Logging", - "PathLib", - "PlistLib", + .product(name: "PathLib", package: "CommandLineToolkit"), + .product(name: "PlistLib", package: "CommandLineToolkit"), "QueueModels", - "Types", + .product(name: "Types", package: "CommandLineToolkit"), "WorkerCapabilitiesModels", ], path: "Sources/WorkerCapabilities" ), .target( - // MARK: WorkerCapabilitiesModels name: "WorkerCapabilitiesModels", dependencies: [ - "Types", + .product(name: "Types", package: "CommandLineToolkit"), ], path: "Sources/WorkerCapabilitiesModels" ), .testTarget( - // MARK: WorkerCapabilitiesTests name: "WorkerCapabilitiesTests", dependencies: [ - "FileSystem", - "FileSystemTestHelpers", - "PlistLib", - "TemporaryStuff", - "TestHelpers", + .product(name: "FileSystem", package: "CommandLineToolkit"), + .product(name: "FileSystemTestHelpers", package: "CommandLineToolkit"), + .product(name: "PlistLib", package: "CommandLineToolkit"), + .product(name: "TestHelpers", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), "WorkerCapabilities", "WorkerCapabilitiesModels", ], path: "Tests/WorkerCapabilitiesTests" ), .target( - // MARK: XCTestJsonCodable name: "XCTestJsonCodable", dependencies: [ ], path: "Sources/XCTestJsonCodable" ), .target( - // MARK: fbxctest name: "fbxctest", dependencies: [ - "AtomicModels", + .product(name: "AtomicModels", package: "CommandLineToolkit"), "BuildArtifacts", "DeveloperDirLocator", "JSONStream", "LocalHostDeterminer", "Logging", - "PathLib", - "ProcessController", + .product(name: "PathLib", package: "CommandLineToolkit"), + .product(name: "ProcessController", package: "CommandLineToolkit"), "ResourceLocation", "ResourceLocationResolver", "Runner", "RunnerModels", "SimulatorPool", "SimulatorPoolModels", - "TemporaryStuff", - "Timer", + .product(name: "Timer", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), ], path: "Sources/fbxctest" ), .testTarget( - // MARK: fbxctestTests name: "fbxctestTests", dependencies: [ "BuildArtifactsTestHelpers", "DeveloperDirLocatorTestHelpers", "JSONStream", - "ProcessController", - "ProcessControllerTestHelpers", + .product(name: "ProcessController", package: "CommandLineToolkit"), + .product(name: "ProcessControllerTestHelpers", package: "CommandLineToolkit"), "ResourceLocationResolverTestHelpers", "Runner", "RunnerModels", "RunnerTestHelpers", "SimulatorPoolTestHelpers", - "TemporaryStuff", - "TestHelpers", + .product(name: "TestHelpers", package: "CommandLineToolkit"), + .product(name: "Tmp", package: "CommandLineToolkit"), "fbxctest", ], path: "Tests/fbxctestTests" diff --git a/Package.swift.template b/Package.swift.template deleted file mode 100644 index f81f46e7..00000000 --- a/Package.swift.template +++ /dev/null @@ -1,75 +0,0 @@ -// swift-tools-version:5.0 - -import PackageDescription - -let package = Package( - name: "EmceeTestRunner", - platforms: [ - .macOS(.v10_14), - ], - products: [ - .executable( - name: "Emcee", - targets: [ - "EmceeBinary", - ] - ), - .library( - name: "EmceePlugin", - targets: [ - "Logging", - "Plugin", - ] - ), - .library( - name: "EmceeCommunications", - targets: [ - "PortDeterminer", - "QueueClient", - "QueueCommunication", - "RemotePortDeterminer", - "RequestSender", - ] - ), - .library( - name: "EmceeInterfaces", - targets: [ - "BuildArtifacts", - "DeveloperDirModels", - "EmceeVersion", - "FileSystem", - "PathLib", - "PluginSupport", - "QueueModels", - "ResourceLocation", - "ResourceLocationResolver", - "RunnerModels", - "SimulatorPoolModels", - "SimulatorVideoRecorder", - "SocketModels", - "TestArgFile", - "TestDiscovery", - "TestsWorkingDirectorySupport", - "TypedResourceLocation", - "WorkerAlivenessModels", - "WorkerCapabilitiesModels", - ] - ), - .executable( - name: "testing_plugin", - targets: ["TestingPlugin"] - ) - ], - dependencies: [ - .package(url: "https://github.com/0x7fs/CountedSet", .branch("master")), - .package(url: "https://github.com/IBM-Swift/BlueSignals.git", .exact("1.0.16")), - .package(url: "https://github.com/Weebly/OrderedSet", .exact("5.0.0")), - .package(url: "https://github.com/avito-tech/GraphiteClient.git", .exact("0.1.1")), - .package(url: "https://github.com/daltoniam/Starscream.git", .exact("3.0.6")), - .package(url: "https://github.com/httpswift/swifter.git", .exact("1.4.6")), - .package(url: "https://github.com/jakeheis/Shout.git", .exact("0.5.4")), - ], - targets: [ -<__TARGETS__> - ] -) diff --git a/PackageGenerator.swift b/PackageGenerator.swift deleted file mode 100644 index 7a11dcb6..00000000 --- a/PackageGenerator.swift +++ /dev/null @@ -1,139 +0,0 @@ -import Foundation - -func log(_ text: String) { - if ProcessInfo.processInfo.environment["DEBUG"] != nil { - print(text) - } -} - -let knownImportsToIgnore = [ - "CSSH", - "Darwin", - "Dispatch", - "Foundation", - "XCTest", - "Network", -] - -let jsonEncoder = JSONEncoder() -jsonEncoder.outputFormatting = [.prettyPrinted, .sortedKeys] - -let importStatementExpression = try NSRegularExpression( - pattern: "^(@testable )?import (.*)$", - options: [.anchorsMatchLines] -) - -struct ModuleDescription { - let name: String - let deps: [String] - let path: String - let isTest: Bool -} - -func generate(at url: URL, isTestTarget: Bool) throws -> [ModuleDescription] { - guard let enumerator = FileManager().enumerator( - at: url, - includingPropertiesForKeys: nil, - options: [.skipsSubdirectoryDescendants, .skipsHiddenFiles] - ) else { - print("Failed to create file enumerator for url '\(url)'") - return [] - } - - var result = [ModuleDescription]() - - while let moduleFolderUrl = enumerator.nextObject() as? URL { - let moduleEnumerator = FileManager().enumerator( - at: moduleFolderUrl, - includingPropertiesForKeys: [.isRegularFileKey], - options: [.skipsHiddenFiles] - ) - let moduleName = moduleFolderUrl.lastPathComponent - log("Analyzing \(moduleName)") - - var importedModuleNames = Set() - - while let moduleFile = moduleEnumerator?.nextObject() as? URL { - if ["md"].contains(moduleFile.pathExtension) { - continue - } - log(" Analyzing \(moduleFile.lastPathComponent)") - guard try moduleFile.resourceValues(forKeys: [.isRegularFileKey]).isRegularFile == true else { - log(" Skipping \(moduleFile.lastPathComponent): is not regular file") - continue - } - let fileContents = try String(contentsOf: moduleFile) - .split(separator: "\n") - .filter { !$0.starts(with: "//") } - for line in fileContents { - let matches = importStatementExpression.matches(in: String(line), options: [], range: NSMakeRange(0, line.count)) - guard matches.count == 1 else { - continue - } - - let importedModuleName = (line as NSString).substring(with: matches[0].range(at: 2)) - importedModuleNames.insert(importedModuleName) - } - } - - let path = moduleFolderUrl.path.dropFirst(moduleFolderUrl.deletingLastPathComponent().deletingLastPathComponent().path.count + 1) - let dependencies = importedModuleNames.filter { !knownImportsToIgnore.contains($0) }.sorted() - - let isTestHelper = moduleFolderUrl.path.hasSuffix("TestHelpers") - - result.append( - ModuleDescription(name: moduleName, deps: dependencies, path: String(path), isTest: isTestTarget && !isTestHelper) - ) - } - - return result -} - -func generatePackageSwift(raplacementForTargets: [String]) throws { - log("Loading template") - var templateContents = try String(contentsOf: URL(fileURLWithPath: "Package.swift.template")) - templateContents = templateContents.replacingOccurrences( - of: "<__TARGETS__>", - with: raplacementForTargets.map { " \($0)" }.joined(separator: "\n") - ) - - if ProcessInfo.processInfo.environment["ON_CI"] != nil { - log("Checking for Package.swift consistency") - let existingContents = try String(contentsOf: URL(fileURLWithPath: "Package.swift")) - if existingContents != templateContents { - print("\(#file):\(#line): ON_CI is set, and Package.swift differs. Please update and commit Package.swift!") - exit(1) - } - } - - log("Saving Package.swift") - try templateContents.write(to: URL(fileURLWithPath: "Package.swift"), atomically: true, encoding: .utf8) -} - -func main() throws { - var moduleDescriptions = [ModuleDescription]() - moduleDescriptions.append( - contentsOf: try generate(at: URL(fileURLWithPath: "Sources"), isTestTarget: false) - ) - moduleDescriptions.append( - contentsOf: try generate(at: URL(fileURLWithPath: "Tests"), isTestTarget: true) - ) - - var generatedTargetStatements = [String]() - let sortedModuleDescriptions: [ModuleDescription] = moduleDescriptions.sorted { $0.name < $1.name } - for moduleDescription in sortedModuleDescriptions { - generatedTargetStatements.append(".\(!moduleDescription.isTest ? "target" : "testTarget")(") - generatedTargetStatements.append(" // MARK: \(moduleDescription.name)") - generatedTargetStatements.append(" name: " + "\"\(moduleDescription.name)\"" + ",") - generatedTargetStatements.append(" dependencies: [") - for dependency in moduleDescription.deps { - generatedTargetStatements.append(" \"\(dependency)\",") - } - generatedTargetStatements.append(" ],") - generatedTargetStatements.append(" path: " + "\"" + moduleDescription.path + "\"") - generatedTargetStatements.append("),") - } - try generatePackageSwift(raplacementForTargets: generatedTargetStatements) -} - -try main() diff --git a/Sources/AppleTools/SimctlBasedSimulatorStateMachineActionExecutor.swift b/Sources/AppleTools/SimctlBasedSimulatorStateMachineActionExecutor.swift index 9f57a26e..31088e6e 100644 --- a/Sources/AppleTools/SimctlBasedSimulatorStateMachineActionExecutor.swift +++ b/Sources/AppleTools/SimctlBasedSimulatorStateMachineActionExecutor.swift @@ -16,7 +16,7 @@ public final class SimctlBasedSimulatorStateMachineActionExecutor: SimulatorStat public var description: String { switch self { case .emptyUdid: - return "Simctl returned an empty udid value, ot the value was not found" + return "Simctl returned an empty udid value, or the value was not found" } } } @@ -48,16 +48,19 @@ public final class SimctlBasedSimulatorStateMachineActionExecutor: SimulatorStat "com.apple.CoreSimulator.SimDeviceType." + testDestination.deviceType.replacingOccurrences(of: " ", with: "-"), "com.apple.CoreSimulator.SimRuntime.iOS-" + testDestination.runtime.replacingOccurrences(of: ".", with: "-") ], - environment: environment, + environment: Environment(environment), automaticManagement: .sigintThenKillAfterRunningFor(interval: timeout) ) ) - try controller.startAndWaitForSuccessfulTermination() - let createdUdid = try String(contentsOf: controller.subprocess.standardStreamsCaptureConfig.stdoutOutputPath().fileUrl, encoding: .utf8).trimmingCharacters(in: .whitespacesAndNewlines) - guard !createdUdid.isEmpty else { throw SimctlUdidParseError.emptyUdid } + var capturedData = Data() + controller.onStdout { _, data, _ in capturedData.append(data) } + try controller.startAndWaitForSuccessfulTermination() - let udid = UDID(value: createdUdid) + guard let createdUdid = String(data: capturedData, encoding: .utf8), !createdUdid.isEmpty else { + throw SimctlUdidParseError.emptyUdid + } + let udid = UDID(value: createdUdid.trimmingCharacters(in: .whitespacesAndNewlines)) return Simulator( testDestination: testDestination, @@ -79,7 +82,7 @@ public final class SimctlBasedSimulatorStateMachineActionExecutor: SimulatorStat "bootstatus", simulator.udid.value, "-bd" ], - environment: environment, + environment: Environment(environment), automaticManagement: .sigintThenKillAfterRunningFor(interval: timeout) ) ) @@ -98,7 +101,7 @@ public final class SimctlBasedSimulatorStateMachineActionExecutor: SimulatorStat "--set", simulator.simulatorSetPath, "shutdown", simulator.udid.value ], - environment: environment, + environment: Environment(environment), automaticManagement: .sigintThenKillAfterRunningFor(interval: timeout) ) ) @@ -117,7 +120,7 @@ public final class SimctlBasedSimulatorStateMachineActionExecutor: SimulatorStat "--set", simulator.simulatorSetPath, "delete", simulator.udid.value ], - environment: environment, + environment: Environment(environment), automaticManagement: .sigintThenKillAfterRunningFor(interval: timeout) ) ) diff --git a/Sources/AppleTools/XcTestRunFileArgument.swift b/Sources/AppleTools/XcTestRunFileArgument.swift index 4b0fa22f..b3de095a 100644 --- a/Sources/AppleTools/XcTestRunFileArgument.swift +++ b/Sources/AppleTools/XcTestRunFileArgument.swift @@ -7,7 +7,7 @@ import ResourceLocation import ResourceLocationResolver import Runner import RunnerModels -import TemporaryStuff +import Tmp public final class XcTestRunFileArgument: SubprocessArgument, CustomStringConvertible { private let buildArtifacts: BuildArtifacts diff --git a/Sources/AppleTools/XcodebuildBasedTestRunner.swift b/Sources/AppleTools/XcodebuildBasedTestRunner.swift index 1b6e8193..524ae5b1 100644 --- a/Sources/AppleTools/XcodebuildBasedTestRunner.swift +++ b/Sources/AppleTools/XcodebuildBasedTestRunner.swift @@ -10,7 +10,7 @@ import ResultStream import Runner import RunnerModels import SimulatorPoolModels -import TemporaryStuff +import Tmp public final class XcodebuildBasedTestRunner: TestRunner { private let xctestJsonLocation: XCTestJsonLocation? @@ -85,7 +85,7 @@ public final class XcodebuildBasedTestRunner: TestRunner { "-parallel-testing-enabled", "NO", "test-without-building", ], - environment: testContext.environment + environment: Environment(testContext.environment) ) ) diff --git a/Sources/DateProvider/DateProvider.swift b/Sources/DateProvider/DateProvider.swift deleted file mode 100644 index 250d6300..00000000 --- a/Sources/DateProvider/DateProvider.swift +++ /dev/null @@ -1,5 +0,0 @@ -import Foundation - -public protocol DateProvider { - func currentDate() -> Date -} diff --git a/Sources/DateProvider/DefaultDateProvider.swift b/Sources/DateProvider/DefaultDateProvider.swift deleted file mode 100644 index 8c4e3c24..00000000 --- a/Sources/DateProvider/DefaultDateProvider.swift +++ /dev/null @@ -1,9 +0,0 @@ -import Foundation - -public final class SystemDateProvider: DateProvider { - public init() {} - - public func currentDate() -> Date { - return Date() - } -} diff --git a/Sources/Deployer/Deployer.swift b/Sources/Deployer/Deployer.swift index d7133649..39dd2490 100644 --- a/Sources/Deployer/Deployer.swift +++ b/Sources/Deployer/Deployer.swift @@ -2,7 +2,7 @@ import Foundation import Logging import PathLib import ProcessController -import TemporaryStuff +import Tmp import UniqueIdentifierGenerator /** Basic class that defines a logic for deploying a number of DeployableItems. */ diff --git a/Sources/Deployer/Packager.swift b/Sources/Deployer/Packager.swift index cee64731..18c728f2 100644 --- a/Sources/Deployer/Packager.swift +++ b/Sources/Deployer/Packager.swift @@ -2,7 +2,7 @@ import Foundation import Logging import PathLib import ProcessController -import TemporaryStuff +import Tmp /** Packs DeployableItem, returns URL to a single file with a package. */ public final class Packager { diff --git a/Sources/DeveloperDirLocator/DefaultDeveloperDirLocator.swift b/Sources/DeveloperDirLocator/DefaultDeveloperDirLocator.swift index 60cd8c2f..4dd7067e 100644 --- a/Sources/DeveloperDirLocator/DefaultDeveloperDirLocator.swift +++ b/Sources/DeveloperDirLocator/DefaultDeveloperDirLocator.swift @@ -31,9 +31,13 @@ public final class DefaultDeveloperDirLocator: DeveloperDirLocator { let processController = try processControllerProvider.createProcessController( subprocess: Subprocess(arguments: ["/usr/bin/xcode-select", "-p"]) ) + var output = "" + processController.onStdout { _, data, _ in + guard let string = String(data: data, encoding: .utf8) else { return } + output.append(string) + } processController.startAndListenUntilProcessDies() - let path = try String(contentsOf: processController.subprocess.standardStreamsCaptureConfig.stdoutOutputPath().fileUrl) - return AbsolutePath(path.trimmingCharacters(in: .whitespacesAndNewlines)) + return AbsolutePath(output.trimmingCharacters(in: .whitespacesAndNewlines)) } private func findDeveloperDir( diff --git a/Sources/DistDeployer/DistDeployer.swift b/Sources/DistDeployer/DistDeployer.swift index 28797a9a..e4e1d0f5 100644 --- a/Sources/DistDeployer/DistDeployer.swift +++ b/Sources/DistDeployer/DistDeployer.swift @@ -2,7 +2,7 @@ import Deployer import Foundation import ProcessController import SSHDeployer -import TemporaryStuff +import Tmp import UniqueIdentifierGenerator /// Class for generic usage: it deploys the provided deployable items to the provided deployment destinations, and diff --git a/Sources/DistDeployer/RemoteQueueLaunchdPlist.swift b/Sources/DistDeployer/RemoteQueueLaunchdPlist.swift index abe0f2b3..3a0d9bfb 100644 --- a/Sources/DistDeployer/RemoteQueueLaunchdPlist.swift +++ b/Sources/DistDeployer/RemoteQueueLaunchdPlist.swift @@ -3,7 +3,7 @@ import Foundation import LaunchdUtils import QueueModels import SSHDeployer -import TemporaryStuff +import Tmp public final class RemoteQueueLaunchdPlist { /// Unique deployment id diff --git a/Sources/DistDeployer/RemoteQueueStarter.swift b/Sources/DistDeployer/RemoteQueueStarter.swift index 32b0f5ce..9f06f002 100644 --- a/Sources/DistDeployer/RemoteQueueStarter.swift +++ b/Sources/DistDeployer/RemoteQueueStarter.swift @@ -3,7 +3,7 @@ import Foundation import PathLib import ProcessController import QueueModels -import TemporaryStuff +import Tmp import UniqueIdentifierGenerator public final class RemoteQueueStarter { diff --git a/Sources/DistDeployer/RemoteWorkerStarter.swift b/Sources/DistDeployer/RemoteWorkerStarter.swift index 7871d7c3..c094bbbb 100644 --- a/Sources/DistDeployer/RemoteWorkerStarter.swift +++ b/Sources/DistDeployer/RemoteWorkerStarter.swift @@ -1,12 +1,4 @@ -import Deployer -import Foundation -import Logging -import PathLib -import ProcessController -import QueueModels import SocketModels -import TemporaryStuff -import UniqueIdentifierGenerator public protocol RemoteWorkerStarter { func deployAndStartWorker( diff --git a/Sources/DistDeployer/RemoteWorkersStarter/DefaultRemoteWorkersStarter.swift b/Sources/DistDeployer/RemoteWorkersStarter/DefaultRemoteWorkersStarter.swift index 3c76a2a4..ed55d891 100644 --- a/Sources/DistDeployer/RemoteWorkersStarter/DefaultRemoteWorkersStarter.swift +++ b/Sources/DistDeployer/RemoteWorkersStarter/DefaultRemoteWorkersStarter.swift @@ -5,7 +5,7 @@ import PathLib import ProcessController import QueueModels import SocketModels -import TemporaryStuff +import Tmp import UniqueIdentifierGenerator public final class DefaultRemoteWorkersStarter: RemoteWorkerStarter { diff --git a/Sources/DistWorker/DistWorker.swift b/Sources/DistWorker/DistWorker.swift index 8c52584f..43046078 100644 --- a/Sources/DistWorker/DistWorker.swift +++ b/Sources/DistWorker/DistWorker.swift @@ -26,7 +26,7 @@ import Scheduler import SimulatorPool import SocketModels import SynchronousWaiter -import TemporaryStuff +import Tmp import Timer import Types import UniqueIdentifierGenerator diff --git a/Sources/EmceeLib/Commands/DistWorkCommand.swift b/Sources/EmceeLib/Commands/DistWorkCommand.swift index fb29ea52..fe4e7981 100644 --- a/Sources/EmceeLib/Commands/DistWorkCommand.swift +++ b/Sources/EmceeLib/Commands/DistWorkCommand.swift @@ -21,7 +21,7 @@ import SignalHandling import SimulatorPool import SocketModels import SynchronousWaiter -import TemporaryStuff +import Tmp import UniqueIdentifierGenerator import WorkerCapabilitiesModels import WorkerCapabilities diff --git a/Sources/EmceeLib/Commands/DumpCommand.swift b/Sources/EmceeLib/Commands/DumpCommand.swift index c1d0b514..a19efa97 100644 --- a/Sources/EmceeLib/Commands/DumpCommand.swift +++ b/Sources/EmceeLib/Commands/DumpCommand.swift @@ -22,7 +22,7 @@ import ScheduleStrategy import Scheduler import SignalHandling import SimulatorPool -import TemporaryStuff +import Tmp import TestDiscovery import URLResource import UniqueIdentifierGenerator diff --git a/Sources/EmceeLib/Commands/RunTestsOnRemoteQueueCommand.swift b/Sources/EmceeLib/Commands/RunTestsOnRemoteQueueCommand.swift index 589b6081..66f60299 100644 --- a/Sources/EmceeLib/Commands/RunTestsOnRemoteQueueCommand.swift +++ b/Sources/EmceeLib/Commands/RunTestsOnRemoteQueueCommand.swift @@ -26,7 +26,7 @@ import SignalHandling import SimulatorPool import SocketModels import SynchronousWaiter -import TemporaryStuff +import Tmp import TestArgFile import TestDiscovery import Types diff --git a/Sources/EmceeLib/Commands/StartQueueServerCommand.swift b/Sources/EmceeLib/Commands/StartQueueServerCommand.swift index b1e26802..a4ccce47 100644 --- a/Sources/EmceeLib/Commands/StartQueueServerCommand.swift +++ b/Sources/EmceeLib/Commands/StartQueueServerCommand.swift @@ -21,7 +21,7 @@ import RemotePortDeterminer import RequestSender import ResourceLocationResolver import ScheduleStrategy -import TemporaryStuff +import Tmp import UniqueIdentifierGenerator import WorkerAlivenessProvider import WorkerCapabilities diff --git a/Sources/EmceeLib/InProcessMain.swift b/Sources/EmceeLib/InProcessMain.swift index 32c19de7..f8614709 100644 --- a/Sources/EmceeLib/InProcessMain.swift +++ b/Sources/EmceeLib/InProcessMain.swift @@ -9,6 +9,7 @@ import LocalHostDeterminer import Logging import LoggingSetup import Metrics +import PathLib import PluginManager import ProcessController import QueueModels @@ -43,6 +44,13 @@ public final class InProcessMain { let logsTimeToLive = TimeUnit.days(14) let logCleaningQueue = OperationQueue() + di.set( + LoggingSetup( + dateProvider: try di.get(), + fileSystem: try di.get() + ) + ) + try setupLogging(di: di, logsTimeToLive: logsTimeToLive, queue: logCleaningQueue) defer { @@ -55,10 +63,7 @@ public final class InProcessMain { Logger.info("Arguments: \(ProcessInfo.processInfo.arguments)") di.set( - DefaultProcessControllerProvider( - dateProvider: try di.get(), - fileSystem: try di.get() - ), + try DetailedAcitivityLoggableProcessControllerProvider(di: di), for: ProcessControllerProvider.self ) @@ -168,10 +173,7 @@ public final class InProcessMain { } private func setupLogging(di: DI, logsTimeToLive: TimeUnit, queue: OperationQueue) throws { - let loggingSetup = LoggingSetup( - dateProvider: try di.get(), - fileSystem: try di.get() - ) + let loggingSetup: LoggingSetup = try di.get() try loggingSetup.setupLogging(stderrVerbosity: Verbosity.info) try loggingSetup.cleanUpLogs( olderThan: try di.get(DateProvider.self).currentDate().addingTimeInterval(-logsTimeToLive.timeInterval), diff --git a/Sources/EmceeLib/MainClass.swift b/Sources/EmceeLib/MainClass.swift index ef8fef15..6a04db4f 100644 --- a/Sources/EmceeLib/MainClass.swift +++ b/Sources/EmceeLib/MainClass.swift @@ -9,23 +9,7 @@ public final class Main { public init() {} public func main() -> Int32 { - if shouldRunInProcess { - return runInProcess() - } else { - return runOutOfProcessAndCleanup() - } - } - - private static let runInProcessEnvName = "EMCEE_RUN_IN_PROCESS" - private var shouldRunInProcess: Bool { - return ProcessInfo.processInfo.environment[Main.runInProcessEnvName] == "true" - } - - private var parentProcessTracker: ParentProcessTracker? - - private func runInProcess() -> Int32 { do { - try startTrackingParentProcessAliveness() try InProcessMain().run() return 0 } catch { @@ -33,35 +17,4 @@ public final class Main { return 1 } } - - private func startTrackingParentProcessAliveness() throws { - parentProcessTracker = try ParentProcessTracker { - Logger.warning("Parent process has died") - OrphanProcessTracker().killAll() - exit(3) - } - } - - private static var innerProcess: Process? - - private func runOutOfProcessAndCleanup() -> Int32 { - let process = Process() - try? process.setStartsNewProcessGroup(false) - - signal(SIGINT, { _ in Main.innerProcess?.interrupt() }) - signal(SIGABRT, { _ in Main.innerProcess?.terminate() }) - signal(SIGTERM, { _ in Main.innerProcess?.terminate() }) - - process.launchPath = ProcessInfo.processInfo.executablePath - process.arguments = Array(ProcessInfo.processInfo.arguments.dropFirst()) - var environment = ProcessInfo.processInfo.environment - environment[Main.runInProcessEnvName] = "true" - environment[ParentProcessTracker.envName] = String(ProcessInfo.processInfo.processIdentifier) - process.environment = environment - Main.innerProcess = process - process.launch() - process.waitUntilExit() - OrphanProcessTracker().killAll() - return process.terminationStatus - } } diff --git a/Sources/EmceeLib/Utils/DefaultSimulatorControllerProvider.swift b/Sources/EmceeLib/Utils/DefaultSimulatorControllerProvider.swift index a39cd5ae..37d478a4 100644 --- a/Sources/EmceeLib/Utils/DefaultSimulatorControllerProvider.swift +++ b/Sources/EmceeLib/Utils/DefaultSimulatorControllerProvider.swift @@ -6,7 +6,7 @@ import PathLib import RunnerModels import SimulatorPool import SimulatorPoolModels -import TemporaryStuff +import Tmp import fbxctest public final class DefaultSimulatorControllerProvider: SimulatorControllerProvider { diff --git a/Sources/EmceeLib/Utils/DetailedAcitivityLoggableProcessControllerProvider.swift b/Sources/EmceeLib/Utils/DetailedAcitivityLoggableProcessControllerProvider.swift new file mode 100644 index 00000000..42c9edc0 --- /dev/null +++ b/Sources/EmceeLib/Utils/DetailedAcitivityLoggableProcessControllerProvider.swift @@ -0,0 +1,50 @@ +import DI +import Foundation +import Logging +import LoggingSetup +import PathLib +import ProcessController + +public final class DetailedAcitivityLoggableProcessControllerProvider: ProcessControllerProvider { + private let processControllerProvider: LoggableProcessControllerProvider + + public init( + di: DI + ) throws { + processControllerProvider = LoggableProcessControllerProvider( + pathProvider: { processName -> (stdout: AbsolutePath, stderr: AbsolutePath) in + let paths = try di.get(LoggingSetup.self).childProcessLogsContainerProvider().paths(subprocessName: processName) + Logger.debug("Subprocess output will be stored: stdout: \(paths.stdout) stderr: \(paths.stderr)") + return paths + }, + provider: DefaultProcessControllerProvider( + dateProvider: try di.get(), + fileSystem: try di.get() + ) + ) + } + + public func createProcessController(subprocess: Subprocess) throws -> ProcessController { + let processController = try processControllerProvider.createProcessController(subprocess: subprocess) + + processController.onStart { sender, _ in + Logger.debug("Started subprocess: \(sender.subprocess)", sender.subprocessInfo.pidInfo) + } + + processController.onSignal { sender, signal, _ in + Logger.debug("Signalled \(signal)", sender.subprocessInfo.pidInfo) + } + + processController.onTermination { sender, _ in + Logger.debug("Process terminated", sender.subprocessInfo.pidInfo) + } + + return processController + } +} + +extension SubprocessInfo { + var pidInfo: PidInfo { + PidInfo(pid: subprocessId, name: subprocessName) + } +} diff --git a/Sources/EmceeLib/Utils/OnDemandSimulatorPoolFactory.swift b/Sources/EmceeLib/Utils/OnDemandSimulatorPoolFactory.swift index e7f68a70..94aa2382 100644 --- a/Sources/EmceeLib/Utils/OnDemandSimulatorPoolFactory.swift +++ b/Sources/EmceeLib/Utils/OnDemandSimulatorPoolFactory.swift @@ -9,7 +9,7 @@ import QueueModels import ResourceLocationResolver import SimulatorPool import SimulatorPoolModels -import TemporaryStuff +import Tmp import UniqueIdentifierGenerator public final class OnDemandSimulatorPoolFactory { diff --git a/Sources/EmceeLib/Utils/SimulatorSetPathDeterminer/SimulatorSetPathDeterminerImpl.swift b/Sources/EmceeLib/Utils/SimulatorSetPathDeterminer/SimulatorSetPathDeterminerImpl.swift index a956e77b..2f8f008f 100644 --- a/Sources/EmceeLib/Utils/SimulatorSetPathDeterminer/SimulatorSetPathDeterminerImpl.swift +++ b/Sources/EmceeLib/Utils/SimulatorSetPathDeterminer/SimulatorSetPathDeterminerImpl.swift @@ -3,7 +3,7 @@ import Foundation import PathLib import RunnerModels import SimulatorPoolModels -import TemporaryStuff +import Tmp import UniqueIdentifierGenerator public final class SimulatorSetPathDeterminerImpl: SimulatorSetPathDeterminer { diff --git a/Sources/EmceeLib/Utils/SimulatorStateMachineActionExecutorProviderImpl.swift b/Sources/EmceeLib/Utils/SimulatorStateMachineActionExecutorProviderImpl.swift index 1ecb4676..2421db2e 100644 --- a/Sources/EmceeLib/Utils/SimulatorStateMachineActionExecutorProviderImpl.swift +++ b/Sources/EmceeLib/Utils/SimulatorStateMachineActionExecutorProviderImpl.swift @@ -9,7 +9,7 @@ import ResourceLocationResolver import RunnerModels import SimulatorPool import SimulatorPoolModels -import TemporaryStuff +import Tmp import fbxctest public final class SimulatorStateMachineActionExecutorProviderImpl: SimulatorStateMachineActionExecutorProvider { diff --git a/Sources/EmceeLib/Utils/TestEntriesValidator/TestEntriesValidator.swift b/Sources/EmceeLib/Utils/TestEntriesValidator/TestEntriesValidator.swift index fb4fc2ce..7f1d4313 100644 --- a/Sources/EmceeLib/Utils/TestEntriesValidator/TestEntriesValidator.swift +++ b/Sources/EmceeLib/Utils/TestEntriesValidator/TestEntriesValidator.swift @@ -3,7 +3,7 @@ import Logging import ResourceLocationResolver import RunnerModels import SimulatorPool -import TemporaryStuff +import Tmp import TestArgFile import TestDiscovery diff --git a/Sources/FileCache/FileCache.swift b/Sources/FileCache/FileCache.swift index bf284d85..9d3f6993 100644 --- a/Sources/FileCache/FileCache.swift +++ b/Sources/FileCache/FileCache.swift @@ -57,7 +57,7 @@ public final class FileCache { self.nameKeyer = nameHasher self.uniqueIdentifierGenerator = uniqueIdentifierGenerator - if try !fileSystem.properties(forFileAtPath: cachesContainer).exists() { + if !fileSystem.properties(forFileAtPath: cachesContainer).exists() { try fileSystem.createDirectory(atPath: cachesContainer, withIntermediateDirectories: true) } @@ -71,7 +71,7 @@ public final class FileCache { do { return try whileLocked { let filePath = try path(forItemWithName: name) - return try fileSystem.properties(forFileAtPath: filePath).exists() + return fileSystem.properties(forFileAtPath: filePath).exists() } } catch { return false @@ -186,7 +186,7 @@ public final class FileCache { } let expectedCachedItemPath = element.appending(component: element.lastComponent).appending(extension: "json") - if try fileSystem.properties(forFileAtPath: expectedCachedItemPath).exists() { + if fileSystem.properties(forFileAtPath: expectedCachedItemPath).exists() { cachedItemInfos[element] = try cachedItemInfo(path: expectedCachedItemPath) } } @@ -197,7 +197,7 @@ public final class FileCache { private func containerPath(forItemWithName name: String) throws -> AbsolutePath { let key = try nameKeyer.key(forName: name) let containerPath = cachesContainer.appending(component: key) - if try !fileSystem.properties(forFileAtPath: containerPath).exists() { + if !fileSystem.properties(forFileAtPath: containerPath).exists() { try fileSystem.createDirectory(atPath: containerPath, withIntermediateDirectories: true) } return containerPath diff --git a/Sources/FileSystem/CommonlyUsedPathsProvider.swift b/Sources/FileSystem/CommonlyUsedPathsProvider.swift deleted file mode 100644 index 10dcc64e..00000000 --- a/Sources/FileSystem/CommonlyUsedPathsProvider.swift +++ /dev/null @@ -1,15 +0,0 @@ -import Foundation -import PathLib - -public enum SearchDomain { - case user - case local - case network - case system -} - -public protocol CommonlyUsedPathsProvider { - func applications(inDomain: SearchDomain, create: Bool) throws -> AbsolutePath - func caches(inDomain: SearchDomain, create: Bool) throws -> AbsolutePath - func library(inDomain: SearchDomain, create: Bool) throws -> AbsolutePath -} diff --git a/Sources/FileSystem/DeepFileSystemEnumerator.swift b/Sources/FileSystem/DeepFileSystemEnumerator.swift deleted file mode 100644 index 7adf5dfc..00000000 --- a/Sources/FileSystem/DeepFileSystemEnumerator.swift +++ /dev/null @@ -1,30 +0,0 @@ -import Foundation -import PathLib - -public final class DeepFileSystemEnumerator: FileSystemEnumerator { - private let path: AbsolutePath - private let fileManager: FileManager - - public enum EnumerationError: Error { - case enumeratorFailure - } - - public init( - fileManager: FileManager, - path: AbsolutePath - ) { - self.fileManager = fileManager - self.path = path - } - - public func each(iterator: (AbsolutePath) throws -> ()) throws { - guard let enumerator = fileManager.enumerator(at: path.fileUrl, includingPropertiesForKeys: nil) else { - throw EnumerationError.enumeratorFailure - } - - for case let fileURL as URL in enumerator { - let absolutePath = AbsolutePath(fileURL) - try iterator(absolutePath) - } - } -} diff --git a/Sources/FileSystem/DefaultCommonlyUsedPathsProvider.swift b/Sources/FileSystem/DefaultCommonlyUsedPathsProvider.swift deleted file mode 100644 index 09091d15..00000000 --- a/Sources/FileSystem/DefaultCommonlyUsedPathsProvider.swift +++ /dev/null @@ -1,58 +0,0 @@ -import Foundation -import PathLib - -public final class DefaultCommonlyUsedPathsProvider: CommonlyUsedPathsProvider { - private let fileManager: FileManager - - public init(fileManager: FileManager) { - self.fileManager = fileManager - } - - public func applications(inDomain domain: SearchDomain, create: Bool) throws -> AbsolutePath { - return AbsolutePath( - try fileManager.url( - for: .applicationDirectory, - in: domain.mask, - appropriateFor: nil, - create: create - ) - ) - } - - public func caches(inDomain domain: SearchDomain, create: Bool) throws -> AbsolutePath { - return AbsolutePath( - try fileManager.url( - for: .cachesDirectory, - in: domain.mask, - appropriateFor: nil, - create: create - ) - ) - } - - public func library(inDomain domain: SearchDomain, create: Bool) throws -> AbsolutePath { - return AbsolutePath( - try fileManager.url( - for: .libraryDirectory, - in: domain.mask, - appropriateFor: nil, - create: create - ) - ) - } -} - -extension SearchDomain { - var mask: FileManager.SearchPathDomainMask { - switch self { - case .local: - return .localDomainMask - case .user: - return .userDomainMask - case .network: - return .networkDomainMask - case .system: - return .systemDomainMask - } - } -} diff --git a/Sources/FileSystem/DefaultFilePropertiesContainer.swift b/Sources/FileSystem/DefaultFilePropertiesContainer.swift deleted file mode 100644 index 44da3274..00000000 --- a/Sources/FileSystem/DefaultFilePropertiesContainer.swift +++ /dev/null @@ -1,73 +0,0 @@ -import Foundation -import PathLib - -public final class DefaultFilePropertiesContainer: FilePropertiesContainer { - private let path: AbsolutePath - private let fileManager = FileManager() - - public init(path: AbsolutePath) { - self.path = path - } - - public enum DefaultFilePropertiesContainerError: Error, CustomStringConvertible { - case emptyValue(AbsolutePath, URLResourceKey) - - public var description: String { - switch self { - case .emptyValue(let path, let property): - return "File at path \(path) does not have a value for property \(property)" - } - } - } - - public func modificationDate() throws -> Date { - let values = try path.fileUrl.resourceValues(forKeys: [.contentModificationDateKey]) - guard let value = values.contentModificationDate else { - throw DefaultFilePropertiesContainerError.emptyValue(path, .contentModificationDateKey) - } - return value - } - - public func set(modificationDate: Date) throws { - var values = URLResourceValues() - values.contentModificationDate = modificationDate - var url = path.fileUrl - try url.setResourceValues(values) - } - - public func isExecutable() throws -> Bool { - let values = try path.fileUrl.resourceValues(forKeys: [.isExecutableKey]) - guard let value = values.isExecutable else { - throw DefaultFilePropertiesContainerError.emptyValue(path, .isExecutableKey) - } - return value - } - - public func exists() throws -> Bool { - fileManager.fileExists(atPath: path.pathString) - } - - public func isDirectory() throws -> Bool { - let values = try path.fileUrl.resourceValues(forKeys: [.isDirectoryKey]) - guard let value = values.isDirectory else { - throw DefaultFilePropertiesContainerError.emptyValue(path, .isDirectoryKey) - } - return value - } - - public func isRegularFile() throws -> Bool { - let values = try path.fileUrl.resourceValues(forKeys: [.isRegularFileKey]) - guard let value = values.isRegularFile else { - throw DefaultFilePropertiesContainerError.emptyValue(path, .isRegularFileKey) - } - return value - } - - public func size() throws -> Int { - let values = try path.fileUrl.resourceValues(forKeys: [.fileSizeKey]) - guard let value = values.fileSize else { - throw DefaultFilePropertiesContainerError.emptyValue(path, .fileSizeKey) - } - return value - } -} diff --git a/Sources/FileSystem/FilePropertiesContainer.swift b/Sources/FileSystem/FilePropertiesContainer.swift deleted file mode 100644 index 15e50447..00000000 --- a/Sources/FileSystem/FilePropertiesContainer.swift +++ /dev/null @@ -1,16 +0,0 @@ -import Foundation - -public protocol FilePropertiesContainer { - func modificationDate() throws -> Date - func set(modificationDate: Date) throws - - func isExecutable() throws -> Bool - func exists() throws -> Bool - func isDirectory() throws -> Bool - func isRegularFile() throws -> Bool - func size() throws -> Int -} - -public extension FilePropertiesContainer { - func touch() throws { try set(modificationDate: Date()) } -} diff --git a/Sources/FileSystem/FileSystem.swift b/Sources/FileSystem/FileSystem.swift deleted file mode 100644 index cddec723..00000000 --- a/Sources/FileSystem/FileSystem.swift +++ /dev/null @@ -1,21 +0,0 @@ -import Foundation -import PathLib - -public enum ContentEnumerationStyle { - case deep - case shallow -} - -public protocol FileSystem { - func contentEnumerator(forPath: AbsolutePath, style: ContentEnumerationStyle) -> FileSystemEnumerator - - func createDirectory(atPath: AbsolutePath, withIntermediateDirectories: Bool) throws - func createFile(atPath: AbsolutePath, data: Data?) throws - - func copy(source: AbsolutePath, destination: AbsolutePath) throws - func move(source: AbsolutePath, destination: AbsolutePath) throws - func delete(fileAtPath: AbsolutePath) throws - - func properties(forFileAtPath: AbsolutePath) -> FilePropertiesContainer - var commonlyUsedPathsProvider: CommonlyUsedPathsProvider { get } -} diff --git a/Sources/FileSystem/FileSystemEnumerator.swift b/Sources/FileSystem/FileSystemEnumerator.swift deleted file mode 100644 index 089511cb..00000000 --- a/Sources/FileSystem/FileSystemEnumerator.swift +++ /dev/null @@ -1,6 +0,0 @@ -import Foundation -import PathLib - -public protocol FileSystemEnumerator { - func each(iterator: (AbsolutePath) throws -> ()) throws -} diff --git a/Sources/FileSystem/LocalFileSystem.swift b/Sources/FileSystem/LocalFileSystem.swift deleted file mode 100644 index 63f49771..00000000 --- a/Sources/FileSystem/LocalFileSystem.swift +++ /dev/null @@ -1,55 +0,0 @@ -import Foundation -import PathLib - -public final class LocalFileSystem: FileSystem { - private let fileManager = FileManager() - - private enum LocalFileSystemError: Error { - case failedToCreateFile(AbsolutePath) - } - - public init() {} - - public func contentEnumerator(forPath path: AbsolutePath, style: ContentEnumerationStyle) -> FileSystemEnumerator { - switch style { - case .deep: - return DeepFileSystemEnumerator(fileManager: fileManager, path: path) - case .shallow: - return ShallowFileSystemEnumerator(fileManager: fileManager, path: path) - } - - } - - public func createDirectory(atPath path: AbsolutePath, withIntermediateDirectories: Bool) throws { - try fileManager.createDirectory( - atPath: path.pathString, - withIntermediateDirectories: withIntermediateDirectories - ) - } - - public func createFile(atPath path: AbsolutePath, data: Data?) throws { - if !fileManager.createFile(atPath: path.pathString, contents: data) { - throw LocalFileSystemError.failedToCreateFile(path) - } - } - - public func copy(source: AbsolutePath, destination: AbsolutePath) throws { - try fileManager.copyItem(at: source.fileUrl, to: destination.fileUrl) - } - - public func move(source: AbsolutePath, destination: AbsolutePath) throws { - try fileManager.moveItem(at: source.fileUrl, to: destination.fileUrl) - } - - public func delete(fileAtPath path: AbsolutePath) throws { - try fileManager.removeItem(at: path.fileUrl) - } - - public func properties(forFileAtPath path: AbsolutePath) -> FilePropertiesContainer { - return DefaultFilePropertiesContainer(path: path) - } - - public var commonlyUsedPathsProvider: CommonlyUsedPathsProvider { - return DefaultCommonlyUsedPathsProvider(fileManager: fileManager) - } -} diff --git a/Sources/FileSystem/ShallowFileSystemEnumerator.swift b/Sources/FileSystem/ShallowFileSystemEnumerator.swift deleted file mode 100644 index ad951867..00000000 --- a/Sources/FileSystem/ShallowFileSystemEnumerator.swift +++ /dev/null @@ -1,27 +0,0 @@ -import Foundation -import PathLib - -public final class ShallowFileSystemEnumerator: FileSystemEnumerator { - private let path: AbsolutePath - private let fileManager: FileManager - - public enum EnumerationError: Error { - case enumeratorFailure - } - - public init( - fileManager: FileManager, - path: AbsolutePath - ) { - self.fileManager = fileManager - self.path = path - } - - public func each(iterator: (AbsolutePath) throws -> ()) throws { - let contents = try fileManager.contentsOfDirectory(atPath: path.pathString) - - for element in contents { - try iterator(path.appending(component: element)) - } - } -} diff --git a/Sources/Graphite/GraphiteMetric.swift b/Sources/Graphite/GraphiteMetric.swift deleted file mode 100644 index 77d03f60..00000000 --- a/Sources/Graphite/GraphiteMetric.swift +++ /dev/null @@ -1,50 +0,0 @@ -import Foundation -import MetricsUtils - -open class GraphiteMetric: CustomStringConvertible, Hashable { - /// Components that form a fully qualified name of a metric. - public let components: [String] - - /// Metric value. - public let value: Double - - /// Timestamp when metric has been collected. - public let timestamp: Date - - /// Common reserved field to be used in variable components. - public static let reservedField = "reserved" - - /// - Parameter fixedComponents: Components that are fixed for this metric, and they must NOT change in the future. - /// Consider introducing a new metric if you need to change this array. - /// - Parameter variableComponents: Components to be used as variable parameters. - /// Consider introducing a new metric if you need to change the count of elements in this array. - /// **Count must NOT change!** Values may change. - /// - Parameter value: The value for the parametrized metric. - /// - Parameter timestamp: The timestamp when the metric has been captured. - public init( - fixedComponents: [StaticString], - variableComponents: [String], - value: Double, - timestamp: Date) - { - self.components = (fixedComponents.map { $0.description } + variableComponents).map { $0.suitableForMetric } - self.value = value - self.timestamp = timestamp - } - - public var description: String { - return "<\(type(of: self)) components=\(components), value=\(value), ts=\(timestamp)>" - } - - public static func ==(left: GraphiteMetric, right: GraphiteMetric) -> Bool { - return left.components == right.components - && left.value == right.value - && left.timestamp == right.timestamp - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(components) - hasher.combine(value) - hasher.combine(timestamp) - } -} diff --git a/Sources/Graphite/GraphiteMetricHandler.swift b/Sources/Graphite/GraphiteMetricHandler.swift deleted file mode 100644 index 3833aa66..00000000 --- a/Sources/Graphite/GraphiteMetricHandler.swift +++ /dev/null @@ -1,6 +0,0 @@ -import Foundation - -public protocol GraphiteMetricHandler { - func handle(metric: GraphiteMetric) - func tearDown(timeout: TimeInterval) -} diff --git a/Sources/Graphite/GraphiteMetricHandlerImpl.swift b/Sources/Graphite/GraphiteMetricHandlerImpl.swift deleted file mode 100644 index 1f21b4ce..00000000 --- a/Sources/Graphite/GraphiteMetricHandlerImpl.swift +++ /dev/null @@ -1,59 +0,0 @@ -import Foundation -import GraphiteClient -import IO -import Logging -import MetricsUtils -import SocketModels - -public final class GraphiteMetricHandlerImpl: GraphiteMetricHandler { - private let graphiteDomain: [String] - private let outputStream: EasyOutputStream - private let graphiteClient: GraphiteClient - - public init( - graphiteDomain: [String], - graphiteSocketAddress: SocketAddress - ) throws { - self.graphiteDomain = graphiteDomain - - let streamReopener = StreamReopener(maximumAttemptsToReopenStream: 10) - - outputStream = EasyOutputStream( - outputStreamProvider: NetworkSocketOutputStreamProvider( - host: graphiteSocketAddress.host, - port: graphiteSocketAddress.port.value - ), - errorHandler: { stream, error in - Logger.error("Graphite stream error: \(error)") - streamReopener.attemptToReopenStream(stream: stream) - }, - streamEndHandler: { stream in - Logger.warning("Graphite stream has been closed") - streamReopener.attemptToReopenStream(stream: stream) - } - ) - - streamReopener.streamHasBeenOpened() - try outputStream.open() - self.graphiteClient = GraphiteClient(easyOutputStream: outputStream) - } - - public func handle(metric: GraphiteMetric) { - do { - try graphiteClient.send( - path: graphiteDomain + metric.components, - value: metric.value, - timestamp: metric.timestamp - ) - } catch { - Logger.warning("Failed to send metric \(metric) to graphite: \(error)") - } - } - - public func tearDown(timeout: TimeInterval) { - let result = outputStream.waitAndClose(timeout: timeout) - if result == .flushTimeout { - Logger.warning("Failed to tear down in time") - } - } -} diff --git a/Sources/LocalQueueServerRunner/RemoteWorkersStarterProvider/DefaultRemoteWorkerStarterProvider.swift b/Sources/LocalQueueServerRunner/RemoteWorkersStarterProvider/DefaultRemoteWorkerStarterProvider.swift index 05eb8343..97213276 100644 --- a/Sources/LocalQueueServerRunner/RemoteWorkersStarterProvider/DefaultRemoteWorkerStarterProvider.swift +++ b/Sources/LocalQueueServerRunner/RemoteWorkersStarterProvider/DefaultRemoteWorkerStarterProvider.swift @@ -4,7 +4,7 @@ import Foundation import ProcessController import QueueModels import SocketModels -import TemporaryStuff +import Tmp import UniqueIdentifierGenerator public final class DefaultRemoteWorkerStarterProvider: RemoteWorkerStarterProvider { diff --git a/Sources/Logging/LogEntry.swift b/Sources/Logging/LogEntry.swift index 729912bf..baf45db0 100644 --- a/Sources/Logging/LogEntry.swift +++ b/Sources/Logging/LogEntry.swift @@ -1,17 +1,17 @@ import Foundation -public final class SubprocessInfo: Equatable { - public let subprocessId: Int32 - public let subprocessName: String +public final class PidInfo: Equatable { + public let pid: Int32 + public let name: String - public init(subprocessId: Int32, subprocessName: String) { - self.subprocessId = subprocessId - self.subprocessName = subprocessName + public init(pid: Int32, name: String) { + self.pid = pid + self.name = name } - public static func ==(left: SubprocessInfo, right: SubprocessInfo) -> Bool { - return left.subprocessId == right.subprocessId - && left.subprocessName == right.subprocessName + public static func ==(left: PidInfo, right: PidInfo) -> Bool { + return left.pid == right.pid + && left.name == right.name } } @@ -19,7 +19,7 @@ public final class LogEntry: Equatable { public let file: StaticString public let line: UInt public let message: String - public let subprocessInfo: SubprocessInfo? + public let pidInfo: PidInfo? public let timestamp: Date public let verbosity: Verbosity @@ -27,14 +27,14 @@ public final class LogEntry: Equatable { file: StaticString = #file, line: UInt = #line, message: String, - subprocessInfo: SubprocessInfo? = nil, + pidInfo: PidInfo? = nil, timestamp: Date = Date(), verbosity: Verbosity ) { self.file = file self.line = line self.message = message - self.subprocessInfo = subprocessInfo + self.pidInfo = pidInfo self.timestamp = timestamp self.verbosity = verbosity } @@ -43,7 +43,7 @@ public final class LogEntry: Equatable { return left.file.description == right.file.description && left.line == right.line && left.message == right.message - && left.subprocessInfo == right.subprocessInfo + && left.pidInfo == right.pidInfo && left.timestamp == right.timestamp && left.verbosity == right.verbosity } diff --git a/Sources/Logging/Logger.swift b/Sources/Logging/Logger.swift index 2fe38810..18775079 100644 --- a/Sources/Logging/Logger.swift +++ b/Sources/Logging/Logger.swift @@ -5,72 +5,72 @@ public final class Logger { public static func verboseDebug( _ message: String, - _ subprocessInfo: SubprocessInfo? = nil, + _ pidInfo: PidInfo? = nil, file: StaticString = #file, line: UInt = #line) { - log(.verboseDebug, message, subprocessInfo, file: file, line: line) + log(.verboseDebug, message, pidInfo, file: file, line: line) } public static func debug( _ message: String, - _ subprocessInfo: SubprocessInfo? = nil, + _ pidInfo: PidInfo? = nil, file: StaticString = #file, line: UInt = #line) { - log(.debug, message, subprocessInfo, file: file, line: line) + log(.debug, message, pidInfo, file: file, line: line) } public static func info( _ message: String, - _ subprocessInfo: SubprocessInfo? = nil, + _ pidInfo: PidInfo? = nil, file: StaticString = #file, line: UInt = #line) { - log(.info, message, subprocessInfo, file: file, line: line) + log(.info, message, pidInfo, file: file, line: line) } public static func warning( _ message: String, - _ subprocessInfo: SubprocessInfo? = nil, + _ pidInfo: PidInfo? = nil, file: StaticString = #file, line: UInt = #line) { - log(.warning, message, subprocessInfo, file: file, line: line) + log(.warning, message, pidInfo, file: file, line: line) } public static func error( _ message: String, - _ subprocessInfo: SubprocessInfo? = nil, + _ pidInfo: PidInfo? = nil, file: StaticString = #file, line: UInt = #line) { - log(.error, message, subprocessInfo, file: file, line: line) + log(.error, message, pidInfo, file: file, line: line) } public static func fatal( _ message: String, - _ subprocessInfo: SubprocessInfo? = nil, + _ pidInfo: PidInfo? = nil, file: StaticString = #file, line: UInt = #line) -> Never { - log(.fatal, message, subprocessInfo, file: file, line: line) + log(.fatal, message, pidInfo, file: file, line: line) fatalError(message) } public static func always( _ message: String, - _ subprocessInfo: SubprocessInfo? = nil, + _ pidInfo: PidInfo? = nil, file: StaticString = #file, line: UInt = #line) { - log(.always, message, subprocessInfo, file: file, line: line) + log(.always, message, pidInfo, file: file, line: line) } public static func log( _ verbosity: Verbosity, _ message: String, - _ subprocessInfo: SubprocessInfo? = nil, + _ pidInfo: PidInfo? = nil, file: StaticString = #file, line: UInt = #line) { @@ -78,7 +78,7 @@ public final class Logger { file: file, line: line, message: message, - subprocessInfo: subprocessInfo, + pidInfo: pidInfo, timestamp: Date(), verbosity: verbosity ) diff --git a/Sources/Logging/NSLogLikeLogEntryTextFormatter.swift b/Sources/Logging/NSLogLikeLogEntryTextFormatter.swift index a8dcdc7e..47740cf8 100644 --- a/Sources/Logging/NSLogLikeLogEntryTextFormatter.swift +++ b/Sources/Logging/NSLogLikeLogEntryTextFormatter.swift @@ -17,8 +17,8 @@ public final class NSLogLikeLogEntryTextFormatter: LogEntryTextFormatter { var result = "[\(logEntry.verbosity.stringCode)] \(timeStamp)" - if let subprocessInfo = logEntry.subprocessInfo { - result += " \(subprocessInfo.subprocessName)[\(subprocessInfo.subprocessId)]" + if let pidInfo = logEntry.pidInfo { + result += " \(pidInfo.name)[\(pidInfo.pid)]" } result += ": " diff --git a/Sources/LoggingSetup/ChildProcessLogsContainerProvider.swift b/Sources/LoggingSetup/ChildProcessLogsContainerProvider.swift new file mode 100644 index 00000000..341ba935 --- /dev/null +++ b/Sources/LoggingSetup/ChildProcessLogsContainerProvider.swift @@ -0,0 +1,41 @@ +import Foundation +import FileSystem +import PathLib +import Tmp + +public protocol ChildProcessLogsContainerProvider { + func paths(subprocessName: String) throws -> (stdout: AbsolutePath, stderr: AbsolutePath) +} + +public final class ChildProcessLogsContainerProviderImpl: ChildProcessLogsContainerProvider { + private let fileSystem: FileSystem + private let mainContainerPath: AbsolutePath + + public init( + fileSystem: FileSystem, + mainContainerPath: AbsolutePath + ) { + self.fileSystem = fileSystem + self.mainContainerPath = mainContainerPath + } + + public func paths(subprocessName: String) throws -> (stdout: AbsolutePath, stderr: AbsolutePath) { + let subprocessSpecificContainer = mainContainerPath.appending( + components: ["subprocesses", subprocessName] + ) + let processContainer = try TemporaryFolder( + containerPath: subprocessSpecificContainer, + prefix: subprocessName, + deleteOnDealloc: false + ).absolutePath + + let stdoutPath = processContainer.appending(component: "stdout.log") + let stderrPath = processContainer.appending(component: "stderr.log") + + try fileSystem.createDirectory(atPath: processContainer, withIntermediateDirectories: true) + try fileSystem.createFile(atPath: stdoutPath, data: nil) + try fileSystem.createFile(atPath: stderrPath, data: nil) + + return (stdout: stdoutPath, stderr: stderrPath) + } +} diff --git a/Sources/LoggingSetup/LoggingSetup.swift b/Sources/LoggingSetup/LoggingSetup.swift index d84d1cf8..77f179a5 100644 --- a/Sources/LoggingSetup/LoggingSetup.swift +++ b/Sources/LoggingSetup/LoggingSetup.swift @@ -7,7 +7,7 @@ import Logging import Metrics import PathLib import Sentry -import TemporaryStuff +import Tmp public final class LoggingSetup { private let dateProvider: DateProvider @@ -44,6 +44,13 @@ public final class LoggingSetup { Logger.always("$ scp \(NSUserName())@\(LocalHostDeterminer.currentHostAddress):\(detailedLogPath.absolutePath) /tmp/\(filename).log && open /tmp/\(filename).log") } + public func childProcessLogsContainerProvider() throws -> ChildProcessLogsContainerProvider { + return ChildProcessLogsContainerProviderImpl( + fileSystem: fileSystem, + mainContainerPath: try logsContainerFolder() + ) + } + public static func tearDown(timeout: TimeInterval) { GlobalLoggerConfig.loggerHandler.tearDownLogging(timeout: timeout) } diff --git a/Sources/LoggingSetup/MutableMetricRecorder+AnalyticsConfiguration.swift b/Sources/LoggingSetup/MutableMetricRecorder+AnalyticsConfiguration.swift index 94abd2e9..6253b49e 100644 --- a/Sources/LoggingSetup/MutableMetricRecorder+AnalyticsConfiguration.swift +++ b/Sources/LoggingSetup/MutableMetricRecorder+AnalyticsConfiguration.swift @@ -24,7 +24,7 @@ extension MutableMetricRecorder { statsdMetricHandler = NoOpMetricHandler() } - setGraphiteMetric(handler: graphiteMetricHandler) - setStatsdMetric(handler: statsdMetricHandler) + try setGraphiteMetric(handler: graphiteMetricHandler) + try setStatsdMetric(handler: statsdMetricHandler) } } diff --git a/Sources/LoggingSetup/SentryLoggerHandler.swift b/Sources/LoggingSetup/SentryLoggerHandler.swift index c863f827..fd872799 100644 --- a/Sources/LoggingSetup/SentryLoggerHandler.swift +++ b/Sources/LoggingSetup/SentryLoggerHandler.swift @@ -37,8 +37,8 @@ public final class SentryLoggerHandler: LoggerHandler { "hostname": hostname, "verbosity": logEntry.verbosity.stringCode ] - if let subprocessInfo = logEntry.subprocessInfo { - extraData["subprocess_name"] = subprocessInfo.subprocessName + if let pidInfo = logEntry.pidInfo { + extraData["subprocess_name"] = pidInfo.name } let sentryEvent = SentryEvent( diff --git a/Sources/Metrics/MetricRecorder.swift b/Sources/Metrics/MetricRecorder.swift deleted file mode 100644 index a79fb398..00000000 --- a/Sources/Metrics/MetricRecorder.swift +++ /dev/null @@ -1,27 +0,0 @@ -import Foundation -import Graphite -import Statsd - -public protocol MetricRecorder { - func capture(_ metric: GraphiteMetric) - func capture(_ metric: StatsdMetric) - func tearDown(timeout: TimeInterval) -} - -extension MetricRecorder { - public func capture(_ metrics: [GraphiteMetric]) { - metrics.forEach(capture) - } - - public func capture(_ metrics: [StatsdMetric]) { - metrics.forEach(capture) - } - - public func capture(_ metrics: GraphiteMetric...) { - capture(metrics) - } - - public func capture(_ metrics: StatsdMetric...) { - capture(metrics) - } -} diff --git a/Sources/Metrics/MetricRecorderImpl.swift b/Sources/Metrics/MetricRecorderImpl.swift deleted file mode 100644 index 353de4a7..00000000 --- a/Sources/Metrics/MetricRecorderImpl.swift +++ /dev/null @@ -1,52 +0,0 @@ -import Foundation -import Graphite -import Statsd - -public final class MetricRecorderImpl: MutableMetricRecorder { - private var graphiteMetricHandler: GraphiteMetricHandler - private var statsdMetricHandler: StatsdMetricHandler - private let queue: DispatchQueue - - public init( - graphiteMetricHandler: GraphiteMetricHandler, - statsdMetricHandler: StatsdMetricHandler, - queue: DispatchQueue = DispatchQueue(label: "MetricRecorderImpl.syncQueue") - ) { - self.graphiteMetricHandler = graphiteMetricHandler - self.statsdMetricHandler = statsdMetricHandler - self.queue = queue - } - - public func setGraphiteMetric(handler: GraphiteMetricHandler) { - queue.async { [weak self] in - self?.graphiteMetricHandler.tearDown(timeout: 10) - self?.graphiteMetricHandler = handler - } - } - - public func setStatsdMetric(handler: StatsdMetricHandler) { - queue.async { [weak self] in - self?.statsdMetricHandler.tearDown(timeout: 10) - self?.statsdMetricHandler = handler - } - } - - public func capture(_ metric: GraphiteMetric) { - queue.async { [weak self] in - self?.graphiteMetricHandler.handle(metric: metric) - } - } - - public func capture(_ metric: StatsdMetric) { - queue.async { [weak self] in - self?.statsdMetricHandler.handle(metric: metric) - } - } - - public func tearDown(timeout: TimeInterval) { - queue.sync { - self.graphiteMetricHandler.tearDown(timeout: timeout) - self.statsdMetricHandler.tearDown(timeout: timeout) - } - } -} diff --git a/Sources/Metrics/MutableMetricRecorder.swift b/Sources/Metrics/MutableMetricRecorder.swift deleted file mode 100644 index 2b7bbde8..00000000 --- a/Sources/Metrics/MutableMetricRecorder.swift +++ /dev/null @@ -1,7 +0,0 @@ -import Graphite -import Statsd - -public protocol MutableMetricRecorder: MetricRecorder { - func setGraphiteMetric(handler: GraphiteMetricHandler) - func setStatsdMetric(handler: StatsdMetricHandler) -} diff --git a/Sources/Metrics/NoOpMetricHandler.swift b/Sources/Metrics/NoOpMetricHandler.swift deleted file mode 100644 index 42a78333..00000000 --- a/Sources/Metrics/NoOpMetricHandler.swift +++ /dev/null @@ -1,10 +0,0 @@ -import Foundation -import Graphite -import Statsd - -public final class NoOpMetricHandler: GraphiteMetricHandler, StatsdMetricHandler { - public init() {} - public func handle(metric: GraphiteMetric) {} - public func handle(metric: StatsdMetric) {} - public func tearDown(timeout: TimeInterval) {} -} diff --git a/Sources/Metrics/TimeMeasurer.swift b/Sources/Metrics/TimeMeasurer.swift deleted file mode 100644 index 17006e98..00000000 --- a/Sources/Metrics/TimeMeasurer.swift +++ /dev/null @@ -1,36 +0,0 @@ -import DateProvider -import Foundation - -public protocol TimeMeasurer { - func measure( - work: () throws -> T, - result: (Error?, TimeInterval) -> () - ) rethrows -> T -} - -public final class TimeMeasurerImpl: TimeMeasurer { - private let dateProvider: DateProvider - - public init( - dateProvider: DateProvider - ) { - self.dateProvider = dateProvider - } - - public func measure( - work: () throws -> T, - result: (Error?, TimeInterval) -> () - ) rethrows -> T { - let startedAt = dateProvider.currentDate() - - do { - let value = try work() - result(nil, dateProvider.currentDate().timeIntervalSince(startedAt)) - return value - } catch { - result(error, dateProvider.currentDate().timeIntervalSince(startedAt)) - throw error - } - - } -} diff --git a/Sources/MetricsUtils/StreamReopener.swift b/Sources/MetricsUtils/StreamReopener.swift deleted file mode 100644 index e4d9fc68..00000000 --- a/Sources/MetricsUtils/StreamReopener.swift +++ /dev/null @@ -1,43 +0,0 @@ -import Foundation -import IO -import Logging - -public class StreamReopener { - private var lastStreamOpenEventTimestamp: TimeInterval = 0 - private var numberOfAttemptsToReopenStream = 0 - private let maximumAttemptsToReopenStream: Int - - public init(maximumAttemptsToReopenStream: Int) { - self.maximumAttemptsToReopenStream = maximumAttemptsToReopenStream - } - - private func shouldAttemptToReopenStream() -> Bool { - let reopenAttemptTimestamp = Date.timeIntervalSinceReferenceDate - let streamReopenAttemptIsWithinShortTimeRange = (reopenAttemptTimestamp - lastStreamOpenEventTimestamp) < 60 - if streamReopenAttemptIsWithinShortTimeRange { - numberOfAttemptsToReopenStream += 1 - } else { - numberOfAttemptsToReopenStream = 0 - } - return numberOfAttemptsToReopenStream < maximumAttemptsToReopenStream - } - - public func streamHasBeenOpened() { - lastStreamOpenEventTimestamp = Date.timeIntervalSinceReferenceDate - } - - public func attemptToReopenStream(stream: EasyOutputStream) { - do { - if shouldAttemptToReopenStream() { - stream.close() - lastStreamOpenEventTimestamp = Date.timeIntervalSinceReferenceDate - try stream.open() - } else { - Logger.warning("Exceeded number of attempts to reopen stream to graphite.") - stream.close() - } - } catch { - Logger.warning("Error re-opening previously closed stream to Graphite: \(error)") - } - } -} diff --git a/Sources/MetricsUtils/String+MetricComponent.swift b/Sources/MetricsUtils/String+MetricComponent.swift deleted file mode 100644 index c4d8d31f..00000000 --- a/Sources/MetricsUtils/String+MetricComponent.swift +++ /dev/null @@ -1,10 +0,0 @@ -import Foundation - -public extension String { - var suitableForMetric: String { - return self - .replacingOccurrences(of: ".", with: "_") - .replacingOccurrences(of: " ", with: "_") - .replacingOccurrences(of: "#", with: "_") - } -} diff --git a/Sources/PathLib/AbsolutePath.swift b/Sources/PathLib/AbsolutePath.swift deleted file mode 100644 index ac1b3831..00000000 --- a/Sources/PathLib/AbsolutePath.swift +++ /dev/null @@ -1,79 +0,0 @@ -import Foundation - -public final class AbsolutePath: Path, Codable, Hashable { - public let components: [String] - - public static let root = AbsolutePath(components: []) - - public static let home = AbsolutePath(NSHomeDirectory()) - - public init(components: [String]) { - self.components = components - } - - public var pathString: String { - return "/" + components.joined(separator: "/") - } - - public var fileUrl: URL { - return URL(fileURLWithPath: pathString) - } - - /// Returns true if current path is a child of given anchor path. - /// Examples: - /// `/path/to/something` is subpath of `/path/to`. - /// `/path/to/something` is NOT subpath of `/path/to/something`. - /// `/path/of/something` is NOT subpath of `/path/to/`. - public func isSubpathOf(anchorPath: AbsolutePath) -> Bool { - guard components.count > anchorPath.components.count else { - return false - } - let headComponents = Array(components.dropLast(components.count - anchorPath.components.count)) - return headComponents == anchorPath.components - } - - /// Finds a `RelativePath` for this instance and a given anchor path. - public func relativePath(anchorPath: AbsolutePath) -> RelativePath { - let pathComponents = components - let anchorComponents = anchorPath.components - - var componentsInCommon = 0 - for (c1, c2) in zip(pathComponents, anchorComponents) { - if c1 != c2 { - break - } - componentsInCommon += 1 - } - - let numberOfParentComponents = anchorComponents.count - componentsInCommon - let numberOfPathComponents = pathComponents.count - componentsInCommon - - var relativeComponents = [String]() - relativeComponents.reserveCapacity(numberOfParentComponents + numberOfPathComponents) - for _ in 0.. Bool { - return left.components == right.components - } -} diff --git a/Sources/PathLib/FileManager+Extensions.swift b/Sources/PathLib/FileManager+Extensions.swift deleted file mode 100644 index 7b9f1b71..00000000 --- a/Sources/PathLib/FileManager+Extensions.swift +++ /dev/null @@ -1,17 +0,0 @@ -import Foundation - -public extension FileManager { - func createDirectory( - atPath path: AbsolutePath, - withIntermediateDirectories: Bool = true - ) throws { - try createDirectory( - atPath: path.pathString, - withIntermediateDirectories: withIntermediateDirectories - ) - } - - var currentAbsolutePath: AbsolutePath { - return AbsolutePath(currentDirectoryPath) - } -} diff --git a/Sources/PathLib/Path+CommonOperations.swift b/Sources/PathLib/Path+CommonOperations.swift deleted file mode 100644 index 333dd5ad..00000000 --- a/Sources/PathLib/Path+CommonOperations.swift +++ /dev/null @@ -1,65 +0,0 @@ -import Foundation - -public extension Path { - init(_ fileUrl: URL) { - self.init(components: StringPathParsing.components(path: fileUrl.path)) - } - - init(_ path: String) { - self.init(components: StringPathParsing.components(path: path)) - } - - func appending(components: [String]) -> Self { - return Self(components: self.components + components) - } - - func appending(relativePath: RelativePath) -> Self { - return Self(components: components + relativePath.components) - } - - func appending(component: String) -> Self { - return Self(components: self.components + [component]) - } - - func appending(extension: String) -> Self { - let lastComponent = self.lastComponent - return removingLastComponent.appending(component: lastComponent + "." + `extension`) - } - - var removingLastComponent: Self { - guard components.count > 0 else { - return self - } - return Self(components: Array(components.dropLast())) - } - - var lastComponent: String { - guard let result = components.last else { - return pathString - } - return result - } - - /// Deletes the filename portion, beginning with the last slash `/' character to the end of string - var dirname: String { - return removingLastComponent.pathString - } - - /// Deletes any prefix ending with the last slash `/' character present in string (after firs stripping trailing slashes) - var basename: String { - return lastComponent - } - - /// Returns a suffix after the last dot symbol in basename. Returns empty string if there is no extension. - /// Correctly handles hidden heading dot ("`.file`" - extension is empty). - var `extension`: String { - let component = lastComponent - guard let dotPosition = component.lastIndex(of: ".") else { - return "" - } - if component.starts(with: "."), component.startIndex == dotPosition { - return "" - } - return String(component.suffix(from: component.index(after: dotPosition))) - } -} diff --git a/Sources/PathLib/Path.swift b/Sources/PathLib/Path.swift deleted file mode 100644 index 6912b762..00000000 --- a/Sources/PathLib/Path.swift +++ /dev/null @@ -1,14 +0,0 @@ -import Foundation - -public protocol Path: CustomStringConvertible { - init(components: [String]) - - var components: [String] { get } - var pathString: String { get } -} - -extension Path { - public var description: String { - return pathString - } -} diff --git a/Sources/PathLib/RelativePath.swift b/Sources/PathLib/RelativePath.swift deleted file mode 100644 index 6698d909..00000000 --- a/Sources/PathLib/RelativePath.swift +++ /dev/null @@ -1,39 +0,0 @@ -import Foundation - -public final class RelativePath: Path, Codable, Hashable { - public let components: [String] - - public static let current = RelativePath(components: []) - - /// Builds a relative paths from given components. If components is empty, relative path will be equal to the current directory (`./`). - public init(components: [String]) { - self.components = components - } - - public var pathString: String { - guard !components.isEmpty else { - return "./" - } - - return components.joined(separator: "/") - } - - public init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - let stringValue = try container.decode(String.self) - self.components = StringPathParsing.components(path: stringValue) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.singleValueContainer() - try container.encode(pathString) - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(components) - } - - public static func == (left: RelativePath, right: RelativePath) -> Bool { - return left.components == right.components - } -} diff --git a/Sources/PathLib/String+ShellEscaping.swift b/Sources/PathLib/String+ShellEscaping.swift deleted file mode 100644 index 04d9fe50..00000000 --- a/Sources/PathLib/String+ShellEscaping.swift +++ /dev/null @@ -1,48 +0,0 @@ -import Foundation - -private func inShellWhitelist(_ codeUnit: UInt8) -> Bool { - switch codeUnit { - case UInt8(ascii: "a")...UInt8(ascii: "z"), - UInt8(ascii: "A")...UInt8(ascii: "Z"), - UInt8(ascii: "0")...UInt8(ascii: "9"), - UInt8(ascii: "-"), - UInt8(ascii: "_"), - UInt8(ascii: "/"), - UInt8(ascii: ":"), - UInt8(ascii: "@"), - UInt8(ascii: "%"), - UInt8(ascii: "+"), - UInt8(ascii: "="), - UInt8(ascii: "."), - UInt8(ascii: ","): - return true - default: - return false - } -} - -public extension String { - func shellEscaped() -> String { - guard let blackListCharacterPosition = utf8.firstIndex(where: { !inShellWhitelist($0) }) else { - return self - } - - guard let singleQuotePosition = utf8[blackListCharacterPosition...].firstIndex(of: UInt8(ascii: "'")) else { - return "'\(self)'" - } - - var result = "'" + String(self[.. [String] { - return path.components(separatedBy: "/").filter { !$0.isEmpty } - } -} diff --git a/Sources/PlistLib/Plist.swift b/Sources/PlistLib/Plist.swift deleted file mode 100644 index 31dd4f84..00000000 --- a/Sources/PlistLib/Plist.swift +++ /dev/null @@ -1,123 +0,0 @@ -import Foundation - -public final class Plist { - /// The root plist entry, either an array or a dict. - public let root: RootPlistEntry - - public init(rootPlistEntry: RootPlistEntry) { - self.root = rootPlistEntry - } - - /// Returns a root object of this plist with all children elements. This can be an `Array` or `Dictionary`. - /// This object can be serialized to a plist format using `PropertyListSerialization`. - public func rootObject() -> Any { root.plistEntry.dumpedValue() } - - /// Creates a `Plist` obejct from given `Data`. - public static func create(fromData data: Data) throws -> Plist { - return Plist(rootPlistEntry: try RootPlistEntry.create(fromData: data)) - } -} - -public extension Plist { - func data(format: PropertyListSerialization.PropertyListFormat) throws -> Data { - return try PropertyListSerialization.data( - fromPropertyList: rootObject(), - format: format, - options: 0 - ) - } -} - -extension RootPlistEntry { - public enum UnexpectedTypeError: CustomStringConvertible, Error { - case unexpectedTypeOfRootObject(Any) - - public var description: String { - switch self { - case .unexpectedTypeOfRootObject(let any): - return "Unexpected root object: \(any)" - } - } - } - - static func create(fromData data: Data, format: UnsafeMutablePointer? = nil) throws -> RootPlistEntry { - let object = try PropertyListSerialization.propertyList( - from: data, - options: [], - format: format - ) - if let dict = object as? NSDictionary { - return RootPlistEntry.dict(try PlistEntry.create(dict: dict)) - } else if let array = object as? NSArray { - return RootPlistEntry.array(try PlistEntry.create(array: array)) - } - throw UnexpectedTypeError.unexpectedTypeOfRootObject(object) - } -} - -public enum PlistReadError: Error { - case keyIsNotTypeOfString(actualKey: Any) - case unrecognizedValue(Any) -} - -extension PlistEntry { - func dumpedValue() -> Any { - switch self { - case .array(let values): - return values.compactMap { $0?.dumpedValue() } - case .dict(let values): - return values.compactMapValues { $0?.dumpedValue() } - case .bool(let value): - return value - case .data(let value): - return value - case .date(let value): - return value - case .number(let value): - return value - case .string(let value): - return value - } - } - - static func create(dict: NSDictionary) throws -> [String: PlistEntry] { - return try dict.reduce(into: [String: PlistEntry]()) { (result: inout [String: PlistEntry], keyValue: (key: Any, value: Any)) in - guard let stringKey = keyValue.key as? String else { - throw PlistReadError.keyIsNotTypeOfString(actualKey: keyValue.key) - } - result[stringKey] = try create(fromAny: keyValue.value) - } - } - - static func create(array: NSArray) throws -> [PlistEntry] { - return try array.map { element in - try create(fromAny: element) - } - } - - static func create(fromAny any: Any) throws -> PlistEntry { - if let arrayElement = any as? NSArray { - return .array( - try PlistEntry.create(array: arrayElement) - ) - } else if let dataElement = any as? Data { - return .data(dataElement) - } else if let stringElement = any as? String { - return .string(stringElement) - } else if let dateElement = any as? Date { - return .date(dateElement) - } else if let numberElement = any as? NSNumber { - if numberElement === kCFBooleanTrue || numberElement === kCFBooleanFalse { - return .bool(numberElement.boolValue) - } else { - return .number(numberElement.doubleValue) - } - } else if let dictElement = any as? NSDictionary { - return .dict( - try PlistEntry.create(dict: dictElement) - ) - } - - throw PlistReadError.unrecognizedValue(any) - } -} diff --git a/Sources/PlistLib/PlistEntry+Access.swift b/Sources/PlistLib/PlistEntry+Access.swift deleted file mode 100644 index b7eaca81..00000000 --- a/Sources/PlistLib/PlistEntry+Access.swift +++ /dev/null @@ -1,160 +0,0 @@ -import Foundation - -public extension PlistEntry { - - // MARK: Dict - - enum PlistEntryError: CustomStringConvertible, Error { - case typeMismatch(PlistEntry, expectedType: Any) - case noObjectForKey(entry: PlistEntry, key: String) - - public var description: String { - switch self { - case .typeMismatch(let entry, let expectedType): - return "Plist entry \(entry) type differs from expected type \(expectedType)" - case .noObjectForKey(let entry, let key): - return "Entry \(entry) does not have object for key \(key)" - } - } - } - - // MARK: Dict - - /// Casts this entry to dict entry and extracts its value. - /// - Throws: Error if this entry is not an dict plist entry. - /// - Returns: Dictionary of `String` to `PlistEntry` elements. - func dictEntry() throws -> [String: PlistEntry] { - try matchType() - } - - /// Casts this entry to dict entry and extracts an optional value for a given key. - /// - Parameter key: The key which `PlistEntry` should be provided, is present. - /// - Throws: Error if this entry is not an dict plist entry. - /// - Returns: `PlistEntry` for a given `key`, or `nil` if no value is present for the given key. - func optionalEntry(forKey key: String) throws -> PlistEntry? { - try dictEntry()[key] - } - - /// Casts this entry to dict entry and extracts an expected value for a given key. - /// - Parameter key: The key which `PlistEntry` should be provided, if present. - /// - Throws: Error if this entry is not an dict plist entry, or if no value is present for the provided `key`. - /// - Returns: `PlistEntry` for a given `key`. - func entry(forKey key: String) throws -> PlistEntry { - guard let entry = try optionalEntry(forKey: key) else { - throw PlistEntryError.noObjectForKey(entry: self, key: key) - } - return entry - } - - /// Casts this entry to dict entry and extracts the optional values for the given keys. - /// - Parameter keys: The keys which `PlistEntry` should be provided, if present. - /// - Throws: Error if this entry is not an dict plist entry. - /// - Returns: A map from key to its plist entry. If the entry is missing for some given key, no error will be thrown. - func optionalEntries(forKeys keys: [String]) throws -> [String: PlistEntry] { - try keys.reduce(into: [String: PlistEntry]()) { (result, key) in - if let entry = try optionalEntry(forKey: key) { - result[key] = entry - } - } - } - - /// Casts this entry to dict entry and extracts the required values for the given keys. - /// - Parameter keys: The keys which `PlistEntry` should be provided, if present. - /// - Throws: Error if this entry is not an dict plist entry, or if entry is missing for any provided key. - /// - Returns: A map from key to its plist entry. - func entries(forKeys keys: [String]) throws -> [String: PlistEntry] { - try keys.reduce(into: [String: PlistEntry]()) { (result, key) in - result[key] = try entry(forKey: key) - } - } - - /// Casts dict entry to a dict whose values are expected to have a single type - /// - Parameter valueType: Expected type of all values of the dictionary - /// - Throws: This method throws error if any value can't be casted to the given type - /// - Returns: Dictionary with string keys and `T` values. - func toTypedDict(_ valueType: T.Type) throws -> [String: T] { - try dictEntry().mapValues { try $0.matchType() } - } - - /// Casts this entry to dict entry and returns its keys. - /// - Throws: Error if this entry is not an dict plist entry. - /// - Returns: An array of keys of dict entry. - func allKeys() throws -> [String] { - Array(try dictEntry().keys.map { String($0) }) - } - - // MARK: Array - - /// Casts this entry to array and extracts its value. - /// - Throws: Error if this entry is not an array plist entry. - /// - Returns: Array of `PlistEntry` elements. - func arrayEntry() throws -> [PlistEntry] { - try matchType() - } - - /// Casts this entry to array and provides a `PlistEntry` under a given `index`. - /// - Throws: Error if this entry is not an array plist entry. - /// - Returns: `PlistEntry` element under given `index`. - func entry(atIndex index: Int) throws -> PlistEntry { - try arrayEntry()[index] - } - - /// Casts array entry to a array whose elements are expected to have a single type `T`. - /// - Parameter valueType: Expected type of all elements of array - /// - Throws: This method throws error if any element can't be casted to the given type - /// - Returns: Array of `T` elements. - func toTypedArray(_ type: T.Type) throws -> [T] { - try arrayEntry().compactMap { try $0.matchType() } - } - - // MARK: Leaf Types Supported by Plist - - func boolValue() throws -> Bool { - try matchType() - } - - func stringValue() throws -> String { - try matchType() - } - - func numberValue() throws -> Double { - try matchType() - } - - func dateValue() throws -> Date { - try matchType() - } - - func dataValue() throws -> Data { - try matchType() - } - - // MARK: Casting to any Type - - /// Casts this plist entry to a given type `T`. - /// Plist supports a limited set of types: `Array`, `Dictionary` with `String` keys, `Date`, `Data`, `Bool`, `Number` (represented as `Double` here for simplicity), `String`. - /// Attempt to cast to any other type will likely throw an error. - /// Note: array and dict entries will return a value with `PlistEntry` objects. Use array and dict specific shortcut methods to cast the whole collection to a desired type instead. - /// - Throws: `PlistEntryError` if this plist entry type is not castable to `T`. - /// - Returns: A value casted to `T`. - func matchType() throws -> T { - switch self { - case .array(let value): - if let value = value as? T { return value } - case .dict(let value): - if let value = value as? T { return value } - case .bool(let value): - if let value = value as? T { return value } - case .data(let value): - if let value = value as? T { return value } - case .date(let value): - if let value = value as? T { return value } - case .number(let value): - if let value = value as? T { return value } - case .string(let value): - if let value = value as? T { return value } - } - - throw PlistEntryError.typeMismatch(self, expectedType: T.self) - } -} diff --git a/Sources/PlistLib/PlistEntry.swift b/Sources/PlistLib/PlistEntry.swift deleted file mode 100644 index ee820924..00000000 --- a/Sources/PlistLib/PlistEntry.swift +++ /dev/null @@ -1,30 +0,0 @@ -import Foundation - -public indirect enum PlistEntry: CustomStringConvertible, Equatable { - case array([PlistEntry?]) - case bool(Bool) - case data(Data) - case date(Date) - case dict([String: PlistEntry?]) - case number(Double) - case string(String) - - public var description: String { - switch self { - case .array(let element): - return "" - case .bool(let element): - return "" - case .data(let element): - return "" - case .date(let element): - return "" - case .dict(let element): - return "" - case .number(let element): - return "" - case .string(let element): - return "" - } - } -} diff --git a/Sources/PlistLib/README.md b/Sources/PlistLib/README.md deleted file mode 100644 index 5e3bebb2..00000000 --- a/Sources/PlistLib/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# PlistLib - -Class `Plist` provides a little DSL around the property lists, avoiding you to query it without casting it to `NSArray` or `NSDictionary` and dealing with casting of leaf values and optionality. -This class also allows you to compose the plist: - -## Creating Plist - -```swift -let plist = Plist(rootPlistEntry: .array([ - .string("first object in array"), - .dict(["key": .bool(true)]) -])) -``` - -For convenience, `array` and `dict` entries accept optional values, which will be ommited when actual Plist data will be generated: - -``` -.dict([ - "key": .bool(true), - "optional_key": nil, -]) -``` - -## Querying Plist - -Basic query: - -```swift -try plist.root.plistEntry.entry(atIndex: 0).stringValue() // "first object in array" - -try plist.root.plistEntry.entry(atIndex: 1).entry(forKey: "key").boolValue() // true - -try plist.root.plistEntry.dataValue() // throws an error, because plist entry is array. -``` - -If you want to cast array to a Swift generic Array: - -``` -let plist = Plist(rootPlistEntry: .array([ - .string("first object"), - .string("second object"), -])) - -let array = try plist.root.plistEntry.typedArray(String.self) // ["first object", "second object"] -``` - -Same for dicts: - -``` -let plist = Plist(rootPlistEntry: .dict([ - "key": .string("value"), - "another_key": .string("one more"), -])) - -let dict = try plist.root.plistEntry.typedDict(String.self) // [key" : "value", "another_key" : "one more"] -``` diff --git a/Sources/PlistLib/RootPlistEntry.swift b/Sources/PlistLib/RootPlistEntry.swift deleted file mode 100644 index aec37e71..00000000 --- a/Sources/PlistLib/RootPlistEntry.swift +++ /dev/null @@ -1,26 +0,0 @@ -import Foundation - -/// This is a plist root object. Plists may have only an array or dict as their root objects. -public enum RootPlistEntry: CustomStringConvertible, Equatable { - case array([PlistEntry]) - case dict([String: PlistEntry]) - - /// Provides `PlistEntry` from this root object, this should be used to query plist. - public var plistEntry: PlistEntry { - switch self { - case .array(let value): - return .array(value) - case .dict(let value): - return .dict(value) - } - } - - public var description: String { - switch self { - case .array(let element): - return "" - case .dict(let element): - return "" - } - } -} diff --git a/Sources/PluginManager/PluginManager.swift b/Sources/PluginManager/PluginManager.swift index 572eed25..f72d7e9b 100644 --- a/Sources/PluginManager/PluginManager.swift +++ b/Sources/PluginManager/PluginManager.swift @@ -115,8 +115,8 @@ public final class PluginManager: EventStream { } } - private func environmentForLaunchingPlugin(pluginSocket: String, pluginIdentifier: String) -> [String: String] { - return [ + private func environmentForLaunchingPlugin(pluginSocket: String, pluginIdentifier: String) -> Environment { + [ PluginSupport.pluginSocketEnv: pluginSocket, PluginSupport.pluginIdentifierEnv: pluginIdentifier ] diff --git a/Sources/ProcessController/AutomaticManagement.swift b/Sources/ProcessController/AutomaticManagement.swift deleted file mode 100644 index cf7fe12f..00000000 --- a/Sources/ProcessController/AutomaticManagement.swift +++ /dev/null @@ -1,95 +0,0 @@ -import Foundation -import SignalHandling -import Logging - -public enum AutomaticManagementItem: CustomStringConvertible, Equatable { - case signalWhenSilent(Signal, TimeInterval) - case signalAfter(Signal, TimeInterval) - - var signal: Signal { - switch self { - case .signalAfter(let signal, _): - return signal - case .signalWhenSilent(let signal, _): - return signal - } - } - - var timeInterval: TimeInterval { - switch self { - case .signalAfter(_, let interval): - return interval - case .signalWhenSilent(_, let interval): - return interval - } - } - - public var description: String { - switch self { - case .signalWhenSilent(let signal, let interval): - return "send \(signal) when silent for \(interval) sec" - case .signalAfter(let signal, let interval): - return "send \(signal) after running for \(interval) sec" - } - } -} - -public struct AutomaticManagement: CustomStringConvertible, Equatable { - public let items: [AutomaticManagementItem] - - public init(items: [AutomaticManagementItem]) { - self.items = items - } - - public var description: String { - var elements: [String] = ["\(type(of: self))"] - if items.isEmpty { - elements.append("no automatic management") - } else { - elements.append("items: \(items)") - } - return "<" + elements.joined(separator: " ") + ">" - } - - public static let noManagement = AutomaticManagement(items: []) - - public static func multiple(_ items: [AutomaticManagementItem]) -> AutomaticManagement { - AutomaticManagement(items: items) - } - - public static func sigintThenKillIfSilent(interval: TimeInterval, killAfter: TimeInterval = 15) -> AutomaticManagement { - AutomaticManagement( - items: [ - .signalWhenSilent(.int, interval), - .signalWhenSilent(.kill, interval + killAfter), - ] - ) - } - - public static func sigtermThenKillIfSilent(interval: TimeInterval, killAfter: TimeInterval = 15) -> AutomaticManagement { - AutomaticManagement( - items: [ - .signalWhenSilent(.term, interval), - .signalWhenSilent(.kill, interval + killAfter), - ] - ) - } - - public static func sigintThenKillAfterRunningFor(interval: TimeInterval, killAfter: TimeInterval = 15) -> AutomaticManagement { - AutomaticManagement( - items: [ - .signalAfter(.int, interval), - .signalAfter(.kill, interval + killAfter), - ] - ) - } - - public static func sigtermThenKillAfterRunningFor(interval: TimeInterval, killAfter: TimeInterval = 15) -> AutomaticManagement { - AutomaticManagement( - items: [ - .signalAfter(.term, interval), - .signalAfter(.kill, interval + killAfter), - ] - ) - } -} diff --git a/Sources/ProcessController/AutomaticManagementItemController.swift b/Sources/ProcessController/AutomaticManagementItemController.swift deleted file mode 100644 index 04bb53e9..00000000 --- a/Sources/ProcessController/AutomaticManagementItemController.swift +++ /dev/null @@ -1,48 +0,0 @@ -import AtomicModels -import DateProvider -import Foundation -import SignalHandling -import Logging - -final class AutomaticManagementItemController { - private let dateProvider: DateProvider - private let item: AutomaticManagementItem - private let lastActivityEvent = AtomicValue(nil) - - init( - dateProvider: DateProvider, - item: AutomaticManagementItem - ) { - self.dateProvider = dateProvider - self.item = item - } - - func processReportedActivity() { - switch item { - case .signalAfter: - break - case .signalWhenSilent: - lastActivityEvent.set(dateProvider.currentDate()) - } - } - - func fireEventIfNecessary(processController: ProcessController) { - guard processController.isProcessRunning else { - lastActivityEvent.set(nil) - Logger.debug("Cannot automatically manage process \(processController.processName)[\(processController.processId)]: process is not running") - return - } - let lastActivityEventDate: Date - if let eventDate = lastActivityEvent.currentValue() { - lastActivityEventDate = eventDate - } else { - lastActivityEventDate = dateProvider.currentDate() - lastActivityEvent.set(lastActivityEventDate) - } - - if dateProvider.currentDate() > lastActivityEventDate.addingTimeInterval(item.timeInterval) { - processController.send(signal: item.signal.intValue) - lastActivityEvent.set(nil) - } - } -} diff --git a/Sources/ProcessController/DefaultProcessController.swift b/Sources/ProcessController/DefaultProcessController.swift deleted file mode 100644 index 8f73e91b..00000000 --- a/Sources/ProcessController/DefaultProcessController.swift +++ /dev/null @@ -1,373 +0,0 @@ -import DateProvider -import Dispatch -import FileSystem -import Foundation -import Logging -import LoggingSetup -import PathLib -import Timer - -public final class DefaultProcessController: ProcessController, CustomStringConvertible { - public let subprocess: Subprocess - public let processName: String - public private(set) var processId: Int32 = 0 - - private let automaticManagementItemControllers: [AutomaticManagementItemController] - private let fileSystem: FileSystem - let listenerQueue = DispatchQueue(label: "DefaultProcessController.listenerQueue") - private let openPipeFileHandleGroup = DispatchGroup() - private let process: Process - private let processTerminationHandlerGroup = DispatchGroup() - private let processTerminationQueue = DispatchQueue(label: "DefaultProcessController.processTerminationQueue") - private var automaticManagementTrackingTimer: DispatchBasedTimer? - - private var didInitiateKillOfProcess = false - private var didStartProcess = false - private var signalListeners = [ListenerWrapper]() - private var startListeners = [ListenerWrapper]() - private var stderrListeners = [ListenerWrapper]() - private var stdoutListeners = [ListenerWrapper]() - private var terminationListeners = [ListenerWrapper]() - - private final class ListenerWrapper { - let uuid: UUID - let listener: T - - init(uuid: UUID, listener: T) { - self.uuid = uuid - self.listener = listener - } - } - - public init( - dateProvider: DateProvider, - fileSystem: FileSystem, - subprocess: Subprocess - ) throws { - automaticManagementItemControllers = subprocess.automaticManagement.items.map { item in - AutomaticManagementItemController(dateProvider: dateProvider, item: item) - } - - let arguments = try subprocess.arguments.map { try $0.stringValue() } - processName = arguments.elementAtIndex(0, "First element is path to executable").lastPathComponent - process = try DefaultProcessController.createProcess( - fileSystem: fileSystem, - arguments: arguments, - environment: subprocess.environment, - workingDirectory: subprocess.workingDirectory - ) - - let logFolder = try fileSystem.folderForStoringLogs(processName: processName) - let uniqueString = ProcessInfo.processInfo.globallyUniqueString - self.subprocess = subprocess.byRedefiningOutput { - $0.byRedefiningIfNotSet( - stdoutOutputPath: logFolder.appending(component: uniqueString + "_stdout.log"), - stderrOutputPath: logFolder.appending(component: uniqueString + "_stderr.log") - ) - } - self.fileSystem = fileSystem - - try setUpProcessListening() - } - - private static func createProcess( - fileSystem: FileSystem, - arguments: [String], - environment: [String: String], - workingDirectory: AbsolutePath - ) throws -> Process { - let pathToExecutable = AbsolutePath(arguments.elementAtIndex(0, "Path to executable")) - - let executableProperties = fileSystem.properties(forFileAtPath: pathToExecutable) - - guard try executableProperties.isExecutable() else { - throw ProcessControllerError.fileIsNotExecutable(path: pathToExecutable) - } - - let process = Process() - process.launchPath = pathToExecutable.pathString - process.arguments = Array(arguments.dropFirst()) - process.environment = environment - process.currentDirectoryPath = workingDirectory.pathString - try process.setStartsNewProcessGroup(false) - return process - } - - public var description: String { - let executable = process.launchPath ?? "unknown executable" - let args = process.arguments?.joined(separator: " ") ?? "" - return "<\(type(of: self)): \(executable) \(args) \(processStatus())>" - } - - // MARK: - Launch and Kill - - public func start() { - if didStartProcess { - return - } - - didStartProcess = true - Logger.debug("Starting subprocess: \(subprocess)", subprocessInfo) - process.launch() - processTerminationHandlerGroup.enter() - process.terminationHandler = { _ in - OrphanProcessTracker().removeProcessFromCleanup(pid: self.processId, name: self.processName) - self.processTerminated() - } - processId = process.processIdentifier - OrphanProcessTracker().storeProcessForCleanup(pid: processId, name: processName) - Logger.debug("Started process \(processId)", subprocessInfo) - startAutomaticManagement() - - listenerQueue.async { - for listenerWrapper in self.startListeners { - let unsubscriber: Unsubscribe = { - self.listenerQueue.async { - self.startListeners.removeAll { $0.uuid == listenerWrapper.uuid } - } - } - listenerWrapper.listener(self, unsubscriber) - } - } - } - - public func waitForProcessToDie() { - process.waitUntilExit() - openPipeFileHandleGroup.wait() - processTerminationHandlerGroup.wait() - } - - public func processStatus() -> ProcessStatus { - if !didStartProcess { - return .notStarted - } - if process.isRunning { - return .stillRunning - } - return .terminated(exitCode: process.terminationStatus) - } - - public func send(signal: Int32) { - listenerQueue.async { - for listenerWrapper in self.signalListeners { - let unsubscriber: Unsubscribe = { - self.listenerQueue.async { - self.signalListeners.removeAll { $0.uuid == listenerWrapper.uuid } - } - } - listenerWrapper.listener(self, signal, unsubscriber) - } - - Logger.debug("Signalling \(signal)", self.subprocessInfo) - kill(-self.processId, signal) - } - } - - public func terminateAndForceKillIfNeeded() { - attemptToKillProcess { process in - Logger.debug("Terminating the process", subprocessInfo) - send(signal: SIGTERM) - } - } - - public func interruptAndForceKillIfNeeded() { - attemptToKillProcess { process in - Logger.debug("Interrupting the process", subprocessInfo) - send(signal: SIGINT) - } - } - - public func onStart(listener: @escaping StartListener) { - startListeners.append(ListenerWrapper(uuid: UUID(), listener: listener)) - } - - public func onStdout(listener: @escaping StdoutListener) { - stdoutListeners.append(ListenerWrapper(uuid: UUID(), listener: listener)) - } - - public func onStderr(listener: @escaping StderrListener) { - stderrListeners.append(ListenerWrapper(uuid: UUID(), listener: listener)) - } - - public func onSignal(listener: @escaping SignalListener) { - signalListeners.append(ListenerWrapper(uuid: UUID(), listener: listener)) - } - - public func onTermination(listener: @escaping TerminationListener) { - terminationListeners.append(ListenerWrapper(uuid: UUID(), listener: listener)) - } - - private func attemptToKillProcess(killer: (Process) -> ()) { - processTerminationQueue.sync { - guard self.didInitiateKillOfProcess == false else { return } - self.didInitiateKillOfProcess = true - killer(process) - processTerminationQueue.asyncAfter(deadline: .now() + 15.0) { - self.forceKillProcess() - } - } - } - - private func forceKillProcess() { - if isProcessRunning { - Logger.warning("Failed to interrupt the process in time, terminating", subprocessInfo) - send(signal: SIGKILL) - - signalListeners.removeAll() - startListeners.removeAll() - stderrListeners.removeAll() - stdoutListeners.removeAll() - } - } - - private func processTerminated() { - Logger.debug("Process terminated", subprocessInfo) - - listenerQueue.async { - for listenerWrapper in self.terminationListeners { - let unsubscriber: Unsubscribe = { - self.listenerQueue.async { - self.signalListeners.removeAll { $0.uuid == listenerWrapper.uuid } - } - } - listenerWrapper.listener(self, unsubscriber) - } - } - - listenerQueue.async(flags: .barrier) { - self.processTerminationHandlerGroup.leave() - } - } - - // MARK: - Hang Monitoring - - private func startAutomaticManagement() { - Logger.debug("Will start automatic process management", subprocessInfo) - - automaticManagementTrackingTimer = DispatchBasedTimer.startedTimer(repeating: .seconds(1), leeway: .seconds(1)) { [weak self] timer in - guard let strongSelf = self else { return timer.stop() } - - strongSelf.automaticManagementItemControllers.forEach { $0.fireEventIfNecessary(processController: strongSelf) } - } - } - - // MARK: - Processing Output - - private func streamFromPipeIntoHandle( - pipe: Pipe, - storageHandle: FileHandle, - onNewData: @escaping (Data) -> (), - onEndOfData: @escaping () -> Void - ) { - pipe.fileHandleForReading.readabilityHandler = { handle in - let data = handle.availableData - if data.isEmpty { - storageHandle.closeFile() - handle.readabilityHandler = nil - onEndOfData() - } else { - storageHandle.write(data) - onNewData(data) - } - } - } - - private func setUpProcessListening() throws { - storeStdForProcess( - path: try subprocess.standardStreamsCaptureConfig.stdoutOutputPath(), - onError: { message in - Logger.warning("Will not store stdout output: \(message)", subprocessInfo) - }, - pipeAssigningClosure: { pipe in - self.process.standardOutput = pipe - self.openPipeFileHandleGroup.enter() - }, - onNewData: didReceiveStdout, - onEndOfData: { - self.listenerQueue.async { - self.openPipeFileHandleGroup.leave() - } - } - ) - - storeStdForProcess( - path: try subprocess.standardStreamsCaptureConfig.stderrOutputPath(), - onError: { message in - Logger.warning("Will not store stderr output: \(message)", subprocessInfo) - }, - pipeAssigningClosure: { pipe in - self.process.standardError = pipe - self.openPipeFileHandleGroup.enter() - }, - onNewData: didReceiveStderr, - onEndOfData: { - self.listenerQueue.async { - self.openPipeFileHandleGroup.leave() - } - } - ) - } - - private func storeStdForProcess( - path: AbsolutePath, - onError: (String) -> (), - pipeAssigningClosure: (Pipe) -> (), - onNewData: @escaping (Data) -> (), - onEndOfData: @escaping () -> () - ) { - guard FileManager.default.createFile(atPath: path.pathString, contents: nil) else { - onError("Failed to create a file at path: '\(path)'") - return - } - guard let storageHandle = FileHandle(forWritingAtPath: path.pathString) else { - onError("Failed to open file handle") - return - } - let pipe = Pipe() - pipeAssigningClosure(pipe) - streamFromPipeIntoHandle( - pipe: pipe, - storageHandle: storageHandle, - onNewData: { data in - self.didProcessDataFromProcess() - onNewData(data) - }, - onEndOfData: { - onEndOfData() - } - ) - } - - private func didReceiveStdout(data: Data) { - listenerQueue.async { - for listenerWrapper in self.stdoutListeners { - let unsubscriber: Unsubscribe = { - self.listenerQueue.async { - self.stdoutListeners.removeAll { $0.uuid == listenerWrapper.uuid } - } - } - listenerWrapper.listener(self, data, unsubscriber) - } - } - } - - private func didReceiveStderr(data: Data) { - listenerQueue.async { - for listenerWrapper in self.stderrListeners { - let unsubscriber: Unsubscribe = { - self.listenerQueue.async { - self.stderrListeners.removeAll { $0.uuid == listenerWrapper.uuid } - } - } - listenerWrapper.listener(self, data, unsubscriber) - } - } - } - - private func didProcessDataFromProcess() { - for controller in automaticManagementItemControllers { - controller.processReportedActivity() - } - } -} - diff --git a/Sources/ProcessController/DefaultProcessControllerProvider.swift b/Sources/ProcessController/DefaultProcessControllerProvider.swift deleted file mode 100644 index 807c4fea..00000000 --- a/Sources/ProcessController/DefaultProcessControllerProvider.swift +++ /dev/null @@ -1,24 +0,0 @@ -import DateProvider -import Foundation -import FileSystem - -public final class DefaultProcessControllerProvider: ProcessControllerProvider { - private let dateProvider: DateProvider - private let fileSystem: FileSystem - - public init( - dateProvider: DateProvider, - fileSystem: FileSystem - ) { - self.dateProvider = dateProvider - self.fileSystem = fileSystem - } - - public func createProcessController(subprocess: Subprocess) throws -> ProcessController { - return try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: subprocess - ) - } -} diff --git a/Sources/ProcessController/OrphanProcessTracker.swift b/Sources/ProcessController/OrphanProcessTracker.swift deleted file mode 100644 index f5850fce..00000000 --- a/Sources/ProcessController/OrphanProcessTracker.swift +++ /dev/null @@ -1,90 +0,0 @@ -import Foundation -import Logging - -public final class OrphanProcessTracker { - private final class Coordinates: Codable, Hashable { - let pid: Int32 - let name: String - - init(pid: Int32, name: String) { - self.pid = pid - self.name = name - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(pid) - hasher.combine(name) - } - - public static func == (left: OrphanProcessTracker.Coordinates, right: OrphanProcessTracker.Coordinates) -> Bool { - return left.pid == right.pid && left.name == right.name - } - } - - public static let envName = "EMCEE_ORPHAN_PROCESSES_FILE" - - public init() {} - - public func storeProcessForCleanup(pid: Int32, name: String) { - whileLocked { - var contents = load() - contents.insert(Coordinates(pid: pid, name: name)) - save(contents) - Logger.debug("Added process \(name):\(pid) to orphan tracking list") - } - } - - public func removeProcessFromCleanup(pid: Int32, name: String) { - whileLocked { - var contents = load() - if let existingProcessData = contents.remove(Coordinates(pid: pid, name: name)) { - save(contents) - Logger.debug("Removed process \(existingProcessData.name):\(existingProcessData.pid) from orphan tracking list") - } else { - Logger.debug("Cannot remove process \(name):\(pid) from orphan tracking list, it is not in the list") - } - } - } - - public func killAll() { - whileLocked { - let coordinates = load() - for coordinate in coordinates { - Logger.debug("Killing: \(coordinate.name):\(coordinate.pid)") - // kills the whole process group - kill(-coordinate.pid, SIGKILL) - } - try? FileManager.default.removeItem(atPath: storagePath) - } - } - - // MARK: - Private stuff - - private let lock = NSRecursiveLock() - private var encoder = JSONEncoder() - private var decoder = JSONDecoder() - private var storagePath: String { - if let specificPath = ProcessInfo.processInfo.environment[OrphanProcessTracker.envName], !specificPath.isEmpty { - return specificPath - } else { - return ProcessInfo.processInfo.executablePath.appending("_orphans.json.ignored") - } - } - - private func load() -> Set { - guard let contents = try? Data(contentsOf: URL(fileURLWithPath: storagePath)) else { return Set() } - guard let array = try? decoder.decode([Coordinates].self, from: contents) else { return Set() } - return Set(array) - } - - private func save(_ coordinates: Set) { - guard let data = try? encoder.encode(coordinates) else { return } - try? data.write(to: URL(fileURLWithPath: storagePath)) - } - - private func whileLocked(work: () -> ()) { - lock.lock() - defer { lock.unlock() } - work() - } -} diff --git a/Sources/ProcessController/ParentProcessTracker.swift b/Sources/ProcessController/ParentProcessTracker.swift deleted file mode 100644 index e5b6c953..00000000 --- a/Sources/ProcessController/ParentProcessTracker.swift +++ /dev/null @@ -1,41 +0,0 @@ -import Dispatch -import Foundation -import Logging -import Timer - -public final class ParentProcessTracker { - private var timer: DispatchBasedTimer? - private let whenParentDies: () -> () - private let parentPid: Int32 - - public enum `Error`: Swift.Error { - case noParentPidProvided - } - - public static let envName = "EMCEE_OUTER_PROCESS_ID" - - public init(whenParentDies: @escaping () -> ()) throws { - self.whenParentDies = whenParentDies - guard let parentPidValue = ProcessInfo.processInfo.environment[ParentProcessTracker.envName], - let parentPid = Int32(parentPidValue) else - { - throw Error.noParentPidProvided - } - self.parentPid = parentPid - startTracking() - } - - private var parentIsAlive: Bool { - return kill(parentPid, 0) == 0 - } - - private func startTracking() { - Logger.debug("Will track parent process aliveness: \(parentPid)") - self.timer = DispatchBasedTimer.startedTimer(repeating: .seconds(1), leeway: .seconds(1)) { timer in - if !self.parentIsAlive { - self.whenParentDies() - timer.stop() - } - } - } -} diff --git a/Sources/ProcessController/ProcessController.swift b/Sources/ProcessController/ProcessController.swift deleted file mode 100644 index 1ed6e42f..00000000 --- a/Sources/ProcessController/ProcessController.swift +++ /dev/null @@ -1,60 +0,0 @@ -import Foundation -import Logging - -public protocol ProcessController: class { - var subprocess: Subprocess { get } - var processName: String { get } - var processId: Int32 { get } - - func start() - func waitForProcessToDie() - func processStatus() -> ProcessStatus - func send(signal: Int32) - - func terminateAndForceKillIfNeeded() - func interruptAndForceKillIfNeeded() - - func onSignal(listener: @escaping SignalListener) - func onStart(listener: @escaping StartListener) - func onStderr(listener: @escaping StderrListener) - func onStdout(listener: @escaping StdoutListener) - func onTermination(listener: @escaping TerminationListener) -} - -public enum ProcessTerminationError: Error, CustomStringConvertible { - case unexpectedProcessStatus(name: String, pid: Int32, processStatus: ProcessStatus) - - public var description: String { - switch self { - case .unexpectedProcessStatus(let name, let pid, let status): - return "Process \(name)[\(pid)] has finished with unexpected status: \(status)" - } - } -} - -public extension ProcessController { - func startAndListenUntilProcessDies() { - start() - waitForProcessToDie() - } - - var isProcessRunning: Bool { - return processStatus() == .stillRunning - } - - var subprocessInfo: SubprocessInfo { - return SubprocessInfo(subprocessId: processId, subprocessName: processName) - } - - func startAndWaitForSuccessfulTermination() throws { - startAndListenUntilProcessDies() - let status = processStatus() - guard status == .terminated(exitCode: 0) else { - throw ProcessTerminationError.unexpectedProcessStatus(name: processName, pid: processId, processStatus: status) - } - } - - func forceKillProcess() { - send(signal: SIGKILL) - } -} diff --git a/Sources/ProcessController/ProcessControllerError.swift b/Sources/ProcessController/ProcessControllerError.swift deleted file mode 100644 index f9681ad3..00000000 --- a/Sources/ProcessController/ProcessControllerError.swift +++ /dev/null @@ -1,13 +0,0 @@ -import Foundation -import PathLib - -public enum ProcessControllerError: CustomStringConvertible, Error { - case fileIsNotExecutable(path: AbsolutePath) - - public var description: String { - switch self { - case .fileIsNotExecutable(let path): - return "File is not executable: \(path)" - } - } -} diff --git a/Sources/ProcessController/ProcessControllerProvider.swift b/Sources/ProcessController/ProcessControllerProvider.swift deleted file mode 100644 index b0b1ed72..00000000 --- a/Sources/ProcessController/ProcessControllerProvider.swift +++ /dev/null @@ -1,5 +0,0 @@ -import Foundation - -public protocol ProcessControllerProvider { - func createProcessController(subprocess: Subprocess) throws -> ProcessController -} diff --git a/Sources/ProcessController/ProcessListener.swift b/Sources/ProcessController/ProcessListener.swift deleted file mode 100644 index 3a001067..00000000 --- a/Sources/ProcessController/ProcessListener.swift +++ /dev/null @@ -1,8 +0,0 @@ -import Foundation - -public typealias Unsubscribe = () -> Void -public typealias SignalListener = (ProcessController, Int32, @escaping Unsubscribe) -> Void -public typealias StartListener = (ProcessController, @escaping Unsubscribe) -> Void -public typealias StderrListener = (ProcessController, Data, @escaping Unsubscribe) -> Void -public typealias StdoutListener = (ProcessController, Data, @escaping Unsubscribe) -> Void -public typealias TerminationListener = (ProcessController, @escaping Unsubscribe) -> Void diff --git a/Sources/ProcessController/ProcessStatus.swift b/Sources/ProcessController/ProcessStatus.swift deleted file mode 100644 index d6a9678c..00000000 --- a/Sources/ProcessController/ProcessStatus.swift +++ /dev/null @@ -1,18 +0,0 @@ -import Foundation - -public enum ProcessStatus: Equatable, CustomStringConvertible { - case notStarted - case stillRunning - case terminated(exitCode: Int32) - - public var description: String { - switch self { - case .notStarted: - return "not started" - case .stillRunning: - return "still running" - case .terminated(let exitCode): - return "exit code \(exitCode)" - } - } -} diff --git a/Sources/ProcessController/StandardStreamsCaptureConfig.swift b/Sources/ProcessController/StandardStreamsCaptureConfig.swift deleted file mode 100644 index 9f982a76..00000000 --- a/Sources/ProcessController/StandardStreamsCaptureConfig.swift +++ /dev/null @@ -1,54 +0,0 @@ -import Foundation -import PathLib - -public final class StandardStreamsCaptureConfig: CustomStringConvertible { - private let stdoutPath: AbsolutePath? - private let stderrPath: AbsolutePath? - - public init( - stdoutPath: AbsolutePath? = nil, - stderrPath: AbsolutePath? = nil - ) { - self.stdoutPath = stdoutPath - self.stderrPath = stderrPath - } - - public var description: String { - let stdout = stdoutPath?.pathString ?? "null" - let stderr = stderrPath?.pathString ?? "null" - return "" - } - - public enum PathIsNotSetError: Error, CustomStringConvertible { - case stdoutPathNotSet - case stderrPathNotSet - - public var description: String { - switch self { - case .stderrPathNotSet: - return "Stderr file path for output is not set. Use config from running process instance." - case .stdoutPathNotSet: - return "Stdout file path for output is not set. Use config from running process instance." - } - } - } - - public func stdoutOutputPath() throws -> AbsolutePath { - guard let path = stdoutPath else { throw PathIsNotSetError.stdoutPathNotSet } - return path - } - - public func stderrOutputPath() throws -> AbsolutePath { - guard let path = stderrPath else { throw PathIsNotSetError.stderrPathNotSet } - return path - } -} - -extension StandardStreamsCaptureConfig { - func byRedefiningIfNotSet(stdoutOutputPath: AbsolutePath, stderrOutputPath: AbsolutePath) -> StandardStreamsCaptureConfig { - StandardStreamsCaptureConfig( - stdoutPath: stdoutPath ?? stdoutOutputPath, - stderrPath: stderrPath ?? stderrOutputPath - ) - } -} diff --git a/Sources/ProcessController/Subprocess+RedefiningOutput.swift b/Sources/ProcessController/Subprocess+RedefiningOutput.swift deleted file mode 100644 index 59dd387d..00000000 --- a/Sources/ProcessController/Subprocess+RedefiningOutput.swift +++ /dev/null @@ -1,15 +0,0 @@ -import Foundation - -extension Subprocess { - func byRedefiningOutput( - redefiner: (StandardStreamsCaptureConfig) throws -> StandardStreamsCaptureConfig - ) rethrows -> Subprocess { - Subprocess( - arguments: arguments, - environment: environment, - automaticManagement: automaticManagement, - standardStreamsCaptureConfig: try redefiner(standardStreamsCaptureConfig), - workingDirectory: workingDirectory - ) - } -} diff --git a/Sources/ProcessController/Subprocess.swift b/Sources/ProcessController/Subprocess.swift deleted file mode 100644 index c9c9e5fa..00000000 --- a/Sources/ProcessController/Subprocess.swift +++ /dev/null @@ -1,30 +0,0 @@ -import Foundation -import PathLib - -public class Subprocess: CustomStringConvertible { - public let arguments: [SubprocessArgument] - public let environment: [String: String] - public let automaticManagement: AutomaticManagement - public let standardStreamsCaptureConfig: StandardStreamsCaptureConfig - public let workingDirectory: AbsolutePath - - public init( - arguments: [SubprocessArgument], - environment: [String: String] = [:], - automaticManagement: AutomaticManagement = .noManagement, - standardStreamsCaptureConfig: StandardStreamsCaptureConfig = StandardStreamsCaptureConfig(), - workingDirectory: AbsolutePath = FileManager.default.currentAbsolutePath - ) { - self.arguments = arguments - self.environment = environment - self.automaticManagement = automaticManagement - self.standardStreamsCaptureConfig = standardStreamsCaptureConfig - self.workingDirectory = workingDirectory - } - - public var description: String { - let environmentDescription = environment.map { "\($0.key)=\($0.value)" }.joined(separator: " ") - let argumentsDescription = arguments.map { "\"\($0)\"" }.joined(separator: " ") - return "<\(type(of: self)) \(environmentDescription) \(argumentsDescription), working dir: \(workingDirectory), std: \(standardStreamsCaptureConfig), automatic management: \(automaticManagement)>" - } -} diff --git a/Sources/ProcessController/SubprocessArgument.swift b/Sources/ProcessController/SubprocessArgument.swift deleted file mode 100644 index 5677e410..00000000 --- a/Sources/ProcessController/SubprocessArgument.swift +++ /dev/null @@ -1,36 +0,0 @@ -import Foundation -import PathLib - -public protocol SubprocessArgument { - func stringValue() throws -> String -} - -extension String: SubprocessArgument { - public func stringValue() throws -> String { - return self - } -} - -extension AbsolutePath: SubprocessArgument { - public func stringValue() throws -> String { - return pathString - } -} - -public final class JoinedSubprocessArgument: SubprocessArgument, CustomStringConvertible { - private let components: [SubprocessArgument] - private let separator: String - - public init(components: [SubprocessArgument], separator: String) { - self.components = components - self.separator = separator - } - - public func stringValue() throws -> String { - return try components.map { try $0.stringValue() }.joined(separator: separator) - } - - public var description: String { - return components.map { "\($0)" }.joined(separator: " ") - } -} diff --git a/Sources/ResourceLocationResolver/ResourceLocationResolverImpl.swift b/Sources/ResourceLocationResolver/ResourceLocationResolverImpl.swift index 50001eb2..bf64a6a2 100644 --- a/Sources/ResourceLocationResolver/ResourceLocationResolverImpl.swift +++ b/Sources/ResourceLocationResolver/ResourceLocationResolverImpl.swift @@ -65,7 +65,7 @@ public final class ResourceLocationResolverImpl: ResourceLocationResolver { let contentsPath = zipFilePath.removingLastComponent.appending(component: "zip_contents") try unarchiveQueue.sync { try urlResource.whileLocked { - if try !fileSystem.properties(forFileAtPath: contentsPath).exists() { + if !fileSystem.properties(forFileAtPath: contentsPath).exists() { let temporaryContentsPath = zipFilePath.removingLastComponent.appending( component: "zip_contents_\(UUID().uuidString)" ) diff --git a/Sources/Runner/ProcessControllerWrappingTestRunnerInvocation.swift b/Sources/Runner/ProcessControllerWrappingTestRunnerInvocation.swift index 72d02ae5..698c56f2 100644 --- a/Sources/Runner/ProcessControllerWrappingTestRunnerInvocation.swift +++ b/Sources/Runner/ProcessControllerWrappingTestRunnerInvocation.swift @@ -19,12 +19,8 @@ public class ProcessControllerWrappingTestRunnerInvocation: TestRunnerInvocation processController.terminateAndForceKillIfNeeded() } - public var subprocessInfo: SubprocessInfo { - SubprocessInfo(subprocessId: processController.processId, subprocessName: processController.processName) - } - - public var output: StandardStreamsCaptureConfig { - processController.subprocess.standardStreamsCaptureConfig + public var pidInfo: PidInfo { + PidInfo(pid: processController.processId, name: processController.processName) } public func wait() { diff --git a/Sources/Runner/ProcessOutputSilenceTracker.swift b/Sources/Runner/ProcessOutputSilenceTracker.swift deleted file mode 100644 index ba95dde0..00000000 --- a/Sources/Runner/ProcessOutputSilenceTracker.swift +++ /dev/null @@ -1,78 +0,0 @@ -import DateProvider -import FileSystem -import Foundation -import Logging -import ProcessController -import Timer - -public final class ProcessOutputSilenceTracker { - private let dateProvider: DateProvider - private let fileSystem: FileSystem - private let onSilence: () -> () - private let silenceDuration: TimeInterval - private let standardStreamsCaptureConfig: StandardStreamsCaptureConfig - private let subprocessInfo: SubprocessInfo - private var timer: DispatchBasedTimer? - - public init( - dateProvider: DateProvider, - fileSystem: FileSystem, - onSilence: @escaping () -> (), - silenceDuration: TimeInterval, - standardStreamsCaptureConfig: StandardStreamsCaptureConfig, - subprocessInfo: SubprocessInfo - ) { - self.dateProvider = dateProvider - self.fileSystem = fileSystem - self.onSilence = onSilence - self.silenceDuration = silenceDuration - self.standardStreamsCaptureConfig = standardStreamsCaptureConfig - self.subprocessInfo = subprocessInfo - } - - deinit { - timer?.stop() - } - - public func startTracking() { - timer = DispatchBasedTimer.startedTimer( - repeating: .seconds(1), - leeway: .seconds(1) - ) { [weak self] sender in - guard let strongSelf = self else { return sender.stop() } - strongSelf.verifyProcessOutputsAnyData() - } - } - - public func stopTracking() { - timer?.stop() - } - - private func verifyProcessOutputsAnyData() { - do { - let currentDate = dateProvider.currentDate() - let stdoutMtime = try fileSystem.properties(forFileAtPath: standardStreamsCaptureConfig.stdoutOutputPath()).modificationDate() - let stderrMtime = try fileSystem.properties(forFileAtPath: standardStreamsCaptureConfig.stderrOutputPath()).modificationDate() - - if currentDate.timeIntervalSince(stdoutMtime) > silenceDuration, - currentDate.timeIntervalSince(stderrMtime) > silenceDuration { - timer?.stop() - Logger.debug("Process has been silent for more than \(LoggableDuration(silenceDuration))", subprocessInfo) - onSilence() - } - } catch { - timer?.stop() - Logger.warning("Failed to check for process output mtime: \(error). Will stop tracking for process aliveness.", subprocessInfo) - } - } -} - -public extension ProcessOutputSilenceTracker { - func whileTracking(work: () throws -> T) rethrows -> T { - startTracking() - defer { - stopTracking() - } - return try work() - } -} diff --git a/Sources/Runner/Runner.swift b/Sources/Runner/Runner.swift index 17406c9c..9862ee6b 100755 --- a/Sources/Runner/Runner.swift +++ b/Sources/Runner/Runner.swift @@ -16,7 +16,7 @@ import ResourceLocationResolver import RunnerModels import SimulatorPoolModels import SynchronousWaiter -import TemporaryStuff +import Tmp import TestsWorkingDirectorySupport public final class Runner { @@ -76,8 +76,7 @@ public final class Runner { if entries.isEmpty { return RunnerRunResult( entriesToRun: entries, - testEntryResults: [], - subprocessStandardStreamsCaptureConfig: nil + testEntryResults: [] ) } @@ -94,7 +93,7 @@ public final class Runner { // is promblem in them, not in infrastructure. var reviveAttempt = 0 - var lastSubprocessStandardStreamsCaptureConfig: StandardStreamsCaptureConfig? = nil + while runResult.nonLostTestEntryResults.count < entries.count, reviveAttempt <= numberOfAttemptsToRevive { let entriesToRun = missingEntriesForScheduledEntries( expectedEntriesToRun: entries, @@ -105,7 +104,6 @@ public final class Runner { developerDir: developerDir, simulator: simulator ) - lastSubprocessStandardStreamsCaptureConfig = runResults.subprocessStandardStreamsCaptureConfig runResult.append(testEntryResults: runResults.testEntryResults) @@ -124,8 +122,7 @@ public final class Runner { testEntryResults: testEntryResults( runResult: runResult, simulatorId: simulator.udid - ), - subprocessStandardStreamsCaptureConfig: lastSubprocessStandardStreamsCaptureConfig + ) ) } @@ -139,8 +136,7 @@ public final class Runner { Logger.info("Nothing to run!") return RunnerRunResult( entriesToRun: entriesToRun, - testEntryResults: [], - subprocessStandardStreamsCaptureConfig: nil + testEntryResults: [] ) } @@ -188,7 +184,7 @@ public final class Runner { TestTimeoutTrackingTestRunnerSream( dateProvider: dateProvider, detectedLongRunningTest: { [dateProvider] testName, testStartedAt in - Logger.debug("Detected long running test \(testName)", testRunnerRunningInvocationContainer.currentValue()?.subprocessInfo) + Logger.debug("Detected long running test \(testName)", testRunnerRunningInvocationContainer.currentValue()?.pidInfo) collectedTestStoppedEvents.append( TestStoppedEvent( testName: testName, @@ -209,35 +205,35 @@ public final class Runner { metricReportingTestRunnerStream, TestRunnerStreamWrapper( onOpenStream: { - Logger.debug("Started executing tests", testRunnerRunningInvocationContainer.currentValue()?.subprocessInfo) + Logger.debug("Started executing tests", testRunnerRunningInvocationContainer.currentValue()?.pidInfo) }, onTestStarted: { testName in collectedTestExceptions = [] - Logger.debug("Test started: \(testName)", testRunnerRunningInvocationContainer.currentValue()?.subprocessInfo) + Logger.debug("Test started: \(testName)", testRunnerRunningInvocationContainer.currentValue()?.pidInfo) }, onTestException: { testException in collectedTestExceptions.append(testException) - Logger.debug("Caught test exception: \(testException)", testRunnerRunningInvocationContainer.currentValue()?.subprocessInfo) + Logger.debug("Caught test exception: \(testException)", testRunnerRunningInvocationContainer.currentValue()?.pidInfo) }, onTestStopped: { testStoppedEvent in let testStoppedEvent = testStoppedEvent.byMergingTestExceptions(testExceptions: collectedTestExceptions) collectedTestStoppedEvents.append(testStoppedEvent) collectedTestExceptions = [] - Logger.debug("Test stopped: \(testStoppedEvent.testName), \(testStoppedEvent.result)", testRunnerRunningInvocationContainer.currentValue()?.subprocessInfo) + Logger.debug("Test stopped: \(testStoppedEvent.testName), \(testStoppedEvent.result)", testRunnerRunningInvocationContainer.currentValue()?.pidInfo) }, onCloseStream: { - Logger.debug("Finished executing tests", testRunnerRunningInvocationContainer.currentValue()?.subprocessInfo) + Logger.debug("Finished executing tests", testRunnerRunningInvocationContainer.currentValue()?.pidInfo) streamClosedCallback.set(result: ()) } ), PreflightPostflightTimeoutTrackingTestRunnerStream( dateProvider: dateProvider, onPreflightTimeout: { - Logger.debug("Detected preflight timeout", testRunnerRunningInvocationContainer.currentValue()?.subprocessInfo) + Logger.debug("Detected preflight timeout", testRunnerRunningInvocationContainer.currentValue()?.pidInfo) testRunnerRunningInvocationContainer.currentValue()?.cancel() }, onPostflightTimeout: { testName in - Logger.debug("Detected postflight timeout, last finished test was \(testName)", testRunnerRunningInvocationContainer.currentValue()?.subprocessInfo) + Logger.debug("Detected postflight timeout, last finished test was \(testName)", testRunnerRunningInvocationContainer.currentValue()?.pidInfo) testRunnerRunningInvocationContainer.currentValue()?.cancel() }, maximumPreflightDuration: configuration.testTimeoutConfiguration.testRunnerMaximumSilenceDuration, @@ -257,20 +253,7 @@ public final class Runner { let runningInvocation = testRunnerInvocation.startExecutingTests() testRunnerRunningInvocationContainer.set(runningInvocation) - let runnerSilenceTracker = ProcessOutputSilenceTracker( - dateProvider: dateProvider, - fileSystem: fileSystem, - onSilence: { [configuration] in - Logger.debug("Test runner has been silent for too long (\(LoggableDuration(configuration.testTimeoutConfiguration.testRunnerMaximumSilenceDuration))), terminating tests", runningInvocation.subprocessInfo) - runningInvocation.cancel() - }, - silenceDuration: configuration.testTimeoutConfiguration.testRunnerMaximumSilenceDuration, - standardStreamsCaptureConfig: runningInvocation.output, - subprocessInfo: runningInvocation.subprocessInfo - ) - try runnerSilenceTracker.whileTracking { - try streamClosedCallback.wait(timeout: .infinity, description: "Test Runner Stream Close") - } + try streamClosedCallback.wait(timeout: .infinity, description: "Test Runner Stream Close") let result = Runner.prepareResults( collectedTestStoppedEvents: collectedTestStoppedEvents, @@ -278,13 +261,12 @@ public final class Runner { simulatorId: simulator.udid ) - Logger.debug("Attempted to run \(entriesToRun.count) tests on simulator \(simulator): \(entriesToRun)", runningInvocation.subprocessInfo) - Logger.debug("Did get \(result.count) results: \(result)", runningInvocation.subprocessInfo) + Logger.debug("Attempted to run \(entriesToRun.count) tests on simulator \(simulator): \(entriesToRun)", runningInvocation.pidInfo) + Logger.debug("Did get \(result.count) results: \(result)", runningInvocation.pidInfo) return RunnerRunResult( entriesToRun: entriesToRun, - testEntryResults: result, - subprocessStandardStreamsCaptureConfig: runningInvocation.output + testEntryResults: result ) } @@ -342,7 +324,7 @@ public final class Runner { private func cleanUpDeadCache(simulator: Simulator) { let deadCachePath = simulator.path.appending(relativePath: RelativePath("data/Library/Caches/com.apple.containermanagerd/Dead")) do { - if try fileSystem.properties(forFileAtPath: deadCachePath).exists() { + if fileSystem.properties(forFileAtPath: deadCachePath).exists() { Logger.debug("Will attempt to clean up simulator dead cache at: \(deadCachePath)") try fileSystem.delete(fileAtPath: deadCachePath) } @@ -497,8 +479,7 @@ private extension TestStoppedEvent { private class NoOpTestRunnerInvocation: TestRunnerInvocation { private class NoOpTestRunnerRunningInvocation: TestRunnerRunningInvocation { init() {} - let output = StandardStreamsCaptureConfig() - let subprocessInfo = SubprocessInfo(subprocessId: 0, subprocessName: "no-op process") + let pidInfo = PidInfo(pid: 0, name: "no-op process") func cancel() {} func wait() {} } diff --git a/Sources/Runner/RunnerRunResult.swift b/Sources/Runner/RunnerRunResult.swift index e3a14b0f..bb096765 100644 --- a/Sources/Runner/RunnerRunResult.swift +++ b/Sources/Runner/RunnerRunResult.swift @@ -7,31 +7,12 @@ import RunnerModels public final class RunnerRunResult { public let entriesToRun: [TestEntry] public let testEntryResults: [TestEntryResult] - public let subprocessStandardStreamsCaptureConfig: StandardStreamsCaptureConfig? public init( entriesToRun: [TestEntry], - testEntryResults: [TestEntryResult], - subprocessStandardStreamsCaptureConfig: StandardStreamsCaptureConfig? + testEntryResults: [TestEntryResult] ) { self.entriesToRun = entriesToRun self.testEntryResults = testEntryResults - self.subprocessStandardStreamsCaptureConfig = subprocessStandardStreamsCaptureConfig - } - - /// Dumps the captured contents of standard streams, helpful for debugging purposes - public func dumpStandardStreams() { - guard let subprocessStandardStreamsCaptureConfig = subprocessStandardStreamsCaptureConfig else { return } - - try? printTail(filePath: subprocessStandardStreamsCaptureConfig.stdoutOutputPath()) - try? printTail(filePath: subprocessStandardStreamsCaptureConfig.stderrOutputPath()) - } - - private func printTail(filePath: AbsolutePath) { - if let fileHandle = FileHandle(forReadingAtPath: filePath.pathString) { - Logger.info("Below is the tail of \(filePath)") - fileHandle.seekToOffsetFromEnd(offset: 10*1024) - fileHandle.stream(toFileHandle: FileHandle.standardError) - } } } diff --git a/Sources/Runner/TestRunner.swift b/Sources/Runner/TestRunner.swift index 3959b3c0..bfc7f352 100644 --- a/Sources/Runner/TestRunner.swift +++ b/Sources/Runner/TestRunner.swift @@ -5,11 +5,10 @@ import Logging import ProcessController import RunnerModels import SimulatorPoolModels -import TemporaryStuff +import Tmp public protocol TestRunnerRunningInvocation { - var output: StandardStreamsCaptureConfig { get } - var subprocessInfo: SubprocessInfo { get } + var pidInfo: PidInfo { get } func cancel() func wait() } diff --git a/Sources/SSHDeployer/DefaultSSHClient.swift b/Sources/SSHDeployer/DefaultSSHClient.swift index 628a6381..77e7fe0e 100644 --- a/Sources/SSHDeployer/DefaultSSHClient.swift +++ b/Sources/SSHDeployer/DefaultSSHClient.swift @@ -1,6 +1,5 @@ import Foundation import Shout -import CSSH import PathLib public final class DefaultSSHClient: SSHClient { diff --git a/Sources/SSHDeployer/SSHDeployer.swift b/Sources/SSHDeployer/SSHDeployer.swift index 5fe01fb7..b2a343f0 100644 --- a/Sources/SSHDeployer/SSHDeployer.swift +++ b/Sources/SSHDeployer/SSHDeployer.swift @@ -3,7 +3,7 @@ import Foundation import Logging import PathLib import ProcessController -import TemporaryStuff +import Tmp import UniqueIdentifierGenerator public final class SSHDeployer: Deployer { diff --git a/Sources/Scheduler/Scheduler.swift b/Sources/Scheduler/Scheduler.swift index 6aaf09c4..729a17e6 100755 --- a/Sources/Scheduler/Scheduler.swift +++ b/Sources/Scheduler/Scheduler.swift @@ -18,7 +18,7 @@ import ScheduleStrategy import SimulatorPool import SimulatorPoolModels import SynchronousWaiter -import TemporaryStuff +import Tmp import UniqueIdentifierGenerator public final class Scheduler { @@ -211,9 +211,8 @@ public final class Scheduler { simulator: allocatedSimulator.simulator ) - if !runnerResult.testEntryResults.filter({ $0.isLost }).isEmpty { - Logger.warning("Some test results are lost") - runnerResult.dumpStandardStreams() + runnerResult.testEntryResults.filter { $0.isLost }.forEach { + Logger.debug("Lost result for \($0)") } return TestingResult( diff --git a/Sources/SignalHandling/Signal.swift b/Sources/SignalHandling/Signal.swift deleted file mode 100644 index 816656a1..00000000 --- a/Sources/SignalHandling/Signal.swift +++ /dev/null @@ -1,83 +0,0 @@ -import Foundation -import Signals - -public enum Signal: Hashable, CustomStringConvertible { - case hup - case int - case quit - case abrt - case kill - case alrm - case term - case pipe - case user(Int) - - public var description: String { - switch self { - case .hup: - return "SIGHUP" - case .int: - return "SIGINT" - case .quit: - return "SIGQUIT" - case .abrt: - return "SIGABRT" - case .kill: - return "SIGKILL" - case .alrm: - return "SIGALRM" - case .term: - return "SIGTERM" - case .pipe: - return "SIGPIPE" - case .user(let value): - return "SIGUSR(\(value))" - } - } - - public var intValue: Int32 { - switch self { - case .hup: - return SIGHUP - case .int: - return SIGINT - case .quit: - return SIGQUIT - case .abrt: - return SIGABRT - case .kill: - return SIGKILL - case .alrm: - return SIGALRM - case .term: - return SIGTERM - case .pipe: - return SIGPIPE - case .user(let value): - return Int32(value) - } - } - - internal var blueSignal: Signals.Signal { - switch self { - case .hup: - return .hup - case .int: - return .int - case .quit: - return .quit - case .abrt: - return .abrt - case .kill: - return .kill - case .alrm: - return .alrm - case .term: - return .term - case .pipe: - return .pipe - case .user(let value): - return .user(value) - } - } -} diff --git a/Sources/SignalHandling/SignalHandling.swift b/Sources/SignalHandling/SignalHandling.swift deleted file mode 100644 index 44f36bd8..00000000 --- a/Sources/SignalHandling/SignalHandling.swift +++ /dev/null @@ -1,39 +0,0 @@ -import Dispatch -import Foundation -import Signals -import Types - -public typealias SignalHandler = (Int32) -> () - -private let syncQueue = DispatchQueue(label: "ru.avito.emcee.SignalHandling") -private var signalHandlers = MapWithCollection() - -public final class SignalHandling { - private init() {} - - /// Captures and holds a given handler and invokes it when any provided signal occurs. - public static func addSignalHandler(signals: Set, handler: @escaping SignalHandler) { - for signal in signals { - addSignalHandler(signal: signal, handler: handler) - } - } - - /// Captures and holds a given handler and invokes it when a required signal occurs. - public static func addSignalHandler(signal: Signal, handler: @escaping SignalHandler) { - syncQueue.sync { - signalHandlers.append(key: signal.intValue, element: handler) - } - - Signals.trap(signal: signal.blueSignal) { signalValue in - _handleSignal(signalValue) - } - } -} - -/// Universal signal handler -private func _handleSignal(_ signalValue: Int32) { - let registeredHandlers = syncQueue.sync { signalHandlers[signalValue] } - for handler in registeredHandlers { - handler(signalValue) - } -} diff --git a/Sources/SimulatorPool/DefaultOnDemandSimulatorPool.swift b/Sources/SimulatorPool/DefaultOnDemandSimulatorPool.swift index 21fd0ce7..c30bf457 100644 --- a/Sources/SimulatorPool/DefaultOnDemandSimulatorPool.swift +++ b/Sources/SimulatorPool/DefaultOnDemandSimulatorPool.swift @@ -3,7 +3,7 @@ import Foundation import Logging import ResourceLocationResolver import RunnerModels -import TemporaryStuff +import Tmp public class DefaultOnDemandSimulatorPool: OnDemandSimulatorPool { private let resourceLocationResolver: ResourceLocationResolver diff --git a/Sources/SimulatorPool/DefaultSimulatorPool.swift b/Sources/SimulatorPool/DefaultSimulatorPool.swift index 30f3115c..976e04c0 100644 --- a/Sources/SimulatorPool/DefaultSimulatorPool.swift +++ b/Sources/SimulatorPool/DefaultSimulatorPool.swift @@ -5,7 +5,7 @@ import Logging import ResourceLocationResolver import RunnerModels import SimulatorPoolModels -import TemporaryStuff +import Tmp public final class DefaultSimulatorPool: SimulatorPool, CustomStringConvertible { private let developerDir: DeveloperDir diff --git a/Sources/SimulatorPool/SimulatorControllerProvider.swift b/Sources/SimulatorPool/SimulatorControllerProvider.swift index 722240b7..3e5b12b3 100644 --- a/Sources/SimulatorPool/SimulatorControllerProvider.swift +++ b/Sources/SimulatorPool/SimulatorControllerProvider.swift @@ -2,7 +2,7 @@ import DeveloperDirModels import Foundation import RunnerModels import SimulatorPoolModels -import TemporaryStuff +import Tmp public protocol SimulatorControllerProvider { func createSimulatorController( diff --git a/Sources/SimulatorPool/SimulatorPool.swift b/Sources/SimulatorPool/SimulatorPool.swift index 3a24b17e..58593533 100644 --- a/Sources/SimulatorPool/SimulatorPool.swift +++ b/Sources/SimulatorPool/SimulatorPool.swift @@ -4,7 +4,6 @@ import Foundation import Logging import ResourceLocationResolver import SimulatorPoolModels -import TemporaryStuff import RunnerModels /** diff --git a/Sources/SimulatorPool/SimulatorSettingsModifierImpl.swift b/Sources/SimulatorPool/SimulatorSettingsModifierImpl.swift index 2a0133a1..f9a0f45b 100644 --- a/Sources/SimulatorPool/SimulatorSettingsModifierImpl.swift +++ b/Sources/SimulatorPool/SimulatorSettingsModifierImpl.swift @@ -5,7 +5,7 @@ import Logging import PlistLib import ProcessController import SimulatorPoolModels -import TemporaryStuff +import Tmp import UniqueIdentifierGenerator public final class SimulatorSettingsModifierImpl: SimulatorSettingsModifier { @@ -31,7 +31,7 @@ public final class SimulatorSettingsModifierImpl: SimulatorSettingsModifier { simulatorSettings: SimulatorSettings, toSimulator simulator: Simulator ) throws { - let environment = try developerDirLocator.suitableEnvironment(forDeveloperDir: developerDir) + let environment = Environment(try developerDirLocator.suitableEnvironment(forDeveloperDir: developerDir)) var didImportPlist = false let globalPreferencesPlist = Plist( @@ -91,7 +91,7 @@ public final class SimulatorSettingsModifierImpl: SimulatorSettingsModifier { private func importDefaults( domain: String, plistToImport: Plist, - environment: [String: String], + environment: Environment, simulator: Simulator ) throws -> Bool { let uniqueId = uniqueIdentifierGenerator.generate() @@ -138,7 +138,7 @@ public final class SimulatorSettingsModifierImpl: SimulatorSettingsModifier { private func kill( daemon: String, - environment: [String: String], + environment: Environment, simulator: Simulator ) throws { try processControllerProvider.startAndWaitForSuccessfulTermination( @@ -151,7 +151,7 @@ public final class SimulatorSettingsModifierImpl: SimulatorSettingsModifier { extension ProcessControllerProvider { func startAndWaitForSuccessfulTermination( arguments: [SubprocessArgument], - environment: [String: String] + environment: Environment ) throws { try createProcessController( subprocess: Subprocess( diff --git a/Sources/SimulatorPool/StateMachineDrivenSimulatorController.swift b/Sources/SimulatorPool/StateMachineDrivenSimulatorController.swift index 11480296..21745f3d 100644 --- a/Sources/SimulatorPool/StateMachineDrivenSimulatorController.swift +++ b/Sources/SimulatorPool/StateMachineDrivenSimulatorController.swift @@ -7,7 +7,7 @@ import PathLib import PlistLib import SimulatorPoolModels import SynchronousWaiter -import TemporaryStuff +import Tmp public final class StateMachineDrivenSimulatorController: SimulatorController, CustomStringConvertible { private let additionalBootAttempts: UInt diff --git a/Sources/SocketModels/Port.swift b/Sources/SocketModels/Port.swift deleted file mode 100644 index e471cbed..00000000 --- a/Sources/SocketModels/Port.swift +++ /dev/null @@ -1,13 +0,0 @@ -import Types - -public final class Port: NewIntType, Strideable { - public typealias Stride = Int - - public func distance(to other: Port) -> Int { - other.value - self.value - } - - public func advanced(by n: Int) -> Self { - return type(of: self).init(value: value + n) - } -} diff --git a/Sources/SocketModels/SocketAddress.swift b/Sources/SocketModels/SocketAddress.swift deleted file mode 100644 index ca0d093c..00000000 --- a/Sources/SocketModels/SocketAddress.swift +++ /dev/null @@ -1,54 +0,0 @@ -import Foundation - -public struct SocketAddress: Codable, CustomStringConvertible, Hashable { - public let host: String - public let port: Port - - public enum ParseError: Error, CustomStringConvertible { - case unsupportedFormat(String) - - public var description: String { - switch self { - case .unsupportedFormat(let input): - return "Unable to parse socket address from input '\(input)'. Expected format: hostname:1234" - } - } - } - - public init(host: String, port: Port) { - self.host = host - self.port = port - } - - public static func from(string: String) throws -> SocketAddress { - let components = string.split(separator: ":") - guard components.count == 2, let port = Int(components[1]) else { - throw ParseError.unsupportedFormat(string) - } - return SocketAddress( - host: String(components[0]), - port: Port(value: port) - ) - } - - public init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - let value = try container.decode(String.self) - let address = try SocketAddress.from(string: value) - host = address.host - port = address.port - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.singleValueContainer() - try container.encode(description) - } - - public var asString: String { - return "\(host):\(port.value)" - } - - public var description: String { - return asString - } -} diff --git a/Sources/Statsd/StatsdClient.swift b/Sources/Statsd/StatsdClient.swift deleted file mode 100644 index 4fdb2b35..00000000 --- a/Sources/Statsd/StatsdClient.swift +++ /dev/null @@ -1,12 +0,0 @@ -import Foundation -import Network - -public protocol StatsdClient: class { - var stateUpdateHandler: ((NWConnection.State) -> Void)? { get set } - var state: NWConnection.State { get } - - func start(queue: DispatchQueue) - func cancel() - - func send(content: Data) -} diff --git a/Sources/Statsd/StatsdClientImpl.swift b/Sources/Statsd/StatsdClientImpl.swift deleted file mode 100644 index 26b5df61..00000000 --- a/Sources/Statsd/StatsdClientImpl.swift +++ /dev/null @@ -1,57 +0,0 @@ -import Foundation -import Logging -import Network -import SocketModels - -public final class StatsdClientImpl: StatsdClient { - struct InvalidPortValue: Error, CustomStringConvertible { - let value: Int - var description: String { - return "Invalid port value \(value)" - } - } - - private let connection: NWConnection - - public init( - statsdSocketAddress: SocketAddress - ) throws { - guard let port = NWEndpoint.Port(rawValue: UInt16(statsdSocketAddress.port.value)) else { - throw InvalidPortValue(value: statsdSocketAddress.port.value) - } - - self.connection = NWConnection( - host: .name(statsdSocketAddress.host, nil), - port: port, - using: .udp - ) - } - - public var stateUpdateHandler: ((NWConnection.State) -> Void)? { - get { connection.stateUpdateHandler } - set { connection.stateUpdateHandler = newValue } - } - - public var state: NWConnection.State { - connection.state - } - - public func start(queue: DispatchQueue) { - connection.start(queue: queue) - } - - public func cancel() { - connection.cancel() - } - - public func send(content: Data) { - connection.send( - content: content, - completion: NWConnection.SendCompletion.contentProcessed { - if let error = $0 { - Logger.error("Statsd metric send failed: \(error)") - } - } - ) - } -} diff --git a/Sources/Statsd/StatsdMetric.swift b/Sources/Statsd/StatsdMetric.swift deleted file mode 100644 index 3b02ff8b..00000000 --- a/Sources/Statsd/StatsdMetric.swift +++ /dev/null @@ -1,51 +0,0 @@ -import Foundation -import MetricsUtils - -open class StatsdMetric: CustomStringConvertible, Hashable { - public enum Value: Hashable { - case gauge(Int) - case time(TimeInterval) - - public func build() -> String { - switch self { - case .gauge(let value): - return "\(value)|g" - case .time(let value): - return "\(Int(value * 1000))|ms" - } - } - } - - public let components: [String] - public let value: Value - - public static let reservedField = "reserved" - - public init( - fixedComponents: [StaticString], - variableComponents: [String], - value: Value - ) { - self.components = (fixedComponents.map { $0.description } + variableComponents).map { $0.suitableForMetric } - self.value = value - } - - public func build(domain: [String]) -> String { - return "\((domain + components).joined(separator: ".")):\(value.build())" - } - - public var description: String { - return "<\(type(of: self)) components=\(components), value=\(value)" - } - - public static func ==(left: StatsdMetric, right: StatsdMetric) -> Bool { - return left.components == right.components - && left.value == right.value - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(components) - hasher.combine(value) - } -} - diff --git a/Sources/Statsd/StatsdMetricHandler.swift b/Sources/Statsd/StatsdMetricHandler.swift deleted file mode 100644 index 906045c8..00000000 --- a/Sources/Statsd/StatsdMetricHandler.swift +++ /dev/null @@ -1,6 +0,0 @@ -import Foundation - -public protocol StatsdMetricHandler { - func handle(metric: StatsdMetric) - func tearDown(timeout: TimeInterval) -} diff --git a/Sources/Statsd/StatsdMetricHandlerImpl.swift b/Sources/Statsd/StatsdMetricHandlerImpl.swift deleted file mode 100644 index af8e6c9c..00000000 --- a/Sources/Statsd/StatsdMetricHandlerImpl.swift +++ /dev/null @@ -1,80 +0,0 @@ -import Foundation -import IO -import Logging -import SocketModels -import Network - -public final class StatsdMetricHandlerImpl: StatsdMetricHandler { - private let statsdDomain: [String] - private let statsdClient: StatsdClient - private let serialQueue: DispatchQueue - - private var metricsBuffer: [StatsdMetric] = [] - - public init( - statsdDomain: [String], - statsdClient: StatsdClient, - serialQueue: DispatchQueue = DispatchQueue(label: "StatsdMetricHandlerImpl.serialQueue") - ) throws { - self.statsdDomain = statsdDomain - self.statsdClient = statsdClient - self.serialQueue = serialQueue - - self.statsdClient.stateUpdateHandler = { [weak self] state in - guard let self = self else { return } - switch state { - case .setup: - Logger.debug("Setting up statsd connection") - case .waiting(let error): - Logger.warning("Statsd connection waiting: \(error)") - case .preparing: - Logger.debug("Preparing statsd connection") - case .ready: - Logger.debug("Connected to statsd endpoint") - self.metricsBuffer.forEach(self.send) - self.metricsBuffer.removeAll() - case .failed(let error): - Logger.error("Statsd connection failed: \(error)") - self.statsdClient.cancel() - case .cancelled: - Logger.warning("Statsd connection was cancelled") - if !self.metricsBuffer.isEmpty { - Logger.warning("Metrics buffer wasn't empty when connection was cancelled: \(self.metricsBuffer)") - } - @unknown default: - Logger.warning("Unknown statsd connection state: \(state)") - } - } - statsdClient.start(queue: serialQueue) - } - - public func handle(metric: StatsdMetric) { - serialQueue.async { [weak self] in - guard let self = self else { return } - let state = self.statsdClient.state - switch state { - case .cancelled, .failed: - Logger.warning("Statsd connection is \(state), metric \(metric) is dropped") - case .waiting, .preparing, .setup: - Logger.warning("Buffering metric \(metric)") - self.metricsBuffer.append(metric) - case .ready: - self.send(metric: metric) - @unknown default: - Logger.warning("Unknown statsd connection state: \(state)") - } - } - } - - public func tearDown(timeout: TimeInterval) { - serialQueue.async { [statsdClient] in - statsdClient.cancel() - } - } - - private func send(metric: StatsdMetric) { - statsdClient.send( - content: Data(metric.build(domain: statsdDomain).utf8) - ) - } -} diff --git a/Sources/SynchronousWaiter/NoOpWaiter.swift b/Sources/SynchronousWaiter/NoOpWaiter.swift deleted file mode 100644 index cdb0d389..00000000 --- a/Sources/SynchronousWaiter/NoOpWaiter.swift +++ /dev/null @@ -1,7 +0,0 @@ -import Foundation - -public final class NoOpWaiter: Waiter { - public init() {} - - public func waitWhile(pollPeriod: TimeInterval, timeout: Timeout, condition: () throws -> Bool) throws {} -} diff --git a/Sources/SynchronousWaiter/SynchronousWaiter.swift b/Sources/SynchronousWaiter/SynchronousWaiter.swift deleted file mode 100644 index eac908c5..00000000 --- a/Sources/SynchronousWaiter/SynchronousWaiter.swift +++ /dev/null @@ -1,35 +0,0 @@ -import Darwin -import Foundation -import Logging - -public final class SynchronousWaiter: Waiter { - public init() {} - - public func waitWhile( - pollPeriod: TimeInterval = 0.3, - timeout: Timeout = .infinity, - condition: WaitCondition - ) throws { - Logger.debug("Waiting for \(timeout.description), checking every \(pollPeriod) sec for up to \(timeout.value) sec") - let startTime = Date().timeIntervalSince1970 - - defer { - Logger.debug("Finished waiting for \(timeout.description), took \(Date().timeIntervalSince1970 - startTime) sec") - } - - while try condition() { - let currentTime = Date().timeIntervalSince1970 - let executionDuration = currentTime - startTime - if executionDuration > timeout.value { - Logger.error("Operation '\(timeout.description)' timed out after running for more than \(LoggableDuration(timeout.value)) (\(LoggableDuration(executionDuration))") - throw TimeoutError.waitTimeout(timeout) - } - if !RunLoop.current.run(mode: RunLoop.Mode.default, before: Date().addingTimeInterval(pollPeriod)) { - let passedPollPeriod = Date().timeIntervalSince1970 - currentTime - if passedPollPeriod < pollPeriod { - Thread.sleep(forTimeInterval: pollPeriod - passedPollPeriod) - } - } - } - } -} diff --git a/Sources/SynchronousWaiter/Timeout.swift b/Sources/SynchronousWaiter/Timeout.swift deleted file mode 100644 index 9803c307..00000000 --- a/Sources/SynchronousWaiter/Timeout.swift +++ /dev/null @@ -1,27 +0,0 @@ -import Foundation - -public struct Timeout: CustomStringConvertible { - public let description: String - public let value: TimeInterval - - public init(description: String, value: TimeInterval) { - self.description = description - self.value = value - } - - public static var infinity: Timeout { - return Timeout(description: "Infinite wait will never timeout", value: .infinity) - } -} - -public enum TimeoutError: Error, CustomStringConvertible { - case waitTimeout(Timeout) - - public var description: String { - switch self { - case .waitTimeout(let timeout): - let rounded = (timeout.value * 1000.0).rounded() / 1000.0 - return "Waiter reached timeout of \(rounded) s for '\(timeout.description)' operation" - } - } -} diff --git a/Sources/SynchronousWaiter/Waiter+Callbacks.swift b/Sources/SynchronousWaiter/Waiter+Callbacks.swift deleted file mode 100644 index f8db519f..00000000 --- a/Sources/SynchronousWaiter/Waiter+Callbacks.swift +++ /dev/null @@ -1,60 +0,0 @@ -import AtomicModels -import Foundation -import Logging - -public struct WaiterHasDiedBeforeValueWasSet: Error, CustomStringConvertible { - public let pollPeriod: TimeInterval - public let timeout: TimeInterval - public let waiterDescription: String - - public init( - pollPeriod: TimeInterval, - timeout: TimeInterval, - waiterDescription: String - ) { - self.pollPeriod = pollPeriod - self.timeout = timeout - self.waiterDescription = waiterDescription - } - - public var description: String { - return "Waiter for '\(waiterDescription)' operation (checking every \(LoggableDuration(pollPeriod)) for up to \(LoggableDuration(timeout)) died before a value was provided" - } -} - -public final class CallbackWaiter { - private let value = AtomicValue(nil) - private weak var waiter: Waiter? - - init(waiter: Waiter) { - self.waiter = waiter - } - - public func set(result: T) { value.set(result) } - public func currentValue() -> T? { value.currentValue() } - - public func wait( - pollPeriod: TimeInterval = 0.1, - timeout: TimeInterval, - description: String - ) throws -> T { - guard let waiter = waiter else { - throw WaiterHasDiedBeforeValueWasSet(pollPeriod: pollPeriod, timeout: timeout, waiterDescription: description) - } - - return try waiter.waitForUnwrap( - pollPeriod: pollPeriod, - timeout: timeout, - valueProvider: { () -> T? in - currentValue() - }, - description: description - ) - } -} - -public extension Waiter { - func createCallbackWaiter() -> CallbackWaiter { - return CallbackWaiter(waiter: self) - } -} diff --git a/Sources/SynchronousWaiter/Waiter+ErrorMapping.swift b/Sources/SynchronousWaiter/Waiter+ErrorMapping.swift deleted file mode 100644 index ffde7e1a..00000000 --- a/Sources/SynchronousWaiter/Waiter+ErrorMapping.swift +++ /dev/null @@ -1,31 +0,0 @@ -import Foundation -import Logging - -public extension Waiter { - - /// Maps a `TimeoutError` to other error and throws it instead of throwing original `TimeoutError`. - /// - Parameters: - /// - work: a place where you perform your wait operation which can throw `TimeoutError`. - /// - timeoutToErrorTransformation: if timeout happens, this mapper will used to transform `TimeoutError` to other error. - /// Any non-`TimeoutError` error won't be transformed. - /// - Throws: transformed error. Any other error that might be thrown from wait condition block will be thrown unmodified. - func mapErrorIfTimeout( - work: (Waiter) throws -> (), - timeoutToErrorTransformation: (Timeout) -> Error - ) rethrows { - do { - try work(self) - } catch { - guard let timeoutError = error as? TimeoutError else { - throw error - } - - switch timeoutError { - case .waitTimeout(let timeout): - let error = timeoutToErrorTransformation(timeout) - Logger.error("Raising eror after waiting for \(timeout.description) for \(LoggableDuration(timeout.value)): \(error)") - throw error - } - } - } -} diff --git a/Sources/SynchronousWaiter/Waiter.swift b/Sources/SynchronousWaiter/Waiter.swift deleted file mode 100644 index 4c4253f7..00000000 --- a/Sources/SynchronousWaiter/Waiter.swift +++ /dev/null @@ -1,64 +0,0 @@ -import Foundation - -public protocol Waiter: class { - typealias WaitCondition = () throws -> Bool - - func waitWhile( - pollPeriod: TimeInterval, - timeout: Timeout, - condition: WaitCondition - ) throws -} - -public extension Waiter { - func wait(pollPeriod: TimeInterval = 0.3, timeout: TimeInterval, description: String) { - try? waitWhile(pollPeriod: pollPeriod, timeout: timeout, description: description) { true } - } - - func waitWhile( - pollPeriod: TimeInterval = 0.5, - timeout: TimeInterval = .infinity, - description: String, - condition: WaitCondition - ) throws { - return try waitWhile( - pollPeriod: pollPeriod, - timeout: Timeout(description: description, value: timeout), - condition: condition - ) - } -} - -public struct NoUnwrappableValueProvidedError: Error, CustomStringConvertible { - public let waiter: Waiter - - public init(waiter: Waiter) { - self.waiter = waiter - } - - public var description: String { - return "No unwrappable value provided back to waiter \(waiter)" - } -} - -public extension Waiter { - func waitForUnwrap( - pollPeriod: TimeInterval = 0.1, - timeout: TimeInterval, - valueProvider: () throws -> T?, - description: String - ) throws -> T { - var result: T? - - try waitWhile(pollPeriod: pollPeriod, timeout: timeout, description: description, condition: { () -> Bool in - result = try valueProvider() - return result == nil - }) - - if let result = result { - return result - } else { - throw NoUnwrappableValueProvidedError(waiter: self) - } - } -} diff --git a/Sources/TemporaryStuff/TempErrors.swift b/Sources/TemporaryStuff/TempErrors.swift deleted file mode 100644 index 76343daa..00000000 --- a/Sources/TemporaryStuff/TempErrors.swift +++ /dev/null @@ -1,24 +0,0 @@ -import Foundation -import PathLib - -public enum ErrnoError: Error, CustomStringConvertible { - case failedToCreateTemporaryFolder(AbsolutePath, code: Int32) - case failedToCreateTemporaryFile(AbsolutePath, code: Int32) - - public var description: String { - switch self { - case .failedToCreateTemporaryFolder(let template, let code): - return "Failed to create temporary directory with template \(template), error code: \(code)" - case .failedToCreateTemporaryFile(let template, let code): - return "Failed to create temporary file with template \(template), error code: \(code)" - } - } -} - -public struct UnknownCanonicalPath: Error, CustomStringConvertible { - let path: String - - public var description: String { - return "Failed to determine canonical path for \(path)" - } -} diff --git a/Sources/TemporaryStuff/TemporaryFile.swift b/Sources/TemporaryStuff/TemporaryFile.swift deleted file mode 100644 index fe173c66..00000000 --- a/Sources/TemporaryStuff/TemporaryFile.swift +++ /dev/null @@ -1,40 +0,0 @@ -import Darwin -import Foundation -import PathLib - -public final class TemporaryFile { - public let fileHandleForWriting: FileHandle - public let absolutePath: AbsolutePath - private let deleteOnDealloc: Bool - - public init( - containerPath: AbsolutePath? = nil, - prefix: String = "TemporaryFile", - suffix: String = "", - closeOnDealloc: Bool = true, - deleteOnDealloc: Bool = true - ) throws { - let containerPath = containerPath ?? AbsolutePath(NSTemporaryDirectory()) - let pathTemplate = containerPath.appending(component: "\(prefix).XXXXXX\(suffix)") - - var templateBytes = [UInt8](pathTemplate.pathString.utf8).map { Int8($0) } + [Int8(0)] - let fileDescriptor = mkstemps(&templateBytes, Int32(suffix.count)) - - if fileDescriptor == -1 { - throw ErrnoError.failedToCreateTemporaryFile(pathTemplate, code: errno) - } - - self.fileHandleForWriting = FileHandle( - fileDescriptor: fileDescriptor, - closeOnDealloc: closeOnDealloc - ) - self.absolutePath = AbsolutePath(String(cString: templateBytes)) - self.deleteOnDealloc = deleteOnDealloc - } - - deinit { - if deleteOnDealloc { - unlink(absolutePath.pathString) - } - } -} diff --git a/Sources/TemporaryStuff/TemporaryFolder.swift b/Sources/TemporaryStuff/TemporaryFolder.swift deleted file mode 100644 index 843ea152..00000000 --- a/Sources/TemporaryStuff/TemporaryFolder.swift +++ /dev/null @@ -1,67 +0,0 @@ -import Darwin -import Foundation -import PathLib - -public final class TemporaryFolder { - public let absolutePath: AbsolutePath - private let deleteOnDealloc: Bool - - public init( - containerPath: AbsolutePath? = nil, - prefix: String = "TemporaryFolder", - deleteOnDealloc: Bool = true - ) throws { - if let containerPath = containerPath { - try FileManager.default.createDirectory(atPath: containerPath) - } - let containerPath = containerPath ?? AbsolutePath(NSTemporaryDirectory()) - let pathTemplate = containerPath.appending(component: "\(prefix).XXXXXX") - var templateBytes = [UInt8](pathTemplate.pathString.utf8).map { Int8($0) } + [Int8(0)] - if mkdtemp(&templateBytes) == nil { - throw ErrnoError.failedToCreateTemporaryFolder(pathTemplate, code: errno) - } - - let resultingPath = String(cString: templateBytes) - let urlValues = try URL(fileURLWithPath: resultingPath).resourceValues(forKeys: [.canonicalPathKey]) - guard let canonicalPath = urlValues.canonicalPath else { - throw UnknownCanonicalPath(path: resultingPath) - } - - self.absolutePath = AbsolutePath(canonicalPath) - self.deleteOnDealloc = deleteOnDealloc - } - - deinit { - if deleteOnDealloc { - try? FileManager.default.removeItem(atPath: absolutePath.pathString) - } else { - rmdir(absolutePath.pathString) - } - } - - public func pathWith(components: [String]) -> AbsolutePath { - return absolutePath.appending(components: components) - } - - public func pathByCreatingDirectories(components: [String]) throws -> AbsolutePath { - let path = pathWith(components: components) - try FileManager.default.createDirectory(atPath: path) - return path - } - - @discardableResult - public func createFile(components: [String] = [], filename: String, contents: Data? = nil) throws -> AbsolutePath { - let container = try pathByCreatingDirectories(components: components) - let path = container.appending(component: filename) - FileManager.default.createFile(atPath: path.pathString, contents: contents) - return path - } - - public static func == (left: TemporaryFolder, right: TemporaryFolder) -> Bool { - return left.absolutePath == right.absolutePath - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(absolutePath) - } -} diff --git a/Sources/TestDiscovery/SpecificTestDiscoverers/ExecutableTestDiscoverer.swift b/Sources/TestDiscovery/SpecificTestDiscoverers/ExecutableTestDiscoverer.swift index 98e945bc..b421853a 100644 --- a/Sources/TestDiscovery/SpecificTestDiscoverers/ExecutableTestDiscoverer.swift +++ b/Sources/TestDiscovery/SpecificTestDiscoverers/ExecutableTestDiscoverer.swift @@ -8,7 +8,7 @@ import PathLib import ProcessController import ResourceLocationResolver import SimulatorPoolModels -import TemporaryStuff +import Tmp import UniqueIdentifierGenerator final class ExecutableTestDiscoverer: SpecificTestDiscoverer { @@ -78,7 +78,7 @@ final class ExecutableTestDiscoverer: SpecificTestDiscoverer { arguments: [ executablePath ], - environment: [ + environment: Environment([ "SIMULATOR_ROOT": latestRuntimeRoot, "DYLD_ROOT_PATH": latestRuntimeRoot, "SIMULATOR_SHARED_RESOURCES_DIRECTORY": tempFolder.pathByCreatingDirectories( @@ -86,10 +86,7 @@ final class ExecutableTestDiscoverer: SpecificTestDiscoverer { ).pathString, "EMCEE_RUNTIME_TESTS_EXPORT_PATH": runtimeEntriesJSONPath.pathString, "EMCEE_XCTEST_BUNDLE_PATH": loadableBundlePath.pathString, - ].merging( - configuration.testExecutionBehavior.environment, - uniquingKeysWith: { (_, new) in new } - ) + ]).merge(with: configuration.testExecutionBehavior.environment) ) ) try controller.startAndWaitForSuccessfulTermination() @@ -110,15 +107,18 @@ final class ExecutableTestDiscoverer: SpecificTestDiscoverer { "/usr/bin/xcrun", "simctl", "list", "-j", "runtimes" ], - environment: try developerDirLocator.suitableEnvironment(forDeveloperDir: developerDir) + environment: Environment( + try developerDirLocator.suitableEnvironment(forDeveloperDir: developerDir) + ) ) ) + + var capturedData = Data() + controller.onStdout { _, data, _ in capturedData.append(data) } + try controller.startAndWaitForSuccessfulTermination() - let runtimes = try JSONDecoder().decode( - SimulatorRuntimes.self, - from: Data(contentsOf: controller.subprocess.standardStreamsCaptureConfig.stdoutOutputPath().fileUrl) - ) + let runtimes = try JSONDecoder().decode(SimulatorRuntimes.self, from: capturedData) guard let runtime = runtimes.runtimes.first( where: { $0.name == "iOS \(testDestination.runtime)" } diff --git a/Sources/TestDiscovery/SpecificTestDiscoverers/ParseFunctionSymbolsTestDiscoverer.swift b/Sources/TestDiscovery/SpecificTestDiscoverers/ParseFunctionSymbolsTestDiscoverer.swift index c1872ec8..47809a36 100644 --- a/Sources/TestDiscovery/SpecificTestDiscoverers/ParseFunctionSymbolsTestDiscoverer.swift +++ b/Sources/TestDiscovery/SpecificTestDiscoverers/ParseFunctionSymbolsTestDiscoverer.swift @@ -13,7 +13,7 @@ import RunnerModels import SimulatorPool import SimulatorPoolModels import SynchronousWaiter -import TemporaryStuff +import Tmp import UniqueIdentifierGenerator final class ParseFunctionSymbolsTestDiscoverer: SpecificTestDiscoverer { @@ -40,24 +40,21 @@ final class ParseFunctionSymbolsTestDiscoverer: SpecificTestDiscoverer { func discoverTestEntries( configuration: TestDiscoveryConfiguration ) throws -> [DiscoveredTestEntry] { - let nmOutputPath = try tempFolder.pathByCreatingDirectories(components: [uniqueIdentifierGenerator.generate()]) let nmProcess = try processControllerProvider.createProcessController( subprocess: Subprocess( arguments: [ "/usr/bin/nm", "-j", "-U", try testBinaryPath(xcTestBundleLocation: configuration.xcTestBundleLocation) - ], - standardStreamsCaptureConfig: StandardStreamsCaptureConfig( - stdoutPath: nmOutputPath.appending(component: "nm_stdout"), - stderrPath: nmOutputPath.appending(component: "nm_stderr") - ) + ] ) ) + var nmOutputData = Data() + nmProcess.onStdout { _, data, _ in nmOutputData.append(data) } try nmProcess.startAndWaitForSuccessfulTermination() return try convert( developerDir: configuration.developerDir, - nmOutput: nmProcess.subprocess.standardStreamsCaptureConfig.stdoutOutputPath() + nmOutputData: nmOutputData ) } @@ -83,9 +80,9 @@ final class ParseFunctionSymbolsTestDiscoverer: SpecificTestDiscoverer { return resourcePath.appending(component: executableName) } - private func convert(developerDir: DeveloperDir, nmOutput: AbsolutePath) throws -> [DiscoveredTestEntry] { - guard let string = String(data: try Data(contentsOf: nmOutput.fileUrl), encoding: .utf8) else { - Logger.error("Failed to load contents of nm output at \(nmOutput)") + private func convert(developerDir: DeveloperDir, nmOutputData: Data) throws -> [DiscoveredTestEntry] { + guard let string = String(data: nmOutputData, encoding: .utf8) else { + Logger.error("Failed to get contents of nm output from \(nmOutputData.count) bytes") return [] } diff --git a/Sources/TestDiscovery/SpecificTestDiscoverers/RuntimeDumpTestDiscoverer.swift b/Sources/TestDiscovery/SpecificTestDiscoverers/RuntimeDumpTestDiscoverer.swift index 703bd942..46c788b6 100644 --- a/Sources/TestDiscovery/SpecificTestDiscoverers/RuntimeDumpTestDiscoverer.swift +++ b/Sources/TestDiscovery/SpecificTestDiscoverers/RuntimeDumpTestDiscoverer.swift @@ -14,7 +14,7 @@ import RunnerModels import SimulatorPool import SimulatorPoolModels import SynchronousWaiter -import TemporaryStuff +import Tmp import UniqueIdentifierGenerator final class RuntimeDumpTestDiscoverer: SpecificTestDiscoverer { @@ -108,7 +108,7 @@ final class RuntimeDumpTestDiscoverer: SpecificTestDiscoverer { ) defer { allocatedSimulator.releaseSimulator() } - let runnerRunResult = try runner.runOnce( + _ = try runner.runOnce( entriesToRun: [testEntryToQueryRuntimeDump], developerDir: configuration.developerDir, simulator: allocatedSimulator.simulator @@ -117,7 +117,6 @@ final class RuntimeDumpTestDiscoverer: SpecificTestDiscoverer { guard let data = try? Data(contentsOf: runtimeEntriesJSONPath.fileUrl), let foundTestEntries = try? JSONDecoder().decode([DiscoveredTestEntry].self, from: data) else { - runnerRunResult.dumpStandardStreams() throw TestExplorationError.fileNotFound(runtimeEntriesJSONPath) } diff --git a/Sources/TestDiscovery/TestDiscoveryQuerierImpl.swift b/Sources/TestDiscovery/TestDiscoveryQuerierImpl.swift index 9620b7d2..25e14356 100644 --- a/Sources/TestDiscovery/TestDiscoveryQuerierImpl.swift +++ b/Sources/TestDiscovery/TestDiscoveryQuerierImpl.swift @@ -16,8 +16,8 @@ import RunnerModels import SimulatorPool import SimulatorPoolModels import SynchronousWaiter -import TemporaryStuff import TestArgFile +import Tmp import UniqueIdentifierGenerator public final class TestDiscoveryQuerierImpl: TestDiscoveryQuerier { diff --git a/Sources/Timer/DispatchBasedTimer.swift b/Sources/Timer/DispatchBasedTimer.swift deleted file mode 100644 index dad3d7f5..00000000 --- a/Sources/Timer/DispatchBasedTimer.swift +++ /dev/null @@ -1,55 +0,0 @@ -import Dispatch -import Foundation - -public final class DispatchBasedTimer { - private var timer: DispatchSourceTimer? - private let queue = DispatchQueue(label: "ru.avito.emcee.Timer.queue") - private let deadline: DispatchTime - private let repeating: DispatchTimeInterval - private let leeway: DispatchTimeInterval - - public init(deadline: DispatchTime = .now(), repeating: DispatchTimeInterval, leeway: DispatchTimeInterval) { - self.deadline = deadline - self.repeating = repeating - self.leeway = leeway - } - - public static func startedTimer( - deadline: DispatchTime = .now(), - repeating: DispatchTimeInterval, - leeway: DispatchTimeInterval, - handler: @escaping (DispatchBasedTimer) -> ()) - -> DispatchBasedTimer - { - let timer = DispatchBasedTimer(deadline: deadline, repeating: repeating, leeway: leeway) - timer.start(handler: handler) - return timer - } - - deinit { - stop() - } - - public func start(handler: @escaping (DispatchBasedTimer) -> ()) { - stop() - - let timer = DispatchSource.makeTimerSource(queue: queue) - timer.schedule(deadline: deadline, repeating: repeating, leeway: leeway) - timer.setEventHandler(handler: { handler(self) }) - timer.resume() - self.timer = timer - } - - public func stop() { - timer?.cancel() - timer?.setEventHandler(handler: nil) - } - - public func pause() { - timer?.suspend() - } - - public func resume() { - timer?.resume() - } -} diff --git a/Sources/Types/Either.swift b/Sources/Types/Either.swift deleted file mode 100644 index a246a47a..00000000 --- a/Sources/Types/Either.swift +++ /dev/null @@ -1,126 +0,0 @@ -import Foundation - -public enum Either: CustomStringConvertible { - case left(Left) - case right(Right) - - public init(_ value: Left) { - self = .left(value) - } - - public init(_ value: Right) { - self = .right(value) - } - - public var description: String { - switch self { - case .left(let value): - return "Result.left(\(value)))" - case .right(let value): - return "Result.right(\(value))" - } - } - - public var isLeft: Bool { - switch self { - case .left: return true - case .right: return false - } - } - - public var isRight: Bool { - return !isLeft - } - - public var left: Left? { - switch self { - case .left(let value): - return value - case .right: - return nil - } - } - - public var right: Right? { - switch self { - case .right(let value): - return value - case .left: - return nil - } - } -} - -public extension Either where Right: Error { - static func success(_ value: Left) -> Either { - return Either.left(value) - } - - static func error(_ error: Right) -> Either { - return Either.right(error) - } - - init(value: Left) { - self = .left(value) - } - - init(error: Right) { - self = .right(error) - } - - func dematerialize() throws -> Left { - switch self { - case .left(let value): - return value - case .right(let error): - throw error - } - } - - func mapResult(_ transform: (Left) -> NewResult) -> Either { - do { - let result = try dematerialize() - return .success(transform(result)) - } catch { - return .error(error) - } - } - - var isSuccess: Bool { return isLeft } - var isError: Bool { return isRight } -} - -extension Either: Equatable where Left: Equatable, Right: Equatable {} - -extension Either: Codable where Left: Codable, Right: Codable { - private enum CodingKeys: String, CodingKey { - case value, caseId - } - - private enum CaseId: String, Codable { - case left, right - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - switch self { - case .left(let value): - try container.encode(CaseId.left, forKey: CodingKeys.caseId) - try container.encode(value, forKey: CodingKeys.value) - case .right(let value): - try container.encode(CaseId.right, forKey: CodingKeys.caseId) - try container.encode(value, forKey: CodingKeys.value) - } - } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - let caseId = try container.decode(CaseId.self, forKey: CodingKeys.caseId) - switch caseId { - case .left: - self = .left(try container.decode(Left.self, forKey: CodingKeys.value)) - case .right: - self = .right(try container.decode(Right.self, forKey: CodingKeys.value)) - } - } -} diff --git a/Sources/Types/MapWithCollection.swift b/Sources/Types/MapWithCollection.swift deleted file mode 100644 index 00b383ad..00000000 --- a/Sources/Types/MapWithCollection.swift +++ /dev/null @@ -1,85 +0,0 @@ -import Foundation - -public struct MapWithCollection where Key : Hashable { - - private var dictionary = [Key: [ValueElement]]() - - public init(_ dictionary: [Key: [ValueElement]] = [:]) { - self.dictionary = dictionary - } - - public subscript(key: Key) -> [ValueElement] { - set { - if newValue.isEmpty { - dictionary.removeValue(forKey: key) - } else { - dictionary[key] = newValue - } - } - get { - return dictionary[key] ?? [] - } - } - - public var values: [[ValueElement]] { - return Array(dictionary.values) - } - - public var flattenValues: [ValueElement] { values.flatMap { $0 } } - - public var asDictionary: [Key: [ValueElement]] { dictionary } - - public mutating func append(key: Key, element: ValueElement) { - append(key: key, elements: [element]) - } - - public mutating func append(key: Key, elements: [ValueElement]) { - self[key] = self[key] + elements - } - - public mutating func removeValue(forKey key: Key) { - dictionary.removeValue(forKey: key) - } - - public var isEmpty: Bool { dictionary.isEmpty } - - public var count: Int { dictionary.count } - - public mutating func extend(_ other: MapWithCollection) { - for keyValue in other.asDictionary { - append(key: keyValue.key, elements: keyValue.value) - } - } -} - -extension MapWithCollection: ExpressibleByDictionaryLiteral { - public typealias Key = Key - public typealias Value = [ValueElement] - - public init(dictionaryLiteral elements: (Key, [ValueElement])...) { - self = MapWithCollection() - for element in elements { - append(key: element.0, elements: element.1) - } - } -} - -extension MapWithCollection: Decodable where Key: Decodable, ValueElement: Decodable { - public init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - self = MapWithCollection( - try container.decode([Key: [ValueElement]].self) - ) - } -} - -extension MapWithCollection: Encodable where Key: Encodable, ValueElement: Encodable { - public func encode(to encoder: Encoder) throws { - var container = encoder.singleValueContainer() - try container.encode(dictionary) - } -} - -extension MapWithCollection: Equatable where Key: Equatable, ValueElement: Equatable { - -} diff --git a/Sources/Types/NewIntType.swift b/Sources/Types/NewIntType.swift deleted file mode 100644 index 8ab86199..00000000 --- a/Sources/Types/NewIntType.swift +++ /dev/null @@ -1,41 +0,0 @@ -import Foundation - -open class NewIntType: ExpressibleByIntegerLiteral, Codable, Hashable, CustomStringConvertible, Comparable { - public typealias IntegerLiteralType = Int - - public let value: Int - - public init(value: Int) { - self.value = value - } - - public required init(integerLiteral value: Int) { - self.value = value - } - - public var description: String { - return "\(value)" - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(value) - } - - public static func ==(left: NewIntType, right: NewIntType) -> Bool { - return left.value == right.value - } - - public required init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - value = try container.decode(Int.self) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.singleValueContainer() - try container.encode(value) - } - - public static func < (left: NewIntType, right: NewIntType) -> Bool { - return left.value < right.value - } -} diff --git a/Sources/Types/NewStringType.swift b/Sources/Types/NewStringType.swift deleted file mode 100644 index 87eae381..00000000 --- a/Sources/Types/NewStringType.swift +++ /dev/null @@ -1,45 +0,0 @@ -import Foundation - -open class NewStringType: ExpressibleByStringLiteral, Codable, Hashable, CustomStringConvertible, Comparable { - public typealias StringLiteralType = String - - public let value: String - - public convenience init(_ value: String) { - self.init(value: value) - } - - public init(value: String) { - self.value = value - } - - public var description: String { - return "\(type(of: self)): \(value)" - } - - required public init(stringLiteral value: StringLiteralType) { - self.value = value - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(value) - } - - public static func ==(left: NewStringType, right: NewStringType) -> Bool { - return left.value == right.value - } - - public required init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - value = try container.decode(String.self) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.singleValueContainer() - try container.encode(value) - } - - public static func < (left: NewStringType, right: NewStringType) -> Bool { - return left.value < right.value - } -} diff --git a/Sources/fbxctest/FbsimctlBasedSimulatorStateMachineActionExecutor.swift b/Sources/fbxctest/FbsimctlBasedSimulatorStateMachineActionExecutor.swift index c37e5fd3..33197be5 100644 --- a/Sources/fbxctest/FbsimctlBasedSimulatorStateMachineActionExecutor.swift +++ b/Sources/fbxctest/FbsimctlBasedSimulatorStateMachineActionExecutor.swift @@ -42,7 +42,7 @@ public final class FbsimctlBasedSimulatorStateMachineActionExecutor: SimulatorSt "create", "iOS \(testDestination.runtime)", testDestination.deviceType ], - environment: environment + environment: Environment(environment) ) ) @@ -79,7 +79,7 @@ public final class FbsimctlBasedSimulatorStateMachineActionExecutor: SimulatorSt "--locale", "ru_US", "--direct-launch", "--", "listen" ], - environment: environment + environment: Environment(environment) ) ) try waitForFbsimctlToBootSimulator( @@ -114,7 +114,7 @@ public final class FbsimctlBasedSimulatorStateMachineActionExecutor: SimulatorSt "simctl", "--set", simulator.simulatorSetPath, "shutdown", simulator.udid.value ], - environment: environment, + environment: Environment(environment), automaticManagement: .sigintThenKillIfSilent(interval: timeout) ) ) @@ -139,7 +139,7 @@ public final class FbsimctlBasedSimulatorStateMachineActionExecutor: SimulatorSt "--json", "--set", simulator.simulatorSetPath, "--simulators", "delete" ], - environment: environment, + environment: Environment(environment), automaticManagement: .sigintThenKillIfSilent(interval: timeout) ) ) diff --git a/Sources/fbxctest/FbsimctlOutputProcessor.swift b/Sources/fbxctest/FbsimctlOutputProcessor.swift index dc13c41c..40e16697 100644 --- a/Sources/fbxctest/FbsimctlOutputProcessor.swift +++ b/Sources/fbxctest/FbsimctlOutputProcessor.swift @@ -38,7 +38,7 @@ public final class FbsimctlOutputProcessor: JSONReaderEventStream { while shouldKeepWaitingForEvent(type: type, name: name) { guard Date().timeIntervalSinceReferenceDate - startTime < timeout else { - Logger.debug("Did not receive event \(name) \(type) within \(timeout) seconds", processController.subprocessInfo) + Logger.debug("Did not receive event \(name) \(type) within \(timeout) seconds") processController.interruptAndForceKillIfNeeded() throw FbsimctlEventWaitError.timeoutOccured(name, type) } @@ -78,13 +78,13 @@ public final class FbsimctlOutputProcessor: JSONReaderEventStream { private func processSingleLiveEvent(eventData: Data) { if let event = try? decoder.decode(FbSimCtlCreateEndedEvent.self, from: eventData) { - Logger.verboseDebug("Parsed event: \(event)", processController.subprocessInfo) + Logger.verboseDebug("Parsed event: \(event)") receivedEvents.withExclusiveAccess { $0.append(event) } return } if let event = try? decoder.decode(FbSimCtlEventWithStringSubject.self, from: eventData) { - Logger.verboseDebug("Parsed event: \(event)", processController.subprocessInfo) + Logger.verboseDebug("Parsed event: \(event)") receivedEvents.withExclusiveAccess { $0.append(event) } return } @@ -92,10 +92,10 @@ public final class FbsimctlOutputProcessor: JSONReaderEventStream { do { let event = try decoder.decode(FbSimCtlEvent.self, from: eventData) receivedEvents.withExclusiveAccess { $0.append(event) } - Logger.verboseDebug("Parsed event: \(event)", processController.subprocessInfo) + Logger.verboseDebug("Parsed event: \(event)") } catch { let dataStringRepresentation = String(data: eventData, encoding: .utf8) - Logger.error("Failed to parse event: '\(String(describing: dataStringRepresentation))': \(error)", processController.subprocessInfo) + Logger.error("Failed to parse event: '\(String(describing: dataStringRepresentation))': \(error)") } } diff --git a/Sources/fbxctest/FbxctestBasedTestRunner.swift b/Sources/fbxctest/FbxctestBasedTestRunner.swift index eed61217..0706ea82 100644 --- a/Sources/fbxctest/FbxctestBasedTestRunner.swift +++ b/Sources/fbxctest/FbxctestBasedTestRunner.swift @@ -8,7 +8,7 @@ import ResourceLocationResolver import Runner import RunnerModels import SimulatorPoolModels -import TemporaryStuff +import Tmp public final class FbxctestBasedTestRunner: TestRunner { private let encoder = JSONEncoder() @@ -138,10 +138,10 @@ public final class FbxctestBasedTestRunner: TestRunner { private func fbxctestEnvironment( testContext: TestContext, fbxctestTempFolder: AbsolutePath - ) -> [String: String] { + ) -> Environment { var result = testContext.environment result["TMPDIR"] = fbxctestTempFolder.pathString - return result + return Environment(result) } private func cleanUp(fbxctestWorkingDirectory: AbsolutePath) { diff --git a/Sources/fbxctest/FbxctestOutputProcessor.swift b/Sources/fbxctest/FbxctestOutputProcessor.swift index 5462e53d..6ef424c2 100644 --- a/Sources/fbxctest/FbxctestOutputProcessor.swift +++ b/Sources/fbxctest/FbxctestOutputProcessor.swift @@ -178,6 +178,6 @@ public final class FbxctestOutputProcessor: TestRunnerInvocation { } private func log_fbxctest(_ text: String) { - Logger.verboseDebug(text, processController.subprocessInfo) + Logger.verboseDebug(text) } } diff --git a/Tests/AppleToolsTests/SimctlBasedSimulatorStateMachineActionExecutorTests.swift b/Tests/AppleToolsTests/SimctlBasedSimulatorStateMachineActionExecutorTests.swift index 9d322fd9..719e5f33 100644 --- a/Tests/AppleToolsTests/SimctlBasedSimulatorStateMachineActionExecutorTests.swift +++ b/Tests/AppleToolsTests/SimctlBasedSimulatorStateMachineActionExecutorTests.swift @@ -5,7 +5,7 @@ import ProcessController import ProcessControllerTestHelpers import SimulatorPoolModels import SimulatorPoolTestHelpers -import TemporaryStuff +import Tmp import XCTest final class SimctlBasedSimulatorStateMachineActionExecutorTests: XCTestCase { @@ -22,7 +22,7 @@ final class SimctlBasedSimulatorStateMachineActionExecutorTests: XCTestCase { func test___when_simctl_finished_with_non_zero_code___create_throws() { let executor = SimctlBasedSimulatorStateMachineActionExecutor( - processControllerProvider: FakeProcessControllerProvider(tempFolder: tempFolder) { subprocess in + processControllerProvider: FakeProcessControllerProvider { subprocess in let controller = FakeProcessController(subprocess: subprocess) controller.overridedProcessStatus = ProcessStatus.terminated(exitCode: 1) return controller @@ -40,18 +40,9 @@ final class SimctlBasedSimulatorStateMachineActionExecutorTests: XCTestCase { func test___when_simctl_does_not_return_udid___create_throws() { let executor = SimctlBasedSimulatorStateMachineActionExecutor( - processControllerProvider: FakeProcessControllerProvider(tempFolder: tempFolder) { subprocess in + processControllerProvider: FakeProcessControllerProvider { subprocess in let controller = FakeProcessController(subprocess: subprocess) controller.overridedProcessStatus = ProcessStatus.terminated(exitCode: 0) - - let pathToStdout = try self.tempFolder.createFile(filename: "stdout.txt") - - controller.subprocess = Subprocess( - arguments: subprocess.arguments, - standardStreamsCaptureConfig: StandardStreamsCaptureConfig( - stdoutPath: pathToStdout - ) - ) return controller }, simulatorSetPath: tempFolder.absolutePath @@ -70,21 +61,13 @@ final class SimctlBasedSimulatorStateMachineActionExecutorTests: XCTestCase { let expectedUdid = UUID().uuidString let executor = SimctlBasedSimulatorStateMachineActionExecutor( - processControllerProvider: FakeProcessControllerProvider(tempFolder: tempFolder) { subprocess in + processControllerProvider: FakeProcessControllerProvider { subprocess in let controller = FakeProcessController(subprocess: subprocess) - controller.overridedProcessStatus = ProcessStatus.terminated(exitCode: 0) - - let pathToStdout = try self.tempFolder.createFile( - filename: "stdout.txt", - contents: Data(expectedUdid.utf8) - ) - - controller.subprocess = Subprocess( - arguments: subprocess.arguments, - standardStreamsCaptureConfig: StandardStreamsCaptureConfig( - stdoutPath: pathToStdout - ) - ) + controller.onStart { _, unsubscribe in + controller.broadcastStdout(data: Data(expectedUdid.utf8)) + controller.overridedProcessStatus = .terminated(exitCode: 0) + unsubscribe() + } return controller }, simulatorSetPath: tempFolder.absolutePath @@ -102,9 +85,35 @@ final class SimctlBasedSimulatorStateMachineActionExecutorTests: XCTestCase { } } + func test___when_simctl_returns_udid___new_lines_ignored() { + let expectedUdid = UUID().uuidString + "\n" + + let executor = SimctlBasedSimulatorStateMachineActionExecutor( + processControllerProvider: FakeProcessControllerProvider { subprocess in + let controller = FakeProcessController(subprocess: subprocess) + controller.onStart { _, unsubscribe in + controller.broadcastStdout(data: Data(expectedUdid.utf8)) + controller.overridedProcessStatus = .terminated(exitCode: 0) + unsubscribe() + } + return controller + }, + simulatorSetPath: tempFolder.absolutePath + ) + + assertDoesNotThrow { + let simulator = try executor.performCreateSimulatorAction( + environment: [:], + testDestination: TestDestinationFixtures.testDestination, + timeout: 60 + ) + XCTAssertEqual(simulator.udid, UDID(value: expectedUdid.trimmingCharacters(in: .whitespacesAndNewlines))) + } + } + func test___create_simulator_simctl_args() { let executor = SimctlBasedSimulatorStateMachineActionExecutor( - processControllerProvider: FakeProcessControllerProvider(tempFolder: tempFolder) { subprocess in + processControllerProvider: FakeProcessControllerProvider { subprocess in XCTAssertEqual( try subprocess.arguments.map { try $0.stringValue() }, [ @@ -134,7 +143,7 @@ final class SimctlBasedSimulatorStateMachineActionExecutorTests: XCTestCase { func test___boot_simulator_simctl_args() { let executor = SimctlBasedSimulatorStateMachineActionExecutor( - processControllerProvider: FakeProcessControllerProvider(tempFolder: tempFolder) { subprocess in + processControllerProvider: FakeProcessControllerProvider { subprocess in XCTAssertEqual( try subprocess.arguments.map { try $0.stringValue() }, [ @@ -163,7 +172,7 @@ final class SimctlBasedSimulatorStateMachineActionExecutorTests: XCTestCase { func test___boot_simulator_throws___if_simctl_fails() { let executor = SimctlBasedSimulatorStateMachineActionExecutor( - processControllerProvider: FakeProcessControllerProvider(tempFolder: tempFolder) { subprocess in + processControllerProvider: FakeProcessControllerProvider { subprocess in let controller = FakeProcessController(subprocess: subprocess) controller.overridedProcessStatus = ProcessStatus.terminated(exitCode: 1) return controller @@ -182,7 +191,7 @@ final class SimctlBasedSimulatorStateMachineActionExecutorTests: XCTestCase { func test___shutdown_simulator_simctl_args() { let executor = SimctlBasedSimulatorStateMachineActionExecutor( - processControllerProvider: FakeProcessControllerProvider(tempFolder: tempFolder) { subprocess in + processControllerProvider: FakeProcessControllerProvider { subprocess in XCTAssertEqual( try subprocess.arguments.map { try $0.stringValue() }, [ @@ -210,7 +219,7 @@ final class SimctlBasedSimulatorStateMachineActionExecutorTests: XCTestCase { func test___shutdown_simulator_throws___if_simctl_fails() { let executor = SimctlBasedSimulatorStateMachineActionExecutor( - processControllerProvider: FakeProcessControllerProvider(tempFolder: tempFolder) { subprocess in + processControllerProvider: FakeProcessControllerProvider { subprocess in let controller = FakeProcessController(subprocess: subprocess) controller.overridedProcessStatus = ProcessStatus.terminated(exitCode: 1) return controller @@ -229,7 +238,7 @@ final class SimctlBasedSimulatorStateMachineActionExecutorTests: XCTestCase { func test___delete_simulator_simctl_args() { let executor = SimctlBasedSimulatorStateMachineActionExecutor( - processControllerProvider: FakeProcessControllerProvider(tempFolder: tempFolder) { subprocess in + processControllerProvider: FakeProcessControllerProvider { subprocess in XCTAssertEqual( try subprocess.arguments.map { try $0.stringValue() }, [ @@ -257,7 +266,7 @@ final class SimctlBasedSimulatorStateMachineActionExecutorTests: XCTestCase { func test___delete_simulator_throws___if_simctl_fails() { let executor = SimctlBasedSimulatorStateMachineActionExecutor( - processControllerProvider: FakeProcessControllerProvider(tempFolder: tempFolder) { subprocess in + processControllerProvider: FakeProcessControllerProvider { subprocess in let controller = FakeProcessController(subprocess: subprocess) controller.overridedProcessStatus = ProcessStatus.terminated(exitCode: 1) return controller diff --git a/Tests/AppleToolsTests/XcTestRunFileArgumentTests.swift b/Tests/AppleToolsTests/XcTestRunFileArgumentTests.swift index 368f6514..95bf85e1 100644 --- a/Tests/AppleToolsTests/XcTestRunFileArgumentTests.swift +++ b/Tests/AppleToolsTests/XcTestRunFileArgumentTests.swift @@ -6,7 +6,7 @@ import QueueModelsTestHelpers import ResourceLocationResolverTestHelpers import RunnerModels import RunnerTestHelpers -import TemporaryStuff +import Tmp import TestHelpers import XCTest diff --git a/Tests/AppleToolsTests/XcodebuildBasedTestRunnerTests.swift b/Tests/AppleToolsTests/XcodebuildBasedTestRunnerTests.swift index 04f35e64..74bb1d62 100644 --- a/Tests/AppleToolsTests/XcodebuildBasedTestRunnerTests.swift +++ b/Tests/AppleToolsTests/XcodebuildBasedTestRunnerTests.swift @@ -19,7 +19,7 @@ import RunnerModels import RunnerTestHelpers import SimulatorPoolModels import SimulatorPoolTestHelpers -import TemporaryStuff +import Tmp import TestHelpers import URLResource import XCTest @@ -29,7 +29,7 @@ final class XcodebuildBasedTestRunnerTests: XCTestCase { private let testRunnerStream = AccumulatingTestRunnerStream() private let dateProvider = DateProviderFixture(Date(timeIntervalSince1970: 100500)) private lazy var contextUuid = UUID() - private lazy var processControllerProvider = FakeProcessControllerProvider(tempFolder: tempFolder) + private lazy var processControllerProvider = FakeProcessControllerProvider() private lazy var resourceLocationResolver = FakeResourceLocationResolver( resolvingResult: .directlyAccessibleFile(path: tempFolder.absolutePath) ) diff --git a/Tests/DateProviderTestHelpers/DateProviderFixture.swift b/Tests/DateProviderTestHelpers/DateProviderFixture.swift deleted file mode 100644 index 3cd9a597..00000000 --- a/Tests/DateProviderTestHelpers/DateProviderFixture.swift +++ /dev/null @@ -1,19 +0,0 @@ -import Foundation -import DateProvider - -public final class DateProviderFixture: DateProvider { - public var result: Date - - public init(_ date: Date = Date()) { - self.result = date - } - - public func with(date: Date) -> Self { - result = date - return self - } - - public func currentDate() -> Date { - return result - } -} diff --git a/Tests/DeployerTests/DeployableBundleTests.swift b/Tests/DeployerTests/DeployableBundleTests.swift index 8d668aac..ceb4ebae 100644 --- a/Tests/DeployerTests/DeployableBundleTests.swift +++ b/Tests/DeployerTests/DeployableBundleTests.swift @@ -1,7 +1,7 @@ @testable import Deployer import Foundation import PathLib -import TemporaryStuff +import Tmp import TestHelpers import XCTest diff --git a/Tests/DeployerTests/DeployerTests.swift b/Tests/DeployerTests/DeployerTests.swift index c31339ba..9490c2c2 100644 --- a/Tests/DeployerTests/DeployerTests.swift +++ b/Tests/DeployerTests/DeployerTests.swift @@ -3,7 +3,7 @@ import Foundation import PathLib import ProcessController import ProcessControllerTestHelpers -import TemporaryStuff +import Tmp import UniqueIdentifierGeneratorTestHelpers import XCTest @@ -33,7 +33,7 @@ class DeployerTests: XCTestCase { password: "pass", remoteDeploymentPath: "/remote/path" ), - processControllerProvider: FakeProcessControllerProvider(tempFolder: tempFolder) { subprocess -> ProcessController in + processControllerProvider: FakeProcessControllerProvider { subprocess -> ProcessController in XCTAssertEqual( try subprocess.arguments.map { try $0.stringValue() }, ["/usr/bin/zip", self.tempFolder.pathWith(components: ["fixed", "simple_file"]).pathString, "-r", "."] @@ -75,7 +75,7 @@ class DeployerTests: XCTestCase { password: "pass", remoteDeploymentPath: "/remote/path" ), - processControllerProvider: FakeProcessControllerProvider(tempFolder: self.tempFolder), + processControllerProvider: FakeProcessControllerProvider(), temporaryFolder: self.tempFolder, uniqueIdentifierGenerator: self.uniqueIdentifierGenerator ) diff --git a/Tests/DeveloperDirLocatorTests/DefaultDeveloperDirLocatorTests.swift b/Tests/DeveloperDirLocatorTests/DefaultDeveloperDirLocatorTests.swift index fa8bd5b1..ba11b3d8 100644 --- a/Tests/DeveloperDirLocatorTests/DefaultDeveloperDirLocatorTests.swift +++ b/Tests/DeveloperDirLocatorTests/DefaultDeveloperDirLocatorTests.swift @@ -4,26 +4,25 @@ import PathLib import ProcessController import ProcessControllerTestHelpers import TestHelpers -import TemporaryStuff +import Tmp import XCTest final class DefaultDeveloperDirLocatorTests: XCTestCase { let currentDeveloperDirPath = AbsolutePath("/expected/path/to/developer/dir") lazy var tempFolder = assertDoesNotThrow { try TemporaryFolder() } - lazy var processControllerProvider = FakeProcessControllerProvider(tempFolder: tempFolder) { subprocess -> ProcessController in + lazy var processControllerProvider = FakeProcessControllerProvider() { subprocess -> ProcessController in XCTAssertEqual( try subprocess.arguments.map { try $0.stringValue() }, ["/usr/bin/xcode-select", "-p"] ) - self.assertDoesNotThrow { - try self.currentDeveloperDirPath.pathString.write( - to: subprocess.standardStreamsCaptureConfig.stdoutOutputPath().fileUrl, - atomically: true, - encoding: .utf8 - ) + + let processController = FakeProcessController(subprocess: subprocess) + processController.onStart { _, unsubscribe in + processController.broadcastStdout(data: Data(self.currentDeveloperDirPath.pathString.utf8)) + unsubscribe() } - return FakeProcessController(subprocess: subprocess) + return processController } func test___current_developer_dir() throws { diff --git a/Tests/DistDeployerTests/DeployablesGeneratorTests.swift b/Tests/DistDeployerTests/DeployablesGeneratorTests.swift index 2d374f6d..a88c8859 100644 --- a/Tests/DistDeployerTests/DeployablesGeneratorTests.swift +++ b/Tests/DistDeployerTests/DeployablesGeneratorTests.swift @@ -2,7 +2,7 @@ import Deployer import PathLib import ResourceLocationResolver -import TemporaryStuff +import Tmp import XCTest class DeployablesGeneratorTests: XCTestCase { diff --git a/Tests/EmceeLibTests/SimulatorSetPathDeterminerTests.swift b/Tests/EmceeLibTests/SimulatorSetPathDeterminerTests.swift index ab907fd6..19514355 100644 --- a/Tests/EmceeLibTests/SimulatorSetPathDeterminerTests.swift +++ b/Tests/EmceeLibTests/SimulatorSetPathDeterminerTests.swift @@ -5,7 +5,7 @@ import Foundation import ResourceLocationResolverTestHelpers import RunnerTestHelpers import SimulatorPoolModels -import TemporaryStuff +import Tmp import TestHelpers import UniqueIdentifierGeneratorTestHelpers import XCTest diff --git a/Tests/EmceeLibTests/SimulatorStateMachineActionExecutorProviderTests.swift b/Tests/EmceeLibTests/SimulatorStateMachineActionExecutorProviderTests.swift index 615976ab..bc4b98d9 100644 --- a/Tests/EmceeLibTests/SimulatorStateMachineActionExecutorProviderTests.swift +++ b/Tests/EmceeLibTests/SimulatorStateMachineActionExecutorProviderTests.swift @@ -10,13 +10,13 @@ import ResourceLocationResolverTestHelpers import RunnerTestHelpers import SimulatorPoolModels import SimulatorPoolTestHelpers -import TemporaryStuff +import Tmp import XCTest import fbxctest final class SimulatorStateMachineActionExecutorProviderTests: XCTestCase { private lazy var tempFolder = assertDoesNotThrow { try TemporaryFolder() } - private lazy var fakeProcessControllerProvider = FakeProcessControllerProvider(tempFolder: tempFolder) + private lazy var fakeProcessControllerProvider = FakeProcessControllerProvider() private lazy var provider = SimulatorStateMachineActionExecutorProviderImpl( dateProvider: DateProviderFixture(), processControllerProvider: fakeProcessControllerProvider, diff --git a/Tests/ExtensionsTests/FileManagerTests.swift b/Tests/ExtensionsTests/FileManagerTests.swift index 3aa25d2f..010ae4b1 100644 --- a/Tests/ExtensionsTests/FileManagerTests.swift +++ b/Tests/ExtensionsTests/FileManagerTests.swift @@ -1,5 +1,5 @@ import Foundation -import TemporaryStuff +import Tmp import XCTest public class FileManagerTests: XCTestCase { diff --git a/Tests/FileCacheTests/FileCacheTests.swift b/Tests/FileCacheTests/FileCacheTests.swift index b751a028..99e438f8 100644 --- a/Tests/FileCacheTests/FileCacheTests.swift +++ b/Tests/FileCacheTests/FileCacheTests.swift @@ -3,7 +3,7 @@ import FileCache import FileSystem import Foundation import PathLib -import TemporaryStuff +import Tmp import TestHelpers import UniqueIdentifierGenerator import UniqueIdentifierGeneratorTestHelpers diff --git a/Tests/FileSystemTestHelpers/FakeFilePropertiesContainer.swift b/Tests/FileSystemTestHelpers/FakeFilePropertiesContainer.swift deleted file mode 100644 index a953724d..00000000 --- a/Tests/FileSystemTestHelpers/FakeFilePropertiesContainer.swift +++ /dev/null @@ -1,30 +0,0 @@ -import FileSystem -import Foundation -import PathLib - -public class FakeFilePropertiesContainer: FilePropertiesContainer { - public let path: AbsolutePath - - public init(path: AbsolutePath) { - self.path = path - } - - public var mdate = Date(timeIntervalSince1970: 500) - public func modificationDate() throws -> Date { mdate } - public func set(modificationDate: Date) throws { mdate = modificationDate } - - public var executable = false - public func isExecutable() throws -> Bool { executable } - - public var pathExists = true - public func exists() throws -> Bool { pathExists } - - public var directory = false - public func isDirectory() throws -> Bool { directory } - - public var regularFile = true - public func isRegularFile() throws -> Bool { regularFile } - - public var fileSize = 0 - public func size() throws -> Int { fileSize } -} diff --git a/Tests/FileSystemTestHelpers/FakeFileSystem.swift b/Tests/FileSystemTestHelpers/FakeFileSystem.swift deleted file mode 100644 index 24fd6841..00000000 --- a/Tests/FileSystemTestHelpers/FakeFileSystem.swift +++ /dev/null @@ -1,49 +0,0 @@ -import FileSystem -import Foundation -import PathLib - -public class FakeFileSystem: FileSystem { - public init(rootPath: AbsolutePath) { - self.fakeCommonlyUsedPathsProvider = FakeCommonlyUsedPathsProvider( - applicationsProvider: { _ in rootPath.appending(components: ["Applications"]) }, - cachesProvider: { _ in rootPath.appending(components: ["Library", "Caches"]) }, - libraryProvider: { _ in rootPath.appending(component: "Library") } - ) - } - - public var fakeCommonlyUsedPathsProvider: FakeCommonlyUsedPathsProvider - public var commonlyUsedPathsProvider: CommonlyUsedPathsProvider { fakeCommonlyUsedPathsProvider } - - public var fakeContentEnumerator: ((path: AbsolutePath, style: ContentEnumerationStyle)) -> FileSystemEnumerator = { args in - FakeFileSystemEnumerator(path: args.path) - } - - public func contentEnumerator(forPath path: AbsolutePath, style: ContentEnumerationStyle) -> FileSystemEnumerator { - fakeContentEnumerator((path: path, style: style)) - } - - public func createDirectory(atPath: AbsolutePath, withIntermediateDirectories: Bool) throws { - - } - - public func createFile(atPath: AbsolutePath, data: Data?) throws { - - } - - public func copy(source: AbsolutePath, destination: AbsolutePath) throws { - - } - - public func move(source: AbsolutePath, destination: AbsolutePath) throws { - - } - - public func delete(fileAtPath: AbsolutePath) throws { - - } - - public var propertiesProvider: (AbsolutePath) -> FilePropertiesContainer = { FakeFilePropertiesContainer(path: $0) } - public func properties(forFileAtPath path: AbsolutePath) -> FilePropertiesContainer { - propertiesProvider(path) - } -} diff --git a/Tests/FileSystemTestHelpers/FakeFileSystemEnumerator.swift b/Tests/FileSystemTestHelpers/FakeFileSystemEnumerator.swift deleted file mode 100644 index 9c16c7b4..00000000 --- a/Tests/FileSystemTestHelpers/FakeFileSystemEnumerator.swift +++ /dev/null @@ -1,16 +0,0 @@ -import FileSystem -import Foundation -import PathLib - -public class FakeFileSystemEnumerator: FileSystemEnumerator { - public let path: AbsolutePath - public var items = [AbsolutePath]() - - public init(path: AbsolutePath) { - self.path = path - } - - public func each(iterator: (AbsolutePath) throws -> ()) throws { - try items.forEach(iterator) - } -} diff --git a/Tests/FileSystemTestHelpers/FileSystemTestHelpers.swift b/Tests/FileSystemTestHelpers/FileSystemTestHelpers.swift deleted file mode 100644 index 55b82053..00000000 --- a/Tests/FileSystemTestHelpers/FileSystemTestHelpers.swift +++ /dev/null @@ -1,31 +0,0 @@ -import Foundation -import FileSystem -import PathLib - -public class FakeCommonlyUsedPathsProvider: CommonlyUsedPathsProvider { - public var applicationsProvider: ((domain: SearchDomain, create: Bool)) throws -> AbsolutePath - public var cachesProvider: ((domain: SearchDomain, create: Bool)) throws -> AbsolutePath - public var libraryProvider: ((domain: SearchDomain, create: Bool)) throws -> AbsolutePath - - public init( - applicationsProvider: @escaping ((domain: SearchDomain, create: Bool)) throws -> AbsolutePath, - cachesProvider: @escaping ((domain: SearchDomain, create: Bool)) throws -> AbsolutePath, - libraryProvider: @escaping ((domain: SearchDomain, create: Bool)) throws -> AbsolutePath - ) { - self.applicationsProvider = applicationsProvider - self.cachesProvider = cachesProvider - self.libraryProvider = libraryProvider - } - - public func applications(inDomain: SearchDomain, create: Bool) throws -> AbsolutePath { - return try applicationsProvider((domain: inDomain, create: create)) - } - - public func caches(inDomain: SearchDomain, create: Bool) throws -> AbsolutePath { - return try cachesProvider((domain: inDomain, create: create)) - } - - public func library(inDomain: SearchDomain, create: Bool) throws -> AbsolutePath { - return try libraryProvider((domain: inDomain, create: create)) - } -} diff --git a/Tests/FileSystemTests/DeepFileSystemEnumeratorTests.swift b/Tests/FileSystemTests/DeepFileSystemEnumeratorTests.swift deleted file mode 100644 index e27cefad..00000000 --- a/Tests/FileSystemTests/DeepFileSystemEnumeratorTests.swift +++ /dev/null @@ -1,26 +0,0 @@ -import FileSystem -import Foundation -import PathLib -import TemporaryStuff -import TestHelpers -import XCTest - -final class DeepFileSystemEnumeratorTests: XCTestCase { - private lazy var tempFolder = assertDoesNotThrow { try TemporaryFolder(deleteOnDealloc: true) } - - func test___enumerating___complete() throws { - let expectedPaths = try createTestDataForEnumeration(tempFolder: tempFolder) - - let enumerator = DeepFileSystemEnumerator( - fileManager: FileManager(), - path: tempFolder.absolutePath - ) - - var paths = Set() - try enumerator.each { (path: AbsolutePath) in - paths.insert(path) - } - - XCTAssertEqual(expectedPaths, paths) - } -} diff --git a/Tests/FileSystemTests/DefaultCommonlyUsedPathsProviderTests.swift b/Tests/FileSystemTests/DefaultCommonlyUsedPathsProviderTests.swift deleted file mode 100644 index 90db6509..00000000 --- a/Tests/FileSystemTests/DefaultCommonlyUsedPathsProviderTests.swift +++ /dev/null @@ -1,30 +0,0 @@ -import FileSystem -import PathLib -import TestHelpers -import XCTest - -final class DefaultCommonlyUsedPathsProviderTests: XCTestCase { - private lazy var defaultCommonlyUsedPathsProvider = DefaultCommonlyUsedPathsProvider(fileManager: fileManager) - private let fileManager = FileManager() - - func test___applications() { - XCTAssertEqual( - try defaultCommonlyUsedPathsProvider.applications(inDomain: .local, create: false), - AbsolutePath("/Applications") - ) - } - - func test___library() { - XCTAssertEqual( - try defaultCommonlyUsedPathsProvider.library(inDomain: .user, create: false).fileUrl, - try fileManager.url(for: .libraryDirectory, in: .userDomainMask, appropriateFor: nil, create: false) - ) - } - - func test___caches() { - XCTAssertEqual( - try defaultCommonlyUsedPathsProvider.caches(inDomain: .user, create: false).fileUrl, - try fileManager.url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: false) - ) - } -} diff --git a/Tests/FileSystemTests/DefaultFilePropertiesContainerTests.swift b/Tests/FileSystemTests/DefaultFilePropertiesContainerTests.swift deleted file mode 100644 index c3477586..00000000 --- a/Tests/FileSystemTests/DefaultFilePropertiesContainerTests.swift +++ /dev/null @@ -1,81 +0,0 @@ -import FileSystem -import Foundation -import TemporaryStuff -import TestHelpers -import XCTest - -final class DefaultFilePropertiesContainerTests: XCTestCase { - private lazy var temporaryFile = assertDoesNotThrow { try TemporaryFile(deleteOnDealloc: true) } - private lazy var filePropertiesContainer = DefaultFilePropertiesContainer(path: temporaryFile.absolutePath) - - func test___modificationDate() { - XCTAssertEqual( - try filePropertiesContainer.modificationDate(), - try temporaryFile.absolutePath.fileUrl.resourceValues(forKeys: [.contentModificationDateKey]).contentModificationDate - ) - } - - func test___setting_modificationDate() throws { - let date = Date(timeIntervalSince1970: 1000) - - try filePropertiesContainer.set(modificationDate: date) - - XCTAssertEqual( - try temporaryFile.absolutePath.fileUrl.resourceValues(forKeys: [.contentModificationDateKey]).contentModificationDate, - date - ) - } - - func test___properties_for_nonexisting_file() { - let properties = DefaultFilePropertiesContainer(path: temporaryFile.absolutePath.appending(component: "nonexisting")) - assertThrows { - try properties.modificationDate() - } - } - - func test___is_executable___when_not_executable() throws { - try FileManager().setAttributes( - [.posixPermissions: 700], - ofItemAtPath: temporaryFile.absolutePath.pathString - ) - - let properties = DefaultFilePropertiesContainer(path: temporaryFile.absolutePath) - XCTAssertFalse(try properties.isExecutable()) - } - - func test___is_executable___when_executable() throws { - try FileManager().setAttributes( - [.posixPermissions: 707], - ofItemAtPath: temporaryFile.absolutePath.pathString - ) - - let properties = DefaultFilePropertiesContainer(path: temporaryFile.absolutePath) - XCTAssertTrue(try properties.isExecutable()) - } - - func test___exists___when_exists() throws { - let properties = DefaultFilePropertiesContainer(path: temporaryFile.absolutePath) - XCTAssertTrue(try properties.exists()) - } - - func test___not_exists___when_not_exists() throws { - let properties = DefaultFilePropertiesContainer(path: temporaryFile.absolutePath.appending(component: "nonexisting")) - XCTAssertFalse(try properties.exists()) - } - - func test___is_directory___for_directory() throws { - let properties = DefaultFilePropertiesContainer(path: temporaryFile.absolutePath.removingLastComponent) - XCTAssertTrue(try properties.isDirectory()) - } - - func test___is_not_directory___for_non_directories() throws { - let properties = DefaultFilePropertiesContainer(path: temporaryFile.absolutePath) - XCTAssertFalse(try properties.isDirectory()) - } - - func test___size() throws { - temporaryFile.fileHandleForWriting.write(Data([0x00, 0x01, 0x02])) - let properties = DefaultFilePropertiesContainer(path: temporaryFile.absolutePath) - XCTAssertEqual(try properties.size(), 3) - } -} diff --git a/Tests/FileSystemTests/LocalFileSystemTests.swift b/Tests/FileSystemTests/LocalFileSystemTests.swift deleted file mode 100644 index 7c754ffb..00000000 --- a/Tests/FileSystemTests/LocalFileSystemTests.swift +++ /dev/null @@ -1,59 +0,0 @@ -import DateProvider -import FileSystem -import Foundation -import PathLib -import TemporaryStuff -import TestHelpers -import XCTest - -final class LocalFileSystemTest: XCTestCase { - private lazy var dateProvider = SystemDateProvider() - private lazy var fileManager = FileManager() - private lazy var fileSystem = LocalFileSystem() - private lazy var tempFolder = assertDoesNotThrow { try TemporaryFolder(deleteOnDealloc: true) } - - func test__enumeration() throws { - let expectedPaths = try createTestDataForEnumeration(tempFolder: tempFolder) - let enumerator = fileSystem.contentEnumerator(forPath: tempFolder.absolutePath, style: .deep) - - var paths = Set() - try enumerator.each { (path: AbsolutePath) in - paths.insert(path) - } - - XCTAssertEqual(expectedPaths, paths) - } - - func test___creating_directory() throws { - let path = tempFolder.pathWith(components: ["new_folder"]) - - XCTAssertFalse(fileManager.fileExists(atPath: path.pathString)) - try fileSystem.createDirectory(atPath: path, withIntermediateDirectories: true) - - var isDir: ObjCBool = false - XCTAssertTrue(fileManager.fileExists(atPath: path.pathString, isDirectory: &isDir)) - XCTAssertTrue(isDir.boolValue) - } - - func test___deleting_file() throws { - let path = try tempFolder.createFile(filename: "file") - - try fileSystem.delete(fileAtPath: path) - XCTAssertFalse(fileManager.fileExists(atPath: path.pathString)) - } - - func test___properties() throws { - let path = try tempFolder.createFile(filename: "file") - - let properties = fileSystem.properties(forFileAtPath: path) - - XCTAssertEqual( - try properties.modificationDate(), - try fileManager.attributesOfItem(atPath: path.pathString)[.modificationDate] as? Date - ) - } - - func test___commonly_used_paths() throws { - XCTAssertTrue(fileSystem.commonlyUsedPathsProvider is DefaultCommonlyUsedPathsProvider) - } -} diff --git a/Tests/FileSystemTests/ShallowFileSystemEnumeratorTests.swift b/Tests/FileSystemTests/ShallowFileSystemEnumeratorTests.swift deleted file mode 100644 index 0afeea3f..00000000 --- a/Tests/FileSystemTests/ShallowFileSystemEnumeratorTests.swift +++ /dev/null @@ -1,27 +0,0 @@ -import FileSystem -import PathLib -import TemporaryStuff -import TestHelpers -import XCTest - -final class ShallowFileSystemEnumeratorTests: XCTestCase { - private lazy var tempFolder = assertDoesNotThrow { try TemporaryFolder(deleteOnDealloc: true) } - - func test___enumerating___complete() throws { - let expectedPaths = try createTestDataForEnumeration(tempFolder: tempFolder).filter { - $0.components.count == tempFolder.absolutePath.components.count + 1 - } - - let enumerator = ShallowFileSystemEnumerator( - fileManager: FileManager(), - path: tempFolder.absolutePath - ) - - var paths = Set() - try enumerator.each { (path: AbsolutePath) in - paths.insert(path) - } - - XCTAssertEqual(expectedPaths, paths) - } -} diff --git a/Tests/FileSystemTests/TestDataForEnumeration.swift b/Tests/FileSystemTests/TestDataForEnumeration.swift deleted file mode 100644 index 7756c7d7..00000000 --- a/Tests/FileSystemTests/TestDataForEnumeration.swift +++ /dev/null @@ -1,12 +0,0 @@ -import PathLib -import TemporaryStuff -import Foundation - -func createTestDataForEnumeration(tempFolder: TemporaryFolder) throws -> Set { - return Set([ - try tempFolder.createFile(filename: "root_file"), - try tempFolder.pathByCreatingDirectories(components: ["empty_folder"]), - try tempFolder.pathByCreatingDirectories(components: ["subfolder"]), - try tempFolder.createFile(components: ["subfolder"], filename: "file_in_subfolder") - ]) -} diff --git a/Tests/LocalQueueServerRunnerTests/LocalQueueServerRunnerTests.swift b/Tests/LocalQueueServerRunnerTests/LocalQueueServerRunnerTests.swift index df7c8459..35551609 100644 --- a/Tests/LocalQueueServerRunnerTests/LocalQueueServerRunnerTests.swift +++ b/Tests/LocalQueueServerRunnerTests/LocalQueueServerRunnerTests.swift @@ -9,7 +9,7 @@ import QueueServerTestHelpers import RemotePortDeterminer import RemotePortDeterminerTestHelpers import ScheduleStrategy -import TemporaryStuff +import Tmp import TestHelpers import UniqueIdentifierGenerator import XCTest diff --git a/Tests/LoggingTests/FileHandleLoggerHandlerTests.swift b/Tests/LoggingTests/FileHandleLoggerHandlerTests.swift index 93982d4c..9fcb6ad4 100644 --- a/Tests/LoggingTests/FileHandleLoggerHandlerTests.swift +++ b/Tests/LoggingTests/FileHandleLoggerHandlerTests.swift @@ -1,6 +1,6 @@ import Foundation import Logging -import TemporaryStuff +import Tmp import XCTest final class FileHandleLoggerHandlerTests: XCTestCase { diff --git a/Tests/LoggingTests/NSLogLikeLogEntryTextFormatterTests.swift b/Tests/LoggingTests/NSLogLikeLogEntryTextFormatterTests.swift index ddaf3f4c..8b50651c 100644 --- a/Tests/LoggingTests/NSLogLikeLogEntryTextFormatterTests.swift +++ b/Tests/LoggingTests/NSLogLikeLogEntryTextFormatterTests.swift @@ -6,7 +6,7 @@ final class NSLogLikeLogEntryTextFormatterTests: XCTestCase { func test() { let entry = LogEntry( message: "message", - subprocessInfo: SubprocessInfo(subprocessId: 42, subprocessName: "subproc"), + pidInfo: PidInfo(pid: 42, name: "subproc"), timestamp: Date(timeIntervalSince1970: 42), verbosity: Verbosity.always ) diff --git a/Tests/MetricsTestHelpers/FakeMetricHandler.swift b/Tests/MetricsTestHelpers/FakeMetricHandler.swift deleted file mode 100644 index e4c463b5..00000000 --- a/Tests/MetricsTestHelpers/FakeMetricHandler.swift +++ /dev/null @@ -1,23 +0,0 @@ -import Foundation -import Graphite -import Metrics -import Statsd - -public final class FakeMetricHandler { - public var metrics = [Metric]() - - public init() {} - - public func handle(metric: Metric) { - metrics.append(metric) - } - - public var tearDownTimeout: TimeInterval = 0 - - public func tearDown(timeout: TimeInterval) { - tearDownTimeout = timeout - } -} - -extension FakeMetricHandler: GraphiteMetricHandler where Metric == GraphiteMetric {} -extension FakeMetricHandler: StatsdMetricHandler where Metric == StatsdMetric {} diff --git a/Tests/MetricsTestHelpers/Metric+TestCompare.swift b/Tests/MetricsTestHelpers/Metric+TestCompare.swift deleted file mode 100644 index 9a0e19fa..00000000 --- a/Tests/MetricsTestHelpers/Metric+TestCompare.swift +++ /dev/null @@ -1,9 +0,0 @@ -import Graphite -import Metrics - -public extension GraphiteMetric { - func testCompare(_ other: GraphiteMetric) -> Bool { - return self.components == other.components - && self.value == other.value - } -} diff --git a/Tests/MetricsTestHelpers/NoOpMetricRecorder.swift b/Tests/MetricsTestHelpers/NoOpMetricRecorder.swift deleted file mode 100644 index 20a60ab5..00000000 --- a/Tests/MetricsTestHelpers/NoOpMetricRecorder.swift +++ /dev/null @@ -1,12 +0,0 @@ -import Foundation -import Graphite -import Metrics -import Statsd - -public final class NoOpMetricRecorder: MetricRecorder { - public init() {} - - public func capture(_ metric: GraphiteMetric) {} - public func capture(_ metric: StatsdMetric) {} - public func tearDown(timeout: TimeInterval) {} -} diff --git a/Tests/MetricsTests/MetricHandlerTests.swift b/Tests/MetricsTests/MetricHandlerTests.swift deleted file mode 100644 index 31b15e18..00000000 --- a/Tests/MetricsTests/MetricHandlerTests.swift +++ /dev/null @@ -1,50 +0,0 @@ -import Foundation -import Graphite -import Metrics -import MetricsTestHelpers -import Statsd -import XCTest - -final class MetricHandlerTests: XCTestCase { - func test___global_metric_handler___captures_graphite_metric() { - let metricHandler = FakeMetricHandler() - let metric = GraphiteMetric( - fixedComponents: ["fixed"], - variableComponents: ["variable"], - value: 33, - timestamp: Date() - ) - - let queue = DispatchQueue(label: "test") - let recorder = MetricRecorderImpl( - graphiteMetricHandler: metricHandler, - statsdMetricHandler: NoOpMetricHandler(), - queue: queue - ) - recorder.capture(metric) - - queue.sync { } - XCTAssertEqual(metricHandler.metrics, [metric]) - } - - func test___global_metric_handler___captures_statsd_metric() { - let metricHandler = FakeMetricHandler() - let metric = StatsdMetric( - fixedComponents: ["fixed"], - variableComponents: ["variable"], - value: .gauge(1) - ) - - let queue = DispatchQueue(label: "test") - let recorder = MetricRecorderImpl( - graphiteMetricHandler: NoOpMetricHandler(), - statsdMetricHandler: metricHandler, - queue: queue - ) - recorder.capture(metric) - - queue.sync { } - XCTAssertEqual(metricHandler.metrics, [metric]) - } -} - diff --git a/Tests/MetricsTests/TimeMeasurerTests.swift b/Tests/MetricsTests/TimeMeasurerTests.swift deleted file mode 100644 index ce1b2dc3..00000000 --- a/Tests/MetricsTests/TimeMeasurerTests.swift +++ /dev/null @@ -1,45 +0,0 @@ -import DateProviderTestHelpers -import Foundation -import Metrics -import TestHelpers -import XCTest - -final class TimeMeasurerTests: XCTestCase { - lazy var dateProvider = DateProviderFixture() - lazy var measurer = TimeMeasurerImpl(dateProvider: dateProvider) - - func test() throws { - dateProvider.result = Date(timeIntervalSinceReferenceDate: 1000) - - let value: Int = measurer.measure( - work: { - dateProvider.result += 1000 - return 42 - }, - result: { error, duration in - XCTAssertEqual(duration, 1000) - } - ) - XCTAssertEqual(value, 42) - } - - func test___rethrows_inner_error() { - dateProvider.result = Date(timeIntervalSinceReferenceDate: 1000) - - assertThrows { - try measurer.measure( - work: { - dateProvider.result += 1000 - throw ErrorForTestingPurposes(text: "text") - }, - result: { error, duration in - guard let error = error as? ErrorForTestingPurposes else { - failTest("Unexpected error") - } - XCTAssertEqual(error.text, "text") - } - ) as Int - } - } -} - diff --git a/Tests/ObservableFileReaderTests/ObservableFileReaderTests.swift b/Tests/ObservableFileReaderTests/ObservableFileReaderTests.swift index a311a02b..67908481 100644 --- a/Tests/ObservableFileReaderTests/ObservableFileReaderTests.swift +++ b/Tests/ObservableFileReaderTests/ObservableFileReaderTests.swift @@ -4,7 +4,7 @@ import Foundation import ObservableFileReader import PathLib import ProcessController -import TemporaryStuff +import Tmp import TestHelpers import XCTest @@ -32,10 +32,10 @@ final class ObservableFileReaderTests: XCTestCase { } } - tempFile.fileHandleForWriting.write("hello") - tempFile.fileHandleForWriting.write(" world") - tempFile.fileHandleForWriting.write("\n123\n") - tempFile.fileHandleForWriting.write("\t") + tempFile.fileHandleForWriting.write(Data("hello".utf8)) + tempFile.fileHandleForWriting.write(Data(" world".utf8)) + tempFile.fileHandleForWriting.write(Data("\n123\n".utf8)) + tempFile.fileHandleForWriting.write(Data("\t".utf8)) wait(for: [collectedTabSymbol], timeout: 15) handler.cancel() diff --git a/Tests/PathLibTests/AbsolutePathTests.swift b/Tests/PathLibTests/AbsolutePathTests.swift deleted file mode 100644 index 5a380f45..00000000 --- a/Tests/PathLibTests/AbsolutePathTests.swift +++ /dev/null @@ -1,78 +0,0 @@ -import Foundation -import PathLib -import XCTest - -class AbsolutePathTests: XCTestCase { - - func test___create_from_components___file_path() { - let path = AbsolutePath(components: ["one", "two", "file"]) - XCTAssertEqual( - path.pathString, - "/one/two/file" - ) - } - - func test___removing_last_component() { - let path = AbsolutePath(components: ["one", "two", "file"]) - XCTAssertEqual( - path.removingLastComponent.pathString, - "/one/two" - ) - } - - func test___last_component() { - let path = AbsolutePath(components: ["one", "two", "file"]) - XCTAssertEqual( - path.lastComponent, - "file" - ) - } - - func test___last_component___when_absolute_path_is_root() { - let path = AbsolutePath(components: []) - XCTAssertEqual( - path.lastComponent, - "/" - ) - } - - func test___removing_last_path_component_from_componentless_path() { - let path = AbsolutePath(components: []) - XCTAssertEqual( - path.removingLastComponent.pathString, - "/" - ) - } - - func test___relative_path_computation() { - let anchor = AbsolutePath("/one/two") - let path = AbsolutePath("/one/two/three/four") - - XCTAssertEqual( - path.relativePath(anchorPath: anchor), - RelativePath("three/four") - ) - } - - func test___relative_path_computation_reversed() { - let path = AbsolutePath("/one/two") - let anchor = AbsolutePath("/one/two/three/four") - - XCTAssertEqual( - path.relativePath(anchorPath: anchor), - RelativePath("../..") - ) - } - - func test___is_subpath() { - XCTAssertTrue( - AbsolutePath("/path/to/something").isSubpathOf(anchorPath: AbsolutePath("/path/to/")) - ) - XCTAssertFalse( - AbsolutePath("/path/to/something").isSubpathOf(anchorPath: AbsolutePath("/path/to/something")) - ) - XCTAssertFalse( - AbsolutePath("/path/of/something").isSubpathOf(anchorPath: AbsolutePath("/path/to/")) - ) - } -} diff --git a/Tests/PathLibTests/PathTests.swift b/Tests/PathLibTests/PathTests.swift deleted file mode 100644 index db9c539e..00000000 --- a/Tests/PathLibTests/PathTests.swift +++ /dev/null @@ -1,30 +0,0 @@ -import Foundation -import PathLib -import XCTest - -class PathTests: XCTestCase { - func test___empty_extension() { - let path = AbsolutePath(components: ["file"]) - XCTAssertEqual(path.extension, "") - } - - func test___extension() { - let path = AbsolutePath(components: ["file.txt"]) - XCTAssertEqual(path.extension, "txt") - } - - func test___extension_multiple_dots() { - let path = AbsolutePath(components: ["file.aaa.txt"]) - XCTAssertEqual(path.extension, "txt") - } - - func test___extension_hidden_file() { - let path = AbsolutePath(components: [".file"]) - XCTAssertEqual(path.extension, "") - } - - func test___extension_hidden_file_with_multiple_dots() { - let path = AbsolutePath(components: [".file.aaa.txt"]) - XCTAssertEqual(path.extension, "txt") - } -} diff --git a/Tests/PathLibTests/RelativePathTests.swift b/Tests/PathLibTests/RelativePathTests.swift deleted file mode 100644 index 5f52ebc8..00000000 --- a/Tests/PathLibTests/RelativePathTests.swift +++ /dev/null @@ -1,33 +0,0 @@ -import Foundation -import PathLib -import XCTest - -class RelativePathTests: XCTestCase { - func test() { - let path = RelativePath(components: ["one", "two"]) - XCTAssertEqual(path.pathString, "one/two") - } - - func test___empty_components() { - XCTAssertEqual( - RelativePath(components: []).pathString, - "./" - ) - } - - func test___removing_last_path_component() { - let path = RelativePath(components: ["two"]) - XCTAssertEqual( - path.removingLastComponent.pathString, - "./" - ) - } - - func test___removing_last_path_component_from_componentless_path() { - let path = RelativePath(components: []) - XCTAssertEqual( - path.removingLastComponent.pathString, - "./" - ) - } -} diff --git a/Tests/PlistLibTests/PlistEntryTests.swift b/Tests/PlistLibTests/PlistEntryTests.swift deleted file mode 100644 index eda31f67..00000000 --- a/Tests/PlistLibTests/PlistEntryTests.swift +++ /dev/null @@ -1,88 +0,0 @@ -import PlistLib -import TestHelpers -import XCTest - -final class PlistEntryTests: XCTestCase { - func test___accessing_entries_in_array() { - let entry = PlistEntry.array([.string("hello")]) - XCTAssertEqual( - try entry.entry(atIndex: 0), - .string("hello") - ) - } - - func test___accessing_entries_in_dict() { - let entry = PlistEntry.dict(["key": .string("hello")]) - - XCTAssertEqual( - try entry.entry(forKey: "key"), - .string("hello") - ) - } - - func test___string() { - let entry = PlistEntry.string("hello") - XCTAssertEqual( - try entry.stringValue(), - "hello" - ) - } - - func test___bool() { - let entry = PlistEntry.bool(true) - XCTAssertEqual( - try entry.boolValue(), - true - ) - } - - func test___date() { - let date = Date() - - let entry = PlistEntry.date(date) - XCTAssertEqual( - try entry.dateValue(), - date - ) - } - - func test___data() { - let data = Data([0x11, 0x22]) - - let entry = PlistEntry.data(data) - XCTAssertEqual( - try entry.dataValue(), - data - ) - } - - func test___accessing_incorrect_value() { - let entry = PlistEntry.string("hello") - - assertThrows { try entry.dateValue() } - } - - func test___accesing_via_typed_functions() { - let entry = PlistEntry.dict([ - "root": .array([ - .string("hello"), - .array([.data(Data([0xFF]))]) - ]) - ]) - - XCTAssertEqual( - try entry.entry(forKey: "root").entry(atIndex: 1).entry(atIndex: 0).dataValue(), - Data([0xFF]) - ) - } - - func test___accessing_bool_using_number___throws() { - let entry = PlistEntry.bool(true) - assertThrows { _ = try entry.numberValue() } - } - - func test___accessing_number_using_bool___throws() { - let entry = PlistEntry.number(3.14) - assertThrows { _ = try entry.boolValue() } - } -} diff --git a/Tests/PlistLibTests/PlistTests.swift b/Tests/PlistLibTests/PlistTests.swift deleted file mode 100644 index 49e8e1fe..00000000 --- a/Tests/PlistLibTests/PlistTests.swift +++ /dev/null @@ -1,143 +0,0 @@ -import Foundation -import PlistLib -import TestHelpers -import XCTest - -final class PlistTests: XCTestCase { - private lazy var plistStringContents = """ - - - - - key - value - - \n - """ - - func test___encoding_to_data() throws { - let plist = Plist( - rootPlistEntry: .dict([ - "key": .string("value") - ]) - ) - let plistData = try plist.data(format: .xml) - - guard let string = String(data: plistData, encoding: .utf8) else { - failTest("Failed to convert data to string") - } - - XCTAssertEqual( - string.replacingOccurrences(of: "\t", with: " "), - plistStringContents - ) - } - - func test___parsing_data() throws { - let plistData = Data(plistStringContents.utf8) - - let plist = try Plist.create(fromData: plistData) - XCTAssertEqual( - plist.root, - RootPlistEntry.dict(["key": .string("value")]) - ) - } - - func test___root_dict_object() throws { - let plist = Plist(rootPlistEntry: .dict(["key": .string("value")])) - XCTAssertEqual( - plist.rootObject() as? NSDictionary, - ["key": "value"] - ) - } - - func test___to_typed_dict___when_dict_is_empty___throws() throws { - let entry = PlistEntry.dict(["key": nil]) - assertThrows { - _ = try entry.toTypedDict(String.self) - } - } - - func test___to_typed_dict___when_dict_is_not_empty___does_not_throw() throws { - let entry = PlistEntry.dict(["key": .string("value")]) - XCTAssertEqual( - try entry.toTypedDict(String.self), - ["key": "value"] - ) - } - - func test___to_typed_dict___when_dict_is_heterogeneous___throws() throws { - let entry = PlistEntry.dict(["key": .string("value"), "key2": .bool(false)]) - assertThrows { _ = try entry.toTypedDict(String.self) } - assertThrows { _ = try entry.toTypedDict(Bool.self) } - } - - func test___root_array_object() throws { - let plist = Plist(rootPlistEntry: .array([.string("hello")])) - XCTAssertEqual( - plist.rootObject() as? NSArray, - ["hello"] - ) - } - - func test___to_typed_array___when_array_is_empty___throws() throws { - let entry = PlistEntry.array([nil]) - assertThrows { - _ = try entry.toTypedArray(String.self) - } - } - - func test___to_typed_array___when_array_is_not_empty___does_not_throw() throws { - let entry = PlistEntry.array([.string("hello")]) - XCTAssertEqual( - try entry.toTypedArray(String.self), - ["hello"] - ) - } - - func test___to_typed_array___when_array_is_heterogeneous___throws() throws { - let entry = PlistEntry.array([.string("hello"), .bool(false)]) - assertThrows { _ = try entry.toTypedArray(String.self) } - assertThrows { _ = try entry.toTypedArray(Bool.self) } - } - - func test___parsing_bool_value() throws { - let plist = Plist(rootPlistEntry: .array([.bool(true)])) - let parsedPlist = try Plist.create(fromData: try plist.data(format: .xml)) - - XCTAssertEqual( - plist.root, - parsedPlist.root - ) - } - - func test___parsing_number_value() throws { - let plist = Plist(rootPlistEntry: .array([.number(123)])) - let parsedPlist = try Plist.create(fromData: try plist.data(format: .xml)) - - XCTAssertEqual( - plist.root, - parsedPlist.root - ) - } - - func test___parsing_data_value() throws { - let plist = Plist(rootPlistEntry: .array([.data(Data([0x42]))])) - let parsedPlist = try Plist.create(fromData: try plist.data(format: .xml)) - - XCTAssertEqual( - plist.root, - parsedPlist.root - ) - } - - func test___parsing_date_value() throws { - let plist = Plist(rootPlistEntry: .array([.date(Date(timeIntervalSinceReferenceDate: 424242))])) - let parsedPlist = try Plist.create(fromData: try plist.data(format: .xml)) - - XCTAssertEqual( - plist.root, - parsedPlist.root - ) - } -} diff --git a/Tests/PluginManagerTests/PluginManagerTests.swift b/Tests/PluginManagerTests/PluginManagerTests.swift index 79f04d01..8ec91b00 100644 --- a/Tests/PluginManagerTests/PluginManagerTests.swift +++ b/Tests/PluginManagerTests/PluginManagerTests.swift @@ -9,7 +9,7 @@ import ProcessControllerTestHelpers import ResourceLocation import ResourceLocationResolverTestHelpers import RunnerTestHelpers -import TemporaryStuff +import Tmp import TestHelpers import XCTest @@ -40,7 +40,7 @@ final class PluginManagerTests: XCTestCase { pluginLocations: [ PluginLocation(.localFilePath(pluginBundlePath.pathString)) ], - processControllerProvider: FakeProcessControllerProvider(tempFolder: tempFolder), + processControllerProvider: FakeProcessControllerProvider(), resourceLocationResolver: resolver ) XCTAssertThrowsError(try manager.startPlugins()) @@ -57,7 +57,7 @@ final class PluginManagerTests: XCTestCase { pluginLocations: [ PluginLocation(.localFilePath(executablePath.pathString)) ], - processControllerProvider: FakeProcessControllerProvider(tempFolder: tempFolder), + processControllerProvider: FakeProcessControllerProvider(), resourceLocationResolver: resolver ) XCTAssertThrowsError(try manager.startPlugins()) diff --git a/Tests/PluginManagerTests/TestingPluginExecutable.swift b/Tests/PluginManagerTests/TestingPluginExecutable.swift index 494345de..8c9f0c37 100644 --- a/Tests/PluginManagerTests/TestingPluginExecutable.swift +++ b/Tests/PluginManagerTests/TestingPluginExecutable.swift @@ -1,4 +1,5 @@ import Foundation +import Extensions final class TestingPluginExecutable { private static let swiftPackagePath = FileManager.default.walkUpTheHierarchy( diff --git a/Tests/ProcessControllerTestHelpers/FakeProcessController.swift b/Tests/ProcessControllerTestHelpers/FakeProcessController.swift deleted file mode 100644 index 5811f4c4..00000000 --- a/Tests/ProcessControllerTestHelpers/FakeProcessController.swift +++ /dev/null @@ -1,104 +0,0 @@ -import Foundation -import ProcessController -import SynchronousWaiter - -public final class FakeProcessController: ProcessController { - public var subprocess: Subprocess - - public init(subprocess: Subprocess, processStatus: ProcessStatus = .notStarted) { - self.subprocess = subprocess - self.overridedProcessStatus = processStatus - } - - public var processName: String { - return try! subprocess.arguments[0].stringValue().lastPathComponent - } - - public var processId: Int32 { - return 0 - } - - public func start() { - for listener in startListeners { - listener(self, {}) - } - } - - public func waitForProcessToDie() { - try? SynchronousWaiter().waitWhile { isProcessRunning } - } - - public var overridedProcessStatus: ProcessStatus = .notStarted - - public func processStatus() -> ProcessStatus { - return overridedProcessStatus - } - - public var signalsSent = [Int32]() - - public func send(signal: Int32) { - signalsSent.append(signal) - - for listener in terminationListeners { - listener(self, {}) - } - } - - public func terminateAndForceKillIfNeeded() { - send(signal: SIGTERM) - overridedProcessStatus = .terminated(exitCode: SIGTERM) - } - - public func interruptAndForceKillIfNeeded() { - send(signal: SIGINT) - overridedProcessStatus = .terminated(exitCode: SIGINT) - } - - public var startListeners = [StartListener]() - - public func onStart(listener: @escaping StartListener) { - startListeners.append(listener) - } - - // Stdout - - public var stdoutListeners = [StdoutListener]() - - public func onStdout(listener: @escaping StdoutListener) { - stdoutListeners.append(listener) - } - - public func broadcastStdout(data: Data) { - stdoutListeners.forEach { $0(self, data, { }) } - } - - // Stderr - - public var stderrListeners = [StdoutListener]() - - public func onStderr(listener: @escaping StderrListener) { - stderrListeners.append(listener) - } - - public func broadcastStderr(data: Data) { - stderrListeners.forEach { $0(self, data, { }) } - } - - // Silence - - public var signalListeners = [SignalListener]() - - public func onSignal(listener: @escaping SignalListener) { - signalListeners.append(listener) - } - - public func broadcastSignal(_ signal: Int32) { - signalListeners.forEach { $0(self, signal, { }) } - } - - public var terminationListeners = [TerminationListener]() - - public func onTermination(listener: @escaping TerminationListener) { - terminationListeners.append(listener) - } -} diff --git a/Tests/ProcessControllerTestHelpers/FakeProcessControllerProvider.swift b/Tests/ProcessControllerTestHelpers/FakeProcessControllerProvider.swift deleted file mode 100644 index 2b250d9d..00000000 --- a/Tests/ProcessControllerTestHelpers/FakeProcessControllerProvider.swift +++ /dev/null @@ -1,30 +0,0 @@ -@testable import ProcessController -import Foundation -import TemporaryStuff - -public final class FakeProcessControllerProvider: ProcessControllerProvider { - public var tempFolder: TemporaryFolder - public var creator: (Subprocess) throws -> (ProcessController) - - public init( - tempFolder: TemporaryFolder, - creator: @escaping (Subprocess) throws -> ProcessController = { FakeProcessController(subprocess: $0)} - ) { - self.tempFolder = tempFolder - self.creator = creator - } - - public func createProcessController(subprocess: Subprocess) throws -> ProcessController { - let uuid = UUID() - return try creator( - subprocess.byRedefiningOutput( - redefiner: { - $0.byRedefiningIfNotSet( - stdoutOutputPath: tempFolder.absolutePath.appending(component: "\(uuid)_stdout.log"), - stderrOutputPath: tempFolder.absolutePath.appending(component: "\(uuid)_stderr.log") - ) - } - ) - ) - } -} diff --git a/Tests/ProcessControllerTests/AutomaticManagementTests.swift b/Tests/ProcessControllerTests/AutomaticManagementTests.swift deleted file mode 100644 index ecea593b..00000000 --- a/Tests/ProcessControllerTests/AutomaticManagementTests.swift +++ /dev/null @@ -1,57 +0,0 @@ -import Foundation -import ProcessController -import SignalHandling -import XCTest - -final class AutomaticManagementTests: XCTestCase { - func test___silent() { - XCTAssertEqual( - AutomaticManagement.sigintThenKillIfSilent(interval: 42, killAfter: 20), - AutomaticManagement( - items: [ - .signalWhenSilent(.int, 42), - .signalWhenSilent(.kill, 62) - ] - ) - ) - - XCTAssertEqual( - AutomaticManagement.sigtermThenKillIfSilent(interval: 42, killAfter: 20), - AutomaticManagement( - items: [ - .signalWhenSilent(.term, 42), - .signalWhenSilent(.kill, 62) - ] - ) - ) - } - - func test___timeout() { - XCTAssertEqual( - AutomaticManagement.sigintThenKillAfterRunningFor(interval: 42, killAfter: 20), - AutomaticManagement( - items: [ - .signalAfter(.int, 42), - .signalAfter(.kill, 62) - ] - ) - ) - - XCTAssertEqual( - AutomaticManagement.sigtermThenKillAfterRunningFor(interval: 42, killAfter: 20), - AutomaticManagement( - items: [ - .signalAfter(.term, 42), - .signalAfter(.kill, 62) - ] - ) - ) - } - - func test___no_management() { - XCTAssertEqual( - AutomaticManagement.noManagement, - AutomaticManagement.multiple([]) - ) - } -} diff --git a/Tests/ProcessControllerTests/DefaultProcessControllerTests.swift b/Tests/ProcessControllerTests/DefaultProcessControllerTests.swift deleted file mode 100644 index dd96971d..00000000 --- a/Tests/ProcessControllerTests/DefaultProcessControllerTests.swift +++ /dev/null @@ -1,567 +0,0 @@ -import DateProvider -import FileSystem -import Foundation -import PathLib -import ProcessController -import TemporaryStuff -import TestHelpers -import XCTest - -final class DefaultProcessControllerTests: XCTestCase { - private let dateProvider = SystemDateProvider() - private let fileSystem = LocalFileSystem() - - func testStartingSimpleSubprocess() throws { - let controller = try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/usr/bin/env"] - ) - ) - controller.startAndListenUntilProcessDies() - XCTAssertEqual(controller.processStatus(), .terminated(exitCode: 0)) - } - - func test___termination_status_is_running___when_process_is_running() throws { - let controller = try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/bin/sleep", "10"] - ) - ) - controller.start() - XCTAssertEqual(controller.processStatus(), .stillRunning) - } - - func test___termination_status_is_not_started___when_process_has_not_yet_started() throws { - let controller = try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/usr/bin/env"] - ) - ) - XCTAssertEqual(controller.processStatus(), .notStarted) - } - - func test___process_cannot_be_started___when_file_does_not_exist() { - assertThrows { - try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/bin/non/existing/file/\(ProcessInfo.processInfo.globallyUniqueString)"] - ) - ) - } - } - - func test___process_cannot_be_started___when_file_is_not_executable() { - let tempFile = assertDoesNotThrow { try TemporaryFile() } - - assertThrows { - try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: [tempFile] - ) - ) - } - } - - func test___successful_termination___does_not_throw() throws { - let controller = assertDoesNotThrow { - try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/usr/bin/env"] - ) - ) - } - assertDoesNotThrow { - try controller.startAndWaitForSuccessfulTermination() - } - } - - func test___termination_with_non_zero_exit_code___throws() throws { - let tempFile = assertDoesNotThrow { try TemporaryFile() } - - let argument = "/\(UUID().uuidString)" - let controller = assertDoesNotThrow { - try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/bin/ls", argument], - standardStreamsCaptureConfig: StandardStreamsCaptureConfig( - stderrPath: tempFile.absolutePath - ) - ) - ) - } - controller.startAndListenUntilProcessDies() - - assertThrows { - try controller.startAndWaitForSuccessfulTermination() - } - } - - func test___successful_execution() throws { - let controller = try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/bin/sleep", "0.01"] - ) - ) - controller.startAndListenUntilProcessDies() - XCTAssertEqual(controller.processStatus(), .terminated(exitCode: 0)) - } - - func test___automatic_interrupt_silence_handler() throws { - let controller = try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/bin/sleep", "999"], - automaticManagement: .sigintThenKillIfSilent(interval: 0.00001) - ) - ) - controller.startAndListenUntilProcessDies() - XCTAssertEqual(controller.processStatus(), .terminated(exitCode: SIGINT)) - } - - func test___automatic_terminate_silence_handler() throws { - let controller = try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/bin/sleep", "999"], - automaticManagement: .sigtermThenKillIfSilent(interval: 0.00001) - ) - ) - controller.startAndListenUntilProcessDies() - XCTAssertEqual(controller.processStatus(), .terminated(exitCode: SIGTERM)) - } - - func testWhenSubprocessFinishesSilenceIsNotReported() throws { - let controller = try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/bin/sleep"], - automaticManagement: .sigtermThenKillIfSilent(interval: 10.0) - ) - ) - var signalled = false - controller.onSignal { _, _, _ in - signalled = true - } - controller.startAndListenUntilProcessDies() - - XCTAssertFalse(signalled) - } - - func test__executing_from_specific_working_directory() throws { - let temporaryFolder = try TemporaryFolder() - - let controller = try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/bin/pwd"], - workingDirectory: temporaryFolder.absolutePath - ) - ) - controller.startAndListenUntilProcessDies() - - XCTAssertEqual( - try String(contentsOfFile: controller.subprocess.standardStreamsCaptureConfig.stdoutOutputPath().pathString), - temporaryFolder.absolutePath.pathString + "\n" - ) - } - - func testGettingStdout() throws { - let tempFile = try TemporaryFile() - - let controller = try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/bin/ls", "/"], - standardStreamsCaptureConfig: StandardStreamsCaptureConfig( - stdoutPath: tempFile.absolutePath - ) - ) - ) - controller.startAndListenUntilProcessDies() - - let data = try Data(contentsOf: URL(fileURLWithPath: tempFile.absolutePath.pathString)) - guard let string = String(data: data, encoding: .utf8) else { - XCTFail("Unable to get stdout string") - return - } - XCTAssertTrue(string.contains("Applications")) - } - - func testGettingStderr() throws { - let tempFile = try TemporaryFile() - - let argument = "/\(UUID().uuidString)" - let controller = try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/bin/ls", argument], - standardStreamsCaptureConfig: StandardStreamsCaptureConfig( - stderrPath: tempFile.absolutePath - ) - ) - ) - controller.startAndListenUntilProcessDies() - - let data = try Data(contentsOf: tempFile.absolutePath.fileUrl) - guard let string = String(data: data, encoding: .utf8) else { - XCTFail("Unable to get stderr string") - return - } - XCTAssertEqual( - string, - "ls: \(argument): No such file or directory\n" - ) - } - - func testGettingStdoutAndStderr() throws { - let stdoutFile = try TemporaryFile() - let stderrFile = try TemporaryFile() - - let argument = "/\(UUID().uuidString)" - let controller = try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/bin/ls", "/", argument], - standardStreamsCaptureConfig: StandardStreamsCaptureConfig( - stdoutPath: stdoutFile.absolutePath, - stderrPath: stderrFile.absolutePath - ) - ) - ) - controller.startAndListenUntilProcessDies() - - let stdoutData = try Data(contentsOf: stdoutFile.absolutePath.fileUrl) - guard let stdoutString = String(data: stdoutData, encoding: .utf8) else { - XCTFail("Unable to get stdout string") - return - } - - let stderrData = try Data(contentsOf: stderrFile.absolutePath.fileUrl) - guard let stderrString = String(data: stderrData, encoding: .utf8) else { - XCTFail("Unable to get stdin string") - return - } - - XCTAssertTrue(stdoutString.contains("Applications")) - XCTAssertTrue(stderrString.contains("ls: \(argument): No such file or directory")) - } - - func test___stdout_listener() throws { - let controller = try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/bin/ls", "/bin/ls"], - environment: ["NSUnbufferedIO": "YES"] - ) - ) - - var stdoutData = Data() - controller.onStdout { _, data, _ in stdoutData.append(contentsOf: data) } - controller.startAndListenUntilProcessDies() - - guard let string = String(data: stdoutData, encoding: .utf8) else { - return XCTFail("Unable to get stdout string") - } - XCTAssertEqual(string, "/bin/ls\n") - } - - func test___stderr_listener() throws { - let argument = UUID().uuidString + UUID().uuidString - - let controller = try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/bin/ls", "/bin/" + argument] - ) - ) - - var stderrData = Data() - controller.onStderr { _, data, _ in stderrData.append(contentsOf: data) } - controller.startAndListenUntilProcessDies() - - guard let string = String(data: stderrData, encoding: .utf8) else { - return XCTFail("Unable to get stdout string") - } - XCTAssertEqual(string, "ls: /bin/\(argument): No such file or directory\n") - } - - func test___start_listener() throws { - let argument = UUID().uuidString + UUID().uuidString - - let controller = try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/bin/ls", "/bin/" + argument] - ) - ) - - let handlerInvoked = XCTestExpectation(description: "Start handler has been invoked") - controller.onStart { _, _ in - handlerInvoked.fulfill() - } - controller.startAndListenUntilProcessDies() - - wait(for: [handlerInvoked], timeout: 10) - } - - func test___termination_listener() throws { - let argument = UUID().uuidString + UUID().uuidString - - let controller = try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/bin/ls", "/bin/" + argument] - ) - ) - - let handlerInvoked = XCTestExpectation(description: "Termination handler has been invoked") - controller.onTermination { _, _ in - handlerInvoked.fulfill() - } - controller.startAndListenUntilProcessDies() - - wait(for: [handlerInvoked], timeout: 10) - } - - func test___callers_waits_for_process_to_die___all_termination_handlers_invoked_before_returning() throws { - let expectation = XCTestExpectation(description: "Termination handler has finished") - - let controller = try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/usr/bin/env"] - ) - ) - controller.onTermination { _, _ in - Thread.sleep(forTimeInterval: 5) - expectation.fulfill() - } - - controller.startAndListenUntilProcessDies() - wait(for: [expectation], timeout: 0) - } - - func test___sigterm_is_sent___when_silent() throws { - let controller = try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/bin/sleep", "10"], - automaticManagement: .sigtermThenKillIfSilent(interval: 0.01) - ) - ) - - let listenerCalled = expectation(description: "Silence listener has been invoked") - - controller.onSignal { sender, signal, unsubscriber in - XCTAssertEqual(signal, SIGTERM) - unsubscriber() - listenerCalled.fulfill() - } - controller.start() - defer { controller.forceKillProcess() } - - wait(for: [listenerCalled], timeout: 10) - } - - func test___sigint_is_sent___when_silent() throws { - let controller = try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/bin/sleep", "10"], - automaticManagement: .sigintThenKillIfSilent(interval: 0.01) - ) - ) - - let listenerCalled = expectation(description: "Silence listener has been invoked") - - controller.onSignal { sender, signal, unsubscriber in - XCTAssertEqual(signal, SIGINT) - unsubscriber() - listenerCalled.fulfill() - } - controller.start() - defer { controller.forceKillProcess() } - - wait(for: [listenerCalled], timeout: 10) - } - - func test___sigint_is_sent___when_running_for_too_long() throws { - let controller = try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/bin/sleep", "99"], - automaticManagement: .sigintThenKillAfterRunningFor(interval: 1) - ) - ) - - let listenerCalled = expectation(description: "Signal listener has been invoked") - - controller.onSignal { sender, signal, unsubscriber in - XCTAssertEqual(signal, SIGINT) - unsubscriber() - listenerCalled.fulfill() - } - controller.start() - defer { controller.forceKillProcess() } - wait(for: [listenerCalled], timeout: 10) - } - - func test___sigterm_is_sent___when_running_for_too_long() throws { - let controller = try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/bin/sleep", "99"], - automaticManagement: .sigtermThenKillAfterRunningFor(interval: 1) - ) - ) - - let listenerCalled = expectation(description: "Signal listener has been invoked") - - controller.onSignal { sender, signal, unsubscriber in - XCTAssertEqual(signal, SIGTERM) - unsubscriber() - listenerCalled.fulfill() - } - controller.start() - defer { controller.forceKillProcess() } - wait(for: [listenerCalled], timeout: 10) - } - - func test___cancelling_stdout_listener___does_not_invoke_cancelled_listener_anymore() throws { - let controller = try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/bin/sh", "-c", "echo aa; sleep 3; echo aa"] - ) - ) - - var collectedData = Data() - - controller.onStdout { sender, data, unsubscriber in - collectedData.append(contentsOf: data) - unsubscriber() - } - controller.startAndListenUntilProcessDies() - - XCTAssertEqual( - collectedData, - Data("aa\n".utf8) - ) - } - - func test___cancelling_stderr_listener___does_not_invoke_cancelled_listener_anymore() throws { - let controller = try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: ["/bin/sh", "-c", ">&2 echo aa; sleep 3; echo aa"] - ) - ) - - var collectedData = Data() - - controller.onStderr { sender, data, unsubscriber in - collectedData.append(contentsOf: data) - unsubscriber() - } - controller.startAndListenUntilProcessDies() - - XCTAssertEqual( - collectedData, - Data("aa\n".utf8) - ) - } - - private func fileContents(path: AbsolutePath) throws -> String { - let data = try Data(contentsOf: path.fileUrl) - guard let contents = String(data: data, encoding: .utf8) else { - fatalError("Unable to get contents of file: \(path)") - } - return contents - } - - private func controllerForCommandLineTestExecutableTool( - stdoutFile: AbsolutePath, - stderrFile: AbsolutePath, - stdinFile: AbsolutePath - ) throws -> ProcessController { - let streamingSwiftTempFile = try TemporaryFile(suffix: ".swift") - try prepareTestScriptToRun( - swiftScriptPath: #file.deletingLastPathComponent.appending(pathComponent: "StdInToStdOutStreamer.swift"), - outputHandle: streamingSwiftTempFile.fileHandleForWriting - ) - let compiledExecutable = try TemporaryFile() - - // precompile - let compiler = try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: [ - "/usr/bin/swiftc", - "-emit-executable", - streamingSwiftTempFile, - "-o", compiledExecutable])) - compiler.startAndListenUntilProcessDies() - - // run the executable - let controller = try DefaultProcessController( - dateProvider: dateProvider, - fileSystem: fileSystem, - subprocess: Subprocess( - arguments: [compiledExecutable], - standardStreamsCaptureConfig: StandardStreamsCaptureConfig( - stdoutPath: stdoutFile, - stderrPath: stderrFile - ) - ) - ) - controller.start() - return controller - } - - private func prepareTestScriptToRun(swiftScriptPath: String, outputHandle: FileHandle) throws { - var swiftTestCode = try String(contentsOfFile: swiftScriptPath) - swiftTestCode = swiftTestCode.replacingOccurrences(of: "//uncomment_from_tests", with: "") - outputHandle.write(swiftTestCode) - } -} - -extension TemporaryFile: SubprocessArgument { - public func stringValue() throws -> String { - return absolutePath.pathString - } -} diff --git a/Tests/ProcessControllerTests/PrintSleepPrint.swift b/Tests/ProcessControllerTests/PrintSleepPrint.swift deleted file mode 100644 index e74cd962..00000000 --- a/Tests/ProcessControllerTests/PrintSleepPrint.swift +++ /dev/null @@ -1,21 +0,0 @@ -import Foundation - -class PrintSleepPrint { - public init() {} - - public func run() { - let fileHandle: FileHandle - - if ProcessInfo.processInfo.environment["EMCEE_TEST_USE_STDERR"] == "true" { - fileHandle = FileHandle.standardError - } else { - fileHandle = FileHandle.standardOutput - } - - fileHandle.write(Data("Print".utf8)) - Thread.sleep(forTimeInterval: 1.0) - fileHandle.write(Data("Finished".utf8)) - } -} - -//uncomment_from_tests PrintSleepPrint().run() diff --git a/Tests/ProcessControllerTests/StdInToStdOutStreamer.swift b/Tests/ProcessControllerTests/StdInToStdOutStreamer.swift deleted file mode 100644 index 94f37138..00000000 --- a/Tests/ProcessControllerTests/StdInToStdOutStreamer.swift +++ /dev/null @@ -1,41 +0,0 @@ -import Foundation - -class StdInToStdOutStreamer { - public init() {} - - public func run() { - write(string: "stdin-to-stdout-streamer started!", file: stdout) - - FileHandle.standardInput.readabilityHandler = { handler in - let stdinData = handler.availableData - if stdinData.isEmpty { - FileHandle.standardInput.readabilityHandler = nil - } else { - guard let string = String(data: stdinData, encoding: .utf8) else { return } - let outputData = Data(string.utf8) - write(data: outputData, file: stdout) - if string.contains("bye") { - FileHandle.standardInput.readabilityHandler = nil - } - } - } - - while FileHandle.standardInput.readabilityHandler != nil { - RunLoop.current.run(mode: .common, before: Date(timeIntervalSinceNow: 0.1)) - } - } -} - -func write(string: String, file: UnsafeMutablePointer) { - write(data: Data(string.utf8), file: file) -} - -func write(data: Data, file: UnsafeMutablePointer) { - data.withUnsafeBytes { (pointer: UnsafeRawBufferPointer) -> Void in - let bytes = pointer.load(as: [Int8].self) - fwrite(bytes, 1, data.count, file) - fflush(file) - } -} - -//uncomment_from_tests StdInToStdOutStreamer().run() diff --git a/Tests/ResourceLocationResolverTests/ResourceLocationResolverTests.swift b/Tests/ResourceLocationResolverTests/ResourceLocationResolverTests.swift index 6bfdc8d0..a8b289c3 100644 --- a/Tests/ResourceLocationResolverTests/ResourceLocationResolverTests.swift +++ b/Tests/ResourceLocationResolverTests/ResourceLocationResolverTests.swift @@ -9,7 +9,7 @@ import ResourceLocation import ResourceLocationResolver import Swifter import SynchronousWaiter -import TemporaryStuff +import Tmp import TestHelpers import URLResource import XCTest diff --git a/Tests/ResourceLocationTests/ResourceLocationTests.swift b/Tests/ResourceLocationTests/ResourceLocationTests.swift index 58e746c0..a0972828 100644 --- a/Tests/ResourceLocationTests/ResourceLocationTests.swift +++ b/Tests/ResourceLocationTests/ResourceLocationTests.swift @@ -1,6 +1,6 @@ import Foundation import ResourceLocation -import TemporaryStuff +import Tmp import XCTest final class ResourceLocationTests: XCTestCase { diff --git a/Tests/ResultStreamModelsTests/RSDateTests.swift b/Tests/ResultStreamModelsTests/RSDateTests.swift index 6ad726d2..cf28922a 100644 --- a/Tests/ResultStreamModelsTests/RSDateTests.swift +++ b/Tests/ResultStreamModelsTests/RSDateTests.swift @@ -35,7 +35,7 @@ final class RSDateTests: XCTestCase { } equals: { computedValue } - + assert { decodedValue._value } equals: { diff --git a/Tests/ResultStreamModelsTests/XCTestCase+JsonParsingCheck.swift b/Tests/ResultStreamModelsTests/XCTestCase+JsonParsingCheck.swift index 76a6e713..38124315 100644 --- a/Tests/ResultStreamModelsTests/XCTestCase+JsonParsingCheck.swift +++ b/Tests/ResultStreamModelsTests/XCTestCase+JsonParsingCheck.swift @@ -5,6 +5,7 @@ import XCTest extension XCTestCase { func check(input: String, equals object: T) { let data = assertNotNil { input.data(using: .utf8) } + assert { try JSONDecoder().decode(T.self, from: data) } equals: { diff --git a/Tests/RunnerTestHelpers/FakeTestRunner.swift b/Tests/RunnerTestHelpers/FakeTestRunner.swift index 251de15f..c8808c29 100644 --- a/Tests/RunnerTestHelpers/FakeTestRunner.swift +++ b/Tests/RunnerTestHelpers/FakeTestRunner.swift @@ -5,14 +5,12 @@ import ProcessController import Runner import RunnerModels import SimulatorPoolModels -import TemporaryStuff +import Tmp public final class FakeTestRunner: TestRunner { public var entriesToRun: [TestEntry]? public var errorToThrowOnRun: Error? private let tempFolder: TemporaryFolder - - public var standardStreamsCaptureConfig = StandardStreamsCaptureConfig() public struct SomeError: Error, CustomStringConvertible { public let description = "some error happened" diff --git a/Tests/RunnerTestHelpers/FakeTestRunnerInvocation.swift b/Tests/RunnerTestHelpers/FakeTestRunnerInvocation.swift index b295b6fd..585684ef 100644 --- a/Tests/RunnerTestHelpers/FakeTestRunnerInvocation.swift +++ b/Tests/RunnerTestHelpers/FakeTestRunnerInvocation.swift @@ -2,7 +2,7 @@ import Foundation import ProcessController import Runner import RunnerModels -import TemporaryStuff +import Tmp public final class FakeTestRunnerInvocation: TestRunnerInvocation { private let entriesToRun: [TestEntry] diff --git a/Tests/RunnerTestHelpers/FakeTestRunnerProvider.swift b/Tests/RunnerTestHelpers/FakeTestRunnerProvider.swift index a4a3213a..80cb45dd 100755 --- a/Tests/RunnerTestHelpers/FakeTestRunnerProvider.swift +++ b/Tests/RunnerTestHelpers/FakeTestRunnerProvider.swift @@ -1,6 +1,6 @@ import Runner import RunnerModels -import TemporaryStuff +import Tmp public final class FakeTestRunnerProvider: TestRunnerProvider { public lazy var predefinedFakeTestRunner = FakeTestRunner( diff --git a/Tests/RunnerTestHelpers/FakeTestRunnerRunningInvocation.swift b/Tests/RunnerTestHelpers/FakeTestRunnerRunningInvocation.swift index 2ff8fb97..176d7b2e 100644 --- a/Tests/RunnerTestHelpers/FakeTestRunnerRunningInvocation.swift +++ b/Tests/RunnerTestHelpers/FakeTestRunnerRunningInvocation.swift @@ -2,7 +2,7 @@ import Foundation import Logging import ProcessController import Runner -import TemporaryStuff +import Tmp public final class FakeTestRunnerRunningInvocation: TestRunnerRunningInvocation { private let tempFolder: TemporaryFolder @@ -18,15 +18,8 @@ public final class FakeTestRunnerRunningInvocation: TestRunnerRunningInvocation onCancel() } - public var output: StandardStreamsCaptureConfig { - StandardStreamsCaptureConfig( - stdoutPath: try? tempFolder.createFile(filename: "\(uuid)_stdout.log"), - stderrPath: try? tempFolder.createFile(filename: "\(uuid)_stderr.log") - ) - } - - public var subprocessInfo: SubprocessInfo { - SubprocessInfo(subprocessId: 42, subprocessName: "fake process") + public var pidInfo: PidInfo { + PidInfo(pid: 42, name: "fake process") } public func wait() { diff --git a/Tests/RunnerTests/ProcessOutputSilenceTrackerTests.swift b/Tests/RunnerTests/ProcessOutputSilenceTrackerTests.swift deleted file mode 100644 index 905dadeb..00000000 --- a/Tests/RunnerTests/ProcessOutputSilenceTrackerTests.swift +++ /dev/null @@ -1,98 +0,0 @@ -import DateProviderTestHelpers -import FileSystemTestHelpers -import Foundation -import Logging -import PathLib -import ProcessController -import Runner -import TemporaryStuff -import TestHelpers -import XCTest - -final class ProcessOutputSilenceTrackerTests: XCTestCase { - lazy var dateProvider = DateProviderFixture() - lazy var expectation = XCTestExpectation() - lazy var fileSystem = FakeFileSystem(rootPath: AbsolutePath(#file)) - lazy var standardStreamsCaptureConfig = StandardStreamsCaptureConfig( - stdoutPath: tempFolder.absolutePath.appending(component: "stdout.txt"), - stderrPath: tempFolder.absolutePath.appending(component: "stderr.txt") - ) - lazy var subprocessInfo = SubprocessInfo(subprocessId: 1234, subprocessName: "process_name") - lazy var tempFolder = assertDoesNotThrow { try TemporaryFolder() } - lazy var tracker = ProcessOutputSilenceTracker( - dateProvider: dateProvider, - fileSystem: fileSystem, - onSilence: expectation.fulfill, - silenceDuration: 5.0, - standardStreamsCaptureConfig: standardStreamsCaptureConfig, - subprocessInfo: subprocessInfo - ) - lazy var pathMtimes = [AbsolutePath: Date]() - - override func setUp() { - fileSystem.propertiesProvider = { [weak self] askedPath in - let container = FakeFilePropertiesContainer(path: askedPath) - - if let mtime = self?.pathMtimes[askedPath] { - container.mdate = mtime - } else { - container.mdate = Date(timeIntervalSince1970: 500) - } - - return container - } - } - - func test___when_process_outputs_to_stdout___silence_not_triggered() throws { - pathMtimes[try standardStreamsCaptureConfig.stdoutOutputPath()] = dateProvider.currentDate() - expectation.isInverted = true - - tracker.startTracking() - - wait(for: [expectation], timeout: 5.0) - } - - func test___when_process_outputs_to_stderr___silence_not_triggered() throws { - pathMtimes[try standardStreamsCaptureConfig.stderrOutputPath()] = dateProvider.currentDate() - expectation.isInverted = true - - tracker.startTracking() - - wait(for: [expectation], timeout: 5.0) - } - - func test___when_process_does_not_output_anything___silence_is_triggered() { - tracker.startTracking() - - wait(for: [expectation], timeout: 5.0) - } - - func test___when_process_becomes_silent___it_reports_silence() throws { - pathMtimes[try standardStreamsCaptureConfig.stdoutOutputPath()] = dateProvider.currentDate() - pathMtimes[try standardStreamsCaptureConfig.stderrOutputPath()] = dateProvider.currentDate() - - tracker.startTracking() - - DispatchQueue.main.async { - self.dateProvider.result += 6.0 - } - - wait(for: [expectation], timeout: 5.0) - } - - func test___when_stop_is_called___it_does_not_report_silence() throws { - expectation.isInverted = true - - pathMtimes[try standardStreamsCaptureConfig.stdoutOutputPath()] = dateProvider.currentDate() - pathMtimes[try standardStreamsCaptureConfig.stderrOutputPath()] = dateProvider.currentDate() - - tracker.startTracking() - tracker.stopTracking() - - DispatchQueue.main.async { - self.dateProvider.result += 6.0 - } - - wait(for: [expectation], timeout: 5.0) - } -} diff --git a/Tests/RunnerTests/RunnerTests.swift b/Tests/RunnerTests/RunnerTests.swift index 1641bdb3..ec220c6b 100644 --- a/Tests/RunnerTests/RunnerTests.swift +++ b/Tests/RunnerTests/RunnerTests.swift @@ -16,7 +16,7 @@ import RunnerTestHelpers import SimulatorPoolModels import SimulatorPoolTestHelpers import SynchronousWaiter -import TemporaryStuff +import Tmp import TestHelpers import XCTest diff --git a/Tests/SSHDeployerTests/SSHDeployerTests.swift b/Tests/SSHDeployerTests/SSHDeployerTests.swift index fddc8c50..918c5f79 100644 --- a/Tests/SSHDeployerTests/SSHDeployerTests.swift +++ b/Tests/SSHDeployerTests/SSHDeployerTests.swift @@ -3,7 +3,7 @@ import Foundation import PathLib import ProcessControllerTestHelpers -import TemporaryStuff +import Tmp import TestHelpers import UniqueIdentifierGeneratorTestHelpers import XCTest @@ -37,7 +37,7 @@ class SSHDeployerTests: XCTestCase { ] ], destination: destination, - processControllerProvider: FakeProcessControllerProvider(tempFolder: tempFolder), + processControllerProvider: FakeProcessControllerProvider(), temporaryFolder: tempFolder, uniqueIdentifierGenerator: uniqueIdentifierGenerator ) diff --git a/Tests/SignalHandlingTests/SignalHandlingTests.swift b/Tests/SignalHandlingTests/SignalHandlingTests.swift deleted file mode 100644 index 982db218..00000000 --- a/Tests/SignalHandlingTests/SignalHandlingTests.swift +++ /dev/null @@ -1,18 +0,0 @@ -import SignalHandling -import Signals -import XCTest - -final class SignalHandlerTests: XCTestCase { - func test___hanlder_fires_when_signal_occurs() { - var didHandle = false - - SignalHandling.addSignalHandler(signal: Signal.user(20)) { value in - XCTAssertEqual(value, 20) - didHandle = true - } - - Signals.raise(signal: Signals.Signal.user(20)) - - XCTAssertTrue(didHandle) - } -} diff --git a/Tests/SimulatorPoolTestHelpers/FakeSimulatorControllerProvider.swift b/Tests/SimulatorPoolTestHelpers/FakeSimulatorControllerProvider.swift index 86d8101e..36ebff6d 100644 --- a/Tests/SimulatorPoolTestHelpers/FakeSimulatorControllerProvider.swift +++ b/Tests/SimulatorPoolTestHelpers/FakeSimulatorControllerProvider.swift @@ -3,7 +3,7 @@ import Foundation import RunnerModels import SimulatorPool import SimulatorPoolModels -import TemporaryStuff +import Tmp public final class FakeSimulatorControllerProvider: SimulatorControllerProvider { public var result: (TestDestination) -> SimulatorController diff --git a/Tests/SimulatorPoolTestHelpers/SimulatorPoolMock.swift b/Tests/SimulatorPoolTestHelpers/SimulatorPoolMock.swift index 5a017f5c..c19963e1 100644 --- a/Tests/SimulatorPoolTestHelpers/SimulatorPoolMock.swift +++ b/Tests/SimulatorPoolTestHelpers/SimulatorPoolMock.swift @@ -3,7 +3,7 @@ import DeveloperDirLocator import DeveloperDirLocatorTestHelpers import PathLib import SimulatorPoolModels -import TemporaryStuff +import Tmp import RunnerModels public final class SimulatorPoolMock: SimulatorPool { diff --git a/Tests/SimulatorPoolTests/DefaultCoreSimulatorStateProviderTests.swift b/Tests/SimulatorPoolTests/DefaultCoreSimulatorStateProviderTests.swift index 363c4ef8..0fd2f7b3 100644 --- a/Tests/SimulatorPoolTests/DefaultCoreSimulatorStateProviderTests.swift +++ b/Tests/SimulatorPoolTests/DefaultCoreSimulatorStateProviderTests.swift @@ -3,7 +3,7 @@ import PlistLib import SimulatorPool import SimulatorPoolModels import SimulatorPoolTestHelpers -import TemporaryStuff +import Tmp import TestHelpers import XCTest diff --git a/Tests/SimulatorPoolTests/DefaultSimulatorPoolTests.swift b/Tests/SimulatorPoolTests/DefaultSimulatorPoolTests.swift index a118ce70..4a2eb7b9 100644 --- a/Tests/SimulatorPoolTests/DefaultSimulatorPoolTests.swift +++ b/Tests/SimulatorPoolTests/DefaultSimulatorPoolTests.swift @@ -3,7 +3,7 @@ import DeveloperDirModels import ResourceLocationResolver import SimulatorPoolTestHelpers import SynchronousWaiter -import TemporaryStuff +import Tmp import TestHelpers import XCTest diff --git a/Tests/SimulatorPoolTests/SimulatorPoolConvenienceTests.swift b/Tests/SimulatorPoolTests/SimulatorPoolConvenienceTests.swift index 96dc382f..8af6e03a 100644 --- a/Tests/SimulatorPoolTests/SimulatorPoolConvenienceTests.swift +++ b/Tests/SimulatorPoolTests/SimulatorPoolConvenienceTests.swift @@ -5,7 +5,7 @@ import SimulatorPool import SimulatorPoolModels import SimulatorPoolTestHelpers import SynchronousWaiter -import TemporaryStuff +import Tmp import XCTest final class SimulatorPoolConvenienceTests: XCTestCase { diff --git a/Tests/SimulatorPoolTests/SimulatorSettingsModifierTests.swift b/Tests/SimulatorPoolTests/SimulatorSettingsModifierTests.swift index f49f00bf..d6621bb4 100644 --- a/Tests/SimulatorPoolTests/SimulatorSettingsModifierTests.swift +++ b/Tests/SimulatorPoolTests/SimulatorSettingsModifierTests.swift @@ -6,7 +6,7 @@ import ProcessController import ProcessControllerTestHelpers import SimulatorPoolModels import SimulatorPoolTestHelpers -import TemporaryStuff +import Tmp import TestHelpers import UniqueIdentifierGenerator import UniqueIdentifierGeneratorTestHelpers @@ -83,7 +83,7 @@ final class SimulatorSettingsModifierTests: XCTestCase { func test___DEVELOPER_DIR_is_present_for_all_subprocess_invocations() throws { processControllerProvider.creator = { [developerDirLocator] subprocess -> ProcessController in XCTAssertEqual( - subprocess.environment["DEVELOPER_DIR"], + subprocess.environment.values["DEVELOPER_DIR"], try developerDirLocator.path(developerDir: .current).pathString, "DEVELOPER_DIR env must be used when executing xcrun" ) @@ -231,7 +231,7 @@ final class SimulatorSettingsModifierTests: XCTestCase { // MARK: - Helper Variables lazy var developerDirLocator = FakeDeveloperDirLocator(result: self.tempFolder.absolutePath.appending(component: "Dev_Dir")) - lazy var processControllerProvider = FakeProcessControllerProvider(tempFolder: tempFolder) + lazy var processControllerProvider = FakeProcessControllerProvider() lazy var simulator = Simulator( testDestination: TestDestinationFixtures.testDestination, udid: UDID(value: "sim_udid"), diff --git a/Tests/SimulatorPoolTests/StateMachineDrivenSimulatorControllerTests.swift b/Tests/SimulatorPoolTests/StateMachineDrivenSimulatorControllerTests.swift index 9da4d35f..1c8d81f9 100644 --- a/Tests/SimulatorPoolTests/StateMachineDrivenSimulatorControllerTests.swift +++ b/Tests/SimulatorPoolTests/StateMachineDrivenSimulatorControllerTests.swift @@ -7,7 +7,7 @@ import SimulatorPool import SimulatorPoolModels import SimulatorPoolTestHelpers import SynchronousWaiter -import TemporaryStuff +import Tmp import TestHelpers import XCTest diff --git a/Tests/StatsdTests/FakeStatsdClient.swift b/Tests/StatsdTests/FakeStatsdClient.swift deleted file mode 100644 index 469833fd..00000000 --- a/Tests/StatsdTests/FakeStatsdClient.swift +++ /dev/null @@ -1,26 +0,0 @@ -import Foundation -import Network -import Statsd - -final class FakeStatsdClient: StatsdClient { - var state: NWConnection.State - - var sentData: [Data] = [] - var stateUpdateHandler: ((NWConnection.State) -> Void)? - - init(initialState: NWConnection.State) { - state = initialState - } - - func cancel() {} - func start(queue: DispatchQueue) {} - - func send(content: Data) { - sentData.append(content) - } - - func update(state: NWConnection.State) { - self.state = state - self.stateUpdateHandler?(state) - } -} diff --git a/Tests/StatsdTests/StatsdMetricHandlerImplTests.swift b/Tests/StatsdTests/StatsdMetricHandlerImplTests.swift deleted file mode 100644 index 74c4f932..00000000 --- a/Tests/StatsdTests/StatsdMetricHandlerImplTests.swift +++ /dev/null @@ -1,81 +0,0 @@ -import Foundation -import Metrics -import Network -import Statsd -import XCTest - -final class StatsdMetricHandlerImplTests: XCTestCase { - func test___handler___doesnt_send_metrics___in_non_ready_states() throws { - let queue = DispatchQueue(label: "test") - let states: [NWConnection.State] = [ - .setup, - .preparing, - .failed(NWError.posix(.E2BIG)), - .waiting(NWError.posix(.E2BIG)), - .cancelled, - ] - - try states.forEach { state in - let client = FakeStatsdClient(initialState: state) - let handler = try StatsdMetricHandlerImpl( - statsdDomain: ["domain"], - statsdClient: client, - serialQueue: queue - ) - - handler.handle(metric: metric()) - - queue.sync {} - XCTAssertTrue(client.sentData.isEmpty) - } - } - - func test___handler___sends_metric___in_ready_state() throws { - let queue = DispatchQueue(label: "test") - let client = FakeStatsdClient(initialState: .ready) - let handler = try StatsdMetricHandlerImpl( - statsdDomain: ["domain"], - statsdClient: client, - serialQueue: queue - ) - - handler.handle(metric: metric()) - - queue.sync {} - XCTAssertEqual( - client.sentData, - [Data("domain.a.b:1000|ms".utf8)] - ) - } - - func test___handler___buffers_metrics___untill_in_ready_state() throws { - let queue = DispatchQueue(label: "test") - let states: [NWConnection.State] = [ - .setup, - .preparing, - .waiting(NWError.posix(.E2BIG)), - ] - - try states.forEach { state in - let client = FakeStatsdClient(initialState: state) - let handler = try StatsdMetricHandlerImpl( - statsdDomain: ["domain"], - statsdClient: client, - serialQueue: queue - ) - - handler.handle(metric: metric()) - queue.async { client.update(state: .ready) } - - queue.sync {} - XCTAssertEqual( - client.sentData, - [Data("domain.a.b:1000|ms".utf8)] - ) - } - } - - private func metric() -> StatsdMetric { - StatsdMetric(fixedComponents: ["a"], variableComponents: ["b"], value: .time(1)) - } -} diff --git a/Tests/StatsdTests/StatsdMetricTests.swift b/Tests/StatsdTests/StatsdMetricTests.swift deleted file mode 100644 index 963eaaa3..00000000 --- a/Tests/StatsdTests/StatsdMetricTests.swift +++ /dev/null @@ -1,27 +0,0 @@ -import Metrics -import Statsd -import XCTest - -final class StatsdMetricTests: XCTestCase { - func test___building___for_gauge() { - XCTAssertEqual( - StatsdMetric( - fixedComponents: ["c", "d"], - variableComponents: ["e", "f"], - value: .gauge(1) - ).build(domain: ["a", "b"]), - "a.b.c.d.e.f:1|g" - ) - } - - func test___building___for_time() { - XCTAssertEqual( - StatsdMetric( - fixedComponents: ["c", "d"], - variableComponents: ["e", "f"], - value: .time(1) - ).build(domain: ["a", "b"]), - "a.b.c.d.e.f:1000|ms" - ) - } -} diff --git a/Tests/SynchronousWaiterTests/SynchronousWaiterTests.swift b/Tests/SynchronousWaiterTests/SynchronousWaiterTests.swift deleted file mode 100644 index 096d20ff..00000000 --- a/Tests/SynchronousWaiterTests/SynchronousWaiterTests.swift +++ /dev/null @@ -1,43 +0,0 @@ -import Foundation -import SynchronousWaiter -import XCTest - -class SynchronousWaiterTest: XCTestCase { - func testWaitWithinRunloop() { - let expectedDuration = 0.75 - let start = Date() - SynchronousWaiter().wait(pollPeriod: 0.01, timeout: expectedDuration, description: "") - let actualDuration = Date().timeIntervalSince(start) - XCTAssertEqual(actualDuration, expectedDuration, accuracy: 0.1) - } - - func testWaitFromEmptyRunLoop() { - let expectedDuration = 0.1 - var actualDuration = 0.0 - - let queue = OperationQueue() - queue.addOperation { - let start = Date() - SynchronousWaiter().wait(pollPeriod: 0.01, timeout: expectedDuration, description: "") - actualDuration = Date().timeIntervalSince(start) - } - queue.waitUntilAllOperationsAreFinished() - - XCTAssertEqual(actualDuration, expectedDuration, accuracy: 0.1) - } - - func testWaitTimeout() { - XCTAssertThrowsError( - try SynchronousWaiter().waitWhile(pollPeriod: 0.01, timeout: 0.1, description: "") { true }, - "Wait should throw specific exception on time out") { errorThrown in - guard let error = errorThrown as? TimeoutError else { - XCTFail("Unexpected error type") - return - } - switch error { - case .waitTimeout(let timeout): - XCTAssertEqual(timeout.value, 0.1, accuracy: 0.01) - } - } - } -} diff --git a/Tests/SynchronousWaiterTests/WaiterTests.swift b/Tests/SynchronousWaiterTests/WaiterTests.swift deleted file mode 100644 index c4897fc2..00000000 --- a/Tests/SynchronousWaiterTests/WaiterTests.swift +++ /dev/null @@ -1,39 +0,0 @@ -import Foundation -import SynchronousWaiter -import TestHelpers -import XCTest - -class WaiterTests: XCTestCase { - let waiterUnderTest: Waiter = SynchronousWaiter() - - func test___waiting_for_unwrap___provides_result_if_provider_returns_result() { - assertDoesNotThrow { - let result: String = try waiterUnderTest.waitForUnwrap( - timeout: 1, - valueProvider: { "hello" }, - description: "" - ) - XCTAssertEqual(result, "hello") - } - } - - func test___waiting_for_unwrap___throws_on_timeout() { - assertThrows { - let _: String = try waiterUnderTest.waitForUnwrap( - timeout: 0, - valueProvider: { nil }, - description: "" - ) - } - } - - func test___waiting_for_unwrap___throws_if_provider_throws() { - assertThrows { - let _: String = try waiterUnderTest.waitForUnwrap( - timeout: 0, - valueProvider: { throw ErrorForTestingPurposes(text: "sample error") }, - description: "" - ) - } - } -} diff --git a/Tests/TemporaryStuffTests/TemporaryStuffTests.swift b/Tests/TemporaryStuffTests/TemporaryStuffTests.swift deleted file mode 100644 index 1c516562..00000000 --- a/Tests/TemporaryStuffTests/TemporaryStuffTests.swift +++ /dev/null @@ -1,31 +0,0 @@ -import Foundation -import TemporaryStuff -import PathLib -import XCTest - -final class TemporaryStuffTests: XCTestCase { - func testCreatingTemporaryStuff() throws { - XCTAssertNoThrow(try TemporaryFolder()) - } - - func testCreatingFolders() throws { - let tempFolder = try TemporaryFolder() - let path = try tempFolder.pathByCreatingDirectories(components: ["a", "b", "c"]) - var isDir: ObjCBool = false - XCTAssertTrue(FileManager.default.fileExists(atPath: path.pathString, isDirectory: &isDir)) - XCTAssertTrue(isDir.boolValue) - } - - func testCreaintFile() throws { - let tempFolder = try TemporaryFolder() - let contents = "hello" - let path = try tempFolder.createFile(components: ["a", "b"], filename: "file.txt", contents: Data(contents.utf8)) - - var isDir: ObjCBool = false - XCTAssertTrue(FileManager.default.fileExists(atPath: path.pathString, isDirectory: &isDir)) - XCTAssertFalse(isDir.boolValue) - - let actualContents = try String(contentsOfFile: path.pathString) - XCTAssertEqual(contents, actualContents) - } -} diff --git a/Tests/TestDiscoveryTests/ExecutableTestDiscovererTests.swift b/Tests/TestDiscoveryTests/ExecutableTestDiscovererTests.swift index 1fe0db02..0cea98f8 100644 --- a/Tests/TestDiscoveryTests/ExecutableTestDiscovererTests.swift +++ b/Tests/TestDiscoveryTests/ExecutableTestDiscovererTests.swift @@ -15,7 +15,7 @@ import ResourceLocationResolverTestHelpers import RunnerModels import RunnerTestHelpers import SimulatorPoolTestHelpers -import TemporaryStuff +import Tmp import TestHelpers import URLResource import UniqueIdentifierGenerator @@ -81,7 +81,7 @@ final class ExecutableTestDiscovererTests: XCTestCase { } XCTAssertEqual( - subprocesses[0].environment["DEVELOPER_DIR"], + subprocesses[0].environment.values["DEVELOPER_DIR"], "/path/to/developer_dir" ) } @@ -100,21 +100,21 @@ final class ExecutableTestDiscovererTests: XCTestCase { } XCTAssertEqual( - subprocesses[1].environment["SIMULATOR_ROOT"], + subprocesses[1].environment.values["SIMULATOR_ROOT"], "/path/to/iOS 12.0.simruntime/Contents/Resources/RuntimeRoot" ) XCTAssertEqual( - subprocesses[1].environment["DYLD_ROOT_PATH"], + subprocesses[1].environment.values["DYLD_ROOT_PATH"], "/path/to/iOS 12.0.simruntime/Contents/Resources/RuntimeRoot" ) XCTAssert( - subprocesses[1].environment["SIMULATOR_SHARED_RESOURCES_DIRECTORY"]?.isEmpty == false + subprocesses[1].environment.values["SIMULATOR_SHARED_RESOURCES_DIRECTORY"]?.isEmpty == false ) XCTAssert( - subprocesses[1].environment["EMCEE_RUNTIME_TESTS_EXPORT_PATH"]?.isEmpty == false + subprocesses[1].environment.values["EMCEE_RUNTIME_TESTS_EXPORT_PATH"]?.isEmpty == false ) XCTAssertEqual( - subprocesses[1].environment["EMCEE_XCTEST_BUNDLE_PATH"], + subprocesses[1].environment.values["EMCEE_XCTEST_BUNDLE_PATH"], "/path/to/bundle.xctest" ) } @@ -173,28 +173,31 @@ final class ExecutableTestDiscovererTests: XCTestCase { resourceLocationResolver: FakeResourceLocationResolver.resolvingTo( path: AbsolutePath(testBundleLocation.resourceLocation.stringValue) ), - processControllerProvider: FakeProcessControllerProvider(tempFolder: tempFolder, creator: { subprocess in + processControllerProvider: FakeProcessControllerProvider { subprocess in onSubprocessCreate?(subprocess) let arguments = try subprocess.arguments.map { try $0.stringValue() } - if arguments.contains("simctl") { - try simctlResponse.write( - to: subprocess.standardStreamsCaptureConfig.stdoutOutputPath().fileUrl, - atomically: true, - encoding: .utf8 - ) - } else if let outputPath = subprocess.environment["EMCEE_RUNTIME_TESTS_EXPORT_PATH"] { - try executableResponse.write( - to: AbsolutePath(outputPath).fileUrl, - atomically: true, - encoding: .utf8 - ) - } let processController = FakeProcessController(subprocess: subprocess) - processController.overridedProcessStatus = .terminated(exitCode: 0) + + processController.onStart { _, unsubscribe in + if arguments.contains("simctl") { + processController.broadcastStdout(data: Data(simctlResponse.utf8)) + } else if let outputPath = subprocess.environment.values["EMCEE_RUNTIME_TESTS_EXPORT_PATH"] { + self.assertDoesNotThrow { + try executableResponse.write( + to: AbsolutePath(outputPath).fileUrl, + atomically: true, + encoding: .utf8 + ) + } + } + processController.overridedProcessStatus = .terminated(exitCode: 0) + unsubscribe() + } + return processController - }), + }, tempFolder: tempFolder, uniqueIdentifierGenerator: UuidBasedUniqueIdentifierGenerator() ) diff --git a/Tests/TestDiscoveryTests/ParseFunctionSymbolsTestDiscovererTests.swift b/Tests/TestDiscoveryTests/ParseFunctionSymbolsTestDiscovererTests.swift index 0cd82706..d762459c 100644 --- a/Tests/TestDiscoveryTests/ParseFunctionSymbolsTestDiscovererTests.swift +++ b/Tests/TestDiscoveryTests/ParseFunctionSymbolsTestDiscovererTests.swift @@ -10,7 +10,7 @@ import ResourceLocationResolverTestHelpers import RunnerModels import RunnerTestHelpers import SimulatorPoolTestHelpers -import TemporaryStuff +import Tmp import TestHelpers import UniqueIdentifierGenerator import UniqueIdentifierGeneratorTestHelpers @@ -59,24 +59,21 @@ final class ParseFunctionSymbolsTestDiscovererTests: XCTestCase { fileSystem: LocalFileSystem() ) ), - processControllerProvider: FakeProcessControllerProvider(tempFolder: tempFolder, creator: { subprocess -> ProcessController in + processControllerProvider: FakeProcessControllerProvider { subprocess -> ProcessController in XCTAssertEqual( try subprocess.arguments.map { try $0.stringValue() }, ["/usr/bin/nm", "-j", "-U", self.testBundlePathInTempFolder.appending(component: self.executableInsideTestBundle).pathString] ) - self.assertDoesNotThrow { - _ = try self.tempFolder.createFile( - components: subprocess.standardStreamsCaptureConfig.stdoutOutputPath().removingLastComponent.relativePath(anchorPath: self.tempFolder.absolutePath).components, - filename: subprocess.standardStreamsCaptureConfig.stdoutOutputPath().lastComponent, - contents: nmOutputData - ) - } - let processController = FakeProcessController(subprocess: subprocess) + processController.onStart { _, unsubscribe in + processController.broadcastStdout(data: nmOutputData ?? Data()) + processController.overridedProcessStatus = .terminated(exitCode: 0) + unsubscribe() + } processController.overridedProcessStatus = .terminated(exitCode: 0) return processController - }), + }, resourceLocationResolver: FakeResourceLocationResolver.resolvingTo(path: testBundlePathInTempFolder), tempFolder: tempFolder, uniqueIdentifierGenerator: uniqueIdentifierGenerator diff --git a/Tests/TestDiscoveryTests/TestDiscoveryQuerierTests.swift b/Tests/TestDiscoveryTests/TestDiscoveryQuerierTests.swift index 545116a6..698f02e0 100644 --- a/Tests/TestDiscoveryTests/TestDiscoveryQuerierTests.swift +++ b/Tests/TestDiscoveryTests/TestDiscoveryQuerierTests.swift @@ -17,7 +17,7 @@ import RunnerModels import RunnerTestHelpers import SimulatorPoolTestHelpers import SynchronousWaiter -import TemporaryStuff +import Tmp import TestArgFile import TestHelpers import UniqueIdentifierGenerator @@ -220,7 +220,7 @@ final class TestDiscoveryQuerierTests: XCTestCase { metricRecorder: NoOpMetricRecorder(), onDemandSimulatorPool: simulatorPool, pluginEventBusProvider: NoOoPluginEventBusProvider(), - processControllerProvider: FakeProcessControllerProvider(tempFolder: tempFolder), + processControllerProvider: FakeProcessControllerProvider(), resourceLocationResolver: resourceLocationResolver, tempFolder: tempFolder, testRunnerProvider: testRunnerProvider, diff --git a/Tests/TestHelpers/Equals.swift b/Tests/TestHelpers/Equals.swift deleted file mode 100644 index 294663de..00000000 --- a/Tests/TestHelpers/Equals.swift +++ /dev/null @@ -1,20 +0,0 @@ -import Foundation -import XCTest - -public func assert( - file: StaticString = #file, - line: UInt = #line, - left: () throws -> T, - equals right: () throws -> T -) { - do { - let leftResult = try left() - let rightResult = try right() - - if leftResult != rightResult { - XCTFail("Values not equal.\nLeft value: \n\(leftResult)\nRight value:\n\(rightResult)", file: file, line: line) - } - } catch { - XCTFail("Error thrown during value comparison.\nError: \(error)", file: file, line: line) - } -} diff --git a/Tests/TestHelpers/ErrorForTestingPurposes.swift b/Tests/TestHelpers/ErrorForTestingPurposes.swift deleted file mode 100644 index f279b6c7..00000000 --- a/Tests/TestHelpers/ErrorForTestingPurposes.swift +++ /dev/null @@ -1,13 +0,0 @@ -import Foundation - -public struct ErrorForTestingPurposes: Error, CustomStringConvertible { - public let text: String - - public init(text: String = "Error for testing purposes") { - self.text = text - } - - public var description: String { - return "\(type(of: self)) \(text)" - } -} diff --git a/Tests/TestHelpers/ExpectationAwaitingError.swift b/Tests/TestHelpers/ExpectationAwaitingError.swift deleted file mode 100644 index acf00cdb..00000000 --- a/Tests/TestHelpers/ExpectationAwaitingError.swift +++ /dev/null @@ -1,5 +0,0 @@ -public final class ExpectationAwaitingError: Error, CustomStringConvertible { - public var description: String { - return "Awaiting for result failed" - } -} diff --git a/Tests/TestHelpers/NilHelpers.swift b/Tests/TestHelpers/NilHelpers.swift deleted file mode 100644 index cd7f581d..00000000 --- a/Tests/TestHelpers/NilHelpers.swift +++ /dev/null @@ -1,16 +0,0 @@ -import Foundation -import XCTest - -public extension XCTestCase { - @discardableResult - func assertNotNil( - file: StaticString = #file, - line: UInt = #line, - work: () throws -> T? - ) rethrows -> T { - guard let value = try work() else { - failTest("Unexpected nil value", file: file, line: line) - } - return value - } -} diff --git a/Tests/TestHelpers/PreventingExecutionAfterFailure.swift b/Tests/TestHelpers/PreventingExecutionAfterFailure.swift deleted file mode 100644 index 72a3f2c3..00000000 --- a/Tests/TestHelpers/PreventingExecutionAfterFailure.swift +++ /dev/null @@ -1,14 +0,0 @@ -import Foundation -import XCTest - -public extension XCTestCase { - func withoutContinuingTestAfterFailure( - work: () -> T - ) -> T { - let shouldContinue = continueAfterFailure - defer { continueAfterFailure = shouldContinue } - - continueAfterFailure = false - return work() - } -} diff --git a/Tests/TestHelpers/TestFailing.swift b/Tests/TestHelpers/TestFailing.swift deleted file mode 100644 index c7e993a1..00000000 --- a/Tests/TestHelpers/TestFailing.swift +++ /dev/null @@ -1,15 +0,0 @@ -import Foundation -import XCTest - -public extension XCTestCase { - func failTest( - _ message: String, - file: StaticString = #file, - line: UInt = #line - ) -> Never { - withoutContinuingTestAfterFailure { - XCTFail(message, file: file, line: line) - } - fatalError("Failing test with message: \(message)") - } -} diff --git a/Tests/TestHelpers/ThrowingHelpers.swift b/Tests/TestHelpers/ThrowingHelpers.swift deleted file mode 100644 index b2d250ca..00000000 --- a/Tests/TestHelpers/ThrowingHelpers.swift +++ /dev/null @@ -1,32 +0,0 @@ -import Foundation -import XCTest - -public extension XCTestCase { - func assertDoesNotThrow( - message: (Error) -> String = { "Unexpected error thrown: \($0)" }, - file: StaticString = #file, - line: UInt = #line, - work: () throws -> T - ) -> T { - return withoutContinuingTestAfterFailure { - do { - return try work() - } catch { - failTest(message(error), file: file, line: line) - } - } - } - - func assertThrows( - file: StaticString = #file, - line: UInt = #line, - work: () throws -> (T) - ) { - do { - _ = try work() - failTest("Expected to throw an error, but no error has been thrown", file: file, line: line) - } catch { - return - } - } -} diff --git a/Tests/TestHelpers/XCTestCase+Syncronious.swift b/Tests/TestHelpers/XCTestCase+Syncronious.swift deleted file mode 100644 index 41a7a86f..00000000 --- a/Tests/TestHelpers/XCTestCase+Syncronious.swift +++ /dev/null @@ -1,34 +0,0 @@ -import XCTest - -extension XCTestCase { - // Makes asynchronous functions syncronous. Example: - // - // let int = runSyncronously { completion in - // DispatchQueue.main.async { - // completion(42) - // } - // } - // - // XCTAssertEqual(int, 42) - // - public func runSyncronously( - timeout: TimeInterval = 15, - asyncFunction: @escaping (_ completion: @escaping (T) -> ()) throws -> () - ) throws -> T { - var resultOrNil: T? - - let expectation = self.expectation(description: "Awaiting for result of type \(T.self)") - try asyncFunction { result in - resultOrNil = result - expectation.fulfill() - } - - wait(for: [expectation], timeout: timeout) - - if let result = resultOrNil { - return result - } else { - throw ExpectationAwaitingError() - } - } -} diff --git a/Tests/TypesTests/EitherTests.swift b/Tests/TypesTests/EitherTests.swift deleted file mode 100644 index d4094019..00000000 --- a/Tests/TypesTests/EitherTests.swift +++ /dev/null @@ -1,81 +0,0 @@ -import Foundation -import Types -import XCTest - -class EitherTests: XCTestCase { - private struct SomeError: Error, Equatable, Codable { - let thisIsError: String - } - - func test___success_is_left() { - XCTAssertEqual( - Either.left("hello"), - Either.success("hello") - ) - } - - func test___comparing_left() { - XCTAssertNotEqual( - Either.left("left"), - Either.left("oops") - ) - } - - func test___error_is_right() { - XCTAssertEqual( - Either.right(SomeError(thisIsError: "error")), - Either.error(SomeError(thisIsError: "error")) - ) - } - - func test___comparing_right() { - XCTAssertNotEqual( - Either.right(SomeError(thisIsError: "error1")), - Either.right(SomeError(thisIsError: "error2")) - ) - } - - func test___encoding_left() throws { - let expected = Either.left("hello") - let data = try JSONEncoder().encode(expected) - let decoded = try JSONDecoder().decode(Either.self, from: data) - XCTAssertEqual(decoded, expected) - } - - func test___encoding_right() throws { - let expected = Either.right(SomeError(thisIsError: "error")) - let data = try JSONEncoder().encode(expected) - let decoded = try JSONDecoder().decode(Either.self, from: data) - XCTAssertEqual(decoded, expected) - } - - func test___left() { - let either = Either.left("hello") - XCTAssertEqual(either.left, "hello") - XCTAssertNil(either.right) - } - - func test___right() { - let either = Either.right(true) - XCTAssertEqual(either.right, true) - XCTAssertNil(either.left) - } - - func test___map_result() { - let either = Either.left(0) - - XCTAssertEqual( - try either.mapResult { _ in "hello" }.dematerialize(), - "hello" - ) - } - - func test___map_result___for_error() { - let error = SomeError(thisIsError: "error") - let either = Either.error(error) - - XCTAssertThrowsError( - try either.mapResult { _ in "hello" }.dematerialize() - ) - } -} diff --git a/Tests/URLResourceTests/URLResourceTests.swift b/Tests/URLResourceTests/URLResourceTests.swift index 3f5a3197..6619bc04 100644 --- a/Tests/URLResourceTests/URLResourceTests.swift +++ b/Tests/URLResourceTests/URLResourceTests.swift @@ -2,7 +2,7 @@ import DateProviderTestHelpers import FileCache import FileSystem import Swifter -import TemporaryStuff +import Tmp import TestHelpers import URLResource import XCTest diff --git a/Tests/WorkerCapabilitiesTests/XcodeCapabilitiesProviderTests.swift b/Tests/WorkerCapabilitiesTests/XcodeCapabilitiesProviderTests.swift index 983c4f49..907154a8 100644 --- a/Tests/WorkerCapabilitiesTests/XcodeCapabilitiesProviderTests.swift +++ b/Tests/WorkerCapabilitiesTests/XcodeCapabilitiesProviderTests.swift @@ -2,7 +2,7 @@ import FileSystem import FileSystemTestHelpers import Foundation import PlistLib -import TemporaryStuff +import Tmp import TestHelpers import WorkerCapabilities import WorkerCapabilitiesModels diff --git a/Tests/fbxctestTests/FbxctestBasedTestRunnerTests.swift b/Tests/fbxctestTests/FbxctestBasedTestRunnerTests.swift index a262b329..9fb9dc75 100644 --- a/Tests/fbxctestTests/FbxctestBasedTestRunnerTests.swift +++ b/Tests/fbxctestTests/FbxctestBasedTestRunnerTests.swift @@ -6,16 +6,15 @@ import Runner import RunnerModels import RunnerTestHelpers import SimulatorPoolTestHelpers -import TemporaryStuff +import Tmp import TestHelpers import XCTest import fbxctest final class FbxctestBasedTestRunnerTests: XCTestCase { - private lazy var tempFolder = assertDoesNotThrow { try TemporaryFolder() } private lazy var runner = FbxctestBasedTestRunner( fbxctestLocation: FbxctestLocationFixtures.fakeFbxctestLocation, - processControllerProvider: FakeProcessControllerProvider(tempFolder: tempFolder), + processControllerProvider: FakeProcessControllerProvider(), resourceLocationResolver: FakeResourceLocationResolver.throwing() ) diff --git a/make.sh b/make.sh index bc06b2c5..de317a8d 100755 --- a/make.sh +++ b/make.sh @@ -23,7 +23,11 @@ function install_deps() { ln -s $(brew --prefix)/opt/openssl@1.1/lib/pkgconfig/libcrypto.pc $(brew --prefix)/lib/pkgconfig/libcrypto.pc fi - swift "PackageGenerator.swift" + swift package resolve +} + +function generate_package_swift() { + swift run --package-path ".build/checkouts/CommandLineToolkit/PackageGenerator/" package-gen . } function generate_emcee_version() { @@ -43,6 +47,7 @@ function open_xcodeproj() { function generate_xcodeproj() { install_deps + generate_package_swift swift package generate-xcodeproj --enable-code-coverage } @@ -55,6 +60,7 @@ function build() { trap reset_emcee_version EXIT generate_emcee_version install_deps + generate_package_swift swift build } @@ -62,6 +68,7 @@ function run_tests_parallel() { trap reset_emcee_version EXIT generate_emcee_version install_deps + generate_package_swift swift test --parallel } @@ -81,4 +88,7 @@ case "$1" in clean) clean ;; + package) + generate_package_swift + ;; esac diff --git a/package.json b/package.json new file mode 100644 index 00000000..5cf7e46f --- /dev/null +++ b/package.json @@ -0,0 +1,155 @@ +{ + "dependencies" : { + "external" : { + "CommandLineToolkit": { + "url": "https://github.com/avito-tech/CommandLineToolkit.git", + "version": { + "branch": "master" + }, + "targetNames": [ + "AtomicModels", + "DateProvider", + "DateProviderTestHelpers", + "FileSystem", + "FileSystemTestHelpers", + "Graphite", + "GraphiteClient", + "IO", + "Metrics", + "MetricsTestHelpers", + "MetricsUtils", + "PathLib", + "PlistLib", + "ProcessController", + "ProcessControllerTestHelpers", + "SignalHandling", + "SocketModels", + "Statsd", + "SynchronousWaiter", + "TestHelpers", + "Timer", + "Tmp", + "TmpTestHelpers", + "Types", + "UserDefaultsLib", + "UserDefaultsLibTestHelpers", + "Waitable", + "XcodeLocator", + "XcodeLocatorModels" + ] + }, + "CountedSet": { + "url": "https://github.com/0x7fs/CountedSet", + "version": { + "branch": "master" + }, + "targetNames": [ + "CountedSet" + ] + }, + "OrderedSet": { + "url": "https://github.com/Weebly/OrderedSet", + "version": { + "exact": "5.0.0" + }, + "targetNames": [ + "OrderedSet" + ] + }, + "Starscream": { + "url": "https://github.com/daltoniam/Starscream.git", + "version": { + "exact": "3.0.6" + }, + "targetNames": [ + "Starscream" + ] + }, + "Swifter": { + "url": "https://github.com/httpswift/swifter.git", + "version": { + "exact": "1.4.6" + }, + "targetNames": [ + "Swifter" + ] + }, + "Shout": { + "url": "https://github.com/jakeheis/Shout.git", + "version": { + "exact": "0.5.4" + }, + "targetNames": [ + "Shout" + ] + } + }, + "implicitSystemModules" : [ + "AppKit", + "Darwin", + "Dispatch", + "Foundation", + "XCTest" + ] + }, + "name" : "EmceeTestRunner", + "platforms" : [ + { + "name" : "macOS", + "version" : "10.15" + } + ], + "products" : [{ + "name": "Emcee", + "productType": "executable", + "targets": [ + "EmceeBinary" + ] + }, { + "name": "testing_plugin", + "productType": "executable", + "targets": [ + "TestingPlugin" + ] + }, { + "name": "EmceePlugin", + "productType": "library", + "targets": [ + "Logging", + "Plugin" + ] + }, { + "name": "EmceeCommunications", + "productType": "library", + "targets": [ + "PortDeterminer", + "QueueClient", + "QueueCommunication", + "RemotePortDeterminer", + "RequestSender" + ] + }, { + "name": "EmceeInterfaces", + "productType": "library", + "targets": [ + "BuildArtifacts", + "DeveloperDirModels", + "EmceeVersion", + "PluginSupport", + "QueueModels", + "ResourceLocation", + "ResourceLocationResolver", + "RunnerModels", + "SimulatorPoolModels", + "SimulatorVideoRecorder", + "TestArgFile", + "TestDiscovery", + "TestsWorkingDirectorySupport", + "TypedResourceLocation", + "WorkerAlivenessModels", + "WorkerCapabilitiesModels" + ] + }], + "swiftToolsVersion" : "5.2", + "targets" : "discoverAutomatically" +}