Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issue when multiple threads accessing the registeredCalls dictionary #20

Open
vigdora opened this issue Sep 14, 2023 · 11 comments
Open
Labels
discussion Let's talk about important things

Comments

@vigdora
Copy link

vigdora commented Sep 14, 2023

when multiple threads are trying to access mock.registeredCalls it crashes.
any suggestion to a thread safe solution?

@vigdora vigdora changed the title multiple threads accessing the registeredCalls dictionary issue when multiple threads accessing the registeredCalls dictionary Sep 14, 2023
@danielsaidi danielsaidi added the discussion Let's talk about important things label Sep 17, 2023
@danielsaidi
Copy link
Owner

Hi @vigdora

I haven't run into this, do you use multithreading in your tests?

@vigdora
Copy link
Author

vigdora commented Sep 17, 2023

Hi @danielsaidi
when I run tests using XCTestCase, I see that multiple threads are running.
upon executing the next lines inside registerCall, it crashes:

let calls = mock.registeredCalls[ref.id] ?? [] 
mock.registeredCalls[ref.id] = calls + [call]

when I wrapped this code with serialQueue, it stopped crashing:

serialQueue.sync {
          let calls = mock.registeredCalls[ref.id] ?? []
          mock.registeredCalls[ref.id] = calls + [call]
      }

do you run unitests on one thread only?
tbh, I am not sure how to force XCTestCase to run only on one thread,
and even so, I suspect it might impact Performance.

@danielsaidi
Copy link
Owner

I usually don't change the default Xcode test setup, and assumed that running tests in parallel would still use isolated processes. So if you see this crash in the default setup, some form of thread safety is probably needed.

@vigdora
Copy link
Author

vigdora commented Sep 17, 2023

@danielsaidi thanks for the quick reply.
it doesn"t happen when running tests in parallel. it actually happen upon running singular test suite. (with multiple tests inside it)
for example:

func fetchData() async throws {
   async let dataX = try await oneRepo.fetchX()
   async let dataY = await oneRepo.fetchY()
       
        let _: [Any] = try await [dataX, dataY ]
}

now lets assume oneRepo is mocked,
upon running the test, I have noticed the fetchX, and fetchY are running on different threads -
thats where the crash happening.
ofcourse I have simplified the code for the sake of example (:

@danielsaidi
Copy link
Owner

Thank you, that's great information 👍

Async functions run on different threads, so that is most definitely the problem. Perhaps it would be worth making the mock a main actor?

@vigdora
Copy link
Author

vigdora commented Sep 17, 2023

yee I think thats a possible solution ( I will make sure it works in the meantime...)
but do you think it worth achieving an allistic solution, such that developers wont need to worry about it when they create a mock?
it took me some time to investigate (;
but anyWay, @mainactor might work here, as you suggested
and regardless, your package is really nice solution over all

@danielsaidi
Copy link
Owner

I most definitively want to add such a solution within the library itself, so devs don't have to do anything.

I only wish I can find a way to reproduce the problem.

@vigdora
Copy link
Author

vigdora commented Sep 18, 2023

@danielsaidi
so I tried adding @mainactor on the mocked class and indeed the mocked methods now run only on the main thread.
but it didn't solve the issue, since inside async registerCall function I still see multiple thread running. (probably calling to call function is changing the thread as well)
you can try to reproduce the issue by creating something similar to the example I showed before,
and than run the test repeatedly around 100-200 times.
if it still won't reproduce I will create a branch for you with the issue later this week - let me know

@danielsaidi
Copy link
Owner

@vigdora

Thank you for continuing to look at this! I am unfortunately very busy with a few other projects, so I will not have time to look at this problem right now.

If you find a way to solve it, I'd be happy to merge it and release a new version. 👍

@tboogh
Copy link
Contributor

tboogh commented Jun 20, 2024

We had similar issues with this so in our fork we use a semaphore to guard the access, it's not the most elegant solution but as a triage it works. https://github.com/BookBeat/MockingKit/tree/thread-safe

@danielsaidi
Copy link
Owner

@vigdora and @tboogh I haven't looked into this in a while, since I haven't used the library for some time. I enabled strict concurrency without getting any warnings whatsoever, which was a bit surprising to me, given that we may have this threading issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion Let's talk about important things
Projects
None yet
Development

No branches or pull requests

3 participants