Replace RxSwift for Async queue (#4026)
* Remove RxSwift from CacheBundleBuilder, CacheFrameworkBuilder, CacheXCFrameworkBuilder and RxBlocking from project * Remove unneeded import * Apply AsyncParsableCommand to LintCodeCommand * Replace RxSwift for AsyncQueue * refactor: remove function * fix: compilation error Co-authored-by: Daniele Formichelli <df@bendingspoons.com>
This commit is contained in:
parent
0540a660cc
commit
d06735adcb
|
@ -35,16 +35,16 @@ public struct TuistAnalyticsDispatcher: AsyncQueueDispatching {
|
||||||
|
|
||||||
public var identifier = TuistAnalyticsDispatcher.dispatcherId
|
public var identifier = TuistAnalyticsDispatcher.dispatcherId
|
||||||
|
|
||||||
public func dispatch(event: AsyncQueueEvent, completion: @escaping () -> Void) throws {
|
public func dispatch(event: AsyncQueueEvent, completion: @escaping () throws -> Void) throws {
|
||||||
guard let commandEvent = event as? CommandEvent else { return }
|
guard let commandEvent = event as? CommandEvent else { return }
|
||||||
|
|
||||||
Task.detached {
|
Task.detached {
|
||||||
_ = try await backends.concurrentMap { try? await $0.send(commandEvent: commandEvent) }
|
_ = try await backends.concurrentMap { try? await $0.send(commandEvent: commandEvent) }
|
||||||
completion()
|
try completion()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func dispatchPersisted(data: Data, completion: @escaping () -> Void) throws {
|
public func dispatchPersisted(data: Data, completion: @escaping () throws -> Void) throws {
|
||||||
let decoder = JSONDecoder()
|
let decoder = JSONDecoder()
|
||||||
let commandEvent = try decoder.decode(CommandEvent.self, from: data)
|
let commandEvent = try decoder.decode(CommandEvent.self, from: data)
|
||||||
return try dispatch(event: commandEvent, completion: completion)
|
return try dispatch(event: commandEvent, completion: completion)
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import Queuer
|
import Queuer
|
||||||
import RxSwift
|
|
||||||
import TuistCore
|
import TuistCore
|
||||||
import TuistSupport
|
import TuistSupport
|
||||||
|
|
||||||
|
@ -8,18 +7,16 @@ public protocol AsyncQueuing {
|
||||||
/// It dispatches the given event.
|
/// It dispatches the given event.
|
||||||
/// - Parameter event: Event to be dispatched.
|
/// - Parameter event: Event to be dispatched.
|
||||||
/// - Parameter didPersistEvent: It's called when the event has been persisted, to make sure it can't get lost
|
/// - Parameter didPersistEvent: It's called when the event has been persisted, to make sure it can't get lost
|
||||||
func dispatch<T: AsyncQueueEvent>(event: T, didPersistEvent: @escaping () -> Void)
|
func dispatch<T: AsyncQueueEvent>(event: T) throws
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AsyncQueue: AsyncQueuing {
|
public class AsyncQueue: AsyncQueuing {
|
||||||
// MARK: - Attributes
|
// MARK: - Attributes
|
||||||
|
|
||||||
private let disposeBag = DisposeBag()
|
|
||||||
private let queue: Queuing
|
private let queue: Queuing
|
||||||
private let ciChecker: CIChecking
|
private let ciChecker: CIChecking
|
||||||
private let persistor: AsyncQueuePersisting
|
private let persistor: AsyncQueuePersisting
|
||||||
private var dispatchers: [String: AsyncQueueDispatching] = [:]
|
private var dispatchers: [String: AsyncQueueDispatching] = [:]
|
||||||
private let persistedEventsSchedulerType: SchedulerType
|
|
||||||
|
|
||||||
public static let sharedInstance = AsyncQueue()
|
public static let sharedInstance = AsyncQueue()
|
||||||
|
|
||||||
|
@ -27,13 +24,11 @@ public class AsyncQueue: AsyncQueuing {
|
||||||
|
|
||||||
init(queue: Queuing = Queuer.shared,
|
init(queue: Queuing = Queuer.shared,
|
||||||
ciChecker: CIChecking = CIChecker(),
|
ciChecker: CIChecking = CIChecker(),
|
||||||
persistor: AsyncQueuePersisting = AsyncQueuePersistor(),
|
persistor: AsyncQueuePersisting = AsyncQueuePersistor())
|
||||||
persistedEventsSchedulerType: SchedulerType = AsyncQueue.schedulerType())
|
|
||||||
{
|
{
|
||||||
self.queue = queue
|
self.queue = queue
|
||||||
self.ciChecker = ciChecker
|
self.ciChecker = ciChecker
|
||||||
self.persistor = persistor
|
self.persistor = persistor
|
||||||
self.persistedEventsSchedulerType = persistedEventsSchedulerType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func register(dispatcher: AsyncQueueDispatching) {
|
public func register(dispatcher: AsyncQueueDispatching) {
|
||||||
|
@ -47,7 +42,7 @@ public class AsyncQueue: AsyncQueuing {
|
||||||
queue.resume()
|
queue.resume()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func dispatch<T: AsyncQueueEvent>(event: T, didPersistEvent: @escaping () -> Void) {
|
public func dispatch<T: AsyncQueueEvent>(event: T) throws {
|
||||||
guard let dispatcher = dispatchers[event.dispatcherId] else {
|
guard let dispatcher = dispatchers[event.dispatcherId] else {
|
||||||
logger.error("Couldn't find dispatcher with id: \(event.dispatcherId)")
|
logger.error("Couldn't find dispatcher with id: \(event.dispatcherId)")
|
||||||
return
|
return
|
||||||
|
@ -56,17 +51,9 @@ public class AsyncQueue: AsyncQueuing {
|
||||||
// We persist the event in case the dispatching is halted because Tuist's
|
// We persist the event in case the dispatching is halted because Tuist's
|
||||||
// process exits. In that case we want to retry again the next time there's
|
// process exits. In that case we want to retry again the next time there's
|
||||||
// opportunity for that.
|
// opportunity for that.
|
||||||
let writeCompletable = persistor.write(event: event)
|
try persistor.write(event: event)
|
||||||
_ = writeCompletable.subscribe { _ in
|
let operation = liveDispatchOperation(event: event, dispatcher: dispatcher)
|
||||||
// Queue event to send
|
queue.addOperation(operation)
|
||||||
let operation = self.liveDispatchOperation(event: event, dispatcher: dispatcher)
|
|
||||||
self.queue.addOperation(operation)
|
|
||||||
didPersistEvent()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func schedulerType() -> SchedulerType {
|
|
||||||
SerialDispatchQueueScheduler(queue: dispatchQueue(), internalSerialQueueName: "tuist-async-queue")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
@ -76,7 +63,7 @@ public class AsyncQueue: AsyncQueuing {
|
||||||
logger.debug("Dispatching event with ID '\(event.id.uuidString)' to '\(dispatcher.identifier)'")
|
logger.debug("Dispatching event with ID '\(event.id.uuidString)' to '\(dispatcher.identifier)'")
|
||||||
do {
|
do {
|
||||||
try dispatcher.dispatch(event: event) {
|
try dispatcher.dispatch(event: event) {
|
||||||
_ = self.persistor.delete(event: event)
|
try self.persistor.delete(event: event)
|
||||||
operation.success = true
|
operation.success = true
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
@ -85,9 +72,9 @@ public class AsyncQueue: AsyncQueuing {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func dispatchPersisted(eventTuple: AsyncQueueEventTuple) {
|
private func dispatchPersisted(eventTuple: AsyncQueueEventTuple) throws {
|
||||||
guard let dispatcher = dispatchers.first(where: { $0.key == eventTuple.dispatcherId })?.value else {
|
guard let dispatcher = dispatchers.first(where: { $0.key == eventTuple.dispatcherId })?.value else {
|
||||||
deletePersistedEvent(filename: eventTuple.filename)
|
try deletePersistedEvent(filename: eventTuple.filename)
|
||||||
logger.error("Couldn't find dispatcher for persisted event with id: \(eventTuple.dispatcherId)")
|
logger.error("Couldn't find dispatcher for persisted event with id: \(eventTuple.dispatcherId)")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -103,7 +90,7 @@ public class AsyncQueue: AsyncQueuing {
|
||||||
do {
|
do {
|
||||||
logger.debug("Dispatching persisted event with ID '\(event.id.uuidString)' to '\(dispatcher.identifier)'")
|
logger.debug("Dispatching persisted event with ID '\(event.id.uuidString)' to '\(dispatcher.identifier)'")
|
||||||
try dispatcher.dispatchPersisted(data: event.data) {
|
try dispatcher.dispatchPersisted(data: event.data) {
|
||||||
self.deletePersistedEvent(filename: event.filename)
|
try self.deletePersistedEvent(filename: event.filename)
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
logger.debug("Failed to dispatch persisted event with ID '\(event.id.uuidString)' to '\(dispatcher.identifier)'")
|
logger.debug("Failed to dispatch persisted event with ID '\(event.id.uuidString)' to '\(dispatcher.identifier)'")
|
||||||
|
@ -117,24 +104,17 @@ public class AsyncQueue: AsyncQueuing {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func loadEvents() {
|
private func loadEvents() {
|
||||||
persistor
|
do {
|
||||||
.readAll()
|
let events = try persistor.readAll()
|
||||||
.subscribe(on: persistedEventsSchedulerType)
|
for event in events {
|
||||||
.subscribe(onSuccess: { events in
|
try dispatchPersisted(eventTuple: event)
|
||||||
events.forEach(self.dispatchPersisted)
|
}
|
||||||
}, onFailure: { error in
|
} catch {
|
||||||
logger.debug("Error loading persisted events: \(error)")
|
logger.debug("Error loading persisted events: \(error)")
|
||||||
})
|
}
|
||||||
.disposed(by: disposeBag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func deletePersistedEvent(filename: String) {
|
private func deletePersistedEvent(filename: String) throws {
|
||||||
persistor.delete(filename: filename).subscribe().disposed(by: disposeBag)
|
try persistor.delete(filename: filename)
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: Private & Static
|
|
||||||
|
|
||||||
private static func dispatchQueue() -> DispatchQueue {
|
|
||||||
DispatchQueue(label: "io.tuist.async-queue", qos: .background)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import RxSwift
|
|
||||||
import TSCBasic
|
import TSCBasic
|
||||||
import TuistCore
|
import TuistCore
|
||||||
import TuistSupport
|
import TuistSupport
|
||||||
|
@ -8,19 +7,19 @@ public typealias AsyncQueueEventTuple = (dispatcherId: String, id: UUID, date: D
|
||||||
|
|
||||||
public protocol AsyncQueuePersisting {
|
public protocol AsyncQueuePersisting {
|
||||||
/// Reads all the persisted events and returns them.
|
/// Reads all the persisted events and returns them.
|
||||||
func readAll() -> Single<[AsyncQueueEventTuple]>
|
func readAll() throws -> [AsyncQueueEventTuple]
|
||||||
|
|
||||||
/// Persiss a given event.
|
/// Persiss a given event.
|
||||||
/// - Parameter event: Event to be persisted.
|
/// - Parameter event: Event to be persisted.
|
||||||
func write<T: AsyncQueueEvent>(event: T) -> Completable
|
func write<T: AsyncQueueEvent>(event: T) throws
|
||||||
|
|
||||||
/// Deletes the given event from disk.
|
/// Deletes the given event from disk.
|
||||||
/// - Parameter event: Event to be deleted.
|
/// - Parameter event: Event to be deleted.
|
||||||
func delete<T: AsyncQueueEvent>(event: T) -> Completable
|
func delete<T: AsyncQueueEvent>(event: T) throws
|
||||||
|
|
||||||
/// Deletes the given file name from disk.
|
/// Deletes the given file name from disk.
|
||||||
/// - Parameter filename: Name of the file to be deleted.
|
/// - Parameter filename: Name of the file to be deleted.
|
||||||
func delete(filename: String) -> Completable
|
func delete(filename: String) throws
|
||||||
}
|
}
|
||||||
|
|
||||||
final class AsyncQueuePersistor: AsyncQueuePersisting {
|
final class AsyncQueuePersistor: AsyncQueuePersisting {
|
||||||
|
@ -35,72 +34,53 @@ final class AsyncQueuePersistor: AsyncQueuePersisting {
|
||||||
self.directory = directory
|
self.directory = directory
|
||||||
}
|
}
|
||||||
|
|
||||||
func write<T: AsyncQueueEvent>(event: T) -> Completable {
|
func write<T: AsyncQueueEvent>(event: T) throws {
|
||||||
Completable.create { observer -> Disposable in
|
let path = directory.appending(component: filename(event: event))
|
||||||
let path = self.directory.appending(component: self.filename(event: event))
|
try createDirectoryIfNeeded()
|
||||||
|
let data = try jsonEncoder.encode(event)
|
||||||
|
try data.write(to: path.url)
|
||||||
|
}
|
||||||
|
|
||||||
|
func delete<T: AsyncQueueEvent>(event: T) throws {
|
||||||
|
try delete(filename: filename(event: event))
|
||||||
|
}
|
||||||
|
|
||||||
|
func delete(filename: String) throws {
|
||||||
|
let path = directory.appending(component: filename)
|
||||||
|
guard FileHandler.shared.exists(path) else { return }
|
||||||
|
try FileHandler.shared.delete(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func readAll() throws -> [AsyncQueueEventTuple] {
|
||||||
|
let paths = FileHandler.shared.glob(directory, glob: "*.json")
|
||||||
|
var events: [AsyncQueueEventTuple] = []
|
||||||
|
paths.forEach { eventPath in
|
||||||
|
let fileName = eventPath.basenameWithoutExt
|
||||||
|
let components = fileName.split(separator: ".")
|
||||||
|
guard components.count == 3,
|
||||||
|
let timestamp = Double(components[0]),
|
||||||
|
let id = UUID(uuidString: String(components[2]))
|
||||||
|
else {
|
||||||
|
/// Changing the naming convention is a breaking change. When detected
|
||||||
|
/// we delete the event.
|
||||||
|
try? FileHandler.shared.delete(eventPath)
|
||||||
|
return
|
||||||
|
}
|
||||||
do {
|
do {
|
||||||
try self.createDirectoryIfNeeded()
|
let data = try Data(contentsOf: eventPath.url)
|
||||||
let data = try self.jsonEncoder.encode(event)
|
let event = (
|
||||||
try data.write(to: path.url)
|
dispatcherId: String(components[1]),
|
||||||
observer(.completed)
|
id: id,
|
||||||
|
date: Date(timeIntervalSince1970: timestamp),
|
||||||
|
data: data,
|
||||||
|
filename: eventPath.basename
|
||||||
|
)
|
||||||
|
events.append(event)
|
||||||
} catch {
|
} catch {
|
||||||
observer(.error(error))
|
try? FileHandler.shared.delete(eventPath)
|
||||||
}
|
}
|
||||||
return Disposables.create()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func delete<T: AsyncQueueEvent>(event: T) -> Completable {
|
|
||||||
delete(filename: filename(event: event))
|
|
||||||
}
|
|
||||||
|
|
||||||
func delete(filename: String) -> Completable {
|
|
||||||
Completable.create { observer -> Disposable in
|
|
||||||
let path = self.directory.appending(component: filename)
|
|
||||||
guard FileHandler.shared.exists(path) else { return Disposables.create() }
|
|
||||||
do {
|
|
||||||
try FileHandler.shared.delete(path)
|
|
||||||
observer(.completed)
|
|
||||||
} catch {
|
|
||||||
observer(.error(error))
|
|
||||||
}
|
|
||||||
return Disposables.create()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func readAll() -> Single<[AsyncQueueEventTuple]> {
|
|
||||||
Single.create { observer -> Disposable in
|
|
||||||
let paths = FileHandler.shared.glob(self.directory, glob: "*.json")
|
|
||||||
var events: [AsyncQueueEventTuple] = []
|
|
||||||
paths.forEach { eventPath in
|
|
||||||
let fileName = eventPath.basenameWithoutExt
|
|
||||||
let components = fileName.split(separator: ".")
|
|
||||||
guard components.count == 3,
|
|
||||||
let timestamp = Double(components[0]),
|
|
||||||
let id = UUID(uuidString: String(components[2]))
|
|
||||||
else {
|
|
||||||
/// Changing the naming convention is a breaking change. When detected
|
|
||||||
/// we delete the event.
|
|
||||||
try? FileHandler.shared.delete(eventPath)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
let data = try Data(contentsOf: eventPath.url)
|
|
||||||
let event = (
|
|
||||||
dispatcherId: String(components[1]),
|
|
||||||
id: id,
|
|
||||||
date: Date(timeIntervalSince1970: timestamp),
|
|
||||||
data: data,
|
|
||||||
filename: eventPath.basename
|
|
||||||
)
|
|
||||||
events.append(event)
|
|
||||||
} catch {
|
|
||||||
try? FileHandler.shared.delete(eventPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
observer(.success(events))
|
|
||||||
return Disposables.create()
|
|
||||||
}
|
}
|
||||||
|
return events
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
|
@ -26,7 +26,7 @@ public class MockAsyncQueueDispatcher: AsyncQueueDispatching {
|
||||||
public var invokedDispatchParametersEventsList = [AsyncQueueEvent]()
|
public var invokedDispatchParametersEventsList = [AsyncQueueEvent]()
|
||||||
public var stubbedDispatchError: Error?
|
public var stubbedDispatchError: Error?
|
||||||
|
|
||||||
public func dispatch(event: AsyncQueueEvent, completion: @escaping () -> Void) throws {
|
public func dispatch(event: AsyncQueueEvent, completion: @escaping () throws -> Void) throws {
|
||||||
invokedDispatch = true
|
invokedDispatch = true
|
||||||
invokedDispatchCount += 1
|
invokedDispatchCount += 1
|
||||||
invokedDispatchParameterEvent = event
|
invokedDispatchParameterEvent = event
|
||||||
|
@ -36,7 +36,7 @@ public class MockAsyncQueueDispatcher: AsyncQueueDispatching {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
invokedDispatchCallBack()
|
invokedDispatchCallBack()
|
||||||
completion()
|
try completion()
|
||||||
}
|
}
|
||||||
|
|
||||||
public var invokedDispatchPersisted = false
|
public var invokedDispatchPersisted = false
|
||||||
|
@ -46,7 +46,7 @@ public class MockAsyncQueueDispatcher: AsyncQueueDispatching {
|
||||||
public var invokedDispatchPersistedParametersDataList = [Data]()
|
public var invokedDispatchPersistedParametersDataList = [Data]()
|
||||||
public var stubbedDispatchPersistedError: Error?
|
public var stubbedDispatchPersistedError: Error?
|
||||||
|
|
||||||
public func dispatchPersisted(data: Data, completion: @escaping () -> Void) throws {
|
public func dispatchPersisted(data: Data, completion: @escaping () throws -> Void) throws {
|
||||||
invokedDispatchPersisted = true
|
invokedDispatchPersisted = true
|
||||||
invokedDispatchPersistedCount += 1
|
invokedDispatchPersistedCount += 1
|
||||||
invokedDispatchPersistedDataParameter = data
|
invokedDispatchPersistedDataParameter = data
|
||||||
|
@ -56,6 +56,6 @@ public class MockAsyncQueueDispatcher: AsyncQueueDispatching {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
invokedDispatchPersistedCallBack()
|
invokedDispatchPersistedCallBack()
|
||||||
completion()
|
try completion()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import RxSwift
|
|
||||||
import TuistAsyncQueue
|
import TuistAsyncQueue
|
||||||
import TuistCore
|
import TuistCore
|
||||||
|
|
||||||
|
@ -8,9 +7,9 @@ public final class MockAsyncQueuePersistor<U: AsyncQueueEvent>: AsyncQueuePersis
|
||||||
|
|
||||||
public var invokedReadAll = false
|
public var invokedReadAll = false
|
||||||
public var invokedReadAllCount = 0
|
public var invokedReadAllCount = 0
|
||||||
public var stubbedReadAllResult: Single<[AsyncQueueEventTuple]> = Single.just([])
|
public var stubbedReadAllResult: [AsyncQueueEventTuple] = []
|
||||||
|
|
||||||
public func readAll() -> Single<[AsyncQueueEventTuple]> {
|
public func readAll() -> [AsyncQueueEventTuple] {
|
||||||
invokedReadAll = true
|
invokedReadAll = true
|
||||||
invokedReadAllCount += 1
|
invokedReadAllCount += 1
|
||||||
return stubbedReadAllResult
|
return stubbedReadAllResult
|
||||||
|
@ -20,45 +19,39 @@ public final class MockAsyncQueuePersistor<U: AsyncQueueEvent>: AsyncQueuePersis
|
||||||
public var invokedWriteCount = 0
|
public var invokedWriteCount = 0
|
||||||
public var invokedWriteEvent: U?
|
public var invokedWriteEvent: U?
|
||||||
public var invokedWriteEvents = [U]()
|
public var invokedWriteEvents = [U]()
|
||||||
public var stubbedWriteResult: Completable = .empty()
|
|
||||||
|
|
||||||
public func write<T: AsyncQueueEvent>(event: T) -> Completable {
|
public func write<T: AsyncQueueEvent>(event: T) {
|
||||||
invokedWrite = true
|
invokedWrite = true
|
||||||
invokedWriteCount += 1
|
invokedWriteCount += 1
|
||||||
if let event = event as? U {
|
if let event = event as? U {
|
||||||
invokedWriteEvent = event
|
invokedWriteEvent = event
|
||||||
invokedWriteEvents.append(event)
|
invokedWriteEvents.append(event)
|
||||||
}
|
}
|
||||||
return stubbedWriteResult
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public var invokedDeleteEventCount = 0
|
public var invokedDeleteEventCount = 0
|
||||||
public var invokedDeleteCallBack: () -> Void = {}
|
public var invokedDeleteCallBack: () -> Void = {}
|
||||||
public var invokedDeleteEvent: U?
|
public var invokedDeleteEvent: U?
|
||||||
public var invokedDeleteEvents = [U]()
|
public var invokedDeleteEvents = [U]()
|
||||||
public var stubbedDeleteEventResult: Completable = .empty()
|
|
||||||
|
|
||||||
public func delete<T: AsyncQueueEvent>(event: T) -> Completable {
|
public func delete<T: AsyncQueueEvent>(event: T) {
|
||||||
invokedDeleteEventCount += 1
|
invokedDeleteEventCount += 1
|
||||||
if let event = event as? U {
|
if let event = event as? U {
|
||||||
invokedDeleteEvent = event
|
invokedDeleteEvent = event
|
||||||
invokedDeleteEvents.append(event)
|
invokedDeleteEvents.append(event)
|
||||||
}
|
}
|
||||||
invokedDeleteCallBack()
|
invokedDeleteCallBack()
|
||||||
return stubbedDeleteEventResult
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public var invokedDeleteFilename = false
|
public var invokedDeleteFilename = false
|
||||||
public var invokedDeleteFilenameCount = 0
|
public var invokedDeleteFilenameCount = 0
|
||||||
public var invokedDeleteFilenameParameter: String?
|
public var invokedDeleteFilenameParameter: String?
|
||||||
public var invokedDeleteFilenameParametersList = [String]()
|
public var invokedDeleteFilenameParametersList = [String]()
|
||||||
public var stubbedDeleteFilenameResult: Completable = .empty()
|
|
||||||
|
|
||||||
public func delete(filename: String) -> Completable {
|
public func delete(filename: String) {
|
||||||
invokedDeleteFilename = true
|
invokedDeleteFilename = true
|
||||||
invokedDeleteFilenameCount += 1
|
invokedDeleteFilenameCount += 1
|
||||||
invokedDeleteFilenameParameter = filename
|
invokedDeleteFilenameParameter = filename
|
||||||
invokedDeleteFilenameParametersList.append(filename)
|
invokedDeleteFilenameParametersList.append(filename)
|
||||||
return stubbedDeleteFilenameResult
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,10 @@ public class MockAsyncQueuer: AsyncQueuing {
|
||||||
public var invokedDispatchParameters: (event: Any, Void)?
|
public var invokedDispatchParameters: (event: Any, Void)?
|
||||||
public var invokedDispatchParametersList = [(event: Any, Void)]()
|
public var invokedDispatchParametersList = [(event: Any, Void)]()
|
||||||
|
|
||||||
public func dispatch<T: AsyncQueueEvent>(event: T, didPersistEvent: @escaping () -> Void) {
|
public func dispatch<T: AsyncQueueEvent>(event: T) throws {
|
||||||
invokedDispatch = true
|
invokedDispatch = true
|
||||||
invokedDispatchCount += 1
|
invokedDispatchCount += 1
|
||||||
invokedDispatchParameters = (event, ())
|
invokedDispatchParameters = (event, ())
|
||||||
invokedDispatchParametersList.append((event, ()))
|
invokedDispatchParametersList.append((event, ()))
|
||||||
didPersistEvent()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,8 @@ public final class CacheXCFrameworkBuilder: CacheArtifactBuilding {
|
||||||
}
|
}
|
||||||
frameworkpaths.append(self.frameworkPath(fromArchivePath: deviceArchivePath, productName: productName))
|
frameworkpaths.append(self.frameworkPath(fromArchivePath: deviceArchivePath, productName: productName))
|
||||||
let xcframeworkPath = outputDirectory.appending(component: "\(productName).xcframework")
|
let xcframeworkPath = outputDirectory.appending(component: "\(productName).xcframework")
|
||||||
try await self.buildXCFramework(frameworks: frameworkpaths, output: xcframeworkPath)
|
try await self.xcodeBuildController.createXCFramework(frameworks: frameworkpaths, output: xcframeworkPath)
|
||||||
|
.printFormattedOutput()
|
||||||
|
|
||||||
try FileHandler.shared.move(
|
try FileHandler.shared.move(
|
||||||
from: xcframeworkPath,
|
from: xcframeworkPath,
|
||||||
|
@ -85,10 +86,6 @@ public final class CacheXCFrameworkBuilder: CacheArtifactBuilding {
|
||||||
|
|
||||||
// MARK: - Fileprivate
|
// MARK: - Fileprivate
|
||||||
|
|
||||||
fileprivate func buildXCFramework(frameworks: [AbsolutePath], output: AbsolutePath) async throws {
|
|
||||||
try await xcodeBuildController.createXCFramework(frameworks: frameworks, output: output).printFormattedOutput()
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate func deviceBuild(projectTarget: XcodeBuildTarget,
|
fileprivate func deviceBuild(projectTarget: XcodeBuildTarget,
|
||||||
scheme: String,
|
scheme: String,
|
||||||
platform: Platform,
|
platform: Platform,
|
||||||
|
|
|
@ -7,9 +7,9 @@ public protocol AsyncQueueDispatching {
|
||||||
|
|
||||||
/// Dispatches a given event.
|
/// Dispatches a given event.
|
||||||
/// - Parameter event: Event to be dispatched.
|
/// - Parameter event: Event to be dispatched.
|
||||||
func dispatch(event: AsyncQueueEvent, completion: @escaping () -> Void) throws
|
func dispatch(event: AsyncQueueEvent, completion: @escaping () throws -> Void) throws
|
||||||
|
|
||||||
/// Dispatch a persisted event.
|
/// Dispatch a persisted event.
|
||||||
/// - Parameter data: Serialized data of the event.
|
/// - Parameter data: Serialized data of the event.
|
||||||
func dispatchPersisted(data: Data, completion: @escaping () -> Void) throws
|
func dispatchPersisted(data: Data, completion: @escaping () throws -> Void) throws
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
import Combine
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
/// `TuistProcess` is a wrapper on top of the cli command to provide
|
|
||||||
/// an asynchronous way to exit the process, which waits for all `futureTask`
|
|
||||||
/// to be completed, with a maximum threshold of time of `maximumWaitingTime` seconds
|
|
||||||
final class TuistProcess {
|
|
||||||
static let shared = TuistProcess()
|
|
||||||
|
|
||||||
private var futureTasks: [Future<Void, Never>] = []
|
|
||||||
private let maximumWaitingTime = DispatchTimeInterval.seconds(2)
|
|
||||||
|
|
||||||
private init() {}
|
|
||||||
|
|
||||||
/// `add` a task that needs to complete before tuist process ends.
|
|
||||||
/// Note that tasks will only have `maximumWaitingTime` seconds to complete
|
|
||||||
/// after tuist is ready to exit, otherwise they will be canceled
|
|
||||||
func add(futureTask: Future<Void, Never>) {
|
|
||||||
futureTasks.append(futureTask)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `asyncExit` will make sure that all important async tasks
|
|
||||||
/// complete before it `exit`s the process
|
|
||||||
func asyncExit(_ code: Int32 = 0) -> Never {
|
|
||||||
let dispatchGroup = DispatchGroup()
|
|
||||||
dispatchGroup.enter()
|
|
||||||
let cancellable = Publishers.MergeMany(futureTasks).collect().sink { _ in
|
|
||||||
dispatchGroup.leave()
|
|
||||||
}
|
|
||||||
// Set `maximumWaitingTime` seconds as a parachute timeout in case something
|
|
||||||
// goes wrong and events don't cmoplete: we don't want tuist's
|
|
||||||
// process to hang forever
|
|
||||||
_ = dispatchGroup.wait(timeout: DispatchTime.now() + maximumWaitingTime)
|
|
||||||
cancellable.cancel()
|
|
||||||
exit(code)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,4 @@
|
||||||
import ArgumentParser
|
import ArgumentParser
|
||||||
import Combine
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import TuistAsyncQueue
|
import TuistAsyncQueue
|
||||||
import TuistSupport
|
import TuistSupport
|
||||||
|
@ -32,7 +31,7 @@ public class TrackableCommand: TrackableParametersDelegate {
|
||||||
self.asyncQueue = asyncQueue
|
self.asyncQueue = asyncQueue
|
||||||
}
|
}
|
||||||
|
|
||||||
func run() async throws -> Future<Void, Never> {
|
func run() async throws {
|
||||||
let timer = clock.startTimer()
|
let timer = clock.startTimer()
|
||||||
if let command = command as? HasTrackableParameters {
|
if let command = command as? HasTrackableParameters {
|
||||||
type(of: command).analyticsDelegate = self
|
type(of: command).analyticsDelegate = self
|
||||||
|
@ -53,11 +52,7 @@ public class TrackableCommand: TrackableParametersDelegate {
|
||||||
durationInMs: durationInMs
|
durationInMs: durationInMs
|
||||||
)
|
)
|
||||||
let commandEvent = commandEventFactory.make(from: info)
|
let commandEvent = commandEventFactory.make(from: info)
|
||||||
return Future { promise in
|
try asyncQueue.dispatch(event: commandEvent)
|
||||||
self.asyncQueue.dispatch(event: commandEvent) {
|
|
||||||
promise(.success(()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func willRun(withParameters parameters: [String: String]) {
|
func willRun(withParameters parameters: [String: String]) {
|
||||||
|
|
|
@ -66,7 +66,6 @@ public struct TuistCommand: ParsableCommand {
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
try await execute(command)
|
try await execute(command)
|
||||||
TuistProcess.shared.asyncExit()
|
|
||||||
} catch let error as FatalError {
|
} catch let error as FatalError {
|
||||||
errorHandler.fatal(error: error)
|
errorHandler.fatal(error: error)
|
||||||
_exit(exitCode(for: error).rawValue)
|
_exit(exitCode(for: error).rawValue)
|
||||||
|
@ -85,8 +84,7 @@ public struct TuistCommand: ParsableCommand {
|
||||||
var command = command
|
var command = command
|
||||||
if Environment.shared.isStatsEnabled {
|
if Environment.shared.isStatsEnabled {
|
||||||
let trackableCommand = TrackableCommand(command: command)
|
let trackableCommand = TrackableCommand(command: command)
|
||||||
let future = try await trackableCommand.run()
|
try await trackableCommand.run()
|
||||||
TuistProcess.shared.add(futureTask: future)
|
|
||||||
} else {
|
} else {
|
||||||
if var asyncCommand = command as? AsyncParsableCommand {
|
if var asyncCommand = command as? AsyncParsableCommand {
|
||||||
try await asyncCommand.runAsync()
|
try await asyncCommand.runAsync()
|
||||||
|
|
|
@ -24,7 +24,10 @@ enum TuistApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
try TuistSupport.Environment.shared.bootstrap()
|
try TuistSupport.Environment.shared.bootstrap()
|
||||||
try TuistAnalytics.bootstrap(config: ConfigLoader().loadConfig(path: path))
|
|
||||||
|
Task.detached(priority: .background) {
|
||||||
|
try TuistAnalytics.bootstrap(config: ConfigLoader().loadConfig(path: path))
|
||||||
|
}
|
||||||
|
|
||||||
await TuistCommand.main()
|
await TuistCommand.main()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import RxSwift
|
|
||||||
import TSCBasic
|
import TSCBasic
|
||||||
import TuistCore
|
import TuistCore
|
||||||
import TuistSupport
|
import TuistSupport
|
||||||
|
@ -22,15 +21,15 @@ final class AsyncQueuePersistorTests: TuistUnitTestCase {
|
||||||
super.tearDown()
|
super.tearDown()
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_write() async throws {
|
func test_write() throws {
|
||||||
// Given
|
// Given
|
||||||
let event = AnyAsyncQueueEvent(dispatcherId: "dispatcher")
|
let event = AnyAsyncQueueEvent(dispatcherId: "dispatcher")
|
||||||
|
|
||||||
// When
|
// When
|
||||||
_ = try await subject.write(event: event).value
|
try subject.write(event: event)
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
let got = try await subject.readAll().value
|
let got = try subject.readAll()
|
||||||
let gotEvent = try XCTUnwrap(got.first)
|
let gotEvent = try XCTUnwrap(got.first)
|
||||||
XCTAssertEqual(gotEvent.dispatcherId, "dispatcher")
|
XCTAssertEqual(gotEvent.dispatcherId, "dispatcher")
|
||||||
XCTAssertEqual(gotEvent.id, event.id)
|
XCTAssertEqual(gotEvent.id, event.id)
|
||||||
|
@ -38,7 +37,7 @@ final class AsyncQueuePersistorTests: TuistUnitTestCase {
|
||||||
XCTAssertEqual(gotEvent.date, normalizedDate)
|
XCTAssertEqual(gotEvent.date, normalizedDate)
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_write_whenDirectoryDoesntExist_itCreatesDirectory() async throws {
|
func test_write_whenDirectoryDoesntExist_itCreatesDirectory() throws {
|
||||||
let temporaryDirectory = try! temporaryPath()
|
let temporaryDirectory = try! temporaryPath()
|
||||||
subject = AsyncQueuePersistor(directory: temporaryDirectory.appending(RelativePath("test/")))
|
subject = AsyncQueuePersistor(directory: temporaryDirectory.appending(RelativePath("test/")))
|
||||||
|
|
||||||
|
@ -46,10 +45,10 @@ final class AsyncQueuePersistorTests: TuistUnitTestCase {
|
||||||
let event = AnyAsyncQueueEvent(dispatcherId: "dispatcher")
|
let event = AnyAsyncQueueEvent(dispatcherId: "dispatcher")
|
||||||
|
|
||||||
// When
|
// When
|
||||||
_ = try await subject.write(event: event).value
|
try subject.write(event: event)
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
let got = try await subject.readAll().value
|
let got = try subject.readAll()
|
||||||
let gotEvent = try XCTUnwrap(got.first)
|
let gotEvent = try XCTUnwrap(got.first)
|
||||||
XCTAssertEqual(gotEvent.dispatcherId, "dispatcher")
|
XCTAssertEqual(gotEvent.dispatcherId, "dispatcher")
|
||||||
XCTAssertEqual(gotEvent.id, event.id)
|
XCTAssertEqual(gotEvent.id, event.id)
|
||||||
|
@ -57,18 +56,18 @@ final class AsyncQueuePersistorTests: TuistUnitTestCase {
|
||||||
XCTAssertEqual(gotEvent.date, normalizedDate)
|
XCTAssertEqual(gotEvent.date, normalizedDate)
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_delete() async throws {
|
func test_delete() throws {
|
||||||
// Given
|
// Given
|
||||||
let event = AnyAsyncQueueEvent(dispatcherId: "dispatcher")
|
let event = AnyAsyncQueueEvent(dispatcherId: "dispatcher")
|
||||||
_ = try await subject.write(event: event).value
|
try subject.write(event: event)
|
||||||
var persistedEvents = try await subject.readAll().value
|
var persistedEvents = try subject.readAll()
|
||||||
XCTAssertEqual(persistedEvents.count, 1)
|
XCTAssertEqual(persistedEvents.count, 1)
|
||||||
|
|
||||||
// When
|
// When
|
||||||
_ = try await subject.delete(event: event).value
|
try subject.delete(event: event)
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
persistedEvents = try await subject.readAll().value
|
persistedEvents = try subject.readAll()
|
||||||
XCTAssertEqual(persistedEvents.count, 0)
|
XCTAssertEqual(persistedEvents.count, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import Queuer
|
import Queuer
|
||||||
import RxSwift
|
|
||||||
import TuistCore
|
import TuistCore
|
||||||
import TuistSupport
|
import TuistSupport
|
||||||
import XCTest
|
import XCTest
|
||||||
|
@ -57,8 +56,7 @@ final class AsyncQueueTests: TuistUnitTestCase {
|
||||||
let asyncQueue = AsyncQueue(
|
let asyncQueue = AsyncQueue(
|
||||||
queue: queue ?? mockQueuer,
|
queue: queue ?? mockQueuer,
|
||||||
ciChecker: ciChecker ?? mockCIChecker,
|
ciChecker: ciChecker ?? mockCIChecker,
|
||||||
persistor: persistor ?? mockPersistor,
|
persistor: persistor ?? mockPersistor
|
||||||
persistedEventsSchedulerType: MainScheduler()
|
|
||||||
)
|
)
|
||||||
asyncQueue.register(dispatcher: mockAsyncQueueDispatcher1)
|
asyncQueue.register(dispatcher: mockAsyncQueueDispatcher1)
|
||||||
asyncQueue.register(dispatcher: mockAsyncQueueDispatcher2)
|
asyncQueue.register(dispatcher: mockAsyncQueueDispatcher2)
|
||||||
|
@ -66,42 +64,34 @@ final class AsyncQueueTests: TuistUnitTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_dispatch_eventIsPersisted() throws {
|
func test_dispatch_eventIsPersisted() throws {
|
||||||
var didComplete = false
|
|
||||||
// Given
|
// Given
|
||||||
let event = AnyAsyncQueueEvent(dispatcherId: dispatcher1ID)
|
let event = AnyAsyncQueueEvent(dispatcherId: dispatcher1ID)
|
||||||
subject = makeSubject()
|
subject = makeSubject()
|
||||||
|
|
||||||
// When
|
// When
|
||||||
subject.dispatch(event: event) {
|
try subject.dispatch(event: event)
|
||||||
// Then
|
|
||||||
guard let persistedEvent = self.mockPersistor.invokedWriteEvent else {
|
// Then
|
||||||
XCTFail("Event not passed to the persistor")
|
guard let persistedEvent = mockPersistor.invokedWriteEvent else {
|
||||||
return
|
XCTFail("Event not passed to the persistor")
|
||||||
}
|
return
|
||||||
XCTAssertEqual(event.id, persistedEvent.id)
|
|
||||||
didComplete = true
|
|
||||||
}
|
}
|
||||||
XCTAssertTrue(didComplete)
|
XCTAssertEqual(event.id, persistedEvent.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_dispatch_eventIsQueued() throws {
|
func test_dispatch_eventIsQueued() throws {
|
||||||
var didComplete = false
|
|
||||||
|
|
||||||
// Given
|
// Given
|
||||||
let event = AnyAsyncQueueEvent(dispatcherId: dispatcher1ID)
|
let event = AnyAsyncQueueEvent(dispatcherId: dispatcher1ID)
|
||||||
subject = makeSubject()
|
subject = makeSubject()
|
||||||
|
|
||||||
// When
|
// When
|
||||||
subject.dispatch(event: event) {
|
try subject.dispatch(event: event)
|
||||||
// Then
|
// Then
|
||||||
guard let queuedOperation = self.mockQueuer.invokedAddOperationParameterOperation as? ConcurrentOperation else {
|
guard let queuedOperation = mockQueuer.invokedAddOperationParameterOperation as? ConcurrentOperation else {
|
||||||
XCTFail("Operation not added to the queuer")
|
XCTFail("Operation not added to the queuer")
|
||||||
return
|
return
|
||||||
}
|
|
||||||
XCTAssertEqual(queuedOperation.name, event.id.uuidString)
|
|
||||||
didComplete = true
|
|
||||||
}
|
}
|
||||||
XCTAssertTrue(didComplete)
|
XCTAssertEqual(queuedOperation.name, event.id.uuidString)
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_dispatch_eventIsPersistedOnDispatcherSuccess() throws {
|
func test_dispatch_eventIsPersistedOnDispatcherSuccess() throws {
|
||||||
|
@ -113,30 +103,26 @@ final class AsyncQueueTests: TuistUnitTestCase {
|
||||||
expectation.fulfill()
|
expectation.fulfill()
|
||||||
}
|
}
|
||||||
// When
|
// When
|
||||||
subject.dispatch(event: event) {
|
try subject.dispatch(event: event)
|
||||||
self.wait(for: [expectation], timeout: self.timeout)
|
wait(for: [expectation], timeout: timeout)
|
||||||
guard let deletedEvent = self.mockPersistor.invokedDeleteEvent else {
|
guard let deletedEvent = mockPersistor.invokedDeleteEvent else {
|
||||||
XCTFail("Event was not deleted by the persistor")
|
XCTFail("Event was not deleted by the persistor")
|
||||||
return
|
return
|
||||||
}
|
|
||||||
// Then
|
|
||||||
XCTAssertEqual(event.id, deletedEvent.id)
|
|
||||||
}
|
}
|
||||||
|
// Then
|
||||||
|
XCTAssertEqual(event.id, deletedEvent.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_dispatch_eventIsPersistedOnCompletion() throws {
|
func test_dispatch_eventIsPersistedOnCompletion() throws {
|
||||||
// Given
|
// Given
|
||||||
let event = AnyAsyncQueueEvent(dispatcherId: dispatcher1ID)
|
let event = AnyAsyncQueueEvent(dispatcherId: dispatcher1ID)
|
||||||
subject = makeSubject(queue: Queuer.shared)
|
subject = makeSubject(queue: Queuer.shared)
|
||||||
let expectation = XCTestExpectation(description: #function)
|
|
||||||
|
|
||||||
// When
|
// When
|
||||||
subject.dispatch(event: event) {
|
try subject.dispatch(event: event)
|
||||||
// Then
|
|
||||||
XCTAssertEqual(self.mockPersistor.invokedWriteEvent?.id, event.id)
|
// Then
|
||||||
expectation.fulfill()
|
XCTAssertEqual(mockPersistor.invokedWriteEvent?.id, event.id)
|
||||||
}
|
|
||||||
wait(for: [expectation], timeout: timeout)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_dispatch_eventIsDispatchedByTheRightDispatcher() throws {
|
func test_dispatch_eventIsDispatchedByTheRightDispatcher() throws {
|
||||||
|
@ -148,19 +134,20 @@ final class AsyncQueueTests: TuistUnitTestCase {
|
||||||
expectation.fulfill()
|
expectation.fulfill()
|
||||||
}
|
}
|
||||||
// When
|
// When
|
||||||
subject.dispatch(event: event) {
|
try subject.dispatch(event: event)
|
||||||
self.wait(for: [expectation], timeout: self.timeout)
|
|
||||||
|
|
||||||
guard let dispatchedEvent = self.mockAsyncQueueDispatcher1.invokedDispatchParameterEvent else {
|
// Then
|
||||||
XCTFail("Event was not dispatched")
|
wait(for: [expectation], timeout: timeout)
|
||||||
return
|
|
||||||
}
|
guard let dispatchedEvent = mockAsyncQueueDispatcher1.invokedDispatchParameterEvent else {
|
||||||
// Then
|
XCTFail("Event was not dispatched")
|
||||||
XCTAssertEqual(event.id, dispatchedEvent.id)
|
return
|
||||||
XCTAssertEqual(self.mockAsyncQueueDispatcher1.invokedDispatchCount, 1)
|
|
||||||
XCTAssertEqual(self.mockAsyncQueueDispatcher2.invokedDispatchCount, 0)
|
|
||||||
XCTAssertNil(self.mockAsyncQueueDispatcher2.invokedDispatchParameterEvent)
|
|
||||||
}
|
}
|
||||||
|
// Then
|
||||||
|
XCTAssertEqual(event.id, dispatchedEvent.id)
|
||||||
|
XCTAssertEqual(mockAsyncQueueDispatcher1.invokedDispatchCount, 1)
|
||||||
|
XCTAssertEqual(mockAsyncQueueDispatcher2.invokedDispatchCount, 0)
|
||||||
|
XCTAssertNil(mockAsyncQueueDispatcher2.invokedDispatchParameterEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_dispatch_queuerTriesThreeTimesToDispatch() throws {
|
func test_dispatch_queuerTriesThreeTimesToDispatch() throws {
|
||||||
|
@ -179,11 +166,11 @@ final class AsyncQueueTests: TuistUnitTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
// When
|
// When
|
||||||
subject.dispatch(event: event) {
|
try subject.dispatch(event: event)
|
||||||
self.wait(for: [expectation], timeout: self.timeout)
|
|
||||||
// Then
|
// Then
|
||||||
XCTAssertEqual(count, 3)
|
wait(for: [expectation], timeout: timeout)
|
||||||
}
|
XCTAssertEqual(count, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_dispatch_doesNotDeleteEventOnError() throws {
|
func test_dispatch_doesNotDeleteEventOnError() throws {
|
||||||
|
@ -202,12 +189,12 @@ final class AsyncQueueTests: TuistUnitTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
// When
|
// When
|
||||||
subject.dispatch(event: event) {
|
try subject.dispatch(event: event)
|
||||||
self.wait(for: [expectation], timeout: self.timeout)
|
|
||||||
// Then
|
// Then
|
||||||
XCTAssertEqual(count, 3)
|
wait(for: [expectation], timeout: timeout)
|
||||||
XCTAssertEqual(self.mockPersistor.invokedDeleteEventCount, 0)
|
XCTAssertEqual(count, 3)
|
||||||
}
|
XCTAssertEqual(mockPersistor.invokedDeleteEventCount, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_start_readsPersistedEventsInitialization() throws {
|
func test_start_readsPersistedEventsInitialization() throws {
|
||||||
|
@ -215,7 +202,7 @@ final class AsyncQueueTests: TuistUnitTestCase {
|
||||||
let eventTuple1: AsyncQueueEventTuple = makeEventTuple(id: 1)
|
let eventTuple1: AsyncQueueEventTuple = makeEventTuple(id: 1)
|
||||||
let eventTuple2: AsyncQueueEventTuple = makeEventTuple(id: 2)
|
let eventTuple2: AsyncQueueEventTuple = makeEventTuple(id: 2)
|
||||||
let eventTuple3: AsyncQueueEventTuple = makeEventTuple(id: 3)
|
let eventTuple3: AsyncQueueEventTuple = makeEventTuple(id: 3)
|
||||||
mockPersistor.stubbedReadAllResult = .just([eventTuple1, eventTuple2, eventTuple3])
|
mockPersistor.stubbedReadAllResult = [eventTuple1, eventTuple2, eventTuple3]
|
||||||
|
|
||||||
// When
|
// When
|
||||||
subject = makeSubject()
|
subject = makeSubject()
|
||||||
|
@ -247,7 +234,7 @@ final class AsyncQueueTests: TuistUnitTestCase {
|
||||||
func test_start_persistedEventIsDispatchedByTheRightDispatcher() throws {
|
func test_start_persistedEventIsDispatchedByTheRightDispatcher() throws {
|
||||||
// Given
|
// Given
|
||||||
let eventTuple1: AsyncQueueEventTuple = makeEventTuple(id: 1)
|
let eventTuple1: AsyncQueueEventTuple = makeEventTuple(id: 1)
|
||||||
mockPersistor.stubbedReadAllResult = .just([eventTuple1])
|
mockPersistor.stubbedReadAllResult = [eventTuple1]
|
||||||
|
|
||||||
let expectation = XCTestExpectation(description: #function)
|
let expectation = XCTestExpectation(description: #function)
|
||||||
mockAsyncQueueDispatcher1.invokedDispatchPersistedCallBack = {
|
mockAsyncQueueDispatcher1.invokedDispatchPersistedCallBack = {
|
||||||
|
@ -273,7 +260,7 @@ final class AsyncQueueTests: TuistUnitTestCase {
|
||||||
// Given
|
// Given
|
||||||
let id: UInt = 1
|
let id: UInt = 1
|
||||||
let eventTuple1: AsyncQueueEventTuple = makeEventTuple(id: id)
|
let eventTuple1: AsyncQueueEventTuple = makeEventTuple(id: id)
|
||||||
mockPersistor.stubbedReadAllResult = .just([eventTuple1])
|
mockPersistor.stubbedReadAllResult = [eventTuple1]
|
||||||
|
|
||||||
let expectation = XCTestExpectation(description: #function)
|
let expectation = XCTestExpectation(description: #function)
|
||||||
mockAsyncQueueDispatcher1.invokedDispatchPersistedCallBack = {
|
mockAsyncQueueDispatcher1.invokedDispatchPersistedCallBack = {
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import RxSwift
|
|
||||||
import TSCBasic
|
import TSCBasic
|
||||||
import TuistCore
|
import TuistCore
|
||||||
import TuistSupport
|
import TuistSupport
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import RxSwift
|
|
||||||
import TSCBasic
|
import TSCBasic
|
||||||
import TuistCore
|
import TuistCore
|
||||||
import TuistGraph
|
import TuistGraph
|
||||||
|
|
|
@ -38,39 +38,29 @@ final class TrackableCommandTests: TuistTestCase {
|
||||||
// Given
|
// Given
|
||||||
makeSubject(flag: true)
|
makeSubject(flag: true)
|
||||||
let expectedParams = ["flag": "true"]
|
let expectedParams = ["flag": "true"]
|
||||||
var didPersisteEvent = false
|
|
||||||
|
|
||||||
// When
|
// When
|
||||||
let future = try await subject.run()
|
try await subject.run()
|
||||||
_ = future.sink {
|
|
||||||
didPersisteEvent = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
XCTAssertEqual(mockAsyncQueue.invokedDispatchCount, 1)
|
XCTAssertEqual(mockAsyncQueue.invokedDispatchCount, 1)
|
||||||
let event = try XCTUnwrap(mockAsyncQueue.invokedDispatchParameters?.event as? CommandEvent)
|
let event = try XCTUnwrap(mockAsyncQueue.invokedDispatchParameters?.event as? CommandEvent)
|
||||||
XCTAssertEqual(event.name, "test")
|
XCTAssertEqual(event.name, "test")
|
||||||
XCTAssertEqual(event.params, expectedParams)
|
XCTAssertEqual(event.params, expectedParams)
|
||||||
XCTAssertTrue(didPersisteEvent)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_whenParamsHaveFlagFalse_dispatchesEventWithExpectedParameters() async throws {
|
func test_whenParamsHaveFlagFalse_dispatchesEventWithExpectedParameters() async throws {
|
||||||
// Given
|
// Given
|
||||||
makeSubject(flag: false)
|
makeSubject(flag: false)
|
||||||
let expectedParams = ["flag": "false"]
|
let expectedParams = ["flag": "false"]
|
||||||
var didPersisteEvent = false
|
|
||||||
// When
|
// When
|
||||||
let future = try await subject.run()
|
try await subject.run()
|
||||||
_ = future.sink {
|
|
||||||
didPersisteEvent = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
XCTAssertEqual(mockAsyncQueue.invokedDispatchCount, 1)
|
XCTAssertEqual(mockAsyncQueue.invokedDispatchCount, 1)
|
||||||
let event = try XCTUnwrap(mockAsyncQueue.invokedDispatchParameters?.event as? CommandEvent)
|
let event = try XCTUnwrap(mockAsyncQueue.invokedDispatchParameters?.event as? CommandEvent)
|
||||||
XCTAssertEqual(event.name, "test")
|
XCTAssertEqual(event.name, "test")
|
||||||
XCTAssertEqual(event.params, expectedParams)
|
XCTAssertEqual(event.params, expectedParams)
|
||||||
XCTAssertTrue(didPersisteEvent)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue