diff -r 000000000000 -r a03f92240627 stif/TestServer/src/TestModuleContainer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stif/TestServer/src/TestModuleContainer.cpp Tue Feb 02 01:57:15 2010 +0200 @@ -0,0 +1,2373 @@ +/* +* 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 +* CTestModuleContainer class member functions. CTestModuleContainer +* class contains interface * to execute various functions in context +* of test execution thread. +* +* CTestModuleContainer is the owner of the test execution thread +* object and the owner of the test module instance. +* +*/ + +// INCLUDE FILES +#include +#include +#include +#include "TestEngineClient.h" +#include +#include +#include "TestServer.h" +#include "TestServerModuleIf.h" +#include "TestServerCommon.h" +#include "PrintQueue.h" +#include "TestThreadContainer.h" +//--PYTHON-- begin +#include "StifPython.h" +//--PYTHON-- end + +// EXTERNAL DATA STRUCTURES + +// EXTERNAL FUNCTION PROTOTYPES + +// The test module execution thread function +TInt ExecutionThread( TAny* aParams ); + +// CONSTANTS + +// MACROS + +// LOCAL CONSTANTS AND MACROS + +// MODULE DATA STRUCTURES + +// LOCAL FUNCTION PROTOTYPES +typedef TInt( *CTestInterfaceFactoryTestModule )( CTestModuleParam*&, TUint32& ); + +// FORWARD DECLARATIONS + +// ==================== LOCAL FUNCTIONS ======================================= + +// ================= MEMBER FUNCTIONS ========================================= + + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: NewL + + Description: Returns new CTestModuleContainer instance. + + Parameters: const TDesC& aName: in: Module name + CTestModule* aSession: in: "Parent" + const TDesC& aConfig: in: Test case (config) file name. + + Return Values: CTestModuleContainer* New instance + + Errors/Exceptions: Function leaves if memory allocation fails or + CTestModuleContainer ConstructL leaves. + Panics if aSession is NULL. + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +CTestModuleContainer* CTestModuleContainer::NewL( const TDesC& aName, + CTestModule* aSession, + const TDesC& aConfig ) + { + + __ASSERT_ALWAYS ( aSession, + CTestServer::PanicServer( ENullTestModule ) ); + + CTestModuleContainer* self = new ( ELeave ) CTestModuleContainer(); + CleanupStack::PushL( self ); + self->ConstructL( aName, aSession, aConfig ); + CleanupStack::Pop( self ); + return self; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: ConstructL + + Description: Second level constructor. + + Function creates the execution thread, creates exception + handler and the thread undertaker for it and then resumes the thread. + + Parameters: const TDesC& aName: in: Module name + CTestModule* aSession: in: "Parent" + const TDesC& aConfig: in: Test case (config) file name. + + Return Values: CTestModuleContainer* New instance + + Errors/Exceptions: Function leaves if thread creation fails, + memory allocation fails or undertaker creation leaves. + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestModuleContainer::ConstructL( const TDesC& aName, + CTestModule* aSession, + const TDesC& aConfig ) + { + + RDebug::Print( aName ); + + iNestedActiveScheduler = new (ELeave) CActiveSchedulerWait; + + iCTestModule = aSession; + + // Create error print handler + iErrorPrintHandler = CErrorPrintHandler::NewL( *this ); + User::LeaveIfError( iErrorPrintSem.CreateLocal( 0 ) ); + + // Construct unique thread name + const TInt KAddressLen = 8; + const TInt KMaxName = 50; // Something smaller than max thread name + TInt len = aName.Length(); + if ( KAddressLen + len > KMaxName ) + { + len = KMaxName - KAddressLen; + } + + // Default heap and stack sizes that may configure by user. + TInt heapMinSize( KTestThreadMinHeap ); + TInt heapMaxSize( KTestThreadMaxHeap ); + TInt stackSize( KStackSize ); + + // Check is user give heap or stack sizes and verify sizes. + GetTestModuleParams( aName, aConfig, stackSize, heapMinSize, heapMaxSize ); + + // Create a new thread + TInt ret = KErrAlreadyExists; + for( TInt i = 0; ret == KErrAlreadyExists; i++ ) + { + TName threadName = aName.Left( len ); + threadName.AppendFormat( _L( "%x" ), ( TUint32 ) this ); + threadName.AppendFormat( _L( "%x" ), i ); + //RDebug::Print( threadName ); + + RDebug::Print(_L("CTestModuleContainer::ConstructL create thread=[%S] stackSize=(%d)"), &threadName, stackSize); + + if ( iCTestModule->GetTestServer()->UiTesting() == false ) + { + ret = iThread.Create( + threadName, // name of thread + CTestThreadContainer::ExecutionThread,// thread function + stackSize, // Stack size + heapMinSize, // Heap sizes + heapMaxSize, + this // Parameter to thread function + ); + } + else + { + ret = iThread.Create( + threadName, // name of thread + CTestThreadContainer::UIExecutionThread,// thread function + stackSize, // Stack size + heapMinSize, // Heap sizes + heapMaxSize, + this // Parameter to thread function + ); + } + + // If test execution thread exist try to create new one + if( ret == KErrAlreadyExists ) + { + RDebug::Print( _L( "Thread[%S] allready exist, creating new one" ), &threadName ); + __TRACE ( KInit, ( CStifLogger::ERed, _L( "Thread[%S] allready exist, creating new one" ), &threadName ) ); + } + + } + + // If thread creation fails, leave here. + if( ret != KErrNone ) + { + RDebug::Print( _L( "Execution thread creation fails with: [%d]" ), ret ); + __TRACE ( KError, ( CStifLogger::ERed, _L( "Execution thread creation fails with: [%d]" ), ret ) ); + User::Leave( ret ); + } + + // Doing nothing + // ChangeOperationNoError ( ESuspend, 0 ); + // Thread suspends always first by default + + // Construct the undertaker to get notifications about the + // thread death. + // This must be trapped to allow to kill just created thread + // nicely without a mess in destructor. + TRAPD ( r, + iUnderTaker = CUnderTaker::NewL ( this ); + CActiveScheduler::Add( iUnderTaker ); + iUnderTaker->StartL(); + ); + + // Can't create or start the undertaker. Kill the thread. + // Undertaker will be deleted in destructor if needed. + if ( r != KErrNone ) + { + iThread.Kill ( r ); + iThread.Close(); + User::Leave( r ); + } + + // Get server thread id ( i.e current thread id ) + RThread tmpThread; + iServerThreadId = tmpThread.Id(); + + // Resume the thread + iThread.Resume(); // Start the thread + iUpAndRunning = ETrue; // Thread is created + + // Add "this" container to active scheduler + CActiveScheduler::Add ( this ); + + // Start error print handler + iErrorPrintHandler->StartL(); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: CTestModuleContainer + + Description: Constructor. + + Initialise semaphores. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +CTestModuleContainer::CTestModuleContainer() : + CActive( CActive::EPriorityStandard ), + iOperationName ( 0, 0 ), + iIsPaused( EFalse ) + { + + // Create operation start semaphore + iOperationStartSemaphore.CreateLocal( 0 ); + + // Operation can be changed without first waiting. + iOperationChangeSemaphore.CreateLocal( 1 ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: ~CTestModuleContainer + + Description: Destructor + + Delete the test execution thread, if it is up and running. Delete + undertaker and close handles. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +CTestModuleContainer::~CTestModuleContainer() + { + + __TRACE ( KThreadOperation, ( _L( "CTestModuleContainer::~CTestModuleContainer in" ) ) ); + + if ( iUpAndRunning ) + { + if( iUnderTaker != NULL ) + { + iUnderTaker->Cancel(); + } + + // Set the operation + ChangeOperationNoError ( EExit, 0 ); + + // Do operation + StartAndWaitOperation(); + + } + + delete iErrorPrintHandler; + iErrorPrintHandler = NULL; + + // Delete heap descriptor + delete iModuleNameBuffer; + iModuleNameBuffer = NULL; + + // Delete undertaker + delete iUnderTaker; + iUnderTaker = NULL; + + // Close error semaphore + if ( iErrorPrintSem.Handle() != 0 ) iErrorPrintSem.Close(); + + // Close the semaphores + iOperationStartSemaphore.Close(); + iOperationChangeSemaphore.Close(); + + // Close handle to thread + iThread.Close(); + + Cancel(); + + delete iNestedActiveScheduler; + iNestedActiveScheduler = NULL; + + __TRACE ( KThreadOperation, ( _L( "CTestModuleContainer::~CTestModuleContainer out" ) ) ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: StartAndWaitOperation + + Description: Signals operation and waits until operation is completed. + + Function executes active scheduler locally to handle both request + completion from execution thread and thread undertaker operations. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TInt CTestModuleContainer::StartAndWaitOperation() + { + + // Change undertaker mode to synchronous + iUnderTaker->SetSynchronousMode( ETrue ); + + iStatus = KRequestPending; + // Get ready to handle operation completion + SetActive(); + + // Start operation + iOperationStartSemaphore.Signal(); + + // Start "nested" active scheduler "locally" + //CActiveScheduler::Start(); + iNestedActiveScheduler->Start(); + + // Request completed or operation crashed, everything + // is done in ModuleContainer's RunL function or in UnderTaker's RunL. + + // Cancel the original request in case than it was the undertaker + // that stopped the active scheduler. Does not do anything if original + // request is already finished. + Cancel(); + + // Undertaker back to "normal" mode + iUnderTaker->SetSynchronousMode ( EFalse ); + + return iModuleResult; + + } + + + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: Initialise + + Description: Initialise the test module + + Initialisation is done in context of test execution thread. + + Parameters: const TDesC& aName :in: Module name + TBool aFirstTime :in: First init? + + + Return Values: TInt Result from init + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TInt CTestModuleContainer::Initialize( const TFileName& aName, + TBool aFirstTime + ) + { + + __TRACE ( KInit, ( _L( "Initializing test module" ) ) ); + + // Set the operation + iErrorResult = ChangeOperation ( EInitializeModule, aName, aFirstTime ); + iModuleResult = KErrNone; + + if ( iErrorResult == KErrNone ) + { + // Wait until operation is completed + StartAndWaitOperation(); + } + + if ( iErrorResult ) + { + __TRACE ( KError, ( CStifLogger::ERed, _L( "Initializing test module failed %d" ), iErrorResult ) ); + } + else if ( iModuleResult ) + { + __TRACE ( KError, ( CStifLogger::ERed, _L( "Initializing test module failed code from module = %d" ), iModuleResult ) ); + } + else + { + __TRACE ( KInit, ( CStifLogger::EBold, _L( "Test module initialization done" ) ) ); + } + + // Return result + return iModuleResult; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: EnumerateTestCases + + Description: Enumerate test cases of the test module + + Enumeration is done in context of test execution thread. + + Parameters: const TDesC& aName :in: Configuration file + + Return Values: TInt Result from enumeration + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TInt CTestModuleContainer::EnumerateTestCases( const TFileName& aName ) + { + + __TRACE ( KInit, ( CStifLogger::EBold, _L( "Enumerating test cases from [%S] (might be empty)" ), &aName ) ); + + // Set the operation + iErrorResult = ChangeOperation( EEnumerateInThread, aName, 0 ); + iModuleResult = KErrNone; + + if ( iErrorResult == KErrNone ) + { + // Wait until operation is completed + StartAndWaitOperation(); + } + + if ( iErrorResult ) + { + __TRACE ( KError, ( CStifLogger::ERed, _L( "Enumerating test cases failed %d" ), iErrorResult ) ); + } + else if ( iModuleResult ) + { + __TRACE ( KError, ( CStifLogger::ERed, _L( "Enumerating test cases failed, code from module = %d" ), iModuleResult ) ); + } + else + { + __TRACE ( KInit, ( _L( "Enumerating test cases done" ) ) ); + } + + // Return result + return iModuleResult; + + } + + + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: FreeEnumerationData + + Description: Frees the enumeration data + + Memory deallocation is done in context of test execution thread. + + Parameters: None + + Return Values: TInt Result from operation + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ + +TInt CTestModuleContainer::FreeEnumerationData() + { + + // Set the operation + ChangeOperationNoError( EFreeEnumerationData, 0 ); + + // Do the operation + StartAndWaitOperation(); + + // Return result + return iModuleResult; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: RunTestCase + + Description: Run a test case + + Running a test case is done in context of test execution thread. This + function is asynchronous ( i.e test is not finished when this function + returns ). + + Parameters: const TFileName& aName :in: Configuration file + TInt aCaseNumber :in: Case number + const RMessage :in: Handle to test msg. + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestModuleContainer::RunTestCase ( const TFileName& aName, + const TInt aCaseNumber, + const RMessage2& aMessage + ) + { + + __TRACE ( KInit, ( CStifLogger::EBold, _L( "Running test case [%S], case [%d]" ), &aName, aCaseNumber ) ); + + // Set the operation + iErrorResult = ChangeOperation( EExecuteTestInThread, aName, aCaseNumber ); + + if ( iErrorResult != KErrNone ) + { + aMessage.Complete ( iErrorResult ); + return; + } + + // Set data + iMessage = aMessage; + + iStatus = KRequestPending; + // Get ready to handle operation completion + SetActive(); + + // Do operation + iOperationStartSemaphore.Signal(); + + // This is asynchronous operation, + // do not wait until completed. + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: SetExecutionSubSession + + Description: Set execution subsession + + Sets module container test execution subsession. Execution subsession + is changed when a module container is reused to run another + test case. + + Parameters: CTestExecution* aExecution :in: Subsession pointer + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestModuleContainer::SetExecutionSubSession( CTestExecution* aExecution ) + { + + iCTestExecution = aExecution; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: PauseThread + + Description: Pauses the thread + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TInt CTestModuleContainer::PauseThread() + { + + if( iThread.ExitType() != EExitPending ) + { + // Thread is not alive anymore + return KErrDied; + } + + if(iCTestExecution != NULL) + { + RMutex printMutex; + printMutex.SetHandle( iCTestExecution->PrintMutexHandle() ); + RMutex eventMutex; + eventMutex.SetHandle( iCTestExecution->EventMutexHandle() ); + RMutex sndMutex; + sndMutex.SetHandle( iCTestExecution->SndMutexHandle() ); + RMutex rcvMutex; + rcvMutex.SetHandle( iCTestExecution->RcvMutexHandle() ); + + printMutex.Wait(); // wait that print operation is done + eventMutex.Wait(); // wait that event operation is done + sndMutex.Wait(); // wait that and operation is done + rcvMutex.Wait(); // wait that event operation is done + + iThread.Suspend(); + + printMutex.Signal(); + eventMutex.Signal(); + sndMutex.Signal(); + rcvMutex.Signal(); + } + else + { + __TRACE( KError,( _L( "STIF internal error - iCTestExecution is NULL in CTestModuleContainer::PauseThread" ) ) ); + User::Panic(_L("NULL pointer exception"), KErrGeneral); + } + + iIsPaused = ETrue; + + return KErrNone; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: ResumeThread + + Description: Resumes the thread + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TInt CTestModuleContainer::ResumeThread() + { + + if( iThread.ExitType() != EExitPending ) + { + // Thread is not alive anymore + return KErrDied; + } + + iThread.Resume(); + + // Pause() - Resume() operations done successfully. + iIsPaused = EFalse; + + return KErrNone; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: KillThread + + Description: Kills the thread + + Parameters: const TInt aCode :in: Kill code + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestModuleContainer::KillThread( const TInt aCode ) + { + + iUpAndRunning = EFalse; + iUnderTaker->Cancel(); + + if(iCTestExecution != NULL) + { + RMutex printMutex; + printMutex.SetHandle( iCTestExecution->PrintMutexHandle() ); + RMutex eventMutex; + eventMutex.SetHandle( iCTestExecution->EventMutexHandle() ); + RMutex sndMutex; + sndMutex.SetHandle( iCTestExecution->SndMutexHandle() ); + RMutex rcvMutex; + rcvMutex.SetHandle( iCTestExecution->RcvMutexHandle() ); + + printMutex.Wait(); // wait that print operation is done + eventMutex.Wait(); // wait that event operation is done + sndMutex.Wait(); // wait that snd operation is done + rcvMutex.Wait(); // wait that event operation is done + + iThread.Kill ( aCode ); + + printMutex.Signal(); + eventMutex.Signal(); + sndMutex.Signal(); + rcvMutex.Signal(); + } + else + { + __TRACE( KError,( _L( "STIF internal error - iCTestExecution is NULL in CTestModuleContainer::KillThread" ) ) ); + User::Panic(_L("NULL pointer exception"), KErrGeneral); + } + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: ChangeOperation + + Description: Multithread safe way to change operation + + Parameters: const TOperation aOperation :in: Operation type + const TFileName* aNameBuffer :in: Filename ( or NULL ) + const TInt aInt :in: Operation specific int + + Return Values: TInt Error code + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TInt CTestModuleContainer::ChangeOperation( const TOperation aOperation, + const TFileName& aNameBuffer, + const TInt aInt ) + { + + TInt ret = KErrNone; + + iOperationChangeSemaphore.Wait(); + + iErrorResult = KErrNone; + iModuleResult = KErrNone; + + TFileName newNameBuffer; + // Check is TestScripter + TInt check = CheckModuleName( aNameBuffer, newNameBuffer ); + delete iModuleNameBuffer; + iModuleNameBuffer = NULL; + if( check == KErrNone ) + { + // Construct heap buffer for configuration file + TRAP( ret, iModuleNameBuffer = HBufC::NewL( newNameBuffer.Length() ) ); + + if( ret == KErrNone ) + { + iOperationName.Set ( iModuleNameBuffer->Des() ); + iOperationName.Copy ( newNameBuffer ); + + iOperationIntBuffer = aInt; + iOperationType = aOperation; + } + else + { + __TRACE ( KError, ( CStifLogger::ERed, _L( "CTestModuleContainer::ChangeOperation NoMemory" ) ) ); + } + } + else + { + // Construct heap buffer for configuration file + TRAP( ret, iModuleNameBuffer = HBufC::NewL( aNameBuffer.Length() ) ); + + if( ret == KErrNone ) + { + iOperationName.Set ( iModuleNameBuffer->Des() ); + iOperationName.Copy ( aNameBuffer ); + + iOperationIntBuffer = aInt; + iOperationType = aOperation; + } + else + { + __TRACE ( KError, ( CStifLogger::ERed, _L( "CTestModuleContainer::ChangeOperation NoMemory" ) ) ); + } + } + + iOperationChangeSemaphore.Signal(); + + return ret; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: ChangeOperationNoError + + Description: Multithread safe way to change operation. This version + of function can't fail. + + Parameters: const TOperation aOperation :in: Operation type + const TInt aInt :in: Operation specific int + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestModuleContainer::ChangeOperationNoError( const TOperation aOperation, + const TInt aInt + ) + { + + iOperationChangeSemaphore.Wait(); + + iErrorResult = KErrNone; + iModuleResult = KErrNone; + iOperationIntBuffer = aInt; + iOperationType = aOperation; + + iOperationChangeSemaphore.Signal(); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: Operation + + Description: Multithread safe way to obtain current operation. + + Parameters: None + + Return Values: TBool Operation + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +//@spe const CTestModuleContainer::TOperation CTestModuleContainer::Operation() +CTestModuleContainer::TOperation CTestModuleContainer::Operation() + { + TOperation operation; + iOperationChangeSemaphore.Wait(); + operation = iOperationType; + iOperationChangeSemaphore.Signal(); + + return operation; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: ModuleResult + + Description: Returns error code from test module + + Parameters: None + + Return Values: TInt Result code from module + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TInt& CTestModuleContainer::ModuleResult() + { + + return iModuleResult; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: OperationErrorResult + + Description: Returns error code from test module + + Parameters: None + + Return Values: TInt Result code from module + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TInt& CTestModuleContainer::OperationErrorResult() + { + + return iModuleResult; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: TestModuleName + + Description: Returns test module name. + + Parameters: None + + Return Values: const TDesC&: test module name + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +const TDesC& CTestModuleContainer::TestModuleName() + { + + return iCTestModule->Name(); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: TestModuleName + + Description: Returns test module name. + + Parameters: None + + Return Values: const TDesC&: test module name + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +const TDesC& CTestModuleContainer::TestModuleIniFile() + { + + return iCTestModule->IniName(); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: ModuleResult + + Description: Returns constant pointer to test case array + + Parameters: None + + Return Values: const RPointerArray* Test cases + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +const RPointerArray* CTestModuleContainer::TestCases() const + { + + if( !iUpAndRunning ) + { + return NULL; + } + + if( iThreadContainer == NULL ) + { + CTestServer::PanicServer( ENullTestThreadContainer ); + } + return iThreadContainer->TestCases(); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: Complete + + Description: Completes operation from any thread + + Parameters: const TInt aCompletionCode :in: Completion code + + Return Values: None + + Errors/Exceptions: Function panics if server's thread can't be opened. + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestModuleContainer::Complete( const TInt aCompletionCode ) + { + + TRequestStatus* req = &iStatus; + User::RequestComplete( req, aCompletionCode ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: DoErrorPrint + + Description: Handle error prints. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestModuleContainer::DoErrorPrint() + { + + iCTestModule->ErrorPrint( iErrorPrint.iPriority, iErrorPrint.iText ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: KillTestinterferenceThread + + Description: Make sure that any of the test interference thread's won't + stay to run if test case is crashed of test interference + object is not deleted. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestModuleContainer::KillTestinterferenceThread() + { + if (iCTestExecution != NULL) + { + iCTestExecution->KillTestinterferenceThread(); + } + else + { + __TRACE( KError,( _L( "STIF internal error - iCTestExecution is NULL in CTestModuleContainer::KillTestinterferenceThread" ) ) ); + User::Panic(_L("NULL pointer exception"), KErrGeneral); + } + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: KillTestMeasurement + + Description: Make sure that any of the test measurement process's won't + stay to run if test case is crashed of test measurement object + is not deleted. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestModuleContainer::KillTestMeasurement() + { + if (iCTestExecution != NULL) + { + iCTestExecution->KillTestMeasurement(); + } + else + { + __TRACE( KError,( _L( "STIF internal error - iCTestExecution is NULL in CTestModuleContainer::KillTestMeasurement" ) ) ); + User::Panic(_L("NULL pointer exception"), KErrGeneral); + } + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: GetRequest + + Description: Return status flags. + + Parameters: TRequestType aType: in: request type + + Return Values: TRequestStatus*: pointer to TRequestStatus + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TRequestStatus* CTestModuleContainer::GetRequest( TRequestType aType ) + { + + TRequestStatus* status = NULL; + + switch( aType ) + { + case ERqTestCase: + status = &iStatus; + break; + case ERqErrorPrint: + status = &iErrorPrintHandler->iStatus; + break; + default: + break; + } + + return status; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: RunL + + Description: Stops active scheduler when operation in another thread + is completed. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestModuleContainer::RunL() + { + + if( iOperationType == CTestModuleContainer::EExecuteTestInThread ) + { + // Make sure that any of the test interference thread's won't stay + // to run. + KillTestinterferenceThread(); + + // Make sure that any of the test measurement process's won't stay + // to run. + KillTestMeasurement(); + + if(iCTestExecution == NULL) + { + __TRACE( KError,( _L( "STIF internal error - iCTestExecution is NULL in CTestModuleContainer::RunL" ) ) ); + User::Leave(KErrGeneral); + } + else + { + // Set the thread state + iCTestExecution->SetThreadState( CTestExecution::EFinished ); + + // If test print queue is empty, then complete request with KEof. If Queue + // is not empty, then do not complete. Queue will be emptied by UI. + iCTestExecution->CompletePrintRequestIfQueueEmpty(); + + // Event queue clean-up + iCTestExecution->CleanupEvents(); + + // Complete the test request + iCTestExecution->CompleteTestExecution( iStatus.Int() ); + + // Test case execution OK and test module thread's pause operation + // is not ongoing. Re-use old test module execution thread + if( iCTestExecution->TestThreadFailure() == CTestExecution::ETestThreadOk && !iIsPaused ) + { + // Return this module to pool + __TRACE( KInit, ( _L("Freeing test module container at 0x%x"), + (TUint32) this ) ); + iCTestModule->FreeTestModule( this ); + } + // Problems in test case execution. Delete this test module thread and + // start next test case in new test module thread. + else + { + if( iIsPaused ) + { + // Test case is paused by user and this RunL is executed also. + // This RunL will make Resume() operation to fail because test + // case is finished. Next test case cannot complete and that is + // why next test case will start at the "clean table". + __TRACE( KInit, ( _L( "Delete test module container at 0x%x because test module thread is paused while test case is finished(Cannot Resume())" ), (TUint32) this ) ); + } + else + { + // delete test module thread if some thread problem has occurred + __TRACE( KInit, ( _L("Delete test module container at 0x%x because of thread leak (0x%x)"), + (TUint32) this, iCTestExecution->TestThreadFailure() ) ); + } + delete this; + } + } + } + else + { + // Synchronous operation is completed, stop "nested" active scheduler. + //CActiveScheduler::Stop(); + iNestedActiveScheduler->AsyncStop(); + // Execution continues from CTestModuleContainer::WaitOperation(). + } + } + + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: DoCancel + + Description: Cancel asyncronous request. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestModuleContainer::DoCancel() + { + + if ( iUpAndRunning == EFalse ) + { + + // Before the completion check if the status was not already completed + // from other thread in CTestThreadContainer::TestComplete(). + // For details see Jira STIF-564 + if(iStatus == KRequestPending) + Complete ( KErrCancel ); + + } + + } + + + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: RunError + + Description: Handle errors. + + Because RunL does not leave, one should never come here. Just forward + error code and let framework panic the server in case of error. + + Parameters: TInt aError: :in: Error code + + Return Values: TInt Error code + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TInt CTestModuleContainer::RunError( TInt aError ) + { + + __TRACE( KError,( _L( "CTestModuleContainer::RunError %d" ), aError ) ); + + return aError; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: ReadParametersFromScriptFileL + + Description: Read test class parameters from script file if parameter(s) + are/is set(TestScripter and TestCombiner). + + Parameters: const TDesC& aConfig: in: Test case (config) file name. + TUint32& aStackSize: inout: Stack size. + TUint32& aHeapMinSize: inout: Heap's minimum size. + TUint32& aHeapMaxSize: inout: Heap's maximum size. + + Return Values: Symbian error code. + + Errors/Exceptions: Leaves if User::LeaveIfError() leaves + Leaves if User::LeaveIfNull() leaves + + Status: Approved + +------------------------------------------------------------------------------- +*/ +TInt CTestModuleContainer::ReadParametersFromScriptFileL( + const TDesC& aConfig, + TInt& aStackSize, + TInt& aHeapMinSize, + TInt& aHeapMaxSize ) + { + // __UHEAP_MARK; + + RFs fileServer; + RFile file; + TInt ret( KErrNone ); + + User::LeaveIfError( fileServer.Connect() ); + CleanupClosePushL( fileServer ); + + __TRACE( KInit, ( _L( "ReadParametersFromScriptFile(): Open configfile [%S]" ), &aConfig ) ); + + TParse parse; + parse.Set( aConfig, NULL, NULL ); + + User::LeaveIfError( fileServer.SetSessionPath( parse.DriveAndPath() ) ); + + User::LeaveIfError( file.Open( fileServer, aConfig, EFileRead | EFileShareAny ) ); + CleanupClosePushL( file ); + + TInt size( 0 ); + User::LeaveIfError( file.Size( size ) ); + + const TInt tmpSize = KMaxName; // 128 + TInt offset( 0 ); // Offset value to parts reading + + // Indications for tags + TBool start_tag_found( EFalse ); + TBool end_tag_found( EFalse ); + // Offset values for start and end position parsing + TInt offset_start( 0 ); + TInt offset_end( 0 ); + + /* Search is combined to section that include tags. After this create new + combined section that include second buffer data and new buffer data. + Section: 1) 1+2 + 2) 2+1 + 2) 1+2 etc. This should ensure that all data is search. + */ + + // Construct modifiable heap-based descriptor. tmp1 to CleanupStack + // This for first data buffer + HBufC8* tmp1 = HBufC8::NewLC( tmpSize ); // 128 + TPtr8 buf1 = tmp1->Des(); + + // Construct modifiable heap-based descriptor. tmp2 to CleanupStack + // This for second data buffer + HBufC8* tmp2 = HBufC8::NewLC( tmpSize ); // 128 + TPtr8 buf2 = tmp2->Des(); + + // Construct modifiable heap-based descriptor. tmp3 to CleanupStack + // This includes both first and second data buffers + HBufC* tmp3 = HBufC::NewLC( tmpSize + tmpSize ); // 256 + TPtr currentSection = tmp3->Des(); + + // Construct modifiable heap-based descriptor. tmp4 to CleanupStack + // This is for changing 8 bit to 16 bit + HBufC* tmp4 = HBufC::NewLC( tmpSize ); // 128 + TPtr to16bit = tmp4->Des(); + + ret = KErrNone; + + // Read data to buffer 1 + // tmp4, tmp3, tmp2 and tmp1 are in CleanupStack => Leave OK + // CleanupClosePushL is used to fileServer and file => Leave OK + User::LeaveIfError( file.Read( offset, buf1, tmpSize ) ); + + // For next buffer reading + offset += tmpSize; + + // Read data to buffer 2 + // tmp4, tmp3, tmp2 and tmp1 are in CleanupStack => Leave OK + // CleanupClosePushL is used to fileServer and file => Leave OK + User::LeaveIfError( file.Read( offset, buf2, tmpSize ) ); + + // 8 bit to 16. Create first combined buffer 1 and buffer 2 that + // is used for searching. + to16bit.Copy( buf1 ); + currentSection.Copy( to16bit ); + to16bit.Copy( buf2 ); + currentSection.Append( to16bit ); + + // Check if small files to be parsed(e.g. settings + one short case). + TInt bigsize( 0 ); + // Check if parsed section is smaller than 256 + if( size < ( tmpSize + tmpSize ) ) + { + bigsize = size; + } + else + { + bigsize = tmpSize + tmpSize; // 256 + } + + do + { + // Start the next buffer reading + offset += tmpSize; + + // Search the start tag + ret = currentSection.Find( KStifSettingsStartTag ); + if( ret != KErrNotFound ) + { + // Succesfully search, take the start offset + ret = file.Seek( ESeekCurrent, offset_start ); + if( ret == KErrNone ) + { + start_tag_found = ETrue; + // Current section is end so offset to beging of the + // combined section. + offset_start = ( offset_start - ( bigsize ) ); + } + } + // Search the end tag + ret = currentSection.Find( KStifSettingsEndTag ); + if( ret != KErrNotFound ) + { + // Succesfully search, take the end offset + ret = file.Seek( ESeekCurrent, offset_end ); + if( ret == KErrNone ) + { + end_tag_found = ETrue; + } + } + + // Both start and end tags are founded, start parsing sizes. + if( start_tag_found && end_tag_found ) + { + TInt length = ( offset_end - offset_start ); + + // Construct modifiable heap-based descriptor. + // setting_buf to CleanupStack + HBufC8* setting_buf = HBufC8::NewLC( length );// 8 bit for reading + TPtr8 setting8 = setting_buf->Des(); + + // Construct modifiable heap-based descriptor. + // setting_buf2 to CleanupStack + HBufC* setting_buf2 = HBufC::NewLC( length );// 16 bit for parsing + TPtr setting16 = setting_buf2->Des(); + + // Read data from the founded STIF settings sections + ret = KErrNone; + // HBufCs are in CleanupStack => Leave OK + // CleanupClosePushL is used to fileServer and file => Leave OK + User::LeaveIfError( file.Read( offset_start, setting8, length ) ); + + // Section 8 bit to 16. + setting16.Copy( setting8 ); + + // Start create parser for parsing heap and stack sizes. + // NOTE: Comments are parsed away from the section. + CStifParser* parser = NULL; + User::LeaveIfNull( parser = CStifParser::NewL( setting16, + CStifParser::ECStyleComments ) ); + CleanupStack::PushL(parser); + + CStifSectionParser* section = NULL; + User::LeaveIfNull( section = parser->SectionL( KStifSettingsStartTag, + KStifSettingsEndTag ) ); + CleanupStack::PushL(section); + TInt lineRet( KErrNone ); + TInt integer( 0 ); + + // Try to get stack size + CStifItemParser* itemLine = NULL; + TRAPD( parse_ret, itemLine = section->GetItemLineL( + KUserDefStackSize ) ); + if ( parse_ret == KErrNone && itemLine != NULL ) + { + lineRet = itemLine->GetInt( KUserDefStackSize, integer ); + if ( lineRet == KErrNone ) + { + aStackSize = integer; + } + } + delete itemLine; + itemLine = NULL; + + // Try to get minimum heap size + TRAP( parse_ret, itemLine = section->GetItemLineL( + KUserDefMinHeap ) ); + if ( parse_ret == KErrNone && itemLine != NULL ) + { + lineRet = itemLine->GetInt( KUserDefMinHeap, integer ); + if ( lineRet == KErrNone ) + { + aHeapMinSize = integer; + } + } + delete itemLine; + itemLine = NULL; + + // Try to get maximum heap size + TRAP( parse_ret, itemLine = section->GetItemLineL( + KUserDefMaxHeap ) ); + if ( parse_ret == KErrNone && itemLine != NULL ) + { + lineRet = itemLine->GetInt( KUserDefMaxHeap, integer ); + if ( lineRet == KErrNone ) + { + aHeapMaxSize = integer; + } + } + delete itemLine; + + CleanupStack::Pop(section); + CleanupStack::Pop(parser); + + CleanupStack::PopAndDestroy( setting_buf2 ); + CleanupStack::PopAndDestroy( setting_buf ); + + delete section; + delete parser; + + break; // Stop the do branch + } + + // Start to create new section for search + + // 8 bit to 16. Last buffer to first + to16bit.Copy( buf2 ); + currentSection.Copy( to16bit ); + + // Read new data to buffer 1 + ret = KErrNone; + User::LeaveIfError( file.Read( offset, buf1, tmpSize ) ); + + // 8 bit to 16. Append + to16bit.Copy( buf1 ); + currentSection.Append( to16bit ); + + // Copy first buffer data to buffer 2. This is added to first + // in section in next run + buf2.Copy( buf1 ); + + } while( offset < size ); + + CleanupStack::PopAndDestroy( tmp4 ); + CleanupStack::PopAndDestroy( tmp3 ); + CleanupStack::PopAndDestroy( tmp2 ); + CleanupStack::PopAndDestroy( tmp1 ); + + CleanupStack::PopAndDestroy( &file ); + CleanupStack::PopAndDestroy( &fileServer ); + file.Close(); + fileServer.Close(); + + //__UHEAP_MARKEND; + + return KErrNone; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: ReadParametersFromTestModule + + Description: Loads dynamically testmodule and calls SetRequirements()- + method for test module parameter handling. + + Parameters: const TDesC& aModuleName: in: Test module name + CTestModuleParam*& aTestModuleParam: inout: Object for handling + test module parameters. + + Return Values: TInt: Symbian error code. + + Errors/Exceptions: None. + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TInt CTestModuleContainer::ReadParametersFromTestModule( + const TDesC& aModuleName, + CTestModuleParam*& aTestModuleParam ) + { + __TRACE( KInit, ( _L( "ReadParametersFromTestModule() [%S]" ), &aModuleName ) ); + RLibrary testModule; + // Load the module + TPtrC dllName; + + // Remove optional index appended to module name + TFileName validModuleName; + RemoveOptionalIndex(aModuleName, validModuleName); + __TRACE(KInit, (_L( "Valid module name is [%S] (extracted from [%S])"), &validModuleName, &aModuleName)); + dllName.Set(validModuleName); + + // Loading should work with and without '.dll' extension. + TInt r = testModule.Load( dllName ); + if ( r != KErrNone ) + { + __TRACE( KError, ( CStifLogger::EError, _L("Can't initialize test module[%S], code = %d"), &dllName, r ) ); + return KErrNotFound; + } + else + { + // Print reset module name + __TRACE( KInit, ( _L("Loaded test module[%S]"), &dllName ) ); + } + + // Verify the UID + TUid KUidTestModule = TUid::Uid ( 0x101FB3E7 ); + TUidType requiredUID( KDynamicLibraryUid, KSharedLibraryUid, KUidTestModule ); + + TUidType moduleUID = testModule.Type(); + if ( moduleUID != requiredUID ) + { + // New instance can't be created + RDebug::Print( ( _L("STIF TF: Test module has invalid UID. Aborting loading!") ) ); + __TRACE ( KError, ( CStifLogger::EError, _L("Test module has invalid UID. Aborting loading!" ) ) ); + testModule.Close(); + return KErrNotSupported; + } + + CTestInterfaceFactoryTestModule libEntry = NULL; + +#if defined( __ARMCC__ ) + { + // In this environment the heap and stack feature may crash if + // test module not include a workaround for ARM RVCT(ARMv5) compiler + // error. For more information see STIF user guide. + __TRACE ( KInit, ( _L( "Workaround for ARM RVCT(ARMv5) compiler error should be included to TestModule." ) ) ); + } +#endif // #if defined(__ARMCC__) + + // Get pointer to second exported function + // Verify that there is function + //CTestInterfaceFactoryTestModule libEntry; + libEntry = (CTestInterfaceFactoryTestModule) testModule.Lookup( 2 ); + if ( libEntry == NULL ) + { + // New instance can't be created + __TRACE( KInit, (_L( "Test module is old version and has not SetRequirements() feature." ) ) ); + testModule.Close(); + return KErrNotSupported; + } + else + { + __TRACE ( KInit, ( _L("Pointer to 2st exported received"))); + } + + // Calls dynamically loaded module's second method. + __TRACE ( KVerbose, (_L("Calling 2st exported at 0x%x"), (TUint32) libEntry )); + TUint32 check = 0; + TInt ret = (*libEntry)( aTestModuleParam, check ); + if( check != KStifTestModuleParameterChanged ) + { + // Problems in def-file definitions. Test module is old wersion + // and has not SetRequirements feature. + RDebug::Print( ( _L( "STIF TF: Test module is old version and has not SetRequirements() feature." ) ) ); + __TRACE( KInit, (_L( "Test module is old version and has not SetRequirements() feature." ) ) ); + testModule.Close(); + return KErrNotSupported; + } + if( ret != KErrNone ) + { + __TRACE (KInit, (_L("ReadParametersFromTestModule; SetRequirements fails with error: %d"), ret ) ); + testModule.Close(); + return ret; + } + + libEntry = NULL; + testModule.Close(); // After close test module's pointer is not + // valid anymore. + + return KErrNone; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: GetTestModuleParams + + Description: Load test module dynamically. If loading is done succesfully + then set test module's parameters according to version. + Verify received parameters. + + Parameters: const TDesC& aModuleName: in: Test module name. + const TDesC& aConfig: in: Test case (config) file name. + TInt& aStackSize: inout: Stack size. + TInt& aHeapMinSize: inout: Heap's minimum size. + TInt& aHeapMaxSize: inout: Heap's maximum size. + + Return Values: TInt: Symbian error code. + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TInt CTestModuleContainer::GetTestModuleParams( const TDesC& aModuleName, + const TDesC& aConfig, + TInt& aStackSize, + TInt& aHeapMinSize, + TInt& aHeapMaxSize ) + { + TInt r( KErrNone ); + + // There is lower case despite what is initialization file given. + // Module name is without dll extension. + // Check is TestScripter or TestCombiner and test case (config) file + // name is given. + if( ( aModuleName.Find( KTestScripterName ) != KErrNotFound || + aModuleName == _L( "testcombiner" ) ) && aConfig != KNullDesC ) + { + TRAPD( ret, r = ReadParametersFromScriptFileL( aConfig, aStackSize, + aHeapMinSize, aHeapMaxSize ) ); + if( r != KErrNone ) + { + __TRACE( KInit, ( CStifLogger::ERed, _L( "Cannot set Test Class's stack or heap sizes, fail with error: %d" ), r ) ); + __TRACE( KInit, ( _L( "Default sizes will be use(See KTestThreadMinHeap, KTestThreadMinHeap and KStackSize)" ) ) ); + return r; + } + if( ret != KErrNone ) + { + __TRACE( KInit, ( CStifLogger::ERed, _L( "Cannot set Test Class's stack or heap sizes, leaves with error: %d" ), r ) ); + __TRACE( KInit, ( _L( "Default sizes will be use(See KTestThreadMinHeap, KTestThreadMinHeap and KStackSize)" ) ) ); + return ret; + } + } + else + { + CTestModuleParam* testModuleParam = NULL; + //--PYTHON-- begin + if(aModuleName.Find(KPythonScripter) != KErrNotFound) + { + RDebug::Print(_L("CTestModuleContainer::GetTestModuleParams reading params for PythonScripter, aModuleName=[%S]"), &aModuleName); + TName n; + n.Copy(KPythonScripter); + r = ReadParametersFromTestModule( n, testModuleParam ); + } + else + //--PYTHON-- end + r = ReadParametersFromTestModule( aModuleName, testModuleParam ); + + if( r != KErrNone ) + { + __TRACE( KInit, ( _L( "Cannot set Test Module's stack or heap sizes, fails with: %d" ), r ) ); + __TRACE( KInit, ( _L( "Default sizes will be use(See KTestThreadMinHeap, KTestThreadMinHeap and KStackSize)" ) ) ); + delete testModuleParam; + return r; + } + + if ( testModuleParam->Version() == 1 ) + { + // Casting + CTestModuleParamVer01* paramVer01 = ( CTestModuleParamVer01* ) testModuleParam; + aStackSize = paramVer01->iTestThreadStackSize; + aHeapMinSize = paramVer01->iTestThreadMinHeap; + aHeapMaxSize = paramVer01->iTestThreadMaxHeap; + } + + delete testModuleParam; + } + + // Verify that sizes are valid. If problems are notices then use default + // value + + // 1) "The panic occurs when the value of the stack size is negative." + if( aStackSize < 0 ) + { + RDebug::Print( ( _L("STIF TF: GetTestModuleParams() fails because value of the stack size is negative, default value is taken into use") ) ); + __TRACE( KInit, ( CStifLogger::ERed, _L("STIF TF: GetTestModuleParams() fails because value of the stack size is negative, default value is taken into use" ) ) ); + // Use default value + aStackSize = KStackSize; + } + + // 2) "The panic occurs if the minimum heap size specified is less + // than KMinHeapSize". + // KMinHeapSize: "Functions that require a new heap to be allocated will + // either panic, or will reset the required heap size to this value if a + // smaller heap size is specified". + if( aHeapMinSize < KMinHeapSize ) + { + RDebug::Print( _L( "STIF TF: GetTestModuleParams() fails because test module minimum heap size is less than KMinHeapSize:[%d], default value is taken into use" ), KMinHeapSize ); + __TRACE( KInit, ( CStifLogger::ERed, _L("STIF TF: GetTestModuleParams() fails because test module minimum heap size is less than KMinHeapSize:[%d], default value is taken into use"), KMinHeapSize ) ); + // Use default value(Note: This is used for now on) + aHeapMinSize = KTestThreadMinHeap; + } + + // 3) "The panic occurs if the minimum heap size specified is greater than + // the maximum size to which the heap can grow". + // Check this last ! + if( aHeapMinSize > aHeapMaxSize ) + { + RDebug::Print( ( _L("STIF TF: GetTestModuleParams() fails because the maximum heap size is specified less than minimum heap size, default values is taken into use" ) ) ); + __TRACE( KInit, ( CStifLogger::ERed, _L( "STIF TF: GetTestModuleParams() fails because the maximum heap size is specified less than minimum heap size, default values is taken into use" ) ) ); + // Use default values + aHeapMinSize = KTestThreadMinHeap; + aHeapMaxSize = KTestThreadMaxHeap; + } + + __TRACE( KInit, ( _L( "[%S] uses:" ), &aModuleName ) ); + __TRACE( KInit, ( _L( "Stack size: [%d]" ), aStackSize ) ); + __TRACE( KInit, ( _L( "Minimum heap size: [%d]" ), aHeapMinSize ) ); + __TRACE( KInit, ( _L( "Maximum heap size: [%d]" ), aHeapMaxSize ) ); + + return KErrNone; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: GetTestCaseTitleL + + Description: Gets title of currently running test case. + + Parameters: TDes& aTestCaseTitle: out: Test case title. + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestModuleContainer::GetTestCaseTitleL(TDes& aTestCaseTitle) + { + iCTestModule->GetTestCaseTitleL(iOperationIntBuffer, aTestCaseTitle); //currently run test case stored in the iOperationIntBuffer variable + } + + +/* +------------------------------------------------------------------------------- + + Class: CTestModuleContainer + + Method: GetTestModule + + Description: Gets pointer to test module + + Parameters: none + + Return Values: CTestModule* : Pointer to test module + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +CTestModule* CTestModuleContainer::GetTestModule() + { + + return iCTestModule; + } + + +/* +------------------------------------------------------------------------------- + + DESCRIPTION + + This module contains implementation of CPrintHandler class member functions. + CErrorPrintHandler listens print notifications from test thread. + +------------------------------------------------------------------------------- +*/ + +// ================= MEMBER FUNCTIONS ========================================= + + +/* +------------------------------------------------------------------------------- + + Class: CErrorPrintHandler + + Method: NewL + + Description: Constructs a new CErrorPrintHandler object. + + Parameters: CTestExecution& aExecution: in: "Parent" + + Return Values: CErrorPrintHandler*: New undertaker + + Errors/Exceptions: Leaves if memory allocation or ConstructL leaves. + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +CErrorPrintHandler* CErrorPrintHandler::NewL( CTestModuleContainer& aContainer ) + { + + CErrorPrintHandler* self = new( ELeave ) CErrorPrintHandler( aContainer ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + + } + +/* +------------------------------------------------------------------------------- + + Class: CErrorPrintHandler + + Method: ConstructL + + Description: Second level constructor. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CErrorPrintHandler::ConstructL() + { + + } + +/* +------------------------------------------------------------------------------- + + Class: CErrorPrintHandler + + Method: CErrorPrintHandler + + Description: Constructor + + Parameters: CTestModuleContainer& aExecution :in: "Parent" + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +CErrorPrintHandler::CErrorPrintHandler( CTestModuleContainer& aContainer ) : + CActive( CActive::EPriorityStandard ), + iContainer( aContainer ) + { + + CActiveScheduler::Add ( this ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CErrorPrintHandler + + Method: ~CErrorPrintHandler + + Description: Destructor. + Cancels active request. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +CErrorPrintHandler::~CErrorPrintHandler() + { + + Cancel(); + + } + +/* +------------------------------------------------------------------------------- + + Class: CErrorPrintHandler + + Method: StartL + + Description: Starts to monitor thread. + + Parameters: None + + Return Values: TInt Always KErrNone + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CErrorPrintHandler::StartL() + { + + __TRACE( KPrint, ( _L( "CErrorPrintHandler::StartL" ) ) ); + + iStatus = KRequestPending; + SetActive(); + + // Signal test thread + iContainer.iErrorPrintSem.Signal(); + + } + +/* +------------------------------------------------------------------------------- + + Class: CErrorPrintHandler + + Method: RunL + + Description: Handles thread death. + Function does: + 1 ) Stops monitoring thread + 1 ) Marks thread death + 2 ) Completes ongoing requests + 3 ) Cleans the memory + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CErrorPrintHandler::RunL() + { + + __TRACE( KPrint, ( _L( "CErrorPrintHandler::RunL [%d]" ), iStatus.Int() ) ); + + iContainer.DoErrorPrint(); + + // enable error print request + iContainer.iErrorPrintHandler->StartL(); + + } + +/* +------------------------------------------------------------------------------- + + Class: CErrorPrintHandler + + Method: DoCancel + + Description: Stops print notification listening. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ + +void CErrorPrintHandler::DoCancel() + { + + __TRACE( KPrint, ( _L( "CErrorPrintHandler::DoCancel" ) ) ); + + // Signal test thread + iContainer.iErrorPrintSem.Wait(); + + TRequestStatus* status = &iStatus; + User::RequestComplete( status, KErrCancel ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CErrorPrintHandler + + Method: RunError + + Description: Handle errors. RunL function does not leave, so one should + never come here. + + Print trace and let framework handle error( i.e to do Panic ) + + Parameters: TInt aError: :in: Error code + + Return Values: TInt Error code + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TInt CErrorPrintHandler::RunError( TInt aError ) + { + + __TRACE( KError,( _L( "CErrorPrintHandler::RunError" ) ) ); + + return aError; + + } + +/* +------------------------------------------------------------------------------- + + Class: - + + Method: CheckModuleName + + Description: Check is module TestScripter. Does parsing and returns new + module name and error codes(Needed operations when creating + server sessions to TestScripter). + + Parameters: TFileName aModuleName: in: Module name for checking. + TFileName& aNewModuleName: inout: Parsed module name. + + Return Values: KErrNone if TestScripter releated module. + KErrNotFound if not TestScripter releated module. + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TInt CheckModuleName( TFileName aModuleName, TFileName& aNewModuleName ) + { +//--PYTHON-- old code has been replaced with the new one +/* + // Check that length is greated than KTestScripterNameLength + if( aModuleName.Length() < KTestScripterNameLength ) + { + return KErrNotFound; + } + // Check is TestScripter + TPtrC check( aModuleName.Mid( 0, KTestScripterNameLength ) ); + TInt ret = check.Compare( KTestScripterName ); + if( ret == KErrNone ) + { + aNewModuleName.Copy( aModuleName.Mid( 0, KTestScripterNameLength ) ); + } + else + { + return KErrNotFound; + } + + return KErrNone; +*/ + + // Check that length is greated than KTestScripterNameLength + if( aModuleName.Length() >= KTestScripterNameLength ) + { + TPtrC check( aModuleName.Mid( 0, KTestScripterNameLength ) ); + TInt ret = check.Compare( KTestScripterName ); + if( ret == KErrNone ) + { + aNewModuleName.Copy( aModuleName.Mid( 0, KTestScripterNameLength ) ); + return KErrNone; + } + } + + // Check that length is greated than KTestScripterNameLength + if( aModuleName.Length() >= KPythonScripterLength ) + { + TPtrC check( aModuleName.Mid( 0, KPythonScripterLength ) ); + TInt ret = check.Compare( KPythonScripter ); + if( ret == KErrNone ) + { + aNewModuleName.Copy( aModuleName.Mid( 0, KPythonScripterLength ) ); + return KErrNone; + } + } + + return KErrNotFound; + } + +/* +------------------------------------------------------------------------------- + + Class: - + + Method: RemoveOptionalIndex + + Description: Remove optional index appended to module name. + If it is found (@ char) then set new module name without it. + This feature is used when iSeparateProcesses is set in + TestEngine. + + Parameters: TFileName aModuleName: in: Module name for checking. + TFileName& aNewModuleName: inout: Parsed module name. + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void RemoveOptionalIndex(const TDesC& aModuleName, TDes& aNewModuleName) + { + //Copy module name to destination buffer + aNewModuleName.Copy(aModuleName); + + //Search for @ char (it means that some index has been appended) + TInt index = aNewModuleName.Find(_L("@")); + + //Remove index form name (if found) + if(index != KErrNotFound) + { + aNewModuleName.Delete(index, aNewModuleName.Length() - index); + } + } + +// End of File