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

GetMock<T> is not thread-safe #149

Closed
ian-g-holm-intel opened this issue Jun 16, 2022 · 4 comments · Fixed by #153
Closed

GetMock<T> is not thread-safe #149

ian-g-holm-intel opened this issue Jun 16, 2022 · 4 comments · Fixed by #153

Comments

@ian-g-holm-intel
Copy link

https://github.com/moq/Moq.AutoMocker/blob/master/Moq.AutoMock/AutoMocker.cs

GetMockImplementation is referencing the dictionary TypeMap, which is not a ThreadSafe collection (should be ConcurrentDictionary). This means if you call GetMock in parallel on multiple threads, you can end up with an exception similar to this.

System.InvalidOperationException: Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct.
at System.Collections.Generic.Dictionary2.TryInsert(TKey key, TValue value, InsertionBehavior behavior) at System.Collections.Generic.Dictionary2.set_Item(TKey key, TValue value)
at Moq.AutoMock.AutoMocker.GetMockImplementation(Type serviceType, Boolean enablePrivate)
at Moq.AutoMock.AutoMocker.GetMock(Type serviceType, Boolean enablePrivate)
at Moq.AutoMock.AutoMocker.GetMock(Type serviceType)
at Moq.AutoMock.AutoMocker.GetMockTService

@Keboo
Copy link
Collaborator

Keboo commented Jun 16, 2022

HI @retik
Thanks for the bug report. I would like to understand your use-case where you are accessing the AutoMocker from multiple threads. So far, the AutoMocker class has never included thread safety (the internal Resolvers collection is another example where multiple threads mutating it can be problematic). Can you provide more information on how you are using it?

@ian-g-holm-intel
Copy link
Author

ian-g-holm-intel commented Jun 16, 2022

Ah I see, didn't realize it wasn't thread-safe. We use it for some simulation implementations of classes, not specifically for unit testing. We bootstrap an instance of AutoMocker in our primary container (Microsoft DI) and then register mocks for various low-level interfaces. Then we can access the mocker in our regression test code and setup mocks to simulate the low-level APIs. I think the problem we ran into was due to us registering using something like this:

serviceCollection.AddTransient(sp => mocker.GetMock<TService>().Object);

The problem this caused was that the GetMock<> isn't called until it is first resolved. So if multiple threads resolve at the same time, GetMock<> gets called in parallel. We seem to be able to work around this by changing it to a singleton that instantiates the mock first.

serviceCollection.AddSingleton(mocker.GetMock<TService>().Object);

So I think we're good for now. I was just assuming that AutoMocker was intended to be threadsafe and would benefit from this. If it's a bigger task to make the whole library thread-safe then it's probably not worth fixing just this one thing.

Thanks.

@Keboo
Copy link
Collaborator

Keboo commented Jun 16, 2022

Thanks for the explanation, that is certainly helpful. It is certainly not documented, and I think it is worth considering if we should make it thread-safe or at least document it.

@ian-g-holm-intel
Copy link
Author

I would highly recommend it since AutoMocker is, at least in my mind, treated much in the same way as an IOC container. And being thread-safe is certainly a requirement of other IOC containers, which is why I think I assumed AutoMocker was as well.

Keboo added a commit to Keboo/Moq.AutoMocker that referenced this issue Oct 3, 2022
Keboo added a commit to Keboo/Moq.AutoMocker that referenced this issue Oct 3, 2022
Keboo added a commit to Keboo/Moq.AutoMocker that referenced this issue Oct 3, 2022
@Keboo Keboo closed this as completed in #153 Oct 3, 2022
Keboo added a commit that referenced this issue Oct 3, 2022
* Making the cache dictionary thread safe

Fixes #149

* Adding comment about the thread safety
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants