I was tracking down a 'pure virtual method' crash in
SipRefreshManagerTest yesterday, and discovered that the cause is one
that is likely to turn up in other places, so I thought I would warn
everyone:
In many of the sipXtackLib tests, we set up a SipUserAgent, and then set
up a message observer on it. In order to prevent a pure virtual method
crash, we have to remove the message observer before deallocating the
message queue that is the destination of the message observer. In many
cases, the message observer is set up at the beginning of the test case
and removed at the end of the test case.
This fails if an assertion in the test case fails. A failed assertion
causes a throw out of the test case, so the allocated objects are
deallocated, but the message observer is not removed first. The result
is that if any messages go through the SipUserAgent due to deallocating
the tested objects, the message observer invokes an undefined function.
The solution to this is to use the setUp() and tearDown() methods in the
test set. setUp is called before entering the test case, and tearDown
is called after exiting the test case -- even if the exit is due to a
throw. Thus, the addition of the message observer should be done in
setUp and the removal should be done in tearDown. This will generally
require moving the declarations of some objects from the test case to
the test suite. Worse, since setUp and tearDown apply to all test cases
in the test suite, you may need to split the test suite into several
test suites, so each test case can have its own, different, setUp and
tearDown.
Thus, what is easily and incorrectly written as:
void test()
{
SipUserAgent userAgent(...);
userAgent.start();
OsMsgQ incomingServerMsgQueue;
userAgent.addMessageObserver(incomingServerMsgQueue, ...);
SipDialogMgr clientDialogMgr;
SipRefreshManager refreshManager(userAgent, clientDialogMgr);
refreshManager.start();
...
userAgent.removeMessageObserver(incomingServerMsgQueue);
refreshManager.stopAllRefreshes();
userAgent.shutdown(TRUE);
}
becomes:
SipUserAgent* userAgentp;
OsMsgQ incomingServerMsgQueue;
SipDialogMgr clientDialogMgr;
SipRefreshManager* refreshManagerp;
void setUp()
{
userAgentp = new SipUserAgent(...);
userAgentp->start();
userAgentp->addMessageObserver(incomingServerMsgQueue, ...);
refreshManagerp = new SipRefreshManager(*userAgentp, clientDialogMgr);
refreshManagerp->start();
}
void tearDown()
{
userAgentp->removeMessageObserver(incomingServerMsgQueue);
refreshManagerp->stopAllRefreshes();
delete refreshManagerp;
userAgentp->shutdown(TRUE);
delete userAgentp;
}
void test()
{
...
}
(What we really want is for C++ to have an "execute-on-exit" postamble
for scopes.)
Dale
_______________________________________________
sipx-dev mailing list [email protected]
List Archive: http://list.sipfoundry.org/archive/sipx-dev
Unsubscribe: http://list.sipfoundry.org/mailman/listinfo/sipx-dev
sipXecs IP PBX -- http://www.sipfoundry.org/