/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: This module contains implementation of CTestServer
* class member functions.
*
*/
// INCLUDE FILES
#include <e32std.h>
#include <e32svr.h>
#include "TestEngineClient.h"
#include <StifTestModule.h>
#include <stifinternal/TestServerClient.h>
#include "TestServer.h"
#include "TestServerCommon.h"
#include "TestServerModuleIf.h"
// EXTERNAL DATA STRUCTURES
// EXTERNAL FUNCTION PROTOTYPES
// CONSTANTS
// MACROS
// LOCAL CONSTANTS AND MACROS
// MODULE DATA STRUCTURES
// Struct to pass parameters to server thread
struct TThreadStartTestServerSession
{
RThread iServerThread; // The server thread
RSemaphore iStarted; // Startup syncronisation semaphore
TInt iStartupResult;// Start-up result
};
// LOCAL FUNCTION PROTOTYPES
// FORWARD DECLARATIONS
// ==================== LOCAL FUNCTIONS =======================================
// None
// ================= MEMBER FUNCTIONS =========================================
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: NewL
Description: Create new Test Module
Parameters: RThread& aClient :in: Handle to client
CTestServer* aServer :in: Pointer to server
Return Values: CTestModule* Pointer to new test module
Errors/Exceptions: Leaves if memory allocation fails or ConstructL leaves.
Status: Approved
-------------------------------------------------------------------------------
*/
CTestModule* CTestModule::NewL( CTestServer* aServer )
{
CTestModule* self=new( ELeave ) CTestModule();
CleanupStack::PushL( self );
self->ConstructL( aServer );
CleanupStack::Pop();
return self;
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: CTestModule
Description: Constructor.
Initialise base class.
Parameters: RThread& aClient :in: Handle to client
Return Values: None
Errors/Exceptions: None
Status: Approved
-------------------------------------------------------------------------------
*/
CTestModule::CTestModule() :
CSession2(),
iIni(0, 0)
{
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: ~CTestModule
Description: Destructor.
Deallocate memory and close handles.
Parameters: None
Return Values: None
Errors/Exceptions: None.
Status: Proposal
-------------------------------------------------------------------------------
*/
CTestModule::~CTestModule()
{
__TRACE( KVerbose, ( _L( "Closing test module" ) ) );
// Free test case related data. No error checking here, because if freeing
// fails, then nothing can be done in destructor.
FreeCaseData();
// Delete all test module instances.
// Cleanup all RTestExecution has been opened by client but not properly
// closed for example if timeout occurs and client died. This almost do
// same than CloseSession() in "if( iTestExecutionHandle )" branch.
if( iTestExecutionHandle )
{
TInt handle = 0;
CObject* theObj = NULL;
TInt count = iTestExecutionHandle->Count();
for( TInt i = 0 ; i < count; i++ )
{
// Get pointer to CTestExecution
theObj=iTestExecutionHandle->operator[]( i );
if( theObj )
{
handle=iTestExecutionHandle->At( theObj );
CTestExecution* testcase = (CTestExecution*) theObj;
// Cancels test(s) execution(timeout, exit, etc)
// For example TestCombiner is timeouted => TestCombiner's
// TestServer+TestModule(s) should cancel also.
testcase->CancelTestExecution();
// CTestExecution will panic if test case is ongoing!!! This
// should be stopped, client should handless this.
iTestExecutionHandle->Remove( handle );
}
}
delete iTestExecutionHandle;
iTestExecutionHandle = NULL;
}
// Delete all FREE Test Module instances.
if( iTestModuleInstances )
{
iTestModuleInstances->ResetAndDestroy();
delete iTestModuleInstances;
iTestModuleInstances = NULL;
}
// Delete ini file heap buffer
delete iIniBuffer;
iIniBuffer = NULL;
// Delete array of test case titles
iTestCaseTitles.ResetAndDestroy();
iTestCaseTitles.Close();
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: ConstructL
Description: Second level constructor.
Parameters: CTestServer* aServer :in: Server
Return Values: None
Errors/Exceptions: Leaves if:
base class CreateL leaves
Object index creation fails
Object container creation fails
Pointer array construction fails
Status: Approved
-------------------------------------------------------------------------------
*/
void CTestModule::ConstructL( CTestServer* aServer )
{
__TRACE( KVerbose, ( _L( "CTestModule::ConstructL - constructing server session" ) ) );
// second-phase construct base class
//CSession2::CreateL( /* *aServer */ );
iTestServer = aServer;
// create new object index
iTestExecutionHandle = CObjectIx::NewL();
// Initialize the object container using the object
// container index in the server.
iContainer = iTestServer->NewContainerL();
iTestModuleInstances = new( ELeave ) RPointerArray<CTestModuleContainer>;
__TRACE( KError, ( _L( "CTestModule::ConstructL - constructing server session done" ) ) );
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: CountResources
Description: Resource counting
Parameters: None
Return Values: TInt Resource count
Errors/Exceptions: None
Status: Approved
-------------------------------------------------------------------------------
*/
TInt CTestModule::CountResources()
{
return iResourceCount;
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: NumResources
Description: Get resources, writes to Message()
Parameters: None
Return Values: None
Errors/Exceptions: Panic client if result can't be written to descriptor.
Status: Approved
-------------------------------------------------------------------------------
*/
void CTestModule::NumResources( const RMessage2& aMessage )
{
TPckgBuf<TInt> countPckg( iResourceCount );
TRAPD( r, aMessage.WriteL( 0, countPckg ) );
if( r !=KErrNone )
{
PanicClient( EBadDescriptor, aMessage );
}
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: PanicClient
Description: Panic clients.
Parameters: TInt aPanic :in: Panic code
Return Values: None
Errors/Exceptions: None
Status: Approved
-------------------------------------------------------------------------------
*/
void CTestModule::PanicClient( const TInt aPanic, const RMessage2& aMessage ) const
{
__TRACE( KError,( _L( "CTestModule::PanicClient code = %d" ), aPanic ) );
_LIT( KTxtTestModule,"CTestModule" );
aMessage.Panic( KTxtTestModule, aPanic );
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: CloseSession
Description: Close session
Parameters: None
Return Values: TInt: Symbian error code.
Errors/Exceptions: None
Status: Approved
-------------------------------------------------------------------------------
*/
TInt CTestModule::CloseSession( const RMessage2& aMessage )
{
__TRACE( KMessage,( _L( "CTestModule::CloseSession in" ) ) );
// Delete all unclosed subsession handle before closing session.
// Remove iTestExecutionHandle contents. iTestExecutionHandle countains
// CTestExecution that handles test case have been created.
if( iTestExecutionHandle )
{
TInt handle = 0;
CObject* theObj = NULL;
TInt count = iTestExecutionHandle->Count();
for( TInt i = 0 ; i < count; i++ )
{
theObj=iTestExecutionHandle->operator[]( i );
if( theObj )
{
handle=iTestExecutionHandle->At( theObj );
// CTestExecution will panic if test case is ongoing!!! This
// should be stopped, client should handle this.
iTestExecutionHandle->Remove( handle );
}
}
delete iTestExecutionHandle;
iTestExecutionHandle = NULL;
}
// Deletion must be done here, because the "CloseSession" message is
// completed before execution continues from CActiveScheduler::Start
// location, and the main thread can continue execution
// and therefore shutdown itself and all threads in that process.
// Delete the object container
iTestServer->DeleteContainer( iContainer );
// Free test case related data
TInt r = FreeCaseData();
// Delete all FREE Test Module instances
iTestModuleInstances->ResetAndDestroy();
delete iTestModuleInstances;
iTestModuleInstances = NULL;
// Inform server that session is closed
iTestServer->SessionClosed();
// Check for avoiding multiple complete, see CTestModule::ServiceL()
if( r != KErrNone )
{
// In error cases do not complete, just return
__TRACE( KMessage,( _L( "CTestModule::CloseSession out (1)" ) ) );
return r;
}
aMessage.Complete( KErrNone );
// After active scheduler shutdown is done, execution continues from
// CTestServer::ThreadFunction()
__TRACE( KMessage,( _L( "CTestModule::CloseSession out (2)" ) ) );
return r;
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: ServiceL
Description: Trap harness for dispatcher
Parameters: const RMessage& aMessage :inout: Message
Return Values: None
Errors/Exceptions: None
Status: Proposal
-------------------------------------------------------------------------------
*/
void CTestModule::ServiceL( const RMessage2& aMessage )
{
// NOTE! HW testing slows down dramatically if adds commants here
//__TRACE( KMessage,( _L( "CTestModule::ServiceL in" ) ) );
TInt r = KErrNone;
TRAPD( ret, r = DispatchMessageL( aMessage ) );
if ( ret != KErrNone )
{
// Complete message on leaving cases with leave code.
__TRACE( KError, ( CStifLogger::ERed, _L( "CTestModule::DispatchMessageL leaved" ) ) );
aMessage.Complete( ret );
}
// Complete message with error code originating from message handling
// function.
if ( r != KErrNone )
{
__TRACE( KError, ( CStifLogger::ERed, _L( "CTestModule::DispatchMessageL returned error" ) ) );
aMessage.Complete( r );
}
// __TRACE( KMessage,( _L( "CTestModule::ServiceL out" ) ) );
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: DispatchMessageL
Description: Dispatch message, calls corresponding function to do it.
Parameters: const RMessage& aMessage :inout: Message to be handled
Return Values: TInt Error code
Errors/Exceptions: Leaves if operation handling function leaves
Status: Proposal
-------------------------------------------------------------------------------
*/
TInt CTestModule::DispatchMessageL( const RMessage2& aMessage )
{
__TRACE( KMessage,( _L( "CTestModule::DispatchMessageL %d" ),
aMessage.Function() ) );
switch( aMessage.Function() )
{
// Session specific
case ETestServerCloseSession: // Close whole session
{
__TRACE( KError ,( _L( "Closing test module session" ) ) );
return CloseSession( aMessage );
}
case ETestServerGetServerThreadId: // Get Server ThreadId
{
__TRACE( KError ,( _L( "Return server thread id" ) ) );
return GetServerThreadIdL( aMessage );
}
case ETestModuleCreateSubSession : // Create new test module subsession
{
__TRACE( KError,( _L( "Creating test module session" ) ) );
return CreateModuleSessionL( aMessage );
}
case ETestModuleCloseSubSession: // Close module subsession
{
// Nothing to do.
aMessage.Complete( KErrNone );
return KErrNone;
}
case ETestExecutionCreateSubSession: // Create new test execution subsession
{
return NewTestExecutionL( aMessage );
}
case ETestModuleEnumerateTestCases: // Enumerate test cases
{
__TRACE( KError,( _L( "Enumerating test cases" ) ) );
return EnumerateTestCasesL( aMessage );
}
case ETestModuleGetTestCases: // Get test cases
{
return GetTestCasesL( aMessage );
}
case ETestModuleErrorNotification: // Request error notification
{
return HandleErrorNotificationL( aMessage );
}
case ETestModuleCancelAsyncRequest:
{
return CancelAsyncRequestL( aMessage );
}
// Subsession specific
case ETestExecutionRunTestCase: // Run test case
{
__TRACE( KInit,( _L( "Running test case" ) ) );
CTestExecution* testCase=CaseFromHandle( aMessage.Int3(), aMessage );
return testCase->RunTestCase( aMessage );
}
case ETestExecutionNotifyProgress: // Test case prints
{
CTestExecution* testCase=CaseFromHandle( aMessage.Int3(), aMessage );
return testCase->NotifyPrint( aMessage );
}
case ETestExecutionNotifyEvent: // Event notifications
{
CTestExecution* testCase=CaseFromHandle( aMessage.Int3(), aMessage );
return testCase->NotifyEvent( aMessage );
}
case ETestExecutionNotifyRemoteCmd: // RemoteCmd notifications
{
CTestExecution* testCase=CaseFromHandle( aMessage.Int3(), aMessage );
return testCase->NotifyRemoteCmd( aMessage );
}
case ETestExecutionReadRemoteCmdInfo: // RemoteCmd reading
{
//CTestExecution* testCase=CaseFromHandle( aMessage.Int3() );
//return testCase->NotifyRemoteCmd( aMessage );
CTestExecution* testCase=CaseFromHandle( aMessage.Int3(), aMessage );
return testCase->ReadRemoteCmdInfo( aMessage );
}
case ETestExecutionResume: // Resume case execution
{
__TRACE( KVerbose,( _L( "Resuming test execution" ) ) );
CTestExecution* testCase=CaseFromHandle( aMessage.Int3(), aMessage );
return testCase->Resume( aMessage );
}
case ETestExecutionPause: // Pause case execution
{
__TRACE( KVerbose,( _L( "Pausing test execution" ) ) );
CTestExecution* testCase=CaseFromHandle( aMessage.Int3(), aMessage );
return testCase->Pause( aMessage );
}
case ETestExecutionCloseSubSession: // Close execution subsession
{
CTestExecution* testCase=CaseFromHandle( aMessage.Int3(), aMessage );
return testCase->CloseTestExecution( aMessage );
}
case ETestExecutionCancelAsyncRequest: // Cancel async request
{
CTestExecution* testCase=CaseFromHandle( aMessage.Int3(), aMessage );
return testCase->CancelRequestL( aMessage );
}
case ETestExecutionNotifyCommand: // Command notifications
{
CTestExecution* testCase=CaseFromHandle( aMessage.Int3(), aMessage );
return testCase->NotifyCommand( aMessage );
}
default: // Invalid request
{
PanicClient( EBadRequest, aMessage );
return KErrNotSupported;
}
}
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: EnumerateTestCases
Description: Enumerates test cases and returns test case count by writing
result to client side package.
Function obtains a TestModule and calls EnumerateTestCases from it.
Test module will be released when calling GetTestCases function.
Parameters: const RMessage& aMessage :inout: Message to be handled
Return Values: TInt Operation result
Errors/Exceptions: None
Status: Proposal
-------------------------------------------------------------------------------
*/
TInt CTestModule::EnumerateTestCasesL( const RMessage2& aMessage )
{
__TRACE( KMessage,( _L( "CTestModule::EnumerateTestCasesL in" ) ) );
// Get data from message
TFileName config;
TRAPD( res, aMessage.ReadL( 0, config ) );
if(res == KErrDied)
{
RDebug::Print(_L("CTestModule::EnumerateTestCasesL() Reading from RMessage ended with KErrDied. Client is not alive anymore and this request will be ignored"));
return res;
}
else if( res != KErrNone )
{
RDebug::Print(_L("CTestModule::EnumerateTestCasesL() #1 Panic client with [%d], res=[%d]"), EBadDescriptor, res);
PanicClient( EBadDescriptor, aMessage );
return res;
}
// Free old case data
User::LeaveIfError( FreeCaseData() );
// Get test cases from the test module
User::LeaveIfError( GetTestModule( iEnumerateModule, config ) );
// Enumerate test cases
iEnumerateModule->EnumerateTestCases( config );
// Something fatal?
TInt r = iEnumerateModule->OperationErrorResult();
if( r != KErrNone )
{
// Enumeration module have crashed.
delete iEnumerateModule;
iEnumerateModule = NULL;
return r;
}
// Error from module?
if( iEnumerateModule->ModuleResult() != KErrNone )
{
return iEnumerateModule->ModuleResult();
}
// Write count to Ptr1()
const RPointerArray<TTestCaseInfo>* testCases = iEnumerateModule->TestCases();
if( testCases == NULL )
{
User::Leave( KErrGeneral );
}
// Store titles (for further use, i.e. when asked for title from the interface via CTestModuleIf->CTestThreadContainer->CTestModuleContainer)
iTestCaseTitles.ResetAndDestroy();
TInt i;
for(i = 0; i < testCases->Count(); i++)
{
//Handle situation when test cases are enumerated not as 0-based (testscripter, ...)
if(i == 0 && (*testCases)[i]->iCaseNumber > 0)
{
iTestCaseTitles.Append(NULL);
}
HBufC* title = (*testCases)[i]->iTitle.AllocL();
iTestCaseTitles.Append(title);
}
TPckgBuf<TInt> countPckg( testCases->Count() );
TRAP( res, aMessage.WriteL( 1, countPckg ) );
if(res == KErrDied)
{
RDebug::Print(_L("CTestModule::EnumerateTestCasesL() Writing to RMessage ended with KErrDied. Client is not alive anymore and this request will be ignored"));
return res;
}
else if( res != KErrNone )
{
RDebug::Print(_L("CTestModule::EnumerateTestCasesL() #2 Panic client with [%d], res=[%d], config=[%S]"), EBadDescriptor, res, &config);
PanicClient( EBadDescriptor, aMessage );
return res;
}
// All ok, complete message
aMessage.Complete( KErrNone );
__TRACE( KMessage,( _L( "CTestModule::EnumerateTestCasesL out" ) ) );
return KErrNone;
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: GetTestCasesL
Description: Get test cases. Enumerate test cases must be called before
calling this function.
Function releases the test module reserved by EnumerateTestCase().
Parameters: const RMessage& aMessage :inout: Message to be handled
Return Values: TInt Operation result
Errors/Exceptions: Leaves if cases have not been enumerated.
Status: Proposal
-------------------------------------------------------------------------------
*/
TInt CTestModule::GetTestCasesL( const RMessage2& aMessage )
{
__TRACE( KMessage,( _L( "CTestModule::GetTestCasesL in" ) ) );
// Leave if cases have not been enumerated.
//User::LeaveIfNull(( TAny* ) iEnumerateModule->TestCases() );
if( ( TAny* ) iEnumerateModule->TestCases() == NULL )
{
User::Leave( KErrGeneral );
}
const TInt len = sizeof( TTestCaseInfo );
// Get cases
const RPointerArray<TTestCaseInfo>& cases = *iEnumerateModule->TestCases();
// Get number of cases
const TInt Kcount = cases.Count();
// Loop through case and copy then to client's descriptor.
for( TInt i = 0; i < Kcount; i++ )
{
// Construct package for source data
TTestCaseInfoPckg tmpPackage( *cases[i] );
// Write to correct location
aMessage.WriteL( 0, tmpPackage, i *len );
}
// Free case data and the test module
User::LeaveIfError( FreeCaseData() );
// Finished
aMessage.Complete( KErrNone );
__TRACE( KMessage,( _L( "CTestModule::GetTestCasesL out" ) ) );
return KErrNone;
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: HandleErrorNotification
Description: Request error notification.
Parameters: const RMessage& aMessage :inout: Message to be handled
Return Values: TInt Operation result
Errors/Exceptions: None
Status: Proposal
-------------------------------------------------------------------------------
*/
TInt CTestModule::HandleErrorNotificationL( const RMessage2& aMessage )
{
iErrorMessage = aMessage;
iErrorMessageAvailable = ETrue;
return KErrNone;
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: GetServerThreadId
Description: Request server state notification.
Parameters: const RMessage& aMessage :inout: Message to be handled
Return Values: TInt Operation result
Errors/Exceptions: None
Status: Proposal
-------------------------------------------------------------------------------
*/
TInt CTestModule::GetServerThreadIdL( const RMessage2& aMessage )
{
TInt id( iTestServer->GetServerThreadId() );
TPckg<TThreadId> threadIdPckg( id );
TRAPD( res, aMessage.WriteL( 0, threadIdPckg ) );
// Finished
aMessage.Complete( res );
return KErrNone;
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: CancelAsyncRequest
Description: Cancels asynchronous request
Parameters: const RMessage& aMessage :inout: Message to be handled
Return Values: TInt Operation result
Errors/Exceptions: None
Status: Proposal
-------------------------------------------------------------------------------
*/
TInt CTestModule::CancelAsyncRequestL( const RMessage2& aMessage )
{
switch ( aMessage.Int0() )
{
case ETestModuleErrorNotification:
{
if ( iErrorMessageAvailable )
{
iErrorMessage.Complete ( KErrCancel );
iErrorMessageAvailable = EFalse;
}
aMessage.Complete ( KErrNone );
break;
}
default:
{
PanicClient( EInvalidRequestCancel, aMessage );
break;
}
}
return KErrNone;
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: ErrorPrint
Description: Prints error
Parameters: const TInt aPriority :in: Priority
TPtrC aError: in: Error
Return Values: None
Errors/Exceptions: None
Status: Proposal
-------------------------------------------------------------------------------
*/
void CTestModule::ErrorPrint( const TInt aPriority,
TPtrC aError )
{
if ( iErrorMessageAvailable )
{
TErrorNotification error;
TErrorNotificationPckg errorPckg ( error );
error.iModule = _L("TestServer");
error.iPriority = aPriority;
error.iText = aError;
TRAPD( r, iErrorMessage.WriteL( 0, errorPckg ) );
// Do not handle errors
iErrorMessageAvailable = EFalse;
iErrorMessage.Complete( r );
}
else
{
RDebug::Print (_L("Error message lost %d [%S]"), aPriority, &aError );
}
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: FreeCaseData
Description: Frees the test case data and test module that is used in
enumeration.
Parameters: None
Return Values: TInt Error code
Errors/Exceptions: None
Status: Proposal
-------------------------------------------------------------------------------
*/
TInt CTestModule::FreeCaseData()
{
__TRACE( KMessage,( _L( "CTestModule::FreeCaseData in" ) ) );
TInt r = KErrNone;
if( iEnumerateModule )
{
// Deallocate testcase memory
iEnumerateModule->FreeEnumerationData();
// Free the module
r = FreeTestModule( iEnumerateModule );
iEnumerateModule = NULL;
}
__TRACE( KMessage,( _L( "CTestModule::FreeCaseData out" ) ) );
return r;
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: CreateModuleSessionL
Description: Creates a new module session.
Just take the initialisation file name from message.
Parameters: const RMessage& aMessage :inout: Message to be handled
Return Values: TInt Operation result
Errors/Exceptions: Leaves if memory allocation fails
Status: Proposal
-------------------------------------------------------------------------------
*/
TInt CTestModule::CreateModuleSessionL( const RMessage2& aMessage )
{
__TRACE( KMessage,( _L( "CTestModule::CreateModuleSession in" ) ) );
// Take parameters
TFileName ini;
TRAPD( res, aMessage.ReadL( 0, ini ) );
if( res != KErrNone )
{
PanicClient( EBadDescriptor, aMessage );
return res;
}
// Construct heap buffer for initialization file name
iIniBuffer = HBufC::NewL( ini.Length() );
iIni.Set ( iIniBuffer->Des() );
iIni.Copy ( ini );
aMessage.Complete( KErrNone );
__TRACE( KMessage,( _L( "CTestModule::CreateModuleSession out" ) ) );
return KErrNone;
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: NewTestExecutionL
Description: Create new test execution subsession
Parameters: const RMessage& aMessage :inout: Message to be handled
Return Values: TInt Operation result
Errors/Exceptions: Function leaves if object can't be created or
it can't be added to container.
Function panics client if message contains invalid
descriptor.
Status: Proposal
-------------------------------------------------------------------------------
*/
TInt CTestModule::NewTestExecutionL( const RMessage2& aMessage )
{
__TRACE( KMessage,( _L( "CTestModule::NewTestExecutionL in" ) ) );
// Get data from message
TInt caseNumber = aMessage.Int0();
TFileName config;
TRAPD( res, aMessage.ReadL( 1, config ) );
if( res != KErrNone )
{
PanicClient( EBadDescriptor, aMessage );
return res;
}
// Make new object
CTestExecution* execution=CTestExecution::NewL( this, caseNumber, config );
// add object to object container to generate unique id
iContainer->AddL( execution );
// add object to object index; this returns a unique handle so we can get it again
TInt handle=iTestExecutionHandle->AddL( execution );
// write the handle to client
TPckg<TInt> handlePckg( handle );
TRAP( res, aMessage.WriteL( 3, handlePckg ) );
if( res != KErrNone )
{
iTestExecutionHandle->Remove( handle );
PanicClient( EBadDescriptor, aMessage );
return res;
}
// notch up another resource
iResourceCount++;
// Complete message
aMessage.Complete( KErrNone );
__TRACE( KMessage,( _L( "CTestModule::NewTestExecutionL out" ) ) );
return KErrNone;
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: DeleteTestExecution
Description: Deletes Test Execution by handle
Parameters: const TUint aHandle :in: Handle
Return Values: None
Errors/Exceptions: Panics client if invalid handle
Status: Proposal
-------------------------------------------------------------------------------
*/
void CTestModule::DeleteTestExecution( const TUint aHandle, const RMessage2& aMessage )
{
// Verify that handle is valid
CaseFromHandle( aHandle, aMessage );
// Remove object
iTestExecutionHandle->Remove( aHandle );
// Decrement resource count.
iResourceCount--;
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: CaseFromHandle
Description: Return subsession from handle
Parameters: const TUint aHandle :in: Handle
Return Values: CTestExecution* Test Execution object
Errors/Exceptions: Function panics client if invalid handle.
Status: Approved
-------------------------------------------------------------------------------
*/
CTestExecution* CTestModule::CaseFromHandle( const TUint aHandle, const RMessage2& aMessage ) const
{
CTestExecution* testcase =( CTestExecution* ) iTestExecutionHandle->At( aHandle );
if( testcase == NULL )
{
PanicClient( EBadSubsessionHandle, aMessage );
}
return testcase;
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: GetTestModule
Description: Gets a CTestModuleBase*. If there is a free entry
in the free list, then it is returned. Otherwise a new one is created.
Parameters: CTestModuleContainer*& aContainer: out: container pointer.
const TDesC& aConfig: in: Test case (config) file name.
Return Values: Symbian OS error code
Errors/Exceptions: None
Status: Proposal
-------------------------------------------------------------------------------
*/
TInt CTestModule::GetTestModule( CTestModuleContainer*& aContainer,
const TDesC& aConfig )
{
TInt ret = KErrNone;
if( iTestModuleInstances->Count() )
{
// Return an existing one
aContainer =( *iTestModuleInstances )[0];
iTestModuleInstances->Remove( 0 );
__TRACE( KInit,( _L( "Reusing old test module container instance at 0x%x" ), (TUint32) aContainer ) );
}
else
{
// Create a new one
__TRACE( KInit,( _L( "Creating new test module instance" ) ) );
TRAPD( err, aContainer = CTestModuleContainer::NewL(
iTestServer->ModuleName(),
this,
aConfig ) );
// If module can't be created, then return NULL.
if( err )
{
__TRACE( KError,( _L( "Can't create new test module container instance" ) ) );
aContainer = NULL;
ret = err;
}
else
{
__TRACE( KInit,( _L( "Test module instance container created" ) ) );
}
if( aContainer )
{
// Initialise module
aContainer->Initialize( iTestServer->ModuleName(), iTestServer->FirstTime() );
if( aContainer->OperationErrorResult() != KErrNone )
{
// Can't initialise module, delete it
__TRACE( KError,( CStifLogger::ERed, _L( "Operation error, can't initialize test module container instance" ) ) );
ret = aContainer->OperationErrorResult();
delete aContainer;
aContainer = NULL;
}
else if( aContainer->ModuleResult() != KErrNone )
{
// Can't initialise module, delete it
__TRACE( KError,( CStifLogger::ERed, _L( "Module error, can't initialize test module container instance" ) ) );
ret = aContainer->ModuleResult();
delete aContainer;
aContainer = NULL;
}
else
{
// Module initialised properly, clear the first time flag.
iTestServer->ClearFirstTime();
__TRACE( KInit,( _L( "Test module container initialized at 0x%x" ), (TUint32) aContainer ) );
}
}
}
return ret;
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: FreeTestModule
Description:Frees a CTestModuleContainer. This function can be called
from the context of the test execution thread.
Parameters: CTestModuleContainer* aModule :in: Module to be freed
Return Values: TInt Error code
Errors/Exceptions: None
Status: Proposal
-------------------------------------------------------------------------------
*/
TInt CTestModule::FreeTestModule( CTestModuleContainer* aModule )
{
// Free the module
TInt r = iTestModuleInstances->Append( aModule );
if( r != KErrNone )
{
delete aModule;
aModule = NULL;
}
return r;
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: IniName
Returns the initialisation file name
Parameters: None
Return Values: const TDesC& Initialisation file name
Errors/Exceptions: None
Status: Proposal
-------------------------------------------------------------------------------
*/
const TDesC& CTestModule::IniName() const
{
return iIni;
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: Name
Returns the module name
Parameters: None
Return Values: const TDesC& Initialisation file name
Errors/Exceptions: None
Status: Proposal
-------------------------------------------------------------------------------
*/
const TDesC& CTestModule::Name() const
{
return iTestServer->ModuleName();
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: GetTestCaseTitleL
Gets title of currently running test case
Parameters: None
Return Values: TInt aTestCaseNumber: in: index of currently running test case
TDes& aTestCaseTitle: out: test case title
Errors/Exceptions: None
Status: Proposal
-------------------------------------------------------------------------------
*/
void CTestModule::GetTestCaseTitleL(TInt aTestCaseNumber, TDes& aTestCaseTitle)
{
RDebug::Print(_L("Trying to get test case title from module. Index=%d, count=%d"), aTestCaseNumber, iTestCaseTitles.Count());
aTestCaseTitle.Copy(*(iTestCaseTitles[aTestCaseNumber]));
}
/*
-------------------------------------------------------------------------------
Class: CTestModule
Method: GetTestServer
Gets pointer to TestServer
Parameters: None
Return Values: CTestServer : pointer to TestServer
Errors/Exceptions: None
Status: Proposal
-------------------------------------------------------------------------------
*/
CTestServer* CTestModule::GetTestServer()
{
return iTestServer;
}
// End of File