Brute force concurrency testing
Testing concurrency is hard, just ask anyone who had tried. And tracking down concurrent bugs is even harder.
I just run into concurrency issue with SvnBridge, and I decided that I have better have a smoke test around to prove that there are no obvious concurrency issues with the code.
Since I already have over a hundred integration tests, I thought that this would make a great concurrency test. We know that all the tests are passing. Now let us see if they are all passing together. This is quick & dirty, but it expose at least two bugs so far, one of them the original one that we have seen:
public class ConcurrentActionsTest { [Fact] public void RunAllTestsConcurrentyly() { List<TestData> tests = new List<TestData>(); Type[] types = Assembly.GetExecutingAssembly().GetTypes(); foreach (Type type in types) { if (type.IsAbstract) continue; if (type == typeof(ConcurrentActionsTest)) continue; foreach (MethodInfo info in type.GetMethods()) { object[] attributes = info.GetCustomAttributes(typeof(SvnBridgeFactAttribute), true); if (attributes.Length == 0) continue; tests.Add(new TestData((SvnBridgeFactAttribute)attributes[0], info)); } } List<IAsyncResult> results = new List<IAsyncResult>(); List<Exception> errors = new List<Exception>(); ExecuteTestDelegate exec = ExecuteTest; foreach (TestData test in tests) { foreach (ITestCommand command in test.Fact.CreateTestCommands(test.Method)) { IAsyncResult invoke = exec.BeginInvoke(test, command, errors, null, null); results.Add(invoke); } } foreach (IAsyncResult result in results) { result.AsyncWaitHandle.WaitOne(); exec.EndInvoke(result); } if (errors.Count > 0) { StringBuilder sb = new StringBuilder(); foreach (Exception error in errors) { sb.AppendLine(error.ToString()); } throw new Exception(sb.ToString()); } } private delegate void ExecuteTestDelegate(TestData test, ITestCommand command, List<Exception> errors); private void ExecuteTest(TestData test, ITestCommand command, List<Exception> errors) { try { object instance = Activator.CreateInstance(test.Method.DeclaringType); command.Execute(instance); } catch (TargetInvocationException e) { lock (errors) errors.Add(e.InnerException); } catch (Exception e) { lock (errors) errors.Add(e); } } private class TestData { public readonly MethodInfo Method; public readonly SvnBridgeFactAttribute Fact; public TestData(SvnBridgeFactAttribute fact, MethodInfo method) { Fact = fact; Method = method; } } }
As I was writing this post, I figure out one issue, the other would require concurrent debugging...

Comments
Comment preview