Skip to main content
Participating Frequently
November 11, 2008
Question

problems with wrong listeners called with async tests

  • November 11, 2008
  • 4 replies
  • 1043 views
I have the following test which does two async tests (this is over a socket connection):

-------------
public function testConnection():void
{
gs.addEventListener(IOErrorEvent.IO_ERROR,
addAsync(onConnectError, 1000));

gs.addEventListener(GErrorEvent.REGISTRATION_ERROR,
addAsync(onConnectRegisterError, 1000));

gs.connect();
}

private function onConnectError(e:IOErrorEvent):void
{
fail("Connection to Growl failed : " + e.text);
}

private function onConnectRegisterError(e:GErrorEvent):void
{
fail("Registration failed : " + "[" + e.code + "] " + e.message);
}
--------------

However, when I run this, i get the following error:

--
Error #1034: Type Coercion failed: cannot convert flash.events::IOErrorEvent@1c3f5e41 to com.adobe.growl.events.GrowlErrorEvent.
--

Digging down on this, it looks like FlexUnit is getting confused and somehow calling the wrong listener for the wrong event.

i.e.

it is calling

onConnectRegisterError(e:GErrorEvent) for the IOErrorEvent.IO_ERROR event

I can confirm this, because If I change to signature of onConnectRegisterError to take an IOErrorEvent

onConnectRegisterError(e:IOErrorEvent):void

the error does not occur.

Has anyone run into anything like this? or had problems with multiple async events in one test?

mike
This topic has been closed for replies.

4 replies

Participating Frequently
November 11, 2008
Yes, I've noticed many subtle problems with addAsync(), in particular<br />having more than one addAsync() active at a time just isn't dealt with<br />well. The root cause of your problem is that the same exact function<br />reference is returned from addAsync every time.<br /><br />In the code sample you gave I don't think addAsync() will do what you<br />want in general though. Unless the gs object fires both events one of<br />the two addAsync() listeners will always fail. A pattern I've used in<br />the multiple listener case is something like this (I don't have a<br />handy example so this maybe a little rough, and not compile :)<br /><br />private var _relayFunction:Function;<br />private var _verifyFunction:Function;<br /><br />private function testFoo():void {<br /> gs.addEventListener(IOErrorEvent.IO_ERROR, onConnectError);<br /> gs.addEventListener(GErrorEvent.REGISTRATION_ERROR, onConnectRegisterError);<br /> gs.connect();<br /> _relayFunction = addAsync(relayFunction, 1000);<br />}<br /><br />private function onConnectError(e:IOErrorEvent):void {<br /> _verifyFunction = verifyConnectError;<br /> _relayFunction(e);<br />}<br /><br />private function onConnectRegisterError(e:GErrorEvent):void {<br /> _verifyFunction = verifyRegisterError;<br /> _relayFunction(e);<br />}<br /><br />private function relayFunction(e:Event) {<br /> _verifyFunction(e);<br />}<br /><br />private function verifyConnectError(e:IOErrorEvent):void {<br /> fail("Connection to Growl failed : " + e.text);<br />}<br /><br />private function verifyConnectRegisterError(e:GErrorEvent):void {<br /> fail("Registration failed : " + "[" + e.code + "] " + e.message);<br />}<br /><br />The basic idea is that you setup a single addAsync() handler that is<br />manually called by each individual handler catching any state that it<br />cares about, in this case the real verification method that we want to<br />use. We need to pass through the relay method so that any asserts or<br />fails we make are within FlexUnit's try/catch handler. You can<br />simplify the logic with a lookup table between event type and<br />verification method or just add a switch to the relay function and<br />register that as the single handler for every event.<br /><br />Might be good to add this to the list of bugs related to FlexUnit that<br />deal with async issues:<br /><br />https://bugs.adobe.com/jira/secure/IssueNavigator.jspa?reset=true&&query=async&summary=true&description=true&body=true&pid=10093<br /><br />-- Daniel R. <danielr@neophi.com> [http://danielr.neophi.com/]<br /><br />On Tue, Nov 11, 2008 at 2:34 PM, Mike Chambers <member@adobeforums.com> wrote:<br />> A new discussion was started by Mike Chambers in<br />><br />> FlexUnit Development --<br />> problems with wrong listeners called with async tests<br />><br />> I have the following test which does two async tests (this is over a socket<br />> connection):<br />><br />> -------------<br />> public function testConnection():void<br />> {<br />> gs.addEventListener(IOErrorEvent.IO_ERROR,<br />> addAsync(onConnectError, 1000));<br />><br />> gs.addEventListener(GErrorEvent.REGISTRATION_ERROR,<br />> addAsync(onConnectRegisterError, 1000));<br />><br />> gs.connect();<br />> }<br />><br />> private function onConnectError(e:IOErrorEvent):void<br />> {<br />> fail("Connection to Growl failed : " + e.text);<br />> }<br />><br />> private function onConnectRegisterError(e:GErrorEvent):void<br />> {<br />> fail("Registration failed : " + "[" + e.code + "] " + e.message);<br />> }<br />> --------------<br />><br />> However, when I run this, i get the following error:<br />><br />> --<br />> Error #1034: Type Coercion failed: cannot convert<br />> flash.events::IOErrorEvent@1c3f5e41 to<br />> com.adobe.growl.events.GrowlErrorEvent.<br />> --<br />><br />> Digging down on this, it looks like FlexUnit is getting confused and somehow<br />> calling the wrong listener for the wrong event.<br />><br />> i.e.<br />><br />> it is calling<br />><br />> onConnectRegisterError(e:GErrorEvent) for the IOErrorEvent.IO_ERROR event<br />><br />> I can confirm this, because If I change to signature of<br />> onConnectRegisterError to take an IOErrorEvent<br />><br />> onConnectRegisterError(e:IOErrorEvent):void<br />><br />> the error does not occur.<br />><br />> Has anyone run into anything like this? or had problems with multiple async<br />> events in one test?<br />><br />> mike<br />><br />> ________________________________<br />> View/reply at problems with wrong listeners called with async tests<br />> Replies by email are OK.<br />> Use the unsubscribe form to cancel your email subscription.<br />><br />>
Participating Frequently
November 11, 2008
ok. I can confirm this is a FlexUnit bug.

----------------
public function testConnection():void
{
//this will get called
gs.addEventListener(IOErrorEvent.IO_ERROR,
addAsync(onConnectError, 1000));

//this should time out (i.e. the event never fires)
gs.addEventListener(GErrorEvent.REGISTRATION_ERROR,
addAsync(onConnectRegisterError, 1000, null, onRegistrationTimeout));
}


//never called
private function onRegistrationTimeout():void
{
trace("onRegistrationTimeout");
fail("registration timed out");
}

//called once
private function onConnectError(e:IOErrorEvent):void
{
trace("onConnectError");
fail("Connection to Growl failed : " + e.text);
}

//should NOT be called, but is called and passed IOError from first async call
private function onConnectRegisterError(e:GErrorEvent):void
{
trace("onConnectRegisterError");
assertTrue("e.application == application", (e.application == application));
fail("Registration failed : " + "[" + e.code + "] " + e.message);
}
----------

Basically, if you have two async calls, and the second one times out, the timeout method for the second will not be called, but instead, the event handler for the second will be called, with the event from the first async call.

mike
Participating Frequently
November 11, 2008
ok. I think I found the issue:

AsyncTestHelper.as

runNext() function

line 110:

objToPass = null;

is never reached (although I am not sure why it isnt reached).

So, the objToPass (an IOErrorEvent) is reused on the second call, which causes the error.

The odd thing is, is that once:

func( objToPass ); //line 107

is called, the rest of the runNext function is never executed, so I have no way to force objToPass to null.

Any thoughts?

mike
Participating Frequently
November 11, 2008
I should add that

gs.addEventListener(GErrorEvent.REGISTRATION_ERROR, addAsync(onConnectRegisterError, 1000));

will time out in this case. So I am thinking that somehow, the IOErrorEvent from the first error is getting passed to the second handler when it times out.

mike