subclassResponsibility (#onAsyncAccept) error when unit testing sockets

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

subclassResponsibility (#onAsyncAccept) error when unit testing sockets

Yar Hwee Boon-3
Hi all

When I run my unit tests which among others, consists of 2 TestCase
subclass that makes connections to a server socket. I get a green
light for all the unit tests however when the tests ends (or when the
2nd TestCase subclass in question runs) I see a walkback below. I'm
still having problem reducing it to a self contained unit test
package, although I can reproduce it everytime. In the meantime, does
the error suggest anything to anyone? Thanks.


'#onAsyncAccept is the responsibility of the subclass'
Socket(Object)>>subclassResponsibility
Socket(SocketAbstract)>>onAsyncAccept
WinAsyncSocket>>wsaEvent:wParam:lParam:
WinAsyncSocket(View)>>dispatchUser:wParam:lParam:map:
WinAsyncSocket>>dispatchUser:wParam:lParam:
WinAsyncSocket(View)>>dispatchMessage:wParam:lParam:
[] in InputState>>wndProc:message:wParam:lParam:cookie:
BlockClosure>>ifCurtailed:
ProcessorScheduler>>callback:evaluate:
InputState>>wndProc:message:wParam:lParam:cookie:
InputState>>pumpMessage:
InputState>>loopWhile:
InputState>>mainLoop
[] in InputState>>forkMain
ExceptionHandler(ExceptionHandlerAbstract)>>markAndTry
[] in ExceptionHandler(ExceptionHandlerAbstract)>>try:
BlockClosure>>ifCurtailed:
BlockClosure>>ensure:
ExceptionHandler(ExceptionHandlerAbstract)>>try:
BlockClosure>>on:do:
[] in BlockClosure>>newProcess


Hwee Boon


Reply | Threaded
Open this post in threaded view
|

Re: subclassResponsibility (#onAsyncAccept) error when unit testing sockets

Bill Dargel
Yar Hwee Boon wrote:
> When I run my unit tests which among others, consists of 2 TestCase
> subclass that makes connections to a server socket. I get a green
> light for all the unit tests however when the tests ends (or when the
> 2nd TestCase subclass in question runs) I see a walkback below. I'm
> still having problem reducing it to a self contained unit test
> package, although I can reproduce it everytime. In the meantime, does
> the error suggest anything to anyone? Thanks.

You're in luck! I ran into the same sort of problem just this past week
and figured out what was going on.

Scenario was that individual tests would run fine. But running batches
of tests would produce errors like you see.

The main  problem I was getting was a 'Remote Socket closed' exception
in ServerSocket>>accept.

Another would be to get a #subclassResponsibility error when
#onAsyncRead (which is implemented by Socket) was sent to a
ServerSocket.

Here's how the errors can arise. Dolphin 5 uses the asynchronous socket
interface, where events about socket activity come through the windows
message queue. WinAsyncSocket uses the Socket descriptor to match up a
windows message to the appropriate socket. However, a socket descriptor
may be reused by Windows after it's been closed.

So imagine this sequence: a test uses a socket (let's call it A). The
test finishes but happens to leave some socket related message in the
windows message queue (which was destined for socket A). The test closes
the socket. The running process immediately moves onto the next
testCase. It also creates a socket (call it B). Windows happens to reuse
the same descriptor for B that had been used for A. Now when the main UI
process gets a chance to run, it gets the socket message (destined for
A), but sends it to the current socket with that descriptor (which is
B).

Messages meant only for Socket can go to ServerSocket, and vise-versa.

Basically the fix is to make sure the windows message queue gets
processed. Probably by putting something in #tearDown after closing any
sockets used by the test. One way might be to put in "SessionManager
inputState pumpMessages".

I ended up using the #waitForUIProcessToIdle method that I added some
time ago to assist with unit testing of the user interface.

It actually waits until all normal priority processes have idled by
seeing when a #userBackgroundPriority process gets a chance to run.

If called from the main UI process, it uses a ModalMsgLoop which
processes the windows message queue. If called from other than the main
UI process, it simply waits on a Semaphore, which gives the main UI
process a chance to run which will process the windows message queue.

hope this helps,
-Bill

-----------------------

waitForUIProcessToIdle
        "General hack to simulate the idling of the system so that testCases
         can proceed once everything in the UI process has been taken care of."

        | waitLoop |
        waitLoop := Processor isActiveMain
                ifTrue: [ModalMsgLoop new]
                ifFalse: [Semaphore new].
       
        [waitLoop signal.
        SessionManager inputState prod]
                        forkAt: Processor userBackgroundPriority.
        waitLoop wait! !

-------------------------------------------
Bill Dargel            [hidden email]
Shoshana Technologies
100 West Joy Road, Ann Arbor, MI 48105  USA


Reply | Threaded
Open this post in threaded view
|

Re: subclassResponsibility (#onAsyncAccept) error when unit testing sockets

Yar Hwee Boon-3
Bill Dargel <[hidden email]> wrote in message news:<[hidden email]>...

> You're in luck! I ran into the same sort of problem just this past week

I absolutely agree.


> So imagine this sequence: a test uses a socket (let's call it A). The
> test finishes but happens to leave some socket related message in the
> windows message queue (which was destined for socket A). The test closes
> the socket. The running process immediately moves onto the next
> testCase. It also creates a socket (call it B). Windows happens to reuse
> the same descriptor for B that had been used for A. Now when the main UI
> process gets a chance to run, it gets the socket message (destined for
> A), but sends it to the current socket with that descriptor (which is
> B).

Thanks, your explanation made the problem clear. Just a thought,
wouldn't a Dolphin Smalltalk program that allows many socket
connections be at high risk to this problem? It sounds like a bug..

> processed. Probably by putting something in #tearDown after closing any
> sockets used by the test. One way might be to put in "SessionManager
> inputState pumpMessages".

I tried exactly that, and the problem went away.

>
> I ended up using the #waitForUIProcessToIdle method that I added some
> time ago to assist with unit testing of the user interface.

When would you need to use this instead of "SessionManager inputState
pumpMessages"?

> hope this helps,

Of course, thanks!! And sorry for the additional questions :)


Hwee Boon


Reply | Threaded
Open this post in threaded view
|

Re: subclassResponsibility (#onAsyncAccept) error when unit testing sockets

Bill Dargel
Yar Hwee Boon wrote:
> Thanks, your explanation made the problem clear. Just a thought,
> wouldn't a Dolphin Smalltalk program that allows many socket
> connections be at high risk to this problem? It sounds like a bug..

It's obviously a potential problem. And it certainly could have figured
into Andy and Blair's thinking when they redid the socket implementation
in Dolphin 6 to use overlapped calls on a synchronous interface. Earlier
this week, while fighting this problem, I was wishing that D6 wasn't
quite so far away.

But, that being said, it might not be a problem for a "typical"
application. (given the caveat that what someone considers typical can
vary quite a bit). To keep a program responsive, the main UI process
needs to be regularly free to handle incoming messages. The architecture
that does that, will also be keeping the sockets happy. I've found that
running batches of unit (and more so acceptance) tests can easily stress
things more, by starving the processing of the windows message queue,
compared to the interactive program that's being tested.

> > I ended up using the #waitForUIProcessToIdle method that I added some
> > time ago to assist with unit testing of the user interface.
>
> When would you need to use this instead of "SessionManager inputState
> pumpMessages"?

I guess for this situation, there isn't a difference. I had used
#waitForUIProcessToIdle just because it's a fix I tend to reach for when
I have a testCase that needs further synchronization with the main UI
process.

I've had situations where an expected result won't be there for a test
to check, until after a co-process or background process has had a
chance to run. This method has just been an easy to use, generic, way to
deal with that, without the testCase having to know about or hook into
some more specific means of synchronization. <grin>One way that I'll
realize that it's needed, is when the assert of a test that failed,
passes by the time I look at it in the debugger.</grin>

-Bill

-------------------------------------------
Bill Dargel            [hidden email]
Shoshana Technologies
100 West Joy Road, Ann Arbor, MI 48105  USA