diff -r 000000000000 -r a03f92240627 stif/TestServer/src/TestExecutionThread.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stif/TestServer/src/TestExecutionThread.cpp Tue Feb 02 01:57:15 2010 +0200 @@ -0,0 +1,2882 @@ +/* +* 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 +* CTestThreadContainer class implementation. These functions are +* called from the context of the test execution thread. +* +*/ + +// INCLUDE FILES +#include +#include +#include +#include +#include "ThreadLogging.h" +#include "TestEngineClient.h" +#include +#include "TestServer.h" +#include "TestThreadContainer.h" +#include "TestServerCommon.h" +#include "TestServerModuleIf.h" +#include "TestServerEvent.h" +#include "TestThreadContainerRunner.h" +#include + +// EXTERNAL DATA STRUCTURES + +// EXTERNAL FUNCTION PROTOTYPES + +// CONSTANTS + +// MACROS +#ifdef THREADLOGGER +#undef THREADLOGGER +#endif +#define THREADLOGGER iThreadLogger + +// LOCAL CONSTANTS AND MACROS + +// MODULE DATA STRUCTURES + +// LOCAL FUNCTION PROTOTYPES + +// FORWARD DECLARATIONS + +// ==================== LOCAL FUNCTIONS ======================================= + +// None + +// ================= MEMBER FUNCTIONS ========================================= + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: NewL + + Description: Returns new CTestThreadContainer instance. + + Parameters: None + + Return Values: CTestThreadContainer* New instance + + Errors/Exceptions: Function leaves if memory allocation fails or + CTestThreadContainer ConstructL leaves. + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +CTestThreadContainer* CTestThreadContainer::NewL( + CTestModuleContainer* aModuleContainer, + TThreadId aServerThreadId ) + { + + CTestThreadContainer* self = + new ( ELeave ) CTestThreadContainer( aModuleContainer ); + CleanupStack::PushL( self ); + self->ConstructL( aServerThreadId ); + CleanupStack::Pop( self ); + return self; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: ConstructL + + Description: Second level constructor. + + Parameters: None + + Return Values: CTestThreadContainer* New instance + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestThreadContainer::ConstructL( TThreadId aServerThreadId ) + { + + User::LeaveIfError( iServerThread.Open( aServerThreadId ) ); + + iErrorPrintSem.SetHandle( ModuleContainer().ErrorPrintSemHandle() ); + User::LeaveIfError( iErrorPrintSem.Duplicate( iServerThread ) ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: CTestThreadContainer + + Description: Constructor. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +CTestThreadContainer::CTestThreadContainer( + CTestModuleContainer* aModuleContainer ): + iModuleContainer( aModuleContainer ), + iCheckResourceFlags( 0 ) + { + + ModuleContainer().SetThreadContainer( this ); + + StifMacroErrorInit(); // Initialization + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: ~CTestThreadContainer + + Description: Destructor + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +CTestThreadContainer::~CTestThreadContainer() + { + + // Close mutexes + if ( iPrintMutex.Handle() != 0 ) iPrintMutex.Close(); + if ( iEventMutex.Handle() != 0 ) iEventMutex.Close(); + if ( iSndMutex.Handle() != 0 ) iSndMutex.Close(); + if ( iRcvMutex.Handle() != 0 ) iRcvMutex.Close(); + if ( iInterferenceMutex.Handle() != 0 ) iInterferenceMutex.Close(); + if ( iMeasurementMutex.Handle() != 0 ) iMeasurementMutex.Close(); + if ( iCommandMutex.Handle() != 0 ) iCommandMutex.Close(); + + // Mutex for testcomplete and cancel operations. Close duplicate mutex + if ( iTestThreadMutex.Handle() != 0 ) iTestThreadMutex.Close(); + + // Close semaphores + if ( iPrintSem.Handle() != 0 ) iPrintSem.Close(); + if ( iErrorPrintSem.Handle() != 0 ) iErrorPrintSem.Close(); + if ( iEventSem.Handle() != 0 ) iEventSem.Close(); + if ( iSndSem.Handle() != 0 ) iSndSem.Close(); + if ( iRcvSem.Handle() != 0 ) iRcvSem.Close(); + if ( iInterferenceSem.Handle() != 0 ) iInterferenceSem.Close(); + if ( iMeasurementSem.Handle() != 0 ) iMeasurementSem.Close(); + //if ( iReceiverSem.Handle() != 0 ) iReceiverSem.Close(); + if ( iCommandSem.Handle() != 0) iCommandSem.Close(); + + iServerThread.Close(); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: InitializeModule + + Description: Initialize test module. + + Function obtains pointer to the first exported function of the test module, + and calls that function to obtain an instance of CTestModuleBase derived + object. After that the "Init()"-method is called. If some operation fails, + module will be deleted and error code is returned. + + This function is a static member function, which is intented to be called + from the context of the test module thread. + + Parameters: RLibrary& aModule :in: Module to be loaded + + Return Values: TInt Error code from module + or memory allocation. + + Errors/Exceptions: None. + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TInt CTestThreadContainer::InitializeModuleInThread ( RLibrary& aModule ) + { + + __TRACEI ( KInit, ( _L("Starting test module initialization") ) ); + __TRACEI ( KInit, ( CStifLogger::EBold, _L("Module name \"%S\""), + &ModuleContainer().OperationName() ) ); + ModuleContainer().OperationText() = _L("E32DLL"); + + TFileName moduleName; + TFileName tmpBuffer; + + TInt r( KErrNone ); + TFileName newNameBuffer; + TInt check = CheckModuleName( ModuleContainer().OperationName(), newNameBuffer ); + if( check == KErrNone ) + { + // Load the module(TestScripter) + r = aModule.Load( newNameBuffer ); + } + else + { + // Load the module(Others) + RemoveOptionalIndex(ModuleContainer().OperationName(), newNameBuffer); + __TRACEI(KInit, (_L( "Valid module name is [%S] (extracted from [%S])"), &newNameBuffer, &ModuleContainer().OperationName())); + r = aModule.Load(newNameBuffer); + } + + if ( r != KErrNone ) + { + __TRACEI (KError, ( CStifLogger::EError, _L("Can't initialize test module code = %d"), r)); + + // Set error codes + ModuleContainer().OperationErrorResult() = r; + return r; + } + else + { + // Print module name + moduleName = aModule.FileName(); + __TRACEI (KInit, ( _L("Loaded test module[%S]"), &moduleName ) ); + } + + // Verify the UID + TUid KUidTestModule = TUid::Uid ( 0x101FB3E7 ); + TUidType requiredUID( KDynamicLibraryUid, KSharedLibraryUid, KUidTestModule ); + + TUidType moduleUID = aModule.Type(); + if ( moduleUID != requiredUID ) + { + // New instance can't be created + RDebug::Print( ( _L("STIF TF: Test module has invalid UID. Aborting loading!") ) ); + __TRACEI (KError, ( CStifLogger::EError, _L("Test module has invalid UID. Aborting loading!"))); + tmpBuffer.Format(_L("Module [%S] has invalid UID"), &moduleName); + ErrorPrint( 1, tmpBuffer ); + ModuleContainer().OperationErrorResult() = KErrNotSupported; + return KErrNotSupported; + } + + // Get pointer to first exported function + ModuleContainer().OperationText() = _L("1st EXPORTED function"); + CTestInterfaceFactory libEntry; + libEntry = (CTestInterfaceFactory) aModule.Lookup(1); + if ( libEntry == NULL ) + { + // New instance can't be created + __TRACEI (KError, ( CStifLogger::EError, _L("Can't initialize test module, NULL libEntry"))); + + // Set error codes + ModuleContainer().OperationErrorResult() = KErrNoMemory; + return KErrNoMemory; + } + else + { + __TRACEI ( KInit, ( _L("Pointer to 1st exported received"))); + } + + // initialize test module + __TRACEI ( KVerbose, (_L("Calling 1st exported at 0x%x"), (TUint32) libEntry )); + TRAPD ( err, iTestModule = (*libEntry)() ); + + // Handle leave from test module + if ( err != KErrNone ) + { + __TRACEI (KError, ( CStifLogger::EError, _L("Leave when calling 1st exported function, code %d"), err)); + tmpBuffer = _L("Leave from test module 1st EXPORTED function"); + ErrorPrint( 1, tmpBuffer ); + delete iTestModule; + iTestModule = NULL; + + // Set error codes + ModuleContainer().OperationErrorResult() = err; + return err; + } + else if ( iTestModule == NULL ) // Handle NULL from test module init + { + __TRACEI (KError, ( CStifLogger::EError, _L("NULL pointer received when constructing test module"))); + tmpBuffer = _L("Test module 1st EXPORTED function returned NULL"); + ErrorPrint( 1, tmpBuffer ); + delete iTestModule; + iTestModule = NULL; + + // Set error codes + ModuleContainer().OperationErrorResult() = KErrNoMemory; + return KErrNoMemory; + } + else + { + __TRACEI (KInit, (_L("Entrypoint successfully called, test module instance at 0x%x"), (TUint32)iTestModule ) ); + } + + // Verify version number. + ModuleContainer().OperationText() = _L("Version"); + TVersion moduleAPIVersion(0,0,0); + TVersion myOldAPIVersion( KOldTestModuleAPIMajor, KOldTestModuleAPIMinor, KOldTestModuleAPIBuild ); + TVersion myAPIVersion( KTestModuleAPIMajor, KTestModuleAPIMinor, KTestModuleAPIBuild ); + TRAP ( err, moduleAPIVersion = iTestModule->Version() ); + + if ( err != KErrNone || (( myOldAPIVersion.iMajor != moduleAPIVersion.iMajor || + myOldAPIVersion.iMinor != moduleAPIVersion.iMinor ) + && + ( myAPIVersion.iMajor != moduleAPIVersion.iMajor || + myAPIVersion.iMinor != moduleAPIVersion.iMinor )) + ) + { + tmpBuffer = moduleAPIVersion.Name(); + __TRACEI (KError, ( CStifLogger::EError, _L("Incorrect test module version. Module version %S"), &tmpBuffer ) ); + tmpBuffer = myOldAPIVersion.Name(); + __TRACEI (KError, ( CStifLogger::EError, _L("Required version %S"), &tmpBuffer ) ); + + tmpBuffer.Format(_L("Invalid version in [%S]"), &moduleName ); + ErrorPrint( 1, tmpBuffer ); + + // Set error codes + ModuleContainer().OperationErrorResult() = KErrNotSupported; + return KErrNotSupported; + } + + ModuleContainer().OperationText() = _L("InitL"); + // Initialize test module + TInt initResult = KErrNone; + TRAP ( err, + CTestModuleIf::NewL( NULL, iTestModule ); + TFileName tmp = ModuleContainer().TestModuleIniFile(); + initResult = iTestModule->InitL( tmp, ModuleContainer().OperationIntBuffer() ); + ); + + // Handle leave from test module + if ( err != KErrNone ) + { + __TRACEI (KError, ( CStifLogger::EError, _L("Leave when initializing test module code %d"), err)); + tmpBuffer = _L("Leave from test module InitL"); + ErrorPrint( 1, tmpBuffer ); + ModuleContainer().OperationText() = _L("DESTRUCTOR"); + delete iTestModule; + iTestModule = NULL; + ModuleContainer().OperationText() = _L(""); + + // Set error codes + ModuleContainer().OperationErrorResult() = err; + return err; + } + else if ( initResult != KErrNone ) + { // Handle failed initialisation of test module + __TRACEI (KError, ( CStifLogger::EError, _L("Can't initialize test module, code %d"), initResult)); + ModuleContainer().OperationText() = _L("DESTRUCTOR"); + delete iTestModule; + iTestModule = NULL; + ModuleContainer().OperationText() = _L(""); + + // Set error code + ModuleContainer().ModuleResult() = initResult; + return initResult; + } + ModuleContainer().OperationText() = _L(""); + + __TRACEI (KInit, ( CStifLogger::EBold, _L("Test module initialization done"))); + + return KErrNone; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: EnumerateInThread + + Description: Enumerate test cases. Function calls GetTestCases method + from the test module. + + This function is a static member function, which is intented to be called + from the context of the test module thread. + + Parameters: None + + Return Values: TInt Error code. + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TInt CTestThreadContainer::EnumerateInThread() + { + + TInt err = KErrNone; + __TRACEI ( KInit, ( CStifLogger::EBold, _L("Calling GetTestCasesL") ) ); + + if ( iCases == NULL ) + { + iCases = new RPointerArray; + if ( iCases == NULL ) + { + ModuleContainer().OperationErrorResult() = KErrNoMemory; + __TRACEI ( KError, ( _L("Can't create pointer array for cases") ) ); + return ModuleContainer().OperationErrorResult(); + } + } + + // Thread ID logging(For error situations) !!!!! ---------- + /* + RThread t; + RDebug::Print(_L("XXXXXXXXXXXXXXXXXXXXXX CurrentThread=[%d]"), t.Id() ); + t.Open( t.Id() ); + RDebug::Print(_L("XXXXXXXXXXXXXXXXXXXXXX Real id=[%d]"), t.Id() ); + t.Close(); + */ + // -------------------------------------------------------- + + ModuleContainer().OperationText() = _L("GetTestCasesL"); + TRAPD (r, err = iTestModule->GetTestCasesL( + ModuleContainer().OperationName(), + *iCases ) ); + ModuleContainer().OperationText() = _L(""); + + // Leave + if ( r != KErrNone ) + { + __TRACEI ( KError, ( CStifLogger::ERed, _L("GetTestCasesL leave code %d"), r ) ); + TName tmpBuffer = _L("Leave from test module GetTestCasesL"); + ErrorPrint( 1, tmpBuffer ); + FreeEnumerationDataInThread(); + + ModuleContainer().OperationErrorResult() = r; + return r; + } + + // Error originating from test module + if ( err != KErrNone ) + { + __TRACEI ( KError, ( CStifLogger::ERed, _L("GetTestCasesL returned error %d"), err ) ); + FreeEnumerationDataInThread(); + + ModuleContainer().ModuleResult() = err; + return err; + } + + __TRACEI ( KInit, ( _L("GetTestCasesL successfully called") ) ); + + // All ok. + return KErrNone; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: FreeEnumerationDataInThread + + Description: Frees the enumeration data. This function is called, when + the enumeration data is read from execution thread heap to server thread + heap. If cases have not been enumerated function does nothing. + + Function is intented to be called from the context of the test module thread. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestThreadContainer::FreeEnumerationDataInThread() + { + + __TRACEI ( KInit, ( _L("Freeing test case array") ) ); + + if ( iCases ) + { + iCases->ResetAndDestroy(); + delete iCases; + iCases = NULL; + } + + __TRACEI ( KInit, ( _L("Freeing test case array done") ) ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: ExecuteTestCaseInThread + + Description: Execute test case. This function calls either RunTestCase or + ExecuteOOMTestCase to execute and report the results. + + This function is a static member function, which is intented to be called + from the context of the test module thread. + + Parameters: None + + Return Values: TInt: Error code + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +TInt CTestThreadContainer::ExecuteTestCaseInThread() + { + TVersion moduleAPIVersion; + moduleAPIVersion = iTestModule->Version(); + + __TRACEI ( KInit, + ( CStifLogger::EBold, _L("Executing test case file=[%S] case=%d"), + &ModuleContainer().OperationName(), + ModuleContainer().OperationIntBuffer() ) ); + + TInt r = KErrNone; + + // Thread handle + RThread thisRt; + r = DuplicateMutexHandles( thisRt ); + + // Result from RunTestCase + TTestResult caseResult; + + // Execution result from RunTestCase + TInt err = KErrNone; + + // Fill in initial values + TestExecution().FullResult().iCaseExecutionResultType = + TFullTestResult::ECaseExecuted; + TestExecution().FullResult().iCaseExecutionResultCode = KErrNone; + TestExecution().FullResult().iStartTime.HomeTime(); + TestExecution().TestThreadFailure() = CTestExecution::ETestThreadOk; + + // Set handle to test execution + TRAP( r, CTestModuleIf::NewL( this, + iTestModule ) ); + + ModuleContainer().OperationText() =_L("RunTestCaseL"); + + // Do resource checks before starting test case + iCheckResourceFlags = 0; + + TInt tmp; + TInt threadHandleCountBeforeTest; + + // Request count check + TInt requestCountBeforeTest = thisRt.RequestCount(); + // Handle count check, not checking process handles + thisRt.HandleCount( tmp, threadHandleCountBeforeTest ); + + // If handle ok, then execute test + if( r == KErrNone ) + { + TInt testCaseNumber = ModuleContainer().OperationIntBuffer(); + + // Do the test + __TRACEI ( KInit, ( _L("About to call RunTestCaseL. If nothing in log \ + after line \"Calling RunTestCaseL\", check testserver log file.") ) ); + + TInt firstMemFailure = 0; + TInt lastMemFailure = 0; + // Store the OOM test type + CTestModuleBase::TOOMFailureType failureType; + + // Check if the current test case is supposed to be run using OOM + if( iTestModule->OOMTestQueryL( ModuleContainer().OperationName(), + testCaseNumber, + failureType, + firstMemFailure, + lastMemFailure ) ) + { + // Run the test case in OOM conditions + r = ExecuteOOMTestCase( testCaseNumber, + firstMemFailure, + lastMemFailure, + err, + caseResult ); + } + else + { + // Run the test case the old way, without OOM testing + __TRACEI ( KInit, ( _L("Calling RunTestCaseL - \ + OOM condition is not set") ) ); + TRAP( r, err = iTestModule->RunTestCaseL( + testCaseNumber, + ModuleContainer().OperationName(), + caseResult ) ); + } + } + + // Do resource checks after test case execution + // Handle count check + TInt threadHandleCountAfterTest; + thisRt.HandleCount( tmp, threadHandleCountAfterTest ); + // Request count check + TInt requestCountAfterTest = thisRt.RequestCount(); + + ModuleContainer().OperationText() =_L(""); + + // Store end time + TestExecution().FullResult().iEndTime.HomeTime(); + // Remove handle to testexecution + TRAPD( rr, CTestModuleIf::NewL( NULL, iTestModule ) ); + + + if ( rr != KErrNone ) + { + __TRACEI ( KError, ( _L("Memory low in executionthread.") ) ); + // Do not actually handle error + } + + // Report test result. Parts of this will be overwritten if error + // is detected + TestExecution().FullResult().iTestResult = caseResult; + + // Get target exit reasons + CTestModuleIf::TExitReason allowedExitReason; + TInt allowedExitCode = KErrNone; + ExitReason( allowedExitReason, allowedExitCode ); + + TBool returnLeakCheckFail = EFalse; + + // Check are STIF macros used + if( iTestMacroInfo.iIndication ) + { + // STIF macros are used. Set description info, test case to + // ECaseExecuted state and case execution result code to KErrNone + // to get test case to failed category. + TName tmpResultDes; + __TRACEI ( KError, ( CStifLogger::ERed, _L("Leave from RunTestCaseL(STIF TF's macro is used)" ) ) ); + // Set result description + tmpResultDes.Copy( _L( "FILE[") ); + tmpResultDes.Append( iTestMacroInfo.iFileDes ); + tmpResultDes.Append( _L( "] FUNCTION[" ) ); + tmpResultDes.Append( iTestMacroInfo.iFunctionDes ); + tmpResultDes.Append( _L( "] LINE[" ) ); + tmpResultDes.AppendNum( iTestMacroInfo.iLine ); + tmpResultDes.Append( _L( "]" ) ); + // Other result information + TestExecution().FullResult().iTestResult.iResult = + iTestMacroInfo.iReceivedError; + TestExecution().FullResult().iTestResult.iResultDes = tmpResultDes; + TestExecution().FullResult().iCaseExecutionResultType = + TFullTestResult::ECaseExecuted; + // Set category to failed cases + TestExecution().FullResult().iCaseExecutionResultCode = KErrNone; + StifMacroErrorInit(); // Initialization back to default + } + else if( r != KErrNone ) + { // Case has left, overwrite normal result description string + __TRACEI ( KError, ( CStifLogger::ERed, _L("Leave from RunTestCaseL, code %d"), r ) ); + // Set result description + TName tmpResultDes = _L("Leave during case:"); + // Check if there was already some description passed to result object + if(caseResult.iResultDes.Length() > 0) + { + tmpResultDes.Format(_L("Leave during case [%S]:"), &caseResult.iResultDes); + if(tmpResultDes.Length() > KStifMaxResultDes) + { + tmpResultDes.SetLength(KStifMaxResultDes); + } + } + // Other result information + TestExecution().FullResult().iTestResult.iResult = KErrGeneral; + TestExecution().FullResult().iTestResult.iResultDes = tmpResultDes; + TestExecution().FullResult().iCaseExecutionResultType = + TFullTestResult::ECaseLeave; + TestExecution().FullResult().iCaseExecutionResultCode = r; + } + else if ( err != KErrNone ) + { + // Case has returned error (e.g. case not found ) + __TRACEI ( KError, ( CStifLogger::ERed, _L("RunTestCaseL returned error %d"), err ) ); + TestExecution().FullResult().iCaseExecutionResultType = + TFullTestResult::ECaseErrorFromModule; + TestExecution().FullResult().iCaseExecutionResultCode = err; + } + else if ( allowedExitReason != CTestModuleIf::ENormal ) + { + // Test is failed, because it should end to panic or exception. + __TRACEI ( KInit, ( _L("Case ended normally even if it should end to panic/exception") ) ); + TestExecution().FullResult().iTestResult.iResult = KErrGeneral; + TestExecution().FullResult().iTestResult.iResultDes = + _L("Case did not ended to panic/exception"); + } + // If test case is passed, check memory leak, handles etc... + else if( caseResult.iResult == KErrNone ) + { + returnLeakCheckFail = ETrue; + } + + // Test case leak checks + // In EKA2 heap size cannot be measured because THeapWalk is no longer supported + LeakChecksForTestCase( returnLeakCheckFail, + threadHandleCountBeforeTest, + threadHandleCountAfterTest, + requestCountBeforeTest, + requestCountAfterTest ); + + // Close execution specific handles + + iPrintMutex.Close(); + iEventMutex.Close(); + iSndMutex.Close(); + iRcvMutex.Close(); + iInterferenceMutex.Close(); + iMeasurementMutex.Close(); + iCommandMutex.Close(); + + // The Wait operation is performed to let the message from TestServer + // to TestEngine achieve TestEngine or TestCombiner. + iCommandSem.Wait(); + + // Note: iTestThreadMutex.iClose() mutex will be used later, close in destructor. + + iPrintSem.Close(); + iEventSem.Close(); + iSndSem.Close(); + iRcvSem.Close(); + iInterferenceSem.Close(); + iMeasurementSem.Close(); + iCommandSem.Close(); + + // Close thread handle + thisRt.Close(); + + __TRACEI ( KVerbose, ( _L("ExecuteTestCase out") ) ); + + // continues from CTestModuleContainer::RunL + + return KErrNone; + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: DuplicateMutexHandles + + Description: Duplicates mutex handles + + Parameters: None + + Return Values: TInt + + Errors/Exceptions: Panic if duplication fails + + Status: Approved + +------------------------------------------------------------------------------- +*/ +TInt CTestThreadContainer::DuplicateMutexHandles( RThread& aThread ) + { + // For duplicating mutexes + iPrintMutex.SetHandle( TestExecution().PrintMutexHandle() ); + iEventMutex.SetHandle( TestExecution().EventMutexHandle() ); + iSndMutex.SetHandle( TestExecution().SndMutexHandle() ); + iRcvMutex.SetHandle( TestExecution().RcvMutexHandle() ); + iInterferenceMutex.SetHandle( TestExecution().InterferenceMutexHandle() ); + iMeasurementMutex.SetHandle( TestExecution().MeasurementMutexHandle() ); + iCommandMutex.SetHandle(TestExecution().CommandMutexHandle()); + + // Mutex for testcomplete and cancel operations. For duplicating mutex + iTestThreadMutex.SetHandle( TestExecution().TestThreadMutexHandle() ); + + // For duplicating semaphores + iPrintSem.SetHandle( TestExecution().PrintSemHandle() ); + iEventSem.SetHandle( TestExecution().EventSemHandle() ); + iSndSem.SetHandle( TestExecution().SndSemHandle() ); + iRcvSem.SetHandle( TestExecution().RcvSemHandle() ); + iInterferenceSem.SetHandle( TestExecution().InterferenceSemHandle() ); + iMeasurementSem.SetHandle( TestExecution().MeasurementSemHandle() ); + iCommandSem.SetHandle(TestExecution().CommandSemHandle()); + + // Store thread id for later use + TestExecution().SetTestThread( aThread.Id() ); + + // Duplicate handles from server thread + TRAPD( r, + User::LeaveIfError( iPrintMutex.Duplicate( iServerThread ) ); + User::LeaveIfError( iEventMutex.Duplicate( iServerThread ) ); + User::LeaveIfError( iSndMutex.Duplicate( iServerThread ) ); + User::LeaveIfError( iRcvMutex.Duplicate( iServerThread ) ); + User::LeaveIfError( iInterferenceMutex.Duplicate( iServerThread ) ); + User::LeaveIfError( iMeasurementMutex.Duplicate( iServerThread ) ); + User::LeaveIfError( iCommandMutex.Duplicate( iServerThread ) ); + + User::LeaveIfError( iTestThreadMutex.Duplicate( iServerThread ) ); + + User::LeaveIfError( iPrintSem.Duplicate( iServerThread ) ); + User::LeaveIfError( iEventSem.Duplicate( iServerThread ) ); + User::LeaveIfError( iSndSem.Duplicate( iServerThread ) ); + User::LeaveIfError( iRcvSem.Duplicate( iServerThread ) ); + User::LeaveIfError( iInterferenceSem.Duplicate( iServerThread ) ); + User::LeaveIfError( iMeasurementSem.Duplicate( iServerThread ) ); + User::LeaveIfError( iCommandSem.Duplicate( iServerThread ) ); + ); + + // Raise panic if duplications failed + if( r != KErrNone ) + { + Panic( EDuplicateFail ); + } + + // Return the result, no error occurred + return KErrNone; + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: ExecuteOOMTestCase + + Description: Executes OOM test case + + Parameters: None + + Return Values: TInt + + Errors/Exceptions: Panic if EOOMDisableLeakChecks is not set and test case + leaks memory. + + Status: Approved + +------------------------------------------------------------------------------- +*/ +TInt CTestThreadContainer::ExecuteOOMTestCase( TInt aTestCaseNumber, + TInt aFirst, + TInt aLast, + TInt& aResult, + TTestResult& caseResult ) + { + TBool OOMwarning = EFalse; + __TRACEI ( KInit, ( _L("CTestThreadContainer::ExecuteOOMTestCase") ) ); + __TRACEI ( KInit, ( _L("Executing test case #%d using OOM"), aTestCaseNumber ) ); + + // OOM test environment initialization + TRAPD( r, iTestModule->OOMTestInitializeL( + ModuleContainer().OperationName(), + aTestCaseNumber ); ); + + for( TInt i=aFirst; iRunTestCaseL( + aTestCaseNumber, + ModuleContainer().OperationName(), + caseResult ) ); + + // Raise panic if test case leaks memory and EOOMDisableLeakChecks is not + // set + if( !( iCheckResourceFlags & CTestModuleIf::EOOMDisableLeakChecks ) ) + { + User::__DbgMarkEnd( RHeap::EUser, 0 ); + } + + // If no error occurred, fake a memory error to make sure that this is + // the last test. If this last allocation goes wrong, it proves that + // either the FAILNEXT() macro has reached its limit or that somewhere + // in the code some object TRAPped the OOM exception and did not leave. + if( ( r != KErrNoMemory ) && ( aResult != KErrNoMemory ) + && ( caseResult.iResult != KErrNoMemory ) ) + { + TInt* dummy = new TInt; + OOMwarning = ( dummy != NULL ); + delete dummy; + } + + // Cancel the simulated heap allocation failure + User::__DbgSetAllocFail( RHeap::EUser, RHeap::ENone, 1 ); + + if( ( r != KErrNoMemory ) && !OOMwarning && ( aResult != KErrNoMemory ) + && ( caseResult.iResult != KErrNoMemory ) ) + { + // If we get here test was executed properly (= no memory error + // and no warning) + break; + } + + if( OOMwarning ) + { + // It is possible that during testing some components TRAP the OOM + // exception and continue to run (do not leave) or they return an + // error other than KErrNoMemory. These situations are making the + // OOM testing really difficult, so they should be detected and + // make the tester aware. + + // Since each test case might have a specific oppinion on handling + // this situation, it is left up to the tester to handle it by + // implementing the OOMHandleWarningL method. STIF will log a + // warning and call OOMHandleWarningL method. + + // Print the OOM error message + __TRACEI ( KInit, ( _L("Possible trapped or non-leaving allocation in test case #%d"), i ) ); + + iTestModule->OOMHandleWarningL( ModuleContainer().OperationName(), aTestCaseNumber, i ); + + // Clear the warning flag + OOMwarning = EFalse; + } + } + + // OOM test environment finalization + __TRACEI ( KInit, ( _L("Calling OOMTestFinalizeL") ) ); + TRAPD( fres, iTestModule->OOMTestFinalizeL( + ModuleContainer().OperationName(), + aTestCaseNumber ); ); + // Check the result + if( fres != KErrNone ) + { + __TRACEI ( KInit, ( _L("OOMTestFinalizeL execution failed with error %d"), fres ) ); + } + + return r; + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: LeakChecksForTestCase + + Description: Checks test case for memory, handle and request leaks + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestThreadContainer::LeakChecksForTestCase( TBool aReturnLeakCheckFail, + TInt aThreadHandleCountBeforeTest, + TInt aThreadHandleCountAfterTest, + TInt aRequestCountBeforeTest, + TInt aRequestCountAfterTest ) + + { + __TRACEI ( KInit, ( _L("CTestThreadContainer::LeakChecksForTestCase") ) ); + + // Note: Request leaks detection is disabled in UI components testing + if( !( iCheckResourceFlags & CTestModuleIf::ETestLeaksRequests ) && + ( aRequestCountBeforeTest != aRequestCountAfterTest ) && + ( !iModuleContainer->GetTestModule()->GetTestServer()->UiTesting())) + { + // Test is failed, because it should end to panic or exception. + __TRACEI ( KError, ( CStifLogger::ERed, + _L("Asynchronous request leak from test module. Request count before:[%d] and after:[%d] test."), + aRequestCountBeforeTest, aRequestCountAfterTest ) ); + + // Set failure status + TestExecution().TestThreadFailure() |= CTestExecution::ETestRequestLeak; + if( aReturnLeakCheckFail ) + { + aReturnLeakCheckFail = EFalse; // return first fail +#ifndef STIF_DISABLE_LEAK_CHECK + // Testcase set to failed when request leak occurred + TestExecution().FullResult().iTestResult.iResult = KErrGeneral; +#endif + TestExecution().FullResult().iTestResult.iResultDes = + _L("Asynchronous request leak from testmodule"); + TestExecution().FullResult().iTestResult.iResultDes. + AppendNum( aRequestCountAfterTest ); + } + } + // Note: Handle leaks detection is disabled in UI components testing + if( !( iCheckResourceFlags & CTestModuleIf::ETestLeaksHandles ) && + ( aThreadHandleCountBeforeTest != aThreadHandleCountAfterTest ) && + ( !iModuleContainer->GetTestModule()->GetTestServer()->UiTesting()) ) + { + // Test is failed, because it should end to panic or exception. + __TRACEI ( KError, ( CStifLogger::ERed, + _L("Thread handle leak from test module. Handle count before:[%d] and after:[%d] test."), + aThreadHandleCountBeforeTest, aThreadHandleCountAfterTest ) ); + + // Set failure status + TestExecution().TestThreadFailure() |= CTestExecution::ETestHandleLeak; + if( aReturnLeakCheckFail ) + { + aReturnLeakCheckFail = EFalse; // return first fail +#ifndef STIF_DISABLE_LEAK_CHECK + // Testcase is set to failed yet when handle leak occurred + TestExecution().FullResult().iTestResult.iResult = KErrGeneral; +#endif + TestExecution().FullResult().iTestResult.iResultDes = + _L("Thread handle leak from testmodule"); + TestExecution().FullResult().iTestResult.iResultDes. + AppendNum( aRequestCountAfterTest ); + } + } + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: DeleteTestModule + + Description: Deletes a test module + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestThreadContainer::DeleteTestModule() + { + + __TRACEI ( KInit, ( _L("Deleting test module instance at 0x%x"), iTestModule ) ); + // Delete the test module + ModuleContainer().OperationText() = _L("DESTRUCTOR"); + TRAPD( r, delete iTestModule ); + ModuleContainer().OperationText() = _L(""); + iTestModule = NULL; + + if ( r ) + { + __TRACEI ( KError, ( _L("Leave when deleting test module, code %d"), r ) ); + } + + __TRACEI ( KInit, ( _L("Test module instance deleted") ) ); + + } + + /* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: TestCases + + Description: Returns constant pointer to test case array + + Parameters: None + + Return Values: const RPointerArray* Test cases + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +const RPointerArray* CTestThreadContainer::TestCases() const + { + + return iCases; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: ErrorPrint + + Description: Prints error + + Parameters: const TInt aPriority :in: Priority + TPtrC aError: in: Error + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestThreadContainer::ErrorPrint( const TInt aPriority, + TPtrC aError ) + { + + // Get access to print stuff + iErrorPrintSem.Wait(); + + // Get status variable from server + TRequestStatus* status = + ModuleContainer().GetRequest( CTestModuleContainer::ERqErrorPrint ); + + if( status == NULL ) + { + Panic( ENullRequest ); + return; + } + + // Fill in progress + TErrorNotification& progress = ModuleContainer().ErrorNotification(); + progress.iPriority = aPriority; + progress.iText = aError; + + // Complete action to server + iServerThread.RequestComplete( status, KErrNone ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: DoNotifyPrint + + Description: If print notification available, notification is copied to + client memory space and request is completed. + Else new print queue item is created and appended to print + queue. If queue is full or memory can't be allocated, + then message will be discarded. + + Parameters: const TInt aPriority : :in: Priority + const TStifInfoName& aDes :in: Description + const TName& aBuffer :in: Value + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestThreadContainer::DoNotifyPrint( const TInt aPriority, + const TStifInfoName& aDes, + const TName& aBuffer ) + { + // Get access to print stuff + iPrintSem.Wait(); + + iPrintMutex.Wait(); // Take mutex to get access to server thread. + // Between Wait and Signal is critical section and this + // verifies that iPrintSem and RequestComplete is done + // successfully. + + // Get status variable from server + TRequestStatus* status = + TestExecution().GetRq( CTestExecution::ERqPrint ); + + if( status == NULL ) + { + iPrintMutex.Signal(); + Panic( ENullRequest ); + return; + } + + if( *status != KRequestPending ) + { + // CPrintHandler::DoCancel called before getting here, just return + iPrintMutex.Signal(); + return; + } + // Fill in progress + TTestProgress& progress = TestExecution().TestProgress(); + progress.iPosition = aPriority; + progress.iDescription = aDes; + progress.iText = aBuffer; + + // Complete action to server + iServerThread.RequestComplete( status, KErrNone ); + + iPrintMutex.Signal(); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: DoNotifyEvent + + Description: Forward event request. + + Parameters: const TEventIf: in: Event definition + TRequestStatus* aStatus: in: TRequestStatus to complete + + Return Values: None + + Errors/Exceptions: Panics if event array can't be created + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TInt CTestThreadContainer::DoNotifyEvent( TEventIf& aEvent, + TRequestStatus* aStatus ) + { + + TInt ret = KErrNone; + + // Send event req + SetEventReq( TEventDef::EEventCmd, aEvent, aStatus ); + + if( aStatus == NULL ) + { + // Synchronous Event command used -> + // Block until completed with ECmdComplete from NotifyEvent + // Cannot be done before ERelEvent, + // because Unset may be blocking the server + User::WaitForRequest( iReqStatus ); + + User::After( 1 );// workaround found for STIF 347 + + // Return result from engine + ret = iReqStatus.Int(); + + } + + return ret; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: CancelEvent + + Description: Cancels pending event request. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestThreadContainer::CancelEvent( TEventIf& aEvent, + TRequestStatus* aStatus ) + { + + __TRACEI( KMessage, ( _L( "CTestThreadContainer::CancelEvent(%d): %S [%p]" ), + aEvent.Type(), &aEvent.Name(), aStatus ) ); + + // Send event req + SetEventReq( TEventDef::EEventCmdCancel, aEvent, aStatus ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: SetExitReason + + Description: Set exit reason + + Parameters: const TExitReason aExitReason in: Exit reason + const TInt aExitCode in: Exit code + + Return Values: None + + Errors/Exceptions: None + + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestThreadContainer::SetExitReason( const CTestModuleIf::TExitReason aExitReason, + const TInt aExitCode ) + { + + TInt exitCode = aExitCode; + + if( ( aExitReason == CTestModuleIf::ENormal ) && + ( aExitCode != KErrNone ) ) + { + __TRACEI( KError, + ( _L( "SetExitReason: Exit type normal uses always exit code 0 (given %d is not used)" ), + exitCode ) ); + exitCode = KErrNone; + } + + ModuleContainer().AllowedExitReason() = aExitReason; + ModuleContainer().AllowedExitCode() = exitCode; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: SetBehavior + + Description: Set test behaviour. + + Parameters: const CTestModuleIf::TTestBehavior aType: in: behaviour type + TAny* aPtr: in: data + + Return Values: Symbian OS error code. + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TInt CTestThreadContainer::SetBehavior( const CTestModuleIf::TTestBehavior aType, + TAny* /*aPtr*/ ) + { + + if( aType & CTestModuleIf::ETestLeaksMem ) + { + iCheckResourceFlags |= CTestModuleIf::ETestLeaksMem; + } + if( aType & CTestModuleIf::ETestLeaksRequests ) + { + iCheckResourceFlags |= CTestModuleIf::ETestLeaksRequests; + } + if( aType & CTestModuleIf::ETestLeaksHandles ) + { + iCheckResourceFlags |= CTestModuleIf::ETestLeaksHandles; + } + // For OOM testing + if( aType & CTestModuleIf::EOOMDisableLeakChecks ) + { + iCheckResourceFlags |= CTestModuleIf::EOOMDisableLeakChecks; + } + if( !( aType & iCheckResourceFlags ) ) + { + return KErrNotFound; + } + + return KErrNone; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: ExitReason + + Description: Gets exit reason + + Parameters: TExitReason& aExitReason out: Exit reason + TInt& aExitCode out: Exit code + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestThreadContainer::ExitReason( CTestModuleIf::TExitReason& aExitReason, + TInt& aExitCode ) + { + + aExitReason = ModuleContainer().AllowedExitReason(); + aExitCode = ModuleContainer().AllowedExitCode(); + + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: SetEventReq + + Description: Sets asynchronous event request. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestThreadContainer::SetEventReq( TEventDef::TEventCmdType aType, + TEventIf& aEvent, + TRequestStatus* aStatus ) + { + // Get access to event stuff + iEventSem.Wait(); + + iEventMutex.Wait(); // Take mutex to get access to server thread. + // Between Wait and Signal is critical section and this + // verifies that iPrintSem and RequestComplete is done + // successfully. + + // Get status variable from server + TRequestStatus* status = + TestExecution().GetRq( CTestExecution::ERqEvent ); + + if( status == NULL ) + { + iEventMutex.Signal(); + Panic( ENullRequest ); + return; + } + if( *status != KRequestPending ) + { + // CEventHandler::DoCancel called before getting here, just return + iEventMutex.Signal(); + return; + } + + // Fill in event on server thread + TEventDef& event = TestExecution().EventDef(); + event.iType = aType; + event.iEvent.Copy( aEvent ); + + if( aStatus ) + { + // Store TRequestStatus which is completed when next EEnable comes in + event.iStatus = aStatus; + } + else + { + iReqStatus = KRequestPending; + event.iStatus = &iReqStatus; + } + + __TRACEI( KMessage ,(_L("SetReq Stat %d, %x"), this, + aStatus )); + + // Complete action to server + iServerThread.RequestComplete( status, KErrNone ); + + iEventMutex.Signal(); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: DoRemoteReceive + + Description: Enable remote receive and send. + + Parameters: + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestThreadContainer::DoRemoteReceive( TStifCommand aRemoteCommand, + TParams aParams, + TInt aLen, + TRequestStatus& aStatus ) + { + + switch( aRemoteCommand ) + { + case EStifCmdSend: // "Send" + case EStifCmdReboot: // "Send" + case EStifCmdStoreState: // "Send" + case EStifCmdGetStoredState: // "Receive, this must be done with two phase" + case EStifCmdMeasurement: // "Receive" + { + __TRACEI( KMessage, ( _L( "CTestThreadContainer::DoRemoteReceive Wait SndSem" ) ) ); + + // Get access to sender + // (for receive, used for securing access to shared memory) + iSndSem.Wait(); + + iSndMutex.Wait(); // Take mutex to get access to server thread. + // Between Wait and Signal is critical section and this + // verifies that iPrintSem and RequestComplete is done + // successfully. + + // Get status variable from server + TRequestStatus* status = + TestExecution().GetRq( CTestExecution::ERqSnd ); + + if( status == NULL ) + { + iSndMutex.Signal(); + Panic( ENullRequest ); + return; + } + if( *status != KRequestPending ) + { + // CSndHandler::DoCancel called before getting here, just return + iSndMutex.Signal(); + return; + } + + // Fill in information + TCmdDef& aDef = TestExecution().SndInfo(); + aDef.iCommand = aRemoteCommand; + aDef.iParam = aParams; + aDef.iLen = aLen; + aDef.iStatus = &aStatus; + + __TRACEI( KMessage , + (_L("CTestThreadContainer::DoRemoteReceive Complete request 0x%x"), + status )); + // Complete action to server + iServerThread.RequestComplete( status, KErrNone ); + + iSndMutex.Signal(); + } + break; + case EStifCmdReceive: // "Receive" + { + __TRACEI( KMessage, ( _L( "CTestThreadContainer::DoRemoteReceive Wait RcvSem" ) ) ); + + // Get access to receive handler + iRcvSem.Wait(); + + iRcvMutex.Wait(); // Take mutex to get access to server thread. + // Between Wait and Signal is critical section and this + // verifies that iPrintSem and RequestComplete is done + // successfully. + + // Get status variable from server + TRequestStatus* status = + TestExecution().GetRq( CTestExecution::ERqRcv ); + + if( status == NULL ) + { + iRcvMutex.Signal(); + Panic( ENullRequest ); + return; + } + if( *status != KRequestPending ) + { + // CRcvHandler::DoCancel called before getting here, just return + iRcvMutex.Signal(); + return; + } + + // Fill in information + TCmdDef& aDef = TestExecution().RcvInfo(); + aDef.iCommand = aRemoteCommand; + aDef.iParam = aParams; + aDef.iLen = aLen; + aDef.iStatus = &aStatus; + + __TRACEI( KMessage , + (_L("CTestThreadContainer::DoRemoteReceive Complete request 0x%x"), + status )); + __TRACEI( KMessage, ( _L( "CTestThreadContainer::DoRemoteReceive signal RcvSem" ) ) ); + //iReceiverSem.Signal(); + + // Complete action to server + iServerThread.RequestComplete( status, KErrNone ); + + iRcvMutex.Signal(); + + } + break; + + default: + TRequestStatus* rs = &aStatus; + User::RequestComplete( rs, KErrNotSupported ); + break; + } + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: DoRemoteReceiveCancel + + Description: Cancel DoRemoteReceive + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TInt CTestThreadContainer::DoRemoteReceiveCancel() + { + + // Get access to receive handler + iRcvSem.Wait(); + + iRcvMutex.Wait(); // Take mutex to get access to server thread. + // Between Wait and Signal is critical section and this + // verifies that iPrintSem and RequestComplete is done + // successfully. + + // Get status variable from server + TRequestStatus* status = + TestExecution().GetRq( CTestExecution::ERqRcv ); + + if( status == NULL ) + { + iRcvMutex.Signal(); + return KErrNotFound; + } + + if( *status != KRequestPending ) + { + // CRcvHandler::DoCancel called before getting here, just return + iRcvMutex.Signal(); + Panic( ENullRequest ); + return KErrNone; + } + + // Fill in information + TCmdDef& aDef = TestExecution().RcvInfo(); + aDef.iCommand = EStifCmdReceiveCancel; + // Complete action to server + iServerThread.RequestComplete( status, KErrNone ); + + iRcvMutex.Signal(); + + return KErrNone; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: TestComplete + + Description: Complete test operation: Get test case, run test case, + complete test case, etc. + + Parameters: TInt aCompletionCode: in: completion code. + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestThreadContainer::TestComplete( TInt aCompletionCode ) + { + + // Get status variable from server + TRequestStatus* status = + ModuleContainer().GetRequest( CTestModuleContainer::ERqTestCase ); + + if( status == NULL ) + { + Panic( ENullRequest ); + return; + } + + // Complete action to server + if( iTestThreadMutex.Handle() == 0 ) + { + // Actual test case is not started yet. Inititialization phase is ongoing. + // Before the completion check if the status was not already completed + // from other thread in CTestModuleContainer::DoCancel(). + // For details see Jira STIF-564 + if(*status == KRequestPending) + iServerThread.RequestComplete( status, aCompletionCode ); + } + else + { + // Test case execution is started. Test is ongoing. + // Before the completion check if the status was not already completed + // from other thread in CTestModuleContainer::DoCancel(). + // For details see Jira STIF-564 + if(*status == KRequestPending) + { + iTestThreadMutex.Wait(); // Block that complete and cancel do not + // executed at the same time. + iServerThread.RequestComplete( status, aCompletionCode ); + iTestThreadMutex.Signal(); + } + } + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: UIExecutionThread + + Description: This is the test module execution thread "main" function". + All test module function calls are executed in context of this execution + thread. + + When the thread is resumed first time, function goes to wait a semaphore. + Operations are initiated by setting operation and signaling the semaphore. + If operation is synchronous, then end of operation is signaled by using + OperationCompleted -Semaphore. When operation is done, function (and thread) + are going to wait OperationSemaphore. + + Function exist either when operation does fatal error, or operation type + is "Exit". The thread function exist from it's main loop and the thread + will be terminated. + + Parameters: TAny* aParams: :in: Pointer to CTestModuleContainer + + Return Values: TInt KErrNone + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TInt CTestThreadContainer::UIExecutionThread( TAny* aParams ) + { + + CTestModuleContainer* moduleContainer = + (CTestModuleContainer*) aParams; + + CTestModule* module = moduleContainer->GetTestModule(); + CTestServer* testServer = module->GetTestServer(); + CTestThreadContainerRunnerFactory* factory = testServer->GetTestThreadContainerRunnerFactory(); + + RThread server; + // Duplicate handles from server thread + TInt ret = server.Open( moduleContainer->ServerThreadId() ); + if( ret != KErrNone ) + { + Panic( EThreadHandleOpenFail ); + } + RSemaphore OperationStartSemaphore; + OperationStartSemaphore.SetHandle( + moduleContainer->OperationStartSemHandle() ); + if( OperationStartSemaphore.Duplicate( server ) != KErrNone ) + { + Panic( EDuplicateFail ); + } + RSemaphore OperationChangeSemaphore; + OperationChangeSemaphore.SetHandle( + moduleContainer->OperationChangeSemHandle() ); + if( OperationChangeSemaphore.Duplicate( server ) != KErrNone ) + { + Panic( EDuplicateFail ); + } + server.Close(); + + CTestThreadContainerRunner* runner = factory->CreateL(); + + runner->Setup( moduleContainer ); + + while ( runner->IsReusable() ) + { + // Thread is going to suspend + runner->CheckSignalFromSuspend(); + + // Wait next operation + OperationStartSemaphore.Wait(); + + // Get operation semaphore + OperationChangeSemaphore.Wait(); + + // Run and wait active object + runner->RunOneIteration(); + + OperationChangeSemaphore.Signal(); + } + + OperationStartSemaphore.Close(); + OperationChangeSemaphore.Close(); + + runner->TeareDown(); + + runner->Deque(); + + factory->DeleteL( runner ); + + return KErrNone; + } + + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: ExecutionThread + + Description: This is the test module execution thread "main" function". + All test module function calls are executed in context of this execution + thread. + + When the thread is resumed first time, function goes to wait a semaphore. + Operations are initiated by setting operation and signaling the semaphore. + If operation is synchronous, then end of operation is signaled by using + OperationCompleted -Semaphore. When operation is done, function (and thread) + are going to wait OperationSemaphore. + + Function exist either when operation does fatal error, or operation type + is "Exit". The thread function exist from it's main loop and the thread + will be terminated. + + Parameters: TAny* aParams: :in: Pointer to CTestModuleContainer + + Return Values: TInt KErrNone + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TInt CTestThreadContainer::ExecutionThread( TAny* aParams ) + { + TInt error( KErrNone ); + + const TUint32 KAll = 0xFFFFFFFF; +#ifndef __HIDE_IPC_V1__ // e.g. 7.0s, 8.0a + RThread currentThread; + currentThread.SetExceptionHandler( ExceptionHandler, KAll ); +#else // PlatSec used. Thread exception management is part of the User class. + User::SetExceptionHandler( ExceptionHandler, KAll ); +#endif // __HIDE_IPC_V1__ + + // Check parameters + __ASSERT_ALWAYS( aParams, Panic( EInvalidCTestThreadContainer ) ); + + CTestModuleContainer* moduleContainer = + (CTestModuleContainer*) aParams; + + // Create cleanup stack + CTrapCleanup* tc = CTrapCleanup::New(); + __ASSERT_ALWAYS( tc, Panic( ECreateTrapCleanup ) ); + + CTestThreadContainer* exec = NULL; + TRAPD( err, + exec = CTestThreadContainer::NewL( moduleContainer, + moduleContainer->ServerThreadId() ); + ); + if( err != KErrNone ) + { + Panic( ENullTestThreadContainer ); + } + + // Construct the logger + TName path = _L("C:\\logs\\testframework\\testserver\\"); + TFileName name = _L("testserver_thread_"); + name.Append( moduleContainer->TestModuleName() ); + + // Create logger, in Wins use HTML in HW default logger + TLoggerSettings loggerSettings; + + // Directory must create by hand if test server log wanted + loggerSettings.iCreateLogDirectories = EFalse; + + loggerSettings.iOverwrite = ETrue; + loggerSettings.iTimeStamp = ETrue; + loggerSettings.iLineBreak = ETrue; + loggerSettings.iEventRanking = EFalse; + loggerSettings.iThreadId = EFalse; + loggerSettings.iHardwareFormat = CStifLogger::ETxt; +#ifndef FORCE_STIF_INTERNAL_LOGGING_TO_RDEBUG + loggerSettings.iEmulatorFormat = CStifLogger::EHtml; + loggerSettings.iHardwareOutput = CStifLogger::EFile; + loggerSettings.iEmulatorOutput = CStifLogger::EFile; +#else + RDebug::Print( _L( "STIF Test Server's thread logging forced to RDebug" ) ); + loggerSettings.iEmulatorFormat = CStifLogger::ETxt; + loggerSettings.iHardwareOutput = CStifLogger::ERDebug; + loggerSettings.iEmulatorOutput = CStifLogger::ERDebug; +#endif + loggerSettings.iUnicode = EFalse; + loggerSettings.iAddTestCaseTitle = EFalse; + + TRAP ( error, exec->iThreadLogger = CStifLogger::NewL( path, name, + loggerSettings ) ); + + RLibrary module; // Handle to test module library + TBool reusable = ETrue; // Is test module reusable? + TBool initialized = EFalse; // Is module initialized? + TBool signalFromSuspend = EFalse; // Send signal from suspend state? + + RThread server; + // Duplicate handles from server thread + TInt ret = server.Open( moduleContainer->ServerThreadId() ); + if( ret != KErrNone ) + { + Panic( EThreadHandleOpenFail ); + } + RSemaphore OperationStartSemaphore; + OperationStartSemaphore.SetHandle( + exec->ModuleContainer().OperationStartSemHandle() ); + if( OperationStartSemaphore.Duplicate( server ) != KErrNone ) + { + Panic( EDuplicateFail ); + } + RSemaphore OperationChangeSemaphore; + OperationChangeSemaphore.SetHandle( + exec->ModuleContainer().OperationChangeSemHandle() ); + if( OperationChangeSemaphore.Duplicate( server ) != KErrNone ) + { + Panic( EDuplicateFail ); + } + server.Close(); + + + ret = KErrNone; + + // The test module thread will stay in this loop until it either + // dies or is exited nicely. + while ( reusable ) + { + // Thread is going to suspend + + if ( signalFromSuspend ) + { + signalFromSuspend = EFalse; + exec->TestComplete( ret ); + } + ret = KErrNone; + + // Wait next operation + OperationStartSemaphore.Wait(); + + // Get operation semaphore + OperationChangeSemaphore.Wait(); + switch ( moduleContainer->OperationType() ) + { + + // Test module initialisation + case CTestModuleContainer::EInitializeModule: + { + __ASSERT_ALWAYS ( !initialized, + Panic( EReInitializingTestModule ) ); + + // Initialize module + if ( exec->InitializeModuleInThread( module ) == KErrNone ) + { + initialized = ETrue; + } + + signalFromSuspend = ETrue; + break; + } + + // Test case enumeration + case CTestModuleContainer::EEnumerateInThread: + { + __ASSERT_ALWAYS ( initialized, + Panic( ETestModuleNotInitialized ) ); + ret = exec->EnumerateInThread(); + + signalFromSuspend = ETrue; + break; + } + + // Free test case enumeration data + case CTestModuleContainer::EFreeEnumerationData: + { + __ASSERT_ALWAYS ( initialized, + Panic( ETestModuleNotInitialized ) ); + exec->FreeEnumerationDataInThread (); + + signalFromSuspend = ETrue; + break; + } + + // Execute test case + case CTestModuleContainer::EExecuteTestInThread: + { + __ASSERT_ALWAYS ( initialized, + Panic( ETestModuleNotInitialized ) ); + ret = exec->ExecuteTestCaseInThread (); + + signalFromSuspend = ETrue; + break; + } + + // Exiting (i.e test server is unloading) + case CTestModuleContainer::EExit: + { + reusable = EFalse; + break; + } + + // Illegal state + default: + { + Panic( EInvalidTestModuleOperation ); + } + } + OperationChangeSemaphore.Signal(); + + } + + OperationStartSemaphore.Close(); + OperationChangeSemaphore.Close(); + + exec->DeleteTestModule(); + + // Close handle to module. No function calls to test + // module are possible after this line. + module.Close(); + + // Delete logger + delete exec->iThreadLogger; + exec->iThreadLogger = NULL; + + // Delete clean-up stack. + delete tc; + tc = NULL; + + // Operation completed ( = Exit completed ) + exec->TestComplete( KErrNone ); + + delete exec; + + return KErrNone; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: Panic + + Description: Panicing function for test thread. + + Parameters: TPanicReason aReason: in: Reason code + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestThreadContainer::Panic( TPanicReason aReason ) + { + + RDebug::Print( _L("CTestThreadContainer::Panic %d"), aReason ); + + User::Panic( _L("CTestThreadContainer::Panic"), aReason ); + + } +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: ServerAlive + + Description: Check that server is alive. + + Parameters: None + + Return Values: None + + Errors/Exceptions: Panics thread if server has died. + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestThreadContainer::IsServerAlive() + { + + if( iServerThread.ExitType() != EExitPending ) + { + // Server thread has died + __RDEBUG( ( _L( "Server died" ) ) ); + Panic( EServerDied ); + } + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: TestExecution + + Description: Return CTestExecution handle to "parent" i.e. server. + + Parameters: None + + Return Values: CTestExecution& + + Errors/Exceptions: Panics thread if server has died. + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +CTestExecution& CTestThreadContainer::TestExecution() + { + + IsServerAlive(); + CTestExecution* execution = iModuleContainer->TestExecution(); + if( execution == NULL ) + { + Panic( ENullExecution ); + } + return *execution; + + }; + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: TestExecution + + Description: Return CTestExecution handle to "parent" i.e. server. + + Parameters: None + + Return Values: CTestExecution& + + Errors/Exceptions: Panics thread if server has died. + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +CTestModuleContainer& CTestThreadContainer::ModuleContainer() + { + + IsServerAlive(); + return *iModuleContainer; + + }; + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: ExceptionHandler + + Description: Test execution thread exception handler + + Just kill thread. Undertaker handles rest. + + Parameters: TExcType: in: Exception type + + Return Values: None + + Errors/Exceptions: This function kills the thread where it is executed in. + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestThreadContainer::ExceptionHandler ( TExcType aType ) + { + + // Kill the current thread, undertaker handles rest + RThread current; + current.Kill( aType ); + + // This line is never executed, because thread has been killed. + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: StifMacroErrorInit + + Description: STIF TF's macro. Initialized TTestMacro. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestThreadContainer::StifMacroErrorInit() + { + iTestMacroInfo.iIndication = EFalse; + iTestMacroInfo.iFileDes = KNullDesC; + iTestMacroInfo.iFunctionDes = KNullDesC; + iTestMacroInfo.iLine = 0; + iTestMacroInfo.iReceivedError = 0; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: StifMacroError + + Description: STIF TF's macros. Saves information for later use. + + Parameters: TInt aMacroType: in: Macro type(0:TL, 1:T1L, 2:T2L, etc.) + TDesC& aFile: in: Modified file information. + TDesC& aFunction: in: Modified function information. + TInt aLine: in: Line information. + TInt aResult: in: Received result. + TInt aExpected1: in: Expected result from user. + TInt aExpected2: in: Expected result from user. + TInt aExpected3: in: Expected result from user. + TInt aExpected4: in: Expected result from user. + TInt aExpected5: in: Expected result from user. + + Return Values: Symbian OS error code + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TInt CTestThreadContainer::StifMacroError( TInt aMacroType, + const TText8* aFile, + const char* aFunction, + TInt aLine, + TInt aResult, + TInt aExpected1, + TInt aExpected2, + TInt aExpected3, + TInt aExpected4, + TInt aExpected5 ) + { + TStifMacroDes file; + TStifMacroDes function; + + // Modifies aFile and aFunction lengths if nesessarily. + // File and function maximun length is KStifMacroMax. + SetMacroInformation( KStifMacroMax, KStifMacroMax, + aFile, aFunction, file, function ); + + // Log more information to file and rdebug + switch( aMacroType ) + { + case 0: // TL macro + { + __TRACEI( KError, ( CStifLogger::ERed, + _L( "FAIL: STIF TF's macro. FILE[%S], FUNCTION[%S], LINE[%d]" ), + &file, &function, aLine ) ); + RDebug::Print( + _L( "FAIL: STIF TF's macro. FILE[%S], FUNCTION[%S], LINE[%d]" ), + &file, &function, aLine ); + break; + } + case 1: // T1L macro + { + __TRACEI( KError, ( CStifLogger::ERed, + _L( "FAIL: STIF TF's macro. RECEIVED[%d], EXPECTED[%d], FILE[%S], FUNCTION[%S], LINE[%d]" ), + aResult, aExpected1, &file, &function, aLine ) ); + RDebug::Print( + _L( "FAIL: STIF TF's macro. RECEIVED[%d], EXPECTED[%d], FILE[%S], FUNCTION[%S], LINE[%d]" ), + aResult, aExpected1, &file, &function, aLine ); + break; + } + case 2: // T2L macro + { + __TRACEI( KError, ( CStifLogger::ERed, + _L( "FAIL: STIF TF's macro. RECEIVED[%d], EXPECTED[%d], EXPECTED[%d], FILE[%S], FUNCTION[%S], LINE[%d]" ), + aResult, aExpected1, aExpected2, &file, &function, aLine ) ); + RDebug::Print( + _L( "FAIL: STIF TF's macro. RECEIVED[%d], EXPECTED[%d], EXPECTED[%d], FILE[%S], FUNCTION[%S], LINE[%d]" ), + aResult, aExpected1, aExpected2, &file, &function, aLine ); + break; + } + case 3: // T3L macro + { + __TRACEI( KError, ( CStifLogger::ERed, + _L( "FAIL: STIF TF's macro. RECEIVED[%d], EXPECTED[%d], EXPECTED[%d], EXPECTED[%d], FILE[%S], FUNCTION[%S], LINE[%d]" ), + aResult, aExpected1, aExpected2, aExpected3, &file, &function, aLine ) ); + RDebug::Print( + _L( "FAIL: STIF TF's macro. RECEIVED[%d], EXPECTED[%d], EXPECTED[%d], EXPECTED[%d], FILE[%S], FUNCTION[%S], LINE[%d]" ), + aResult, aExpected1, aExpected2, aExpected3, &file, &function, aLine ); + break; + } + case 4: // T4L macro + { + __TRACEI( KError, ( CStifLogger::ERed, + _L( "FAIL: STIF TF's macro. RECEIVED[%d], EXPECTED[%d], EXPECTED[%d], EXPECTED[%d], EXPECTED[%d], FILE[%S], FUNCTION[%S], LINE[%d]" ), + aResult, aExpected1, aExpected2, aExpected3, aExpected4, &file, &function, aLine ) ); + RDebug::Print( + _L( "FAIL: STIF TF's macro. RECEIVED[%d], EXPECTED[%d], EXPECTED[%d], EXPECTED[%d], EXPECTED[%d], FILE[%S], FUNCTION[%S], LINE[%d]" ), + aResult, aExpected1, aExpected2, aExpected3, aExpected4, &file, &function, aLine ); + break; + } + case 5: // T5L macro + { + __TRACEI( KError, ( CStifLogger::ERed, + _L( "FAIL: STIF TF's macro. RECEIVED[%d], EXPECTED[%d], EXPECTED[%d], EXPECTED[%d], EXPECTED[%d], EXPECTED[%d], FILE[%S], FUNCTION[%S], LINE[%d]" ), + aResult, aExpected1, aExpected2, aExpected3, aExpected4, aExpected5, &file, &function, aLine ) ); + RDebug::Print( + _L( "FAIL: STIF TF's macro. RECEIVED[%d], EXPECTED[%d], EXPECTED[%d], EXPECTED[%d], EXPECTED[%d], EXPECTED[%d], FILE[%S], FUNCTION[%S], LINE[%d]" ), + aResult, aExpected1, aExpected2, aExpected3, aExpected4, aExpected5, &file, &function, aLine ); + break; + } + default: // default, faulty handling + { + __TRACEI( KError, ( CStifLogger::EError, + _L( "CTestThreadContainer::StifMacroError(): Macro faulty handling(Macro type is incorrect)" ) ) ); + RDebug::Print( + _L( "ERROR: CTestThreadContainer::StifMacroError(): Macro faulty handling(Macro type is incorrect)" ) ); + return KErrArgument; // Test case goes to crashed category + } + } + + // Modifies aFile and aFunction lengths if nesessarily. + // File maximun length is KStifMacroMaxFile. + // Function maximun length is KStifMacroMaxFunction. + SetMacroInformation( KStifMacroMaxFile, KStifMacroMaxFunction, + aFile, aFunction, file, function ); + + // Set information for later use(this information is + // limited and can be seen in UI) + iTestMacroInfo.iIndication = ETrue; + iTestMacroInfo.iFileDes = file; + iTestMacroInfo.iFunctionDes = function; + iTestMacroInfo.iLine = aLine; + if( aResult == KErrNone ) + { + // aResult is KErrNone. TL macro is used or expected result(s) are/is + // negative value(s). Received error code is mapped to KErrArgument + // because this is erronous case. + iTestMacroInfo.iReceivedError = KErrArgument; + } + else + { + iTestMacroInfo.iReceivedError = aResult; + } + + return KErrNone; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: SetMacroInformation + + Description: Modifies aRecFile and aRecFunction lengths if nesessarily. + + Parameters: TInt aMaxLength: in: Maximum length of file information. + TInt aMaxLength: in: Maximum length of function information. + const TText8* aRecFile: in: Received file information. + char* aRecFunction: in: Received function information. + TDes& aFile: inout: Modified file. + TDes& aFunction: inout: Modified function. + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestThreadContainer::SetMacroInformation( TInt aFileMaxLength, + TInt aFuntionMaxLength, + const TText8* aRecFile, + const char* aRecFunction, + TDes& aFile, + TDes& aFunction ) + { + // Create 8 to 16 + TPtrC8 buf_file; + buf_file.Set( aRecFile ); + // File description length is limited. Extracts the rightmost part of the + // data. + aFile.Copy( buf_file.Right( aFileMaxLength ) ); + aFile.LowerCase(); + + if( aRecFunction ) + { + // Create 8 to 16 + TPtrC8 buf_func; + buf_func.Set( (const unsigned char*)aRecFunction ); + // Function description length is limited. Extracts the leftmost part + // of the data. + aFunction.Copy( buf_func.Left( aFuntionMaxLength ) ); + aFunction.LowerCase(); + } + else + { + // Function is not given(WINS) + aFunction.Copy( _L( "-" ) ); + } + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: AddInterferenceThread + + Description: With this can be store information about test interference + thread to client space. + + Parameters: RThread aSTIFTestInterference: in: Thread information to store + + Return Values: TInt: Symbian OS error code. + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TInt CTestThreadContainer::AddInterferenceThread( + RThread aSTIFTestInterference ) + { + // Get access to test interference stuff + iInterferenceSem.Wait(); + + iInterferenceMutex.Wait(); // Take mutex to get access to server thread. + // Between Wait and Signal is critical section + // and this verifies that iInterferenceSem and + // RequestComplete is done successfully. + + // Get status variable from server + TRequestStatus* status = + TestExecution().GetRq( CTestExecution::ERqInterference ); + + if( status == NULL ) + { + iInterferenceMutex.Signal(); + Panic( ENullRequest ); + return KErrNone; + } + + if( *status != KRequestPending ) + { + // CInterferenceHandler::DoCancel called before getting here, + // just return + iInterferenceMutex.Signal(); + return KErrNone; + } + + // Add thread to Array. Via array can handle test interference thread's + // kill in panic etc. cases + TTestInterference& testInterface = TestExecution().TestInterference(); + testInterface.iThreadId = aSTIFTestInterference.Id(); + testInterface.iOperation = TTestInterference::EAppend; + + // Complete action to server + iServerThread.RequestComplete( status, KErrNone ); + // Goes to CInterferenceHandler::RunL() + + iInterferenceMutex.Signal(); + + return KErrNone; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: RemoveInterferenceThread + + Description: With this can be remove information about test interference + thread from client space. + + Parameters: RThread aSTIFTestInterference: in: Thread information to store + + Return Values: TInt: Symbian OS error code. + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TInt CTestThreadContainer::RemoveInterferenceThread( + RThread aSTIFTestInterference ) + { + // Get access to test interference stuff + iInterferenceSem.Wait(); + + iInterferenceMutex.Wait(); // Take mutex to get access to server thread. + // Between Wait and Signal is critical section + // and this verifies that iInterferenceSem and + // RequestComplete is done successfully. + + // Get status variable from server + TRequestStatus* status = + TestExecution().GetRq( CTestExecution::ERqInterference ); + + if( status == NULL ) + { + iInterferenceMutex.Signal(); + Panic( ENullRequest ); + return KErrNone; + } + + if( *status != KRequestPending ) + { + // CInterferenceHandler::DoCancel called before getting here, just return + iInterferenceMutex.Signal(); + return KErrNone; + } + + // Add thread to Array. Via array can handle test interference thread's + // kill in panic etc. cases + TTestInterference& testInterface = TestExecution().TestInterference(); + testInterface.iThreadId = aSTIFTestInterference.Id(); + testInterface.iOperation = TTestInterference::ERemove; + + // Complete action to server + iServerThread.RequestComplete( status, KErrNone ); + // Goes to CInterferenceHandler::RunL() + + iInterferenceMutex.Signal(); + + return KErrNone; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: HandleMeasurementProcess + + Description: With this can be stored information about test measurement + to TestServer space. + + Parameters: CSTIFTestMeasurement::TMeasurement aSTIFMeasurementInfo: in: + Struct for measurement information. + + Return Values: TInt: Symbian OS error code. + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +TInt CTestThreadContainer::HandleMeasurementProcess( + CSTIFTestMeasurement::TStifMeasurementStruct aSTIFMeasurementInfo ) + { + // Get access to test measurement stuff + + // This is syncronous operation and other request cannot executed at the + // same time. In this case iMeasurementSem is not signaled in StarL(). + // So iMeasurementSem.Wait(); is not needed in this case. + + iMeasurementMutex.Wait(); // Take mutex to get access to server thread. + // Between Wait and Signal is critical section + // and this verifies that iMeasurementSem and + // RequestComplete is done successfully. + + // Get status variable from server + TRequestStatus* status = + TestExecution().GetRq( CTestExecution::ERqMeasurement ); + + if( status == NULL ) + { + iMeasurementMutex.Signal(); + Panic( ENullRequest ); + return KErrNone; + } + + if( *status != KRequestPending ) + { + // CMeasurementHandler::DoCancel called before getting here, + // just return + iMeasurementMutex.Signal(); + return KErrNone; + } + + TTestMeasurement& testmeasurement = TestExecution().TestMeasurement(); + testmeasurement.iMeasurementStruct = aSTIFMeasurementInfo; + + // Complete action to server + iServerThread.RequestComplete( status, KErrNone ); + // Goes to CMeasurementHandler::RunL() + + // Make this synchronous and block until needed operations are done. + iMeasurementSem.Wait(); + // This continue here when iMeasurementSem.Signal is said in + // CMeasurementHandler::RunL(). So when measurement operations are done. + + // Error code from measurement related operations + TInt ret( testmeasurement.iMeasurementStruct.iOperationResult ); + + iMeasurementMutex.Signal(); + + return ret; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: SetEventReq + + Description: Sets asynchronous event request. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestThreadContainer::DoNotifyCommand(TCommand aCommand, const TDesC8& aParamsPckg) + { + // Get access to command stuff + iCommandSem.Wait(); + + iCommandMutex.Wait(); // Take mutex to get access to server thread. + // Between Wait and Signal is critical section and this + // verifies that iCommandSem and RequestComplete is done + // successfully. + + // Get status variable from server + TRequestStatus* status = TestExecution().GetRq(CTestExecution::ERqCommand); + + if(status == NULL) + { + iCommandMutex.Signal(); + Panic(ENullRequest); + return; + } + if(*status != KRequestPending) + { + iCommandMutex.Signal(); + return; + } + + // Fill in information + CCommandDef& aDef = TestExecution().CommandDef(); + aDef.iCommand = aCommand; + aDef.iParamsPckg.Copy(aParamsPckg); + + // Complete action to server + iServerThread.RequestComplete(status, KErrNone); + + iCommandMutex.Signal(); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: GetTestCaseTitleL + + Description: Gets title of currently running test. + + Parameters: aTestCaseTitle: OUT: test case title descriptor + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestThreadContainer::GetTestCaseTitleL(TDes& aTestCaseTitle) + { + ModuleContainer().GetTestCaseTitleL(aTestCaseTitle); + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: SetThreadLogger + + Description: Sets thread logger. + + Parameters: CStifLogger* aThreadLogger: in: Pointer to thread logger. + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestThreadContainer::SetThreadLogger( CStifLogger* aThreadLogger ) + { + + iThreadLogger = aThreadLogger; + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: SetThreadLogger + + Description: Gets thread logger. + + Parameters: None + + Return Values: Pointer to CStifLogger. + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +CStifLogger* CTestThreadContainer::GetThreadLogger() + { + + return iThreadLogger; + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: UITesting + + Description: Gets information if testserver supports UI testing. + + Parameters: None + + Return Values: True if testserver supports UI testing, False if testserver + doesn't support UI testing. + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +EXPORT_C TBool CTestThreadContainer::UITesting() + { + + return iModuleContainer->GetTestModule()->GetTestServer()->UiTesting(); + } + +/* +------------------------------------------------------------------------------- + + Class: CTestThreadContainer + + Method: GetUiEnvProxy + + Description: Gets UIEnvProxy. + + Parameters: None + + Return Values: Pointer to UIEnvProxy + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +EXPORT_C CUiEnvProxy* CTestThreadContainer::GetUiEnvProxy() + { + + return iModuleContainer->GetTestModule()->GetTestServer()->GetUiEnvProxy(); + } + +// End of File