Testing Thread Safety With Activator C# - c#

I am working on a little project at home trying to improve my coding skills. I am currently working on building a factory. I was telling some co-workers about the way it was implemented and they had informed me that it could have issues with threading and deadlocks. I created a unit test, but I am unsure if this is valid or would even catch the issue. Here is my setup.
public class InventoryFactory : BaseFactory, IInventoryFactory
{
public IInventoryEngine Create(InventoryFactoryConfiguration configuration)
{
IInventoryRepository repository = BuildInventoryRepository(configuration.RepositoryConfiguration);
IInventoryService service = BuildInventoryService(configuration.ServiceConfiguration);
IInventoryEngine engine = BuildInventoryEngine(configuration.EngineConfiguration, repository, service);
return engine;
}
private IInventoryRepository BuildInventoryRepository(FactoryConfigurationModel configuration)
{
IInventoryRepository repository =
base.CreateInstance<IInventoryRepository>(configuration.AssemblyFile, configuration.FullyQualifiedClassName);
return repository;
}
private IInventoryService BuildInventoryService(FactoryConfigurationModel configuration)
{
IInventoryService service =
base.CreateInstance<IInventoryService>(configuration.AssemblyFile, configuration.FullyQualifiedClassName);
return service;
}
private IInventoryEngine BuildInventoryEngine(FactoryConfigurationModel configuration, IInventoryRepository repository, IInventoryService service)
{
IInventoryEngine engine =
base.CreateInstance<IInventoryEngine>(configuration.AssemblyFile, configuration.FullyQualifiedClassName, repository, service);
return engine;
}
}
public class BaseFactory
{
protected T CreateInstance<T>(string assemblyFile, string fullyQualifiedClassName, params object[] arguments)
{
Assembly assembly = Assembly.LoadFrom(assemblyFile);
Type classType = assembly.GetType(fullyQualifiedClassName);
T instance = (T)Activator.CreateInstance(classType, arguments);
return instance;
}
}
This is my current unit test to try seeing if any issues would occur.
[TestMethod]
public void InventoryFactoryThreadTest()
{
Task task1 = Task.Factory.StartNew(() =>
{
FactoryConfigurationModel repositoryConfiguration = new FactoryConfigurationModel("foo", "bar");
FactoryConfigurationModel serviceConfiguration = new FactoryConfigurationModel("foo", "bar");
FactoryConfigurationModel engineConfiguration = new FactoryConfigurationModel("foo", "bar");
InventoryFactoryConfiguration factoryConfiguration = new InventoryFactoryConfiguration(repositoryConfiguration, serviceConfiguration, engineConfiguration);
InventoryFactory factory = new InventoryFactory();
try
{
for (int i = 0; i < 150000; i++)
{
IInventoryEngine engine = factory.Create(factoryConfiguration);
}
}
catch (System.Exception ex)
{
Assert.Fail(ex.StackTrace);
}
});
Task task2 = Task.Factory.StartNew(() =>
{
FactoryConfigurationModel repositoryConfiguration = new FactoryConfigurationModel("foo", "bar");
FactoryConfigurationModel serviceConfiguration = new FactoryConfigurationModel("foo", "bar");
FactoryConfigurationModel engineConfiguration = new FactoryConfigurationModel("foo", "bar");
InventoryFactoryConfiguration factoryConfiguration = new InventoryFactoryConfiguration(repositoryConfiguration, serviceConfiguration, engineConfiguration);
InventoryFactory factory = new InventoryFactory();
try
{
for (int i = 0; i < 150000; i++)
{
IInventoryEngine engine = factory.Create(factoryConfiguration);
}
}
catch (System.Exception ex)
{
Assert.Fail(ex.StackTrace);
}
});
Task task3 = Task.Factory.StartNew(() =>
{
FactoryConfigurationModel repositoryConfiguration = new FactoryConfigurationModel("foo", "bar");
FactoryConfigurationModel serviceConfiguration = new FactoryConfigurationModel("foo", "bar");
FactoryConfigurationModel engineConfiguration = new FactoryConfigurationModel("foo", "bar");
InventoryFactoryConfiguration factoryConfiguration = new InventoryFactoryConfiguration(repositoryConfiguration, serviceConfiguration, engineConfiguration);
InventoryFactory factory = new InventoryFactory();
try
{
for (int i = 0; i < 150000; i++)
{
IInventoryEngine engine = factory.Create(factoryConfiguration);
}
}
catch (System.Exception ex)
{
Assert.Fail(ex.StackTrace);
}
});
Task.WaitAll(task1, task2, task3);
}
From what I understand, the potential threading issue would be with the Activator.CreateInstance() method. My questions are: Is this a valid test to be able to see if threading is not safe. If this is not, could you tell me why?
Thank you ahead of time!

Calling Activator.CreateInstance is effectively the same as calling new Something(). Unless there's something in the class's constructor doing something really odd that affects some shared state, thread safety and deadlocks won't be a concern.
Inventing wheels is fun, but I recommend looking at some that have already been invented. Windsor, Autofac, and other Ioc/DI containers are really good at creating object instances, including scanning specified assemblies for interface implementations. You can specify whether you want it to create a new class instance each time or return the same instance over and over. You don't have to call constructors, which makes it easier to create classes with lots of complex nested dependencies. That in turn frees you up to write smaller, more testable classes without having to worry about how you'll construct them. It's awesome. If you're at the point where you see a need to create factories like this then it's probably time to look at IoC containers.
Also, there's a problem with testing to see if something is thread safe. Multithreading issues are unpredictable so it's hard to rule them out with tests. If something isn't thread safe it could pass all sorts of tests but blow up in another environment. That's not to say that the testing is bad. It's just never 100% conclusive.

I don't see the threading issue since you are creating and returning new individual instances of type T. May want to see if Assembly.LoadFrom is thread safe.
To be safe:
public class BaseFactory
{
private static object _monitor = new object();
protected T CreateInstance<T>(string assemblyFile, string fullyQualifiedClassName, params object[] arguments)
{
lock(_monitor)
{
Assembly assembly = Assembly.LoadFrom(assemblyFile);
Type classType = assembly.GetType(fullyQualifiedClassName);
T instance = (T)Activator.CreateInstance(classType, arguments);
return instance;
}
}
}

Related

Load and concurrency tests for WCF service

Since this morning, I have to load/stress test a WCF service and concurrency access (within an app console to be simple), but the WCF service is totally opaque to me. I can't edit it or view the source code.
What I've tried so far :
So, in the Main() program, I am calling a method to initialize some services :
private static void Init()
{
_serviceCommunicationMock = Mock.Of<ITrackingCommunicationService>();
Mock.Get(_serviceCommunicationMock).Setup(x => x.GetIdentityCardAsync(It.IsAny<string>())).ReturnsAsync(() =>
{
new TrackingWcfCommunicationOptions
{
EndPointAddress = "http://172.16.0.2/IIT/[COMPANY].Tracking/TrackingService"
};
string jsonContent = System.IO.File.ReadAllText(GetRandomFile());
return jsonContent.Parse();
});
_serviceValidationMock = Mock.Of<IIdentityCardValidation>();
Mock.Get(_serviceValidationMock).Setup(x => x.VerifyProductIdentityCard(It.IsAny<IdentityCard>())).Returns(
new [COMPANY].Tracking.Core.Business.Model.ResultValidation()
{
IsValid = true,
ErrorMessages = new List<string>()
});
_trackingManager = new TrackingManager(_serviceCommunicationMock, _serviceValidationMock);
}
After this, I'm calling an other method to try to stress tests my WCF as following :
private async static void DoSomething()
{
var taskList = new List<Task<IdentityCard>>();
for (int iterator = 0; iterator < 1; iterator++)
{
async Task<IdentityCard> func()
{
var response = await _trackingManager.GetIdentityCardAsync("Vhdn3UpJsDp6ue6LQWy5gZ");
return response;
}
taskList.Add(func());
}
await Task.WhenAll(taskList);
foreach (var task in taskList)
{
Console.WriteLine(task.Result);
}
}
But the problem is in the Init() method, it already returns a random file but I excepted to call the _trackingManager.GetIdentityCardAsync([GUID]). But it simple impossible as I'm a beginner in Moq AND in WCF.
Could someone help me ?

Multiple contexts in a Singleton service

Currently i'm designing a logger service to log HttpRequests made by HttpClient.
This logger service is Singleton and i want to have scoped contexts inside it.
Here's my logger:
public Logger
{
public LogContext Context { get; set; }
public void LogRequest(HttpRequestLog log)
{
context.AddLog(log);
}
}
I'm using the logger inside a DelegatingHandler:
private readonly Logger logger;
public LoggingDelegatingHandler(Logger logger)
{
this.logger = logger;
}
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
await base.SendAsync(request, cancellationToken);
this.logger.LogRequest(new HttpRequestog());
}
Then when i make some request using HttpClient, i want to have the logs for this specific call:
private void InvokeApi()
{
var logContext = new LogContext();
this.Logger.LogContext = logContext;
var httpClient = httpClientFactory.CreateClient(CustomClientName);
await httpClient.GetAsync($"http://localhost:11111");
var httpRequestLogs = logContext.Logs;
}
The problem is, it works but it's not thread safe. If i have parallel executions of InvokeApi, the context will not be the correct.
How can i have a attached context for each execution properly?
I'm registering the HttpClient like this:
services.AddSingleton<Logger>();
services.AddHttpClient(CentaurusHttpClient)
.ConfigurePrimaryHttpMessageHandler((c) => new HttpClientHandler()
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
})
.AddHttpMessageHandler(sp => new LoggingDelegatingHandler(sp.GetRequiredService<Logger>()));
I'm testing this piece of code using this:
public void Test_Parallel_Logging()
{
Random random = new Random();
Action test = async () =>
{
await RunScopedAsync(async scope =>
{
IServiceProvider sp = scope.ServiceProvider;
var httpClientFactory = sp.GetRequiredService<IHttpClientFactory>();
using (var context = new HttpRequestContext(sp.GetRequiredService<Logger>()))
{
try
{
var httpClient = httpClientFactory.CreateClient();
await httpClient.GetAsync($"http://localhost:{random.Next(11111, 55555)}");
}
catch (HttpRequestException ex)
{
Output.WriteLine("count: " + context?.Logs?.Count);
}
}
});
};
Parallel.Invoke(new Action[] { test, test, test });
}
This logger service is Singleton and i want to have scoped contexts inside it.
The Logger has a singleton lifetime, so its LogContext property also has a singleton lifetime.
For the kind of scoped data you're wanting, AsyncLocal<T> is an appropriate solution. I tend to prefer following a "provider"/"consumer" pattern similar to React's Context, although the more common name in the .NET world for "consumer" is "accessor". In this case, you could make the Logger itself into the provider, though I generally try to keep it a separate type.
IMO this is most cleanly done by providing your own explicit scope, and not tying into the "scope" lifetime of your DI container. It's possible to do it with DI container scopes but you end up with some weird code like resolving producers and then doing nothing with them - and if a future maintainer removes (what appears to be) unused injected types, then the accessors break.
So I recommend your own scope, as such:
public Logger
{
private readonly AsyncLocal<LogContext> _context = new();
public void LogRequest(HttpRequestLog log)
{
var context = _context.Value;
if (context == null)
throw new InvalidOperationException("LogRequest was called without anyone calling SetContext");
context.AddLog(log);
}
public IDisposable SetContext(LogContext context)
{
var oldValue = _context.Value;
_context.Value = context;
// I use Nito.Disposables; replace with whatever Action-Disposable type you have.
return new Disposable(() => _context.Value = oldValue);
}
}
Usage (note the explicit scoping provided by using):
private void InvokeApi()
{
var logContext = new LogContext();
using (this.Logger.SetContext(logContext))
{
var httpClient = httpClientFactory.CreateClient(CustomClientName);
await httpClient.GetAsync($"http://localhost:11111");
var httpRequestLogs = logContext.Logs;
}
}

Sharing a thread-safe field between instances of a Transient service in C# / NETC core?

I need to share some locks (aka "object" fields) and regular data fields between functions called from a Transient service in .NET Core.
Naturally, these locks and fields should be declared in a thread-safe manner.
What would be the best way to approach it? I am thinking of a separate Singleton service. Do I have to add some keywords to the fields and locks declared so these are thread-safe?
I am well familiar with Java multithreading but never done it so far in C#.
This is the most simple example I can think of. It uses lock. You can also use Monitor. Basically I resolve a transient service 3 times. And then start a couple of threads which will increase the value of a shared service.
class Program
{
static async Task Main(string[] args)
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<ValueService>();
serviceCollection.AddTransient<Service>();
var provider = serviceCollection.BuildServiceProvider();
var serviceOne = provider.GetRequiredService<Service>();
var serviceTwo = provider.GetRequiredService<Service>();
var serviceThree = provider.GetRequiredService<Service>();
// Manipulate the same object 1500 times, from different threads.
var task1 = serviceOne.DoStuff(500);
var task2 = serviceTwo.DoStuff(500);
var task3 = serviceThree.DoStuff(500);
// Wait for all the threads to complete.
await Task.WhenAll(task1, task2, task3);
// Verify the result.
var valueService = provider.GetRequiredService<ValueService>();
Console.WriteLine(valueService.SomeValue);
Console.ReadKey();
}
}
internal class Service
{
private readonly ValueService _service;
public Service(ValueService service)
{
_service = service;
}
public Task DoStuff(int noOfTimes)
{
var tasks = new Task[noOfTimes];
for (int i = 0; i < noOfTimes; i++)
{
tasks[i] = Task.Run(() =>
{
Thread.Sleep(100);
_service.Increase();
});
}
return Task.WhenAll(tasks);
}
}
internal class ValueService
{
public void Increase()
{
// Use lock to make sure that only one thread is changing the field at the time.
// Remove the lock statement and you will notice some "unwanted" behaviour.
lock (_lock)
{
SomeValue++;
}
// Alternatively you can use Interlocked.Increment(SomeValue)
}
private readonly object _lock = new object();
public int SomeValue { get; private set; }
}

Unit test that legacy code reacts to ThreadAbortException in a certain way

I've got an existing bit of legacy code that I want to get under test. Here's a repro of the essentials:
public class LegacyUnit
{
private readonly ICollaborator collaborator;
public LegacyUnit(ICollaborator collaborator)
{
this.collaborator = collaborator;
}
public object GetStuff(HttpContextBase context, string input)
{
try
{
if (input == "")
{
context.Response.End();
}
collaborator.DoOtherStuff();
return "Done!";
}
catch (ThreadAbortException)
{ }
return null;
}
}
Now, this legacy unit has some issues, but for now I'm just trying to get it under test. Specifically, I want to test that collaborator.DoOtherStuff is not called if Response.End() raised a ThreadAbort.
The problem: how do you raise such an exception?
I've read through this question and its answers on ThreadAbortException, and understand that it's special. However, I don't see from those posts how to handle this in unit tests.
Here's my attempt:
[Test]
public void DoesNotCallCollaboratorOnThreadAbort()
{
var testResponseMock = new Mock<HttpResponseBase>();
var testContextMock = new Mock<HttpContextBase>();
var collaboratorMock = new Mock<ICollaborator>();
testContextMock.Setup(x => x.Response).Returns(testResponseMock.Object);
testResponseMock.Setup(x => x.End()).Throws<ThreadAbortException>(); // Compile error
var unit = new LegacyUnit(collaboratorMock.Object);
unit.GetStuff(testContextMock.Object, "");
collaboratorMock.Verify(c => c.DoOtherStuff(), Times.Never);
}
Obviously the compiler complains: ThreadAbortException has no available constructor. Also, it's sealed (probably for good reasons), so creating a "testable" sub-class won't work.
What is the proper way to get such code under test? Is it even feasible, or is the LegacyUnit just too test-unfriendly?
Full, minimal repro (empty .NET 4.5 class library with NUnit 2.6.4 and Moq 4.5.9):
public interface ICollaborator
{
void DoOtherStuff();
}
public class LegacyUnit
{
private readonly ICollaborator collaborator;
public LegacyUnit(ICollaborator collaborator)
{
this.collaborator = collaborator;
}
public object GetStuff(HttpContextBase context, string input)
{
try
{
if (input == "") context.Response.End();
collaborator.DoOtherStuff();
return "Done!";
}
catch (ThreadAbortException)
{ }
return null;
}
}
[TestFixture]
public class LegacyUnitTests
{
[Test]
public void DoesNotCallCollaboratorOnThreadAbort()
{
var testResponseMock = new Mock<HttpResponseBase>();
var testContextMock = new Mock<HttpContextBase>();
var collaboratorMock = new Mock<ICollaborator>();
testContextMock.Setup(x => x.Response).Returns(testResponseMock.Object);
testResponseMock.Setup(x => x.End()).Throws<ThreadAbortException>(); // Compile error here
var unit = new LegacyUnit(collaboratorMock.Object);
unit.GetStuff(testContextMock.Object, "");
collaboratorMock.Verify(c => c.DoOtherStuff(), Times.Never);
}
}
ThreadAbortException is raised in the target thread by calling Abort on it. You can create a thread to run the test and call Abort in your mock of testResponseMock.End e.g.
testContextMock.Setup(x => x.Response).Returns(testResponseMock.Object);
var unit = new LegacyUnit(collaboratorMock.Object);
var thread = new Thread(() => unit.GetStuff(testContextMock.Object, ""));
testResponseMock.Setup(x => x.End()).Callback(() => { Thread.CurrentThread.Abort(); });
thread.Start();
thread.Join();
collaboratorMock.Verify(c => c.DoOtherStuff(), Times.Never);

Are these Singleton Unit Tests actually working as expected?

I have a bootstrapper object that I'm trying to test (using xunit). The tests appear to pass, but I'm seeing some weird things in one of the test runners I use (ncrunch). I use both ncrunch and the resharper xunit runner. My idea was to take the assembly that the singleton is in, load it into a new appdomain, run my tests using reflection, then unload the app domain. As I said, the tests pass in both ncrunch and resharper, but ncrunch is not showing the execution paths that I expect. Here's the code:
public class Bootstrapper
{
private static Bootstrapper booted;
public Bootstrapper()
{
// performs boot tasks
}
public static void Boot()
{
if (booted == null)
{
var staticboot = new Bootstrapper();
Booted = staticboot;
}
}
public static Bootstrapper Booted
{
get
{
if (booted == null) throw new InvalidOperationException("Should call Boot() before accessing the booted object");
return booted;
}
set { booted = value; }
}
}
public class Tests
{
[Fact]
public void TryingToAccessBootedKernelBeforeBootThrowsException()
{
var setup = this.SetupTestingDomainWithAssembly("StackOverflowQuestion.Tests.dll");
var kernelType = setup.Item2.GetType("StackOverflowQuestion.Tests.Bootstrapper");
var bootedkernelProperty = kernelType.GetProperty("Booted");
try
{
bootedkernelProperty.GetValue(null);
}
catch (Exception e)
{
Assert.IsType(typeof(InvalidOperationException), e.InnerException);
}
AppDomain.Unload(setup.Item1);
}
[Fact]
public void CanAccessKernelAfterBooting()
{
var setup = this.SetupTestingDomainWithAssembly("StackOverflowQuestion.Tests.dll");
var kernelType = setup.Item2.GetType("StackOverflowQuestion.Tests.Bootstrapper");
var bootMethod = kernelType.GetMethod("Boot");
bootMethod.Invoke(null, new object[] { });
var bootedkernelProperty = kernelType.GetProperty("Booted");
Assert.DoesNotThrow(() => bootedkernelProperty.GetValue(null));
AppDomain.Unload(setup.Item1);
}
[Fact]
public void BootIsIdempotent()
{
var setup = this.SetupTestingDomainWithAssembly("StackOverflowQuestion.Tests.dll");
var kernelType = setup.Item2.GetType("StackOverflowQuestion.Tests.Bootstrapper");
var bootMethod = kernelType.GetMethod("Boot");
bootMethod.Invoke(null, new object[] {});
var bootedkernelProperty = kernelType.GetProperty("Booted");
var bootedKernel = (Bootstrapper)bootedkernelProperty.GetValue(null);
bootMethod.Invoke(null, new object[] {});
var secondCall = (Bootstrapper)bootedkernelProperty.GetValue(null);
Assert.Equal(bootedKernel, secondCall);
AppDomain.Unload(setup.Item1);
}
private Tuple<AppDomain, Assembly> SetupTestingDomainWithAssembly(string assemblyPath)
{
// we guarantee that each domain will have a unique name.
AppDomain testingDomain = AppDomain.CreateDomain(DateTime.Now.Ticks.ToString());
var pancakesAssemblyName = new AssemblyName();
pancakesAssemblyName.CodeBase = assemblyPath;
var assembly = testingDomain.Load(pancakesAssemblyName);
return new Tuple<AppDomain, Assembly>(testingDomain, assembly);
}
}
Now, I recognize that there is some cleanup that needs to happen code-wise, but I was happy to see them all green. If I fiddle with them to make them fail, that works as expected. The only thing that's kind of smelly is that ncrunch is reporting weird execution paths. Specifically, ncrunch is showing that the line that throws the invalid operation exception is never executed.
I suppose it's possible that ncrunch has a bug when dealing with other application domains, but it's more likely that I don't actually understand what's going on with the app domains, but I'm not sure where to continue from here.
Also, I do know that singletons are bad, but I believe bootstrappers are one place where they actually are useful. You want to guarantee that they are only booted once.
Unless I'm missing something here.. it doesn't look like you are actually invoking anything in your other app domain. Your reflection is occurring in the current app domain. Take a look at the DoCallback method: http://msdn.microsoft.com/en-us/library/system.appdomain.docallback.aspx
public class Tests
{
[Fact]
public void TryingToAccessBootedKernelBeforeBootThrowsException()
{
var appDomain = AppDomain.Create(Guid.NewGuid());
try
{
appDomain.DoCallBack(new CrossAppDomainDelegate(TryingToAccessBootedKernelBeforeBootThrowsException_AppDomainCallback));
}
catch (Exception e)
{
Assert.IsType(typeof(InvalidOperationException), e.InnerException);
}
AppDomain.Unload(appDomain);
}
public static void TryingToAccessBootedKernelBeforeBootThrowsException_AppDomainCallback()
{
var bootstrapper = BootStrapper.Booted;
}
}

Categories