--- /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 <e32std.h>
+#include <e32svr.h>
+#include <e32uid.h>
+#include "TestEngineClient.h"
+#include <StifTestModule.h>
+#include <stifinternal/TestServerClient.h>
+#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<TTestCaseInfo>* Test cases
+
+ Errors/Exceptions: None
+
+ Status: Proposal
+
+-------------------------------------------------------------------------------
+*/
+const RPointerArray<TTestCaseInfo>* 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