My definition of monkey testing is basically playing with a program in as if I was a monkey (press every button, unplug things, go in the wrong order..etc etc)
So I made a rather simple SmartCard library that when I "enable" it it just polls the smart card reader for a card, and reports back information. see code
private void CardStatusChange()
{
readerState[0].dwCurrentState = SCardState.SCARD_STATE_UNAWARE;
while (run)
{
System.Threading.Thread.Sleep(100);
if (SCWrapper.SCardGetStatusChange(scHandle, UInt32.MaxValue, readerState, 1) == SCardFunctionReturnCodes.SCARD_S_SUCCESS)
{
readerState[0].dwCurrentState = readerState[0].dwEventState;
SendCardStatus(readerState[0].dwEventState);
}
}
}
private void SendCardStatus(SCardState sCardState)
{
//case SCardState.SCARD_STATE_UNAWARE:
//case SCardState.SCARD_STATE_IGNORE:
//case SCardState.SCARD_STATE_CHANGED:
//case SCardState.SCARD_STATE_UNKNOWN:
//case SCardState.SCARD_STATE_UNAVAILABLE:
//case SCardState.SCARD_STATE_EMPTY:
if (HasStateMask(sCardState, SCardState.SCARD_STATE_EMPTY))
OnCardUnplugged(); //fire event
//case SCardState.SCARD_STATE_PRESENT:
if (HasStateMask(sCardState, SCardState.SCARD_STATE_PRESENT))
{
OnCardPluggedIn(); //fire event
SendCardATR(readerState[0].rgbAtr); //fire event
}
//case SCardState.SCARD_STATE_ATRMATCH:
OnATRMatch(HasStateMask(sCardState, SCardState.SCARD_STATE_ATRMATCH));
//case SCardState.SCARD_STATE_EXCLUSIVE:
//case SCardState.SCARD_STATE_INUSE:
OnCardInUse(HasStateMask(sCardState, SCardState.SCARD_STATE_INUSE));
//case SCardState.SCARD_STATE_MUTE:
//case SCardState.SCARD_STATE_UNPOWERED:
}
private bool HasStateMask(SCardState theValue, SCardState theMask)
{
return ((theValue & theMask) == theMask);
}
This part works as expected in that while my thread is running I can plug in and unplug a smartcard as often and as quickly as I want without problem. What I'm struggling with is the Threading portion of it. Visual Studio screams at me for using suspend and I found a bug when using suspend in my thread so I am taking that out (in other words don't comment on that) but this is how I "open" and "enable" my smart card
public override bool Open()
{
readerThread = new Thread(CardStatusChange);
//code here to setup the smart card
return true;
}
public override bool Enable()
{
run = true;
//thread start checking for card events
switch (readerThread.ThreadState)
{//this is probably a mistake
case ThreadState.AbortRequested:
break;
case ThreadState.Aborted:
break;
case ThreadState.Background:
break;
case ThreadState.Running:
break;
case ThreadState.StopRequested:
break;
case ThreadState.Stopped:
break;
case ThreadState.SuspendRequested:
break;
case ThreadState.Suspended:
readerThread.Resume();//TODO remove
break;
case ThreadState.Unstarted:
readerThread.Start();
break;
case ThreadState.WaitSleepJoin:
break;
default:
break;
}
return true;
}
public override void Disable()
{
run = false;
readerThread.Suspend(); //TODO remove
}
I've never been too good at threading, but I do need this as a thread (I think I do atleast I am open to other ideas). So how should I really Enable and Disable? I used to just set run to true or false, but my monkey testing showed that this doesn't always work and sometimes Windows would cry that it can't start a running thread... SO I dunno what to do. Any thoughts?
1 Answer 1
As requested by Ryan Gates I should post my results. I don't remember the entire scope of what i did, but I do know where the code is :)
So the basics are that I want the thread to be able to exit without causing any strange hicups if the user decides to use my library incorrectly. So I made the thread turn into a background thread. I was able to remove the ugly switch statement and just check the appropriate bits are set to make sure I can start my thread (basically only allows one thread to read a smart card instead of multiple reading the same card)
On Disable what I did was set my flag to kill the loop in my readerThread thread. I then wait for it to exit by using the thread.Join
Clear as mud??? I can try to clear up more if anyone has questions.
public override bool Open()
{
//Code to setup SmartCard
readerThread = new Thread(CardStatusChange);
readerThread.IsBackground = true;
return true;
}
public override bool Enable()
{
run = true;
//thread start checking for card events
Globals.tracer.TraceInformation("Checking Thread State:{0}", readerThread.ThreadState);
var startable = (readerThread.ThreadState & ThreadState.Unstarted);
if (startable > 0)
readerThread.Start();
return true;
}
public override void Disable()
{
run = false;
if(readerThread.ThreadState == ThreadState.Unstarted)
readerThread.Join();
}
readerThread.Suspend()
I change it toreadertThread.Join()
. Then I just check for the Unstarted flag for Enable and fire it up. So far it is working good with no hicups. still have further testing. \$\endgroup\$