// NeL - MMORPG Framework
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
#ifndef UT_NET_LAYER3
#define UT_NET_LAYER3
#include
#include
uint16 TestPort1 = 56000;
uint NbTestReceived = 0;
CMessage msgoutExpectingAnswer0, msgoutSimple0, msgoutSimple50;
// Data structure for messages
struct TData
{
string PayloadString;
bool ExpectingAnswer;
// Constructor
TData() : ExpectingAnswer(false) {}
// Serial
void serial( NLMISC::IStream& s )
{
s.serial( PayloadString );
s.serial( ExpectingAnswer );
}
};
// This callback must not take more than 10 ms
void cbTest( CMessage &msgin, TSockId from, CCallbackNetBase &netbase )
{
TTime before = CTime::getLocalTime();
// Read data from the message
TData data;
msgin.serial( data );
if ( data.PayloadString == "Payload" )
++NbTestReceived;
// Send the answer if required
if ( data.ExpectingAnswer )
netbase.send( msgoutSimple0, from );
// Check that the duration is compatible with our timeout tests
TTime maxDuration;
if ( msgin.getName() == "TEST_50" )
{
while ( CTime::getLocalTime() - before < 49 ); // wait
maxDuration = 70;
}
else
maxDuration = 10;
TTime actualDuration = CTime::getLocalTime() - before;
if ( actualDuration > maxDuration )
nlerror( "The callback cbTest takes too long (%u) for %s, please fix the test", (uint)actualDuration, msgin.getName().c_str() );
}
static TCallbackItem CallbackArray[] =
{
{ "TEST_0", cbTest },
{ "TEST_50", cbTest }
};
// Test suite for layer 3
class CUTNetLayer3: public Test::Suite
{
public:
//
CUTNetLayer3 ()
{
_Server = NULL;
_Client = NULL;
TEST_ADD(CUTNetLayer3::sendReceiveUpdate);
}
//
~CUTNetLayer3 ()
{
if ( _Server )
delete _Server;
_Server = NULL;
if ( _Client )
delete _Client;
_Client = NULL;
}
//
void sendReceiveUpdate()
{
// Prepare messages for tests
TData data;
data.PayloadString = "Payload";
data.ExpectingAnswer = true;
msgoutExpectingAnswer0.clear(); // optional
msgoutExpectingAnswer0.setType( "TEST_0" ); // could be passed to the constructor
msgoutExpectingAnswer0.serial( data );
data.ExpectingAnswer = false;
msgoutSimple0.clear(); // optional
msgoutSimple0.setType( "TEST_0" ); // could be passed to the constructor
msgoutSimple0.serial( data );
msgoutSimple50.clear(); // optional
msgoutSimple50.setType( "TEST_50" ); // could be passed to the constructor
msgoutSimple50.serial( data );
// Init connections
_Server = new CCallbackServer();
_Server->init( TestPort1 );
_Server->addCallbackArray( CallbackArray, sizeof(CallbackArray)/sizeof(TCallbackItem) );
_Client = new CCallbackClient();
_Client->connect( CInetAddress( "localhost", TestPort1 ) );
_Client->addCallbackArray( CallbackArray, sizeof(CallbackArray)/sizeof(TCallbackItem) );
// TEST: Simple message transmission
NbTestReceived = 0;
_Client->send( msgoutExpectingAnswer0 );
for ( uint i=0; i!=10; ++i ) // give some time to receive
{
_Client->update();
_Server->update(); // legacy version
nlSleep( 50 );
}
TEST_ASSERT( NbTestReceived == 2 ); // answer and reply
// TEST: ONE-SHOT update mode on the receiver
NbTestReceived = 0;
for ( uint i=0; i!=20; ++i ) // send 20 messages
_Client->send( msgoutSimple0 );
while ( NbTestReceived < 20 )
{
_Client->update2();
uint prevNbTestReceived = NbTestReceived;
_Server->update2( 0 ); // shortest time-out = ONE-SHOT mode
TEST_ASSERT( (NbTestReceived == prevNbTestReceived) ||
(NbTestReceived == prevNbTestReceived + 1) );
nlSleep( 10 );
}
// TEST: GREEDY update mode on the receiver
NbTestReceived = 0;
for ( uint i=0; i!=20; ++i ) // send 20 messages
_Client->send( msgoutSimple0 );
for ( uint i=0; i!=10; ++i ) // make sure all messages are flushed
{
_Client->update2();
nlSleep( 10 );
}
_Server->update2( -1 ); // receive all
TEST_ASSERT( NbTestReceived == 20 );
// TEST: CONSTRAINED update mode on the receiver
NbTestReceived = 0;
for ( uint i=0; i!=20; ++i ) // send 20 messages that will trigger a time-consuming callback
_Client->send( msgoutSimple50 );
for ( uint i=0; i!=10; ++i ) // make sure all messages are flushed
{
_Client->update2();
nlSleep( 10 );
}
while ( NbTestReceived < 20 )
{
uint prevNbTestReceived = NbTestReceived;
_Server->update2( 80 ); // no more time than two callback executions
TEST_ASSERT( NbTestReceived <= prevNbTestReceived + 2 );
}
// TEST: CONSTRAINED with minTime update mode on the receiver
NbTestReceived = 0;
while ( NbTestReceived < 20 )
{
_Client->send( msgoutSimple0 );
_Client->send( msgoutSimple0 ); // send 2 messages at a time
_Client->update2();
TTime before = CTime::getLocalTime();
_Server->update2( -1, 30 );
TTime duration = CTime::getLocalTime() - before;
TEST_ASSERT( duration >= 30 );
}
}
private:
CCallbackServer *_Server;
CCallbackClient *_Client;
};
#endif