Skip to content

Commit

Permalink
Expose automatic simulator shutdown via test arg file
Browse files Browse the repository at this point in the history
  • Loading branch information
Vladislav Alekseev committed Feb 19, 2020
1 parent 908d9eb commit 74cd154
Show file tree
Hide file tree
Showing 16 changed files with 79 additions and 34 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@ All notable changes to this project will be documented in this file.
"create": 30,
"boot": 180,
"shutdown": 20,
"delete": 20
"delete": 20,
"automaticSimulatorShutdown": 3600
}
}
```

- Emcee now allows you to control automatic simulator shutdown by setting `simulatorOperationTimeouts.automaticSimulatorShutdown` in test arg file to a positive value in seconds after which simulator will be shut down if it stays idle. When it is needed again, it will be booted. Shutting down simulators allows to free up some RAM and reduce swap size.

## 2020-02-14

- `ToolchainConfiguration` object and `toolchainConfiguration` field have been removed from test arg file, because this object contained only `developerDir` value. You must provide a value via `developerDir` field in test arg file instead.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,17 @@ import fbxctest

public final class DefaultSimulatorControllerProvider: SimulatorControllerProvider {
private let additionalBootAttempts: UInt
private let automaticSimulatorShutdown: TimeInterval
private let developerDirLocator: DeveloperDirLocator
private let simulatorBootQueue: DispatchQueue
private let simulatorStateMachineActionExecutorProvider: SimulatorStateMachineActionExecutorProvider

public init(
additionalBootAttempts: UInt,
automaticSimulatorShutdown: TimeInterval,
developerDirLocator: DeveloperDirLocator,
simulatorBootQueue: DispatchQueue,
simulatorStateMachineActionExecutorProvider: SimulatorStateMachineActionExecutorProvider
) {
self.additionalBootAttempts = additionalBootAttempts
self.automaticSimulatorShutdown = automaticSimulatorShutdown
self.developerDirLocator = developerDirLocator
self.simulatorBootQueue = simulatorBootQueue
self.simulatorStateMachineActionExecutorProvider = simulatorStateMachineActionExecutorProvider
Expand All @@ -33,18 +30,16 @@ public final class DefaultSimulatorControllerProvider: SimulatorControllerProvid
public func createSimulatorController(
developerDir: DeveloperDir,
simulatorControlTool: SimulatorControlTool,
simulatorOperationTimeouts: SimulatorOperationTimeouts,
testDestination: TestDestination,
testRunnerTool: TestRunnerTool
) throws -> SimulatorController {
return ActivityAwareSimulatorController(
automaticShutdownTimePeriod: automaticSimulatorShutdown,
automaticShutdownTimePeriod: 3600,
delegate: StateMachineDrivenSimulatorController(
additionalBootAttempts: additionalBootAttempts,
bootQueue: simulatorBootQueue,
developerDir: developerDir,
developerDirLocator: developerDirLocator,
simulatorOperationTimeouts: simulatorOperationTimeouts,
simulatorStateMachine: SimulatorStateMachine(),
simulatorStateMachineActionExecutor: try simulatorStateMachineActionExecutorProvider.simulatorStateMachineActionExecutor(
simulatorControlTool: simulatorControlTool,
Expand Down
1 change: 0 additions & 1 deletion Sources/EmceeLib/Utils/OnDemandSimulatorPoolFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ public final class OnDemandSimulatorPoolFactory {
resourceLocationResolver: resourceLocationResolver,
simulatorControllerProvider: DefaultSimulatorControllerProvider(
additionalBootAttempts: 2,
automaticSimulatorShutdown: 3600,
developerDirLocator: developerDirLocator,
simulatorBootQueue: simulatorBootQueue,
simulatorStateMachineActionExecutorProvider: SimulatorStateMachineActionExecutorProviderImpl(
Expand Down
20 changes: 17 additions & 3 deletions Sources/SimulatorPool/ActivityAwareSimulatorController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,34 @@ import Logging
import SimulatorPoolModels

public final class ActivityAwareSimulatorController: SimulatorController {
private let automaticTerminationControllerFactory: AutomaticTerminationControllerFactory
private var automaticTerminationControllerFactory: AutomaticTerminationControllerFactory
private var automaticShutdownController: AutomaticTerminationController?
private let delegate: SimulatorController

public init(
automaticShutdownTimePeriod: TimeInterval,
delegate: SimulatorController
) {
self.automaticTerminationControllerFactory = AutomaticTerminationControllerFactory(
automaticTerminationPolicy: .afterBeingIdle(period: automaticShutdownTimePeriod)
automaticTerminationControllerFactory = ActivityAwareSimulatorController.automaticTerminationController(
period: automaticShutdownTimePeriod
)
self.delegate = delegate
}

private static func automaticTerminationController(period: TimeInterval) -> AutomaticTerminationControllerFactory {
return AutomaticTerminationControllerFactory(
automaticTerminationPolicy: .afterBeingIdle(period: period)
)
}

public func apply(simulatorOperationTimeouts: SimulatorOperationTimeouts) {
delegate.apply(simulatorOperationTimeouts: simulatorOperationTimeouts)

automaticTerminationControllerFactory = ActivityAwareSimulatorController.automaticTerminationController(
period: simulatorOperationTimeouts.automaticSimulatorShutdown
)
}

public func bootedSimulator() throws -> Simulator {
return try delegate.bootedSimulator()
}
Expand Down
1 change: 0 additions & 1 deletion Sources/SimulatorPool/DefaultSimulatorPool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ public final class DefaultSimulatorPool: SimulatorPool, CustomStringConvertible
let controller = try simulatorControllerProvider.createSimulatorController(
developerDir: developerDir,
simulatorControlTool: simulatorControlTool,
simulatorOperationTimeouts: simulatorOperationTimeouts,
testDestination: testDestination,
testRunnerTool: testRunnerTool
)
Expand Down
2 changes: 2 additions & 0 deletions Sources/SimulatorPool/SimulatorController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import Foundation
import SimulatorPoolModels

public protocol SimulatorController {
func apply(simulatorOperationTimeouts: SimulatorOperationTimeouts)

func bootedSimulator() throws -> Simulator
func shutdownSimulator() throws
func deleteSimulator() throws
Expand Down
1 change: 0 additions & 1 deletion Sources/SimulatorPool/SimulatorControllerProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ public protocol SimulatorControllerProvider {
func createSimulatorController(
developerDir: DeveloperDir,
simulatorControlTool: SimulatorControlTool,
simulatorOperationTimeouts: SimulatorOperationTimeouts,
testDestination: TestDestination,
testRunnerTool: TestRunnerTool
) throws -> SimulatorController
Expand Down
1 change: 1 addition & 0 deletions Sources/SimulatorPool/SimulatorPool+Convenience.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ extension SimulatorPool {
let simulatorController = try self.allocateSimulatorController(
simulatorOperationTimeouts: simulatorOperationTimeouts
)
simulatorController.apply(simulatorOperationTimeouts: simulatorOperationTimeouts)

do {
return AllocatedSimulator(
Expand Down
19 changes: 12 additions & 7 deletions Sources/SimulatorPool/StateMachineDrivenSimulatorController.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import AtomicModels
import DeveloperDirLocator
import Foundation
import Logging
Expand All @@ -11,7 +12,9 @@ public final class StateMachineDrivenSimulatorController: SimulatorController, C
private let bootQueue: DispatchQueue
private let developerDir: DeveloperDir
private let developerDirLocator: DeveloperDirLocator
private let simulatorOperationTimeouts: SimulatorOperationTimeouts
private let simulatorOperationTimeouts = AtomicValue<SimulatorOperationTimeouts>(
SimulatorOperationTimeouts(create: 30, boot: 180, delete: 20, shutdown: 20, automaticSimulatorShutdown: 3600)
)
private let simulatorStateMachine: SimulatorStateMachine
private let simulatorStateMachineActionExecutor: SimulatorStateMachineActionExecutor
private let testDestination: TestDestination
Expand All @@ -24,7 +27,6 @@ public final class StateMachineDrivenSimulatorController: SimulatorController, C
bootQueue: DispatchQueue,
developerDir: DeveloperDir,
developerDirLocator: DeveloperDirLocator,
simulatorOperationTimeouts: SimulatorOperationTimeouts,
simulatorStateMachine: SimulatorStateMachine,
simulatorStateMachineActionExecutor: SimulatorStateMachineActionExecutor,
testDestination: TestDestination,
Expand All @@ -34,7 +36,6 @@ public final class StateMachineDrivenSimulatorController: SimulatorController, C
self.bootQueue = bootQueue
self.developerDir = developerDir
self.developerDirLocator = developerDirLocator
self.simulatorOperationTimeouts = simulatorOperationTimeouts
self.simulatorStateMachine = simulatorStateMachine
self.simulatorStateMachineActionExecutor = simulatorStateMachineActionExecutor
self.testDestination = testDestination
Expand All @@ -43,6 +44,10 @@ public final class StateMachineDrivenSimulatorController: SimulatorController, C

// MARK: - SimulatorController

public func apply(simulatorOperationTimeouts: SimulatorOperationTimeouts) {
self.simulatorOperationTimeouts.set(simulatorOperationTimeouts)
}

public func bootedSimulator() throws -> Simulator {
try attemptToSwitchState(targetStates: [.booted])

Expand Down Expand Up @@ -102,7 +107,7 @@ public final class StateMachineDrivenSimulatorController: SimulatorController, C
let simulator = try simulatorStateMachineActionExecutor.performCreateSimulatorAction(
environment: try environment(),
testDestination: testDestination,
timeout: simulatorOperationTimeouts.create
timeout: simulatorOperationTimeouts.currentValue().create
)
Logger.debug("Created simulator: \(simulator)")
return simulator
Expand All @@ -123,7 +128,7 @@ public final class StateMachineDrivenSimulatorController: SimulatorController, C
environment: try self.environment(),
path: simulator.path,
simulatorUuid: simulator.udid,
timeout: self.simulatorOperationTimeouts.boot
timeout: self.simulatorOperationTimeouts.currentValue().boot
)
}

Expand Down Expand Up @@ -155,7 +160,7 @@ public final class StateMachineDrivenSimulatorController: SimulatorController, C
environment: try environment(),
path: simulator.path,
simulatorUuid: simulator.udid,
timeout: simulatorOperationTimeouts.shutdown
timeout: simulatorOperationTimeouts.currentValue().shutdown
)
}

Expand All @@ -166,7 +171,7 @@ public final class StateMachineDrivenSimulatorController: SimulatorController, C
environment: try environment(),
path: simulator.path,
simulatorUuid: simulator.udid,
timeout: simulatorOperationTimeouts.delete
timeout: simulatorOperationTimeouts.currentValue().delete
)

try attemptToDeleteSimulatorFiles(simulator: simulator)
Expand Down
7 changes: 5 additions & 2 deletions Sources/SimulatorPoolModels/SimulatorOperationTimeouts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,23 @@ public struct SimulatorOperationTimeouts: Codable, CustomStringConvertible, Hash
public let boot: TimeInterval
public let delete: TimeInterval
public let shutdown: TimeInterval
public let automaticSimulatorShutdown: TimeInterval

public init(
create: TimeInterval,
boot: TimeInterval,
delete: TimeInterval,
shutdown: TimeInterval
shutdown: TimeInterval,
automaticSimulatorShutdown: TimeInterval
) {
self.create = create
self.boot = boot
self.delete = delete
self.shutdown = shutdown
self.automaticSimulatorShutdown = automaticSimulatorShutdown
}

public var description: String {
return "<\(type(of: self)): create: \(create), boot: \(boot), delete: \(delete), shutdown: \(shutdown)>"
return "<\(type(of: self)): create: \(create), boot: \(boot), delete: \(delete), shutdown: \(shutdown), automatic shutdown: \(automaticSimulatorShutdown)>"
}
}
5 changes: 5 additions & 0 deletions Tests/SimulatorPoolTestHelpers/FakeSimulatorController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,18 @@ public final class FakeSimulatorController: SimulatorController {
public var didCallShutdown = false
public var isBusy = false
public var onShutdown: () -> () = {}
public var simulatorOperationTimeouts: SimulatorOperationTimeouts?

public init(simulator: Simulator, simulatorControlTool: SimulatorControlTool, developerDir: DeveloperDir) {
self.simulator = simulator
self.simulatorControlTool = simulatorControlTool
self.developerDir = developerDir
}

public func apply(simulatorOperationTimeouts: SimulatorOperationTimeouts) {
self.simulatorOperationTimeouts = simulatorOperationTimeouts
}

public func bootedSimulator() throws -> Simulator {
return simulator
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ public final class FakeSimulatorControllerProvider: SimulatorControllerProvider
public func createSimulatorController(
developerDir: DeveloperDir,
simulatorControlTool: SimulatorControlTool,
simulatorOperationTimeouts: SimulatorOperationTimeouts,
testDestination: TestDestination,
testRunnerTool: TestRunnerTool
) throws -> SimulatorController {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,29 @@ public final class SimulatorOperationTimeoutsFixture {
public var boot: TimeInterval
public var delete: TimeInterval
public var shutdown: TimeInterval
public var automaticSimulatorShutdown: TimeInterval

public init(
create: TimeInterval = 42,
boot: TimeInterval = 43,
delete: TimeInterval = 44,
shutdown: TimeInterval = 45
shutdown: TimeInterval = 45,
automaticSimulatorShutdown: TimeInterval = 46
) {
self.create = create
self.boot = boot
self.delete = delete
self.shutdown = shutdown
self.automaticSimulatorShutdown = automaticSimulatorShutdown
}

public func simulatorOperationTimeouts() -> SimulatorOperationTimeouts {
return SimulatorOperationTimeouts(
create: create,
boot: boot,
delete: delete,
shutdown: shutdown
shutdown: shutdown,
automaticSimulatorShutdown: automaticSimulatorShutdown
)
}
}
15 changes: 13 additions & 2 deletions Tests/SimulatorPoolTests/SimulatorPoolConvenienceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,31 @@ import XCTest
import SimulatorPool
import ModelsTestHelpers
import TemporaryStuff
import SimulatorPoolModels
import SimulatorPoolTestHelpers
import SynchronousWaiter

final class SimulatorPoolConvenienceTests: XCTestCase {
private let simulatorOperationTimeouts = SimulatorOperationTimeouts(create: 1, boot: 2, delete: 3, shutdown: 4, automaticSimulatorShutdown: 5)

func test__simulator_contoller_frees__upon_release() throws {
let pool = SimulatorPoolMock()
let allocatedSimulator = try pool.allocateSimulator(
simulatorOperationTimeouts: SimulatorOperationTimeoutsFixture().simulatorOperationTimeouts()
simulatorOperationTimeouts: simulatorOperationTimeouts
)
allocatedSimulator.releaseSimulator()

guard let fakeSimulatorController = pool.freedSimulatorContoller as? FakeSimulatorController else {
return XCTFail("Unexpected behaviour")
}

XCTAssertEqual(
allocatedSimulator.simulator,
(pool.freedSimulatorContoller as? FakeSimulatorController)?.simulator
fakeSimulatorController.simulator
)
XCTAssertEqual(
fakeSimulatorController.simulatorOperationTimeouts,
simulatorOperationTimeouts
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,8 @@ final class StateMachineDrivenSimulatorControllerTests: XCTestCase {
create: .infinity,
boot: .infinity,
delete: .infinity,
shutdown: .infinity
shutdown: .infinity,
automaticSimulatorShutdown: .infinity
)
) -> StateMachineDrivenSimulatorController {
let tempFolder = assertDoesNotThrow {
Expand Down Expand Up @@ -211,30 +212,33 @@ final class StateMachineDrivenSimulatorControllerTests: XCTestCase {
developerDirLocator: DeveloperDirLocator,
timeouts: SimulatorOperationTimeouts
) -> StateMachineDrivenSimulatorController {
return StateMachineDrivenSimulatorController(
let controller = StateMachineDrivenSimulatorController(
additionalBootAttempts: additionalBootAttempts,
bootQueue: DispatchQueue(label: "serial"),
developerDir: .current,
developerDirLocator: developerDirLocator,
simulatorOperationTimeouts: timeouts,
simulatorStateMachine: SimulatorStateMachine(),
simulatorStateMachineActionExecutor: actionExecutor,
testDestination: expectedTestDestination,
waiter: NoOpWaiter()
)
controller.apply(simulatorOperationTimeouts: timeouts)
return controller
}

private func createTimeouts(
create: TimeInterval = .infinity,
boot: TimeInterval = .infinity,
delete: TimeInterval = .infinity,
shutdown: TimeInterval = .infinity
shutdown: TimeInterval = .infinity,
automaticSimulatorShutdown: TimeInterval = .infinity
) -> SimulatorOperationTimeouts {
return SimulatorOperationTimeouts(
create: create,
boot: boot,
delete: delete,
shutdown: shutdown
shutdown: shutdown,
automaticSimulatorShutdown: automaticSimulatorShutdown
)
}

Expand Down
Loading

0 comments on commit 74cd154

Please sign in to comment.