You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is the generated mock for the example code above:
class APIClientMock: APIClient {
init() { }
private(set) var fetchDataCallCount = 0
var fetchDataArgValues = [AnyObject]()
var fetchDataHandler: ((AnyObject) async -> (Int))?
func fetchData(_ id: AnyObject) async -> Int {
fetchDataCallCount += 1
fetchDataArgValues.append(id)
if let fetchDataHandler = fetchDataHandler {
return await fetchDataHandler(id)
}
return 0
}
}
What did you expect to happen?
The mock should be thread safe, or at least there should be a way to generate the mock in a thread safe manor.
Some possibilities:
Isolate the mocked function to an actor, e.g. MainActor. That way the mock's logic always runs on the same thread.
Isolate the history properties to an actor.
Isolate the entire class to an actor.
Use an actor instead of a class.
What happened instead?
The mock is not thread safe.
If you run the following code, the mock will crash with an EXC_BAD_ACCESS error on the fetchDataArgValues.append(id) line above.
let mockAPI = APIClientMock()
await withTaskGroup(of: Int.self, body: { taskGroup in
for _ in 0..<1_000 {
taskGroup.addTask {
await mockAPI.fetchData(NSObject())
}
}
await taskGroup.waitForAll()
})
This is because the fetchData function and fetchDataArgValues property are not actor isolated, and since the fetchData function is async it can be run on any thread.
When multiple threads simultaneously try to read/write fetchDataArgValues this is unsafe, and the resultant EXC_BAD_ACCESS is caused by this.
Mockolo Environment
Mockolo Version: 2.0.1 Dependency Manager: mint Xcode Version: 15.0 Swift Version: Swift 5.9 (5.9.0.128.108)
The text was updated successfully, but these errors were encountered:
stuaustin
changed the title
Async functions are unsafe in generated mocks, and can crash if used from multiple threads simulatenously
Async functions are unsafe in generated mocks, and can crash if used from multiple threads simultaneously
Nov 28, 2023
What did you do?
Created a mock for a protocol with an async function, e.g.
This is the generated mock for the example code above:
What did you expect to happen?
The mock should be thread safe, or at least there should be a way to generate the mock in a thread safe manor.
Some possibilities:
What happened instead?
The mock is not thread safe.
If you run the following code, the mock will crash with an EXC_BAD_ACCESS error on the
fetchDataArgValues.append(id)
line above.This is because the
fetchData
function andfetchDataArgValues
property are not actor isolated, and since thefetchData
function is async it can be run on any thread.When multiple threads simultaneously try to read/write
fetchDataArgValues
this is unsafe, and the resultant EXC_BAD_ACCESS is caused by this.Mockolo Environment
Mockolo Version: 2.0.1
Dependency Manager: mint
Xcode Version: 15.0
Swift Version: Swift 5.9 (5.9.0.128.108)
The text was updated successfully, but these errors were encountered: