push 22
push 22

Reputation: 1182

"Thread was being aborted." in test that tests code that fires a delegate on a background thread

I have some old code that I'm trying to writes tests for. the code parses a log file (on a background thread) and when finished fires off a passed in delegate.

i.e.

public delegate void finread(LogData l, LRParseState l, string e="");
void Thread_ParseLog(object info) {
  var info = ti as ThreadInfo;
  // some time later
  info.fin(log, state, error);
}
public static void ParseErrorLog(string log, finread fin){
    var pts = new ParameterizedThreadStart(Thread_ParseLog);
    new Thread(pts).Start(new ThreadInfo(log, fin));
}

The code is production code and every thing works ok and has done for a long time, but when I try and test it I get the "Thread was being aborted." exception raised in the Thread_ParseLog method.

The test looks like this:

void llt(string name, Action<LogData, LRParseState> test) {
    finread d = (LogData l, LRParseState s, string e) => {
      test(l, s);
    };
    LogReader.ParseErrorLog(name, d);
}
[TestMethod]
public void Create_LogReader_Big_Log() {
    llt(ERROR_LOG, (log, state) => {
        Assert.IsTrue(log != null); // never get here!
    });
}

The test data is largeish, about 55mb, which takes about 500ms to process normally.

I'm also getting errors in the output window:

Exception thrown: 'System.Threading.ThreadAbortException' in mscorlib.dll System.AppDomainUnloadedException: Attempted to access an unloaded AppDomain. This can happen if the test(s) started a thread but did not stop it. Make sure that all the threads started by the test(s) are stopped before completion.

Which seem to point at some kind of thread sync problems, but there's nothing i can do about the code i'm testing.

It's, obviously, the way I've written my test and I can fix it by changing my test but I'm not sure why its happening.

TIA.

Upvotes: 5

Views: 2830

Answers (2)

Zach J.
Zach J.

Reputation: 214

Use an async test method and give it a small delay to run.

[TestMethod]
public async Task Create_LogReader_Big_Log()
{
    llt(ERROR_LOG, (log, state) => {
        Assert.IsTrue(log != null); // never get here!
    });
    await Task.Delay(3000);
}

Upvotes: 2

NineBerry
NineBerry

Reputation: 28499

Use synchronization mechanisms like for example a ManualResetEvent to wait for the asynchronous parts of the test to finish before leaving the test method.

[TestMethod]
public void Create_LogReader_Big_Log() {
    // Use this event to wait until the asynchronous code has been executed 
    // before leaving the test method
    ManualResetEvent resetEvent = new ManualResetEvent(false);
    LogData logDataReceived = null;

    llt(ERROR_LOG, (log, state) => {
        logDataReceived = log;

        // Signal that the test has reached the end
        resetEvent.Set();
    });

    // Wait for the event to be set
    resetEvent.WaitOne();

    // Additionally wait for a grace period to allow the other thread to fully terminate
    Thread.Sleep(500);

    // Now perform the asserts on the received data
    Assert.IsTrue(logDataReceived != null);
}

Upvotes: 7

Related Questions