Skip to content

Commit

Permalink
Delete revive on worker functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
Vladislav Alekseev committed Nov 29, 2021
1 parent 182c933 commit 9c6a7ff
Show file tree
Hide file tree
Showing 12 changed files with 76 additions and 152 deletions.
5 changes: 0 additions & 5 deletions Sources/QueueModels/Bucket.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,17 @@ import WorkerCapabilitiesModels
public struct Bucket: Codable, Hashable, CustomStringConvertible {
public private(set) var bucketId: BucketId
public let analyticsConfiguration: AnalyticsConfiguration
public let pluginLocations: Set<PluginLocation>
public let workerCapabilityRequirements: Set<WorkerCapabilityRequirement>
public private(set) var payload: Payload

private init(
bucketId: BucketId,
analyticsConfiguration: AnalyticsConfiguration,
pluginLocations: Set<PluginLocation>,
workerCapabilityRequirements: Set<WorkerCapabilityRequirement>,
payload: Payload
) {
self.bucketId = bucketId
self.analyticsConfiguration = analyticsConfiguration
self.pluginLocations = pluginLocations
self.workerCapabilityRequirements = workerCapabilityRequirements
self.payload = payload
}
Expand All @@ -35,14 +32,12 @@ public struct Bucket: Codable, Hashable, CustomStringConvertible {
public static func newBucket(
bucketId: BucketId,
analyticsConfiguration: AnalyticsConfiguration,
pluginLocations: Set<PluginLocation>,
workerCapabilityRequirements: Set<WorkerCapabilityRequirement>,
payload: Payload
) -> Bucket {
return Bucket(
bucketId: bucketId,
analyticsConfiguration: analyticsConfiguration,
pluginLocations: pluginLocations,
workerCapabilityRequirements: workerCapabilityRequirements,
payload: payload
)
Expand Down
7 changes: 6 additions & 1 deletion Sources/QueueModels/Payload.swift
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import BuildArtifacts
import DeveloperDirModels
import Foundation
import PluginSupport
import RunnerModels
import SimulatorPoolModels
import Foundation

public struct Payload: Codable, Hashable, CustomStringConvertible {
public let buildArtifacts: BuildArtifacts
public let developerDir: DeveloperDir
public let pluginLocations: Set<PluginLocation>
public let simulatorOperationTimeouts: SimulatorOperationTimeouts
public let simulatorSettings: SimulatorSettings
public let testDestination: TestDestination
Expand All @@ -17,6 +19,7 @@ public struct Payload: Codable, Hashable, CustomStringConvertible {
public init(
buildArtifacts: BuildArtifacts,
developerDir: DeveloperDir,
pluginLocations: Set<PluginLocation>,
simulatorOperationTimeouts: SimulatorOperationTimeouts,
simulatorSettings: SimulatorSettings,
testDestination: TestDestination,
Expand All @@ -26,6 +29,7 @@ public struct Payload: Codable, Hashable, CustomStringConvertible {
) {
self.buildArtifacts = buildArtifacts
self.developerDir = developerDir
self.pluginLocations = pluginLocations
self.simulatorOperationTimeouts = simulatorOperationTimeouts
self.simulatorSettings = simulatorSettings
self.testDestination = testDestination
Expand All @@ -42,6 +46,7 @@ public struct Payload: Codable, Hashable, CustomStringConvertible {
Payload(
buildArtifacts: buildArtifacts,
developerDir: developerDir,
pluginLocations: pluginLocations,
simulatorOperationTimeouts: simulatorOperationTimeouts,
simulatorSettings: simulatorSettings,
testDestination: testDestination,
Expand Down
105 changes: 19 additions & 86 deletions Sources/Runner/Runner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,10 @@ import Tmp
import UniqueIdentifierGenerator

public final class Runner {
private let configuration: RunnerConfiguration
private let dateProvider: DateProvider
private let developerDirLocator: DeveloperDirLocator
private let fileSystem: FileSystem
private let logger: ContextualLogger
private let persistentMetricsJobId: String?
private let pluginEventBusProvider: PluginEventBusProvider
private let pluginTearDownQueue = OperationQueue()
private let runnerWasteCollectorProvider: RunnerWasteCollectorProvider
Expand All @@ -38,19 +36,16 @@ public final class Runner {
private let version: Version
private let waiter: Waiter

public static let skipReviveAttemptsEnvName = "EMCEE_SKIP_REVIVE_ATTEMPTS"
public static let logCapturingModeEnvName = "EMCEE_LOG_CAPTURE_MODE"

public static let runnerWorkingDir = "runnerWorkingDir"
public static let testsWorkingDir = "testsWorkingDir"

public init(
configuration: RunnerConfiguration,
dateProvider: DateProvider,
developerDirLocator: DeveloperDirLocator,
fileSystem: FileSystem,
logger: ContextualLogger,
persistentMetricsJobId: String?,
pluginEventBusProvider: PluginEventBusProvider,
runnerWasteCollectorProvider: RunnerWasteCollectorProvider,
specificMetricRecorder: SpecificMetricRecorder,
Expand All @@ -61,12 +56,10 @@ public final class Runner {
version: Version,
waiter: Waiter
) {
self.configuration = configuration
self.dateProvider = dateProvider
self.developerDirLocator = developerDirLocator
self.fileSystem = fileSystem
self.logger = logger
self.persistentMetricsJobId = persistentMetricsJobId
self.pluginEventBusProvider = pluginEventBusProvider
self.runnerWasteCollectorProvider = runnerWasteCollectorProvider
self.specificMetricRecorder = specificMetricRecorder
Expand All @@ -78,71 +71,10 @@ public final class Runner {
self.waiter = waiter
}

/** Runs the given tests, attempting to restart the runner in case of crash. */
public func run(
entries: [TestEntry],
developerDir: DeveloperDir,
simulator: Simulator
) throws -> RunnerRunResult {
if entries.isEmpty {
return RunnerRunResult(
entriesToRun: entries,
testEntryResults: []
)
}

let runResult = RunResult()

// To not retry forever.
// It is unlikely that multiple revives would provide any results, so we leave only a single retry.
let numberOfAttemptsToRevive = 1

// Something may crash (xcodebuild/xctest), many tests may be not started. Some external code that uses Runner
// may have its own logic for restarting particular tests, but here at Runner we deal with crashes of bunches
// of tests, many of which can be even not started. Simplifying this: if something that runs tests is crashed,
// we should retry running tests more than if some test fails. External code will treat failed tests as it
// is promblem in them, not in infrastructure.

var reviveAttempt = 0

let lostTestProcessingMode: LostTestProcessingMode = configuration.environment[Self.skipReviveAttemptsEnvName] == "true" ? .reportError : .reportLost

while runResult.nonLostTestEntryResults.count < entries.count, reviveAttempt <= numberOfAttemptsToRevive {
let missingEntriesToRun = missingEntriesForScheduledEntries(
expectedEntriesToRun: entries,
collectedResults: runResult
)
let runResults = try runOnce(
entriesToRun: missingEntriesToRun,
developerDir: developerDir,
simulator: simulator,
lostTestProcessingMode: reviveAttempt == numberOfAttemptsToRevive ? .reportError : lostTestProcessingMode
)

runResult.append(testEntryResults: runResults.testEntryResults)

if runResults.testEntryResults.filter({ !$0.isLost }).isEmpty {
// Here, if we do not receive events at all, we will get 0 results. We try to revive a limited number of times.
reviveAttempt += 1
logger.warning("Got no results. Attempting to revive #\(reviveAttempt) out of allowed \(numberOfAttemptsToRevive) attempts to revive")
} else {
// Here, we actually got events, so we could reset revive attempts.
reviveAttempt = 0
}
}

return RunnerRunResult(
entriesToRun: entries,
testEntryResults: runResult.testEntryResults
)
}

/// Runs the given tests once without any attempts to restart the failed or crashed tests.
public func runOnce(
entriesToRun: [TestEntry],
developerDir: DeveloperDir,
simulator: Simulator,
lostTestProcessingMode: LostTestProcessingMode
configuration: RunnerConfiguration
) throws -> RunnerRunResult {
if entriesToRun.isEmpty {
return RunnerRunResult(
Expand All @@ -163,19 +95,18 @@ public final class Runner {
)

let testContext = try createTestContext(
developerDir: developerDir,
simulator: simulator,
configuration: configuration,
testRunner: testRunner
)

let runnerWasteCollector = runnerWasteCollectorProvider.createRunnerWasteCollector()
runnerWasteCollector.scheduleCollection(path: testContext.testsWorkingDirectory)
runnerWasteCollector.scheduleCollection(path: testContext.testRunnerWorkingDirectory)
runnerWasteCollector.scheduleCollection(path: simulator.path.appending(relativePath: "data/Library/Caches/com.apple.containermanagerd/Dead"))
runnerWasteCollector.scheduleCollection(path: configuration.simulator.path.appending(relativePath: "data/Library/Caches/com.apple.containermanagerd/Dead"))

let runnerResultsPreparer = RunnerResultsPreparerImpl(
dateProvider: dateProvider,
lostTestProcessingMode: lostTestProcessingMode
lostTestProcessingMode: configuration.lostTestProcessingMode
)

let eventBus = try pluginEventBusProvider.createEventBus(
Expand All @@ -190,7 +121,7 @@ public final class Runner {
}

var logger = self.logger
logger.debug("Will run \(entriesToRun.count) tests on simulator \(simulator)")
logger.debug("Will run \(entriesToRun.count) tests on simulator \(configuration.simulator)")

let singleTestMaximumDuration = configuration.testTimeoutConfiguration.singleTestMaximumDuration

Expand All @@ -210,7 +141,7 @@ public final class Runner {
collectedTestExceptions: collectedTestExceptions,
collectedLogs: collectedLogs,
requestedEntriesToRun: entriesToRun,
simulatorId: simulator.udid
simulatorId: configuration.simulator.udid
)
}
),
Expand Down Expand Up @@ -241,7 +172,7 @@ public final class Runner {
dateProvider: dateProvider,
version: version,
host: LocalHostDeterminer.currentHostAddress,
persistentMetricsJobId: persistentMetricsJobId,
persistentMetricsJobId: configuration.persistentMetricsJobId,
specificMetricRecorder: specificMetricRecorder
),
TestRunnerStreamWrapper(
Expand Down Expand Up @@ -302,7 +233,7 @@ public final class Runner {
entriesToRun: entriesToRun,
logger: logger,
runnerWasteCollector: runnerWasteCollector,
simulator: simulator,
simulator: configuration.simulator,
testContext: testContext,
testRunnerStream: testRunnerStream
).startExecutingTests()
Expand All @@ -322,10 +253,10 @@ public final class Runner {
collectedTestExceptions: collectedTestExceptions,
collectedLogs: collectedLogs,
requestedEntriesToRun: entriesToRun,
simulatorId: simulator.udid
simulatorId: configuration.simulator.udid
)

logger.debug("Attempted to run \(entriesToRun.count) tests on simulator \(simulator): \(entriesToRun)")
logger.debug("Attempted to run \(entriesToRun.count) tests on simulator \(configuration.simulator): \(entriesToRun)")
logger.debug("Did get \(result.count) results: \(result)")

return RunnerRunResult(
Expand All @@ -341,8 +272,7 @@ public final class Runner {
}

private func createTestContext(
developerDir: DeveloperDir,
simulator: Simulator,
configuration: RunnerConfiguration,
testRunner: TestRunner
) throws -> TestContext {
let contextId = uniqueIdentifierGenerator.generate()
Expand All @@ -356,18 +286,21 @@ public final class Runner {
let additionalEnvironment = testRunner.additionalEnvironment(testRunnerWorkingDirectory: testRunnerWorkingDirectory)
var environment = configuration.environment
environment[TestsWorkingDirectorySupport.envTestsWorkingDirectory] = testsWorkingDirectory.pathString
environment = try developerDirLocator.suitableEnvironment(forDeveloperDir: developerDir, byUpdatingEnvironment: environment)
environment = try developerDirLocator.suitableEnvironment(
forDeveloperDir: configuration.developerDir,
byUpdatingEnvironment: environment
)
additionalEnvironment.forEach {
environment[$0.key] = $0.value
}

return TestContext(
contextId: contextId,
developerDir: developerDir,
developerDir: configuration.developerDir,
environment: environment,
simulatorPath: simulator.path,
simulatorUdid: simulator.udid,
testDestination: simulator.testDestination,
simulatorPath: configuration.simulator.path,
simulatorUdid: configuration.simulator.udid,
testDestination: configuration.simulator.testDestination,
testRunnerWorkingDirectory: testRunnerWorkingDirectory,
testsWorkingDirectory: testsWorkingDirectory
)
Expand Down
13 changes: 13 additions & 0 deletions Sources/RunnerModels/RunnerConfiguration.swift
Original file line number Diff line number Diff line change
@@ -1,25 +1,38 @@
import BuildArtifacts
import DeveloperDirModels
import Foundation
import PluginSupport
import SimulatorPoolModels

public struct RunnerConfiguration {
public let buildArtifacts: BuildArtifacts
public let developerDir: DeveloperDir
public let environment: [String: String]
public let lostTestProcessingMode: LostTestProcessingMode
public let persistentMetricsJobId: String?
public let pluginLocations: Set<PluginLocation>
public let simulator: Simulator
public let simulatorSettings: SimulatorSettings
public let testTimeoutConfiguration: TestTimeoutConfiguration

public init(
buildArtifacts: BuildArtifacts,
developerDir: DeveloperDir,
environment: [String: String],
lostTestProcessingMode: LostTestProcessingMode,
persistentMetricsJobId: String?,
pluginLocations: Set<PluginLocation>,
simulator: Simulator,
simulatorSettings: SimulatorSettings,
testTimeoutConfiguration: TestTimeoutConfiguration
) {
self.buildArtifacts = buildArtifacts
self.developerDir = developerDir
self.environment = environment
self.lostTestProcessingMode = lostTestProcessingMode
self.persistentMetricsJobId = persistentMetricsJobId
self.pluginLocations = pluginLocations
self.simulator = simulator
self.simulatorSettings = simulatorSettings
self.testTimeoutConfiguration = testTimeoutConfiguration
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/ScheduleStrategy/Support/BucketGeneratorImpl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ public class BucketGeneratorImpl: BucketGenerator {
return Bucket.newBucket(
bucketId: BucketId(value: uniqueIdentifierGenerator.generate()),
analyticsConfiguration: entry.analyticsConfiguration,
pluginLocations: entry.pluginLocations,
workerCapabilityRequirements: entry.workerCapabilityRequirements,
payload: Payload(
buildArtifacts: entry.buildArtifacts,
developerDir: entry.developerDir,
pluginLocations: entry.pluginLocations,
simulatorOperationTimeouts: entry.simulatorOperationTimeouts,
simulatorSettings: entry.simulatorSettings,
testDestination: entry.testDestination,
Expand Down
25 changes: 13 additions & 12 deletions Sources/Scheduler/Scheduler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -218,18 +218,10 @@ public final class Scheduler {
)

let runner = Runner(
configuration: RunnerConfiguration(
buildArtifacts: bucket.payload.buildArtifacts,
environment: bucket.payload.testExecutionBehavior.environment,
pluginLocations: bucket.pluginLocations,
simulatorSettings: bucket.payload.simulatorSettings,
testTimeoutConfiguration: bucket.payload.testTimeoutConfiguration
),
dateProvider: try di.get(),
developerDirLocator: try di.get(),
fileSystem: try di.get(),
logger: logger,
persistentMetricsJobId: bucket.analyticsConfiguration.persistentMetricsJobId,
pluginEventBusProvider: try di.get(),
runnerWasteCollectorProvider: try di.get(),
specificMetricRecorder: specificMetricRecorder,
Expand All @@ -240,10 +232,19 @@ public final class Scheduler {
waiter: try di.get()
)

let runnerResult = try runner.run(
entries: testsToRun,
developerDir: bucket.payload.developerDir,
simulator: allocatedSimulator.simulator
let runnerResult = try runner.runOnce(
entriesToRun: testsToRun,
configuration: RunnerConfiguration(
buildArtifacts: bucket.payload.buildArtifacts,
developerDir: bucket.payload.developerDir,
environment: bucket.payload.testExecutionBehavior.environment,
lostTestProcessingMode: .reportError,
persistentMetricsJobId: bucket.analyticsConfiguration.persistentMetricsJobId,
pluginLocations: bucket.payload.pluginLocations,
simulator: allocatedSimulator.simulator,
simulatorSettings: bucket.payload.simulatorSettings,
testTimeoutConfiguration: bucket.payload.testTimeoutConfiguration
)
)

runnerResult.testEntryResults.filter { $0.isLost }.forEach {
Expand Down
Loading

0 comments on commit 9c6a7ff

Please sign in to comment.