diff -r 7fdc9a71d314 -r 8ad140f3dd41 stif/TestEngine/src/TestCaseController.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stif/TestEngine/src/TestCaseController.cpp Wed Oct 13 16:17:58 2010 +0300 @@ -0,0 +1,2880 @@ +/* +* 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 +* CTestCaseController class member functions. +* +*/ + + +// INCLUDE FILES +#include +#include +#include +#include "StifTFwIfProt.h" +#include "TestCaseController.h" +#include "TestModuleController.h" +#include "TestReport.h" +#include "Logging.h" +#include "StifHWReset.h" + +// EXTERNAL DATA STRUCTURES +// None + +// EXTERNAL FUNCTION PROTOTYPES +// None + +// CONSTANTS +// None + +// MACROS +// None + +// LOCAL CONSTANTS AND MACROS +// None + +// MODULE DATA STRUCTURES +// None + +// LOCAL FUNCTION PROTOTYPES +// None + +// FORWARD DECLARATIONS +// None + +// ==================== LOCAL FUNCTIONS ======================================= +// None + + +#define LOGGER iEngine->Logger() + +// ================= MEMBER FUNCTIONS ========================================= + +/* +------------------------------------------------------------------------------- + + Class: CTestCaseController + + Method: CTestCaseController + + Description: Default constructor + + C++ default constructor can NOT contain any code, that + might leave. + + Parameters: CTestEngine* aEngine: in: Pointer to CTestEngine + RTestExecution aTestExecution: in: Handle to RTestExecution + CAtsLogger& aAtsLogger: in: Reference to CAtsLogger + RTestExecution aTestExecution: in: Handle to RTestExecution + const TTestInfo& aTestInfo: in: Test Info + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +CTestCaseController::CTestCaseController( CTestEngine* aEngine, + CTestReport* aTestReport, + CAtsLogger& aAtsLogger, + RTestExecution aTestExecution, + const TTestInfo& aTestInfo ) : + CActive( CActive::EPriorityStandard ), + iEngine( aEngine ), + iTestReport( aTestReport ), + iTestExecution( aTestExecution ), + iTestInfo( aTestInfo ), + iState( ETestCaseIdle ), + iResultPckg( iResult ), + iAtsLogger( aAtsLogger ) + { + CActiveScheduler::Add( this ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestCaseController + + Method: ConstructL + + Description: Symbian OS second phase constructor + + Symbian OS default constructor can leave. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestCaseController::ConstructL() + { + __TRACE( KVerbose, ( _L( "CTestCaseController::ConstructL, [%S]" ), &iTestInfo.iTestCaseInfo.iTitle ) ); + + // Logger settings + TLoggerSettings loggerSettings; + loggerSettings.iCreateLogDirectories = EFalse; + loggerSettings.iOverwrite = ETrue; + loggerSettings.iTimeStamp = EFalse; + loggerSettings.iLineBreak = EFalse; + loggerSettings.iEventRanking = EFalse; + loggerSettings.iThreadId = EFalse; + loggerSettings.iHardwareFormat = CStifLogger::ETxt; + loggerSettings.iHardwareOutput = CStifLogger::ERDebug; + loggerSettings.iEmulatorFormat = CStifLogger::ETxt; + loggerSettings.iEmulatorOutput = CStifLogger::ERDebug; + loggerSettings.iUnicode = EFalse; + loggerSettings.iAddTestCaseTitle = EFalse; + + iRDebugLogger = CStifLogger::NewL( _L( "" ), _L( "" ), loggerSettings ); + + // If timeout is specified, then create timeout handler. + if ( iTestInfo.iTestCaseInfo.iTimeout > TTimeIntervalMicroSeconds(0) ) + { + iTimeout = CTestCaseTimeout::NewL ( this, + iTestInfo.iTestCaseInfo.iTimeout ); + } + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestCaseController + + Method: NewL + + Description: Two-phased constructor. + + Parameters: CTestEngine* aEngine: in: Pointer to CTestEngine + CTestReport* aTestReport: in: Pointer to CTestReport + CAtsLogger& aAtsLogger: in: Reference to CAtsLogger + RTestExecution aTestExecution: in: Handle to RTestExecution + const TTestInfo& aTestInfo: in: Test Info + + Return Values: CTestCaseController* : pointer to created object + + Errors/Exceptions: Leaves if construction of CTestCaseController fails + + Status: Approved + +------------------------------------------------------------------------------- +*/ +CTestCaseController* CTestCaseController::NewL( CTestEngine* aEngine, + CTestReport* aTestReport, + CAtsLogger& aAtsLogger, + RTestExecution aTestExecution, + const TTestInfo& aTestInfo ) + { + CTestCaseController* self = new ( ELeave ) CTestCaseController( aEngine, + aTestReport, aAtsLogger, aTestExecution, aTestInfo ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestCaseController + + Method: ~CTestCaseController + + Description: Destructor + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +CTestCaseController::~CTestCaseController() + { + __TRACE( KVerbose, ( _L( "CTestCaseController::~CTestCaseController" ) ) ); + Cancel(); + + delete iRDebugLogger; + delete iTimeout; + delete iTestCaseArguments; + } + +/* +------------------------------------------------------------------------------- + + Class: CTestCaseController + + Method: StartL + + Description: Start active object + + Parameters: const RMessage& aMessage: in: Server message + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestCaseController::StartL( const RMessage2& aMessage ) + { + iRDebugLogger->Log( _L( "Starting testcase [%S]" ), &iTestInfo.iTestCaseInfo.iTitle ); + __TRACE( KInit, ( _L(" Starting testcase [%S]"), &iTestInfo.iTestCaseInfo.iTitle ) ); + + // Check that this request is not pending!! + __ASSERT_ALWAYS( iState != ETestCaseRunning, + iEngine->PanicClient( EReqPending, aMessage ) ); + iMessage = aMessage; + + iState = ETestCaseRunning; + + delete iTestCaseArguments; + iTestCaseArguments = NULL; + + TInt testCaseArgumentsLength = iMessage.GetDesLength( 1 ); + if ( ( testCaseArgumentsLength != KErrArgument ) && ( testCaseArgumentsLength != KErrBadDescriptor ) ) + { + iTestCaseArguments = HBufC::NewL( testCaseArgumentsLength ); + TPtr testCaseArgumentsPtr( iTestCaseArguments->Des() ); + User::LeaveIfError( iMessage.Read( 1, testCaseArgumentsPtr ) ); + iTestExecution.RunTestCase( iResultPckg, *iTestCaseArguments, iStatus ); + } + else + { + iTestExecution.RunTestCase( iResultPckg, iStatus ); + } + SetActive(); + + // If testcase has timeout (handler), then start it + if ( iTimeout ) + { + iTimeout->Start(); + } + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestCaseController + + Method: Timeout + + Description: Timeouts active request. + - Cancel request + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestCaseController::Timeout() + { + if ( iState == ETestCaseRunning ) + { + iState = ETestCaseTimeout; + Cancel(); + } + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestCaseController + + Method: RunL + + Description: RunL handles completed requests. Leaves are handled in + RunError method + + Parameters: None + + Return Values: None + + Errors/Exceptions: Leaves if AddTestCaseResultL leaves + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestCaseController::RunL() + { + iState = ETestCaseCompleted; + + + // "iStatus.Int()" error code is received from system's framework not from + // test case execution. + if ( iStatus.Int() != KErrNone ) + { + if ( iStatus.Int() == KErrServerTerminated ) + { + // something went badly wrong! + __TRACE( KInit, ( CStifLogger::ERed, + _L( "TestCase [%S] cannot be executed, STIF panics with[%d]" ), + &iTestInfo.iTestCaseInfo.iTitle, + iStatus.Int() ) ); + + __TRACE( KInit, ( CStifLogger::ERed, + _L( "Possible reason: Test case has paniced seriously" ) ) ); + + // We don't leave here but we write information to + // forward(testreport etc.) + _LIT( KLeaveInfo, "Test case execution fails" ); + // Sets test case to crash category + iResult.iCaseExecutionResultCode = iStatus.Int(); + // Test case result + iResult.iTestResult.iResult = iStatus.Int(); + iResult.iTestResult.iResultDes = KLeaveInfo; + + } + + else + { + // For example testmodule's NewL or testmodule's constructor has + // leaved and STIF cannot connect to test module + __TRACE( KInit, ( CStifLogger::ERed, + _L( "TestCase [%S] cannot execute, TestModule loading operations fails with[%d]" ), + &iTestInfo.iTestCaseInfo.iTitle, + iStatus.Int() ) ); + __TRACE( KInit, ( CStifLogger::ERed, + _L( "Possible reason: TestModule's NewL or Constructor has leaved and STIF cannot connect to test module" ) ) ); + + // We don't leave here but we write information to + // forward(testreport etc.) + _LIT( KLeaveInfo, "TestModule loading fails, cannot connect to the TestModule" ); + // Sets test case to crash category + iResult.iCaseExecutionResultCode = iStatus.Int(); + // Test case result + iResult.iTestResult.iResult = iStatus.Int(); + iResult.iTestResult.iResultDes = KLeaveInfo; + } + } + + else + { + + // Cancel event request, because the testcase is completed + iTestExecution.CancelAsyncRequest( ETestExecutionNotifyEvent ); + } + + // Test case is executed + if( iTestInfo.iTestCaseInfo.iTitle.Length() > 0 ) + { + iRDebugLogger->Log( _L( "TestCase [%S] finished with verdict[%d]" ), + &iTestInfo.iTestCaseInfo.iTitle, + iResult.iTestResult.iResult ); + + __TRACE( KInit, ( _L( " TestCase [%S] finished with verdict[%d]" ), + &iTestInfo.iTestCaseInfo.iTitle, + iResult.iTestResult.iResult ) ); + } + else + { + iRDebugLogger->Log( _L( "TestCase [%d] finished with verdict[%d]" ), + iTestInfo.iTestCaseInfo.iCaseNumber, + iResult.iTestResult.iResult ); + + __TRACE( KInit, ( _L( " TestCase [%d] finished with verdict[%d]" ), + iTestInfo.iTestCaseInfo.iCaseNumber, + iResult.iTestResult.iResult ) ); + } + __TRACE( KVerbose, ( + _L( "CTestCaseController::RunL: iStatus=[%d]" ), iStatus.Int() )); + + GenerateXmlLogL(); + + // Report test case result + if( iTestReport ) + { + iTestReport->AddTestCaseResultL( iTestInfo, iResult, iStatus.Int() ); + iTestReport->UpdateReportSummaryL(); + } + + TRAPD( ret, iMessage.WriteL( 0, iResultPckg ) ); + + // Case done + iMessage.Complete( ret ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestCaseController + + Method: DoCancel + + Description: Cancel active request + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestCaseController::DoCancel() + { + + switch ( iState ) + { + case ETestCaseRunning: + iTestExecution.CancelAsyncRequest( ETestExecutionRunTestCase ); + if( iTestInfo.iTestCaseInfo.iTitle.Length() > 0 ) + { + iRDebugLogger->Log( _L( "TestCase [%S] execution aborted" ), + &iTestInfo.iTestCaseInfo.iTitle ); + + __TRACE( KInit, ( _L( "TestCase [%S] execution aborted" ), + &iTestInfo.iTestCaseInfo.iTitle ) ); + } + else + { + iRDebugLogger->Log( _L( "TestCase [%S] execution aborted" ), + iTestInfo.iTestCaseInfo.iCaseNumber ); + + __TRACE( KInit, ( _L( "TestCase [%S] execution aborted" ), + iTestInfo.iTestCaseInfo.iCaseNumber ) ); + } + break; + case ETestCaseTimeout: + iTestExecution.CancelAsyncRequest( ETestExecutionRunTestCase ); + // Update result to timeout + iResult.iCaseExecutionResultType = TFullTestResult::ECaseTimeout; + iResult.iTestResult.iResultDes = _L("Test case was timeouted and cancelled"); + + if( iTestReport ) + { + iTestReport->AddTestCaseResultL( iTestInfo, iResult, KErrTimedOut ); + } + + if( iTestInfo.iTestCaseInfo.iTitle.Length() > 0 ) + { + iRDebugLogger->Log( _L( "TestCase [%S] finished with verdict[%d]" ), + &iTestInfo.iTestCaseInfo.iTitle, + iResult.iTestResult.iResult ); + + __TRACE( KInit, ( _L( " TestCase [%S] finished with verdict[%d]" ), + &iTestInfo.iTestCaseInfo.iTitle, + iResult.iTestResult.iResult ) ); + } + else + { + iRDebugLogger->Log( _L( "TestCase [%d] finished with verdict[%d]" ), + iTestInfo.iTestCaseInfo.iCaseNumber, + iResult.iTestResult.iResult ); + + __TRACE( KInit, ( _L( " TestCase [%d] finished with verdict[%d]" ), + iTestInfo.iTestCaseInfo.iCaseNumber, + iResult.iTestResult.iResult ) ); + } + + break; + case ETestCaseSuicided: + { + //Store current results because cancel operation overwrites it + TInt currentTestResult = iResult.iTestResult.iResult; + TInt currentExecutionResult = iResult.iCaseExecutionResultCode; + iTestExecution.CancelAsyncRequest(ETestExecutionRunTestCase); + // Update result to suicide + switch(iStopExecutionType) + { + case EOk: + iResult.iCaseExecutionResultType = TFullTestResult::ECaseExecuted; + iResult.iTestResult.iResultDes = _L("Test case passed (StopExecution())"); + break; + case EFail: + iResult.iCaseExecutionResultType = TFullTestResult::ECaseExecuted; + iResult.iTestResult.iResultDes = _L("Test case failed (StopExecution())"); + break; + default: //EAbort + iResult.iCaseExecutionResultType = TFullTestResult::ECaseSuicided; + iResult.iTestResult.iResultDes = _L("Test case killed (StopExecution())"); + } + iResult.iTestResult.iResult = currentTestResult; + iResult.iCaseExecutionResultCode = currentExecutionResult; + } + if(iTestReport) + { + iTestReport->AddTestCaseResultL(iTestInfo, iResult, KErrNone); + } + + // Log some message + if(iTestInfo.iTestCaseInfo.iTitle.Length() > 0) + { + _LIT(KTestCaseDesc, "TestCase [%S] finished with verdict [%d]"); + switch(iStopExecutionType) + { + case EOk: + { + _LIT(KTestCaseResult, "***Testcase PASSED***"); + + iRDebugLogger->Log(KTestCaseResult); + __TRACE(KInit, (KTestCaseResult)); + iRDebugLogger->Log(KTestCaseDesc, &iTestInfo.iTestCaseInfo.iTitle, iResult.iTestResult.iResult); + __TRACE(KInit, (KTestCaseDesc, &iTestInfo.iTestCaseInfo.iTitle, iResult.iTestResult.iResult)); + break; + } + case EFail: + { + _LIT(KTestCaseResult, "***Testcase FAILED***"); + + iRDebugLogger->Log(KTestCaseResult); + __TRACE(KInit, (KTestCaseResult)); + iRDebugLogger->Log(KTestCaseDesc, &iTestInfo.iTestCaseInfo.iTitle, iResult.iTestResult.iResult); + __TRACE(KInit, (KTestCaseDesc, &iTestInfo.iTestCaseInfo.iTitle, iResult.iTestResult.iResult)); + break; + } + default: //EAbort + { + _LIT(KTestCaseResult, "***Testcase KILLED***"); + + iRDebugLogger->Log(KTestCaseResult); + __TRACE(KInit, (KTestCaseResult)); + iRDebugLogger->Log(KTestCaseDesc, &iTestInfo.iTestCaseInfo.iTitle, iResult.iTestResult.iResult); + __TRACE(KInit, (KTestCaseDesc, &iTestInfo.iTestCaseInfo.iTitle, iResult.iTestResult.iResult)); + } + } + } + else + { + _LIT(KTestCaseDesc, "TestCase [%d] finished with verdict [%d]"); + switch(iStopExecutionType) + { + case EOk: + { + _LIT(KTestCaseResult, "***Testcase PASSED***"); + + iRDebugLogger->Log(KTestCaseResult); + __TRACE(KInit, (KTestCaseResult)); + iRDebugLogger->Log(KTestCaseDesc, iTestInfo.iTestCaseInfo.iCaseNumber, iResult.iTestResult.iResult); + __TRACE(KInit, (KTestCaseDesc, iTestInfo.iTestCaseInfo.iCaseNumber, iResult.iTestResult.iResult)); + break; + } + case EFail: + { + _LIT(KTestCaseResult, "***Testcase FAILED***"); + + iRDebugLogger->Log(KTestCaseResult); + __TRACE(KInit, (KTestCaseResult)); + iRDebugLogger->Log(KTestCaseDesc, iTestInfo.iTestCaseInfo.iCaseNumber, iResult.iTestResult.iResult); + __TRACE(KInit, (KTestCaseDesc, iTestInfo.iTestCaseInfo.iCaseNumber, iResult.iTestResult.iResult)); + break; + } + default: //EAbort + { + _LIT(KTestCaseResult, "***Testcase KILLED***"); + + iRDebugLogger->Log(KTestCaseResult); + __TRACE(KInit, (KTestCaseResult)); + iRDebugLogger->Log(KTestCaseDesc, iTestInfo.iTestCaseInfo.iCaseNumber, iResult.iTestResult.iResult); + __TRACE(KInit, (KTestCaseDesc, iTestInfo.iTestCaseInfo.iCaseNumber, iResult.iTestResult.iResult)); + } + } + } + break; + case ETestCaseIdle: + case ETestCaseCompleted: + default: + // DoCancel called in wrong state => Panic + _LIT( KTestCaseController, "CTestCaseController" ); + User::Panic( KTestCaseController, EDoCancelDisorder ); + break; + } + + // Write result and complete + TRAPD( ret, iMessage.WriteL( 0, iResultPckg ) ); + + iMessage.Complete( ret ); + + iState = ETestCaseCompleted; + + // Generate xml result log + GenerateXmlLogL(); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestCaseController + + Method: RunError + + Description: Handle errors. + + Parameters: TInt aError: in: Symbian OS error: Error code + + Return Values: TInt KErrNone: Always returned KErrNone + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +TInt CTestCaseController::RunError( TInt aError ) + { + __TRACE( KError, ( CStifLogger::ERed, + _L( "CTestCaseController::RunError: Test case execution has failed! aError=[%d]" ), aError ) ); + TInt completionError = aError; + + // Write result, because it could include descriptive result for + // failed case + TRAPD( err, iMessage.WriteL( 0, iResultPckg ); ); + + if ( err != KErrNone ) + { + completionError = err; + } + + // Complete message with error + iMessage.Complete( completionError ); + + return KErrNone; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestCaseController + + Method: GenerateXmlLogL + + Description: Generate XML log. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestCaseController::GenerateXmlLogL() + { + + // Report result with AtsLogger + iAtsLogger.BeginTestCaseReportL( iTestInfo.iTestCaseInfo.iTitle, + KErrNone, // Expected result not supported + iResult.iStartTime ); + + if( iResult.iCaseExecutionResultCode != KErrNone ) + { + iAtsLogger.SetTestCaseResultL( iResult.iCaseExecutionResultCode ); + iAtsLogger.TestCaseFailed(); + if( iResult.iTestResult.iResultDes.Length() > 0 ) + { + iAtsLogger.ErrorL( iResult.iTestResult.iResultDes ); + } + } + else + { + iAtsLogger.SetTestCaseResultL( iResult.iTestResult.iResult ); + if( iResult.iTestResult.iResult == KErrNone ) + { + iAtsLogger.TestCasePassed(); + } + else + { + iAtsLogger.TestCaseFailed(); + if( iResult.iTestResult.iResultDes.Length() > 0 ) + { + iAtsLogger.ErrorL( iResult.iTestResult.iResultDes ); + } + } + } + // Set test case result to ATS Logger + iAtsLogger.EndTestCaseL(); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestCaseController + + Method: GetTestCaseInfo + + Description: Get testcase info(test module, config file, test case, etc). + + Parameters: TTestInfo& aTestInfo: inout: Test information + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestCaseController::GetTestCaseInfo( TTestInfo& aTestInfo ) + { + aTestInfo = iTestInfo; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestCaseController + + Method: Suicide + + Description: Cancels active request. + + Parameters: aCode: the reason of suicide + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +void CTestCaseController::Suicide(TStopExecutionType aType, TInt aCode) + { + if(iState == ETestCaseRunning) + { + iStopExecutionType = aType; + switch(iStopExecutionType) + { + case EOk: + iResult.iTestResult.iResult = KErrNone; + iResult.iCaseExecutionResultCode = KErrNone; + break; + case EFail: + iResult.iTestResult.iResult = aCode; + iResult.iCaseExecutionResultCode = KErrNone; + break; + default: //EAbort + iResult.iTestResult.iResult = aCode; + iResult.iCaseExecutionResultCode = aCode; + } + iState = ETestCaseSuicided; + Cancel(); + } + } + +/* +------------------------------------------------------------------------------- + + DESCRIPTION + + This module contains implementation of CTestProgressNotifier class member + functions. + +------------------------------------------------------------------------------- +*/ + +// ================= MEMBER FUNCTIONS ========================================= + +/* +------------------------------------------------------------------------------- + + Class: CTestProgressNotifier + + Method: CTestProgressNotifier + + Description: Default constructor + + C++ default constructor can NOT contain any code, that + might leave. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +CTestProgressNotifier::CTestProgressNotifier( CTestEngine* aEngine, + RTestExecution aTestExecution ) : + CActive( CActive::EPriorityStandard ), + iEngine( aEngine ), + iTestExecution( aTestExecution ), + iState( ETestProgressIdle ), + iProgressPckg( iProgress ) + { + CActiveScheduler::Add( this ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestProgressNotifier + + Method: ConstructL + + Description: Symbian OS second phase constructor + + Symbian OS default constructor can leave. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestProgressNotifier::ConstructL() + { + __TRACE( KVerbose, ( _L( "CTestProgressNotifier::ConstructL" ) ) ); + } + +/* +------------------------------------------------------------------------------- + + Class: CTestProgressNotifier + + Method: NewL + + Description: Two-phased constructor. + + Parameters: CTestEngine* aEngine: in: Pointer to CTestEngine + RTestExecution aTestExecution: in: Handle to RTestExecution + + Return Values: CTestProgressNotifier* : pointer to created object + + Errors/Exceptions: Leaves if construction of CTestProgressNotifier fails + + Status: Approved + +------------------------------------------------------------------------------- +*/ +CTestProgressNotifier* CTestProgressNotifier::NewL( CTestEngine* aEngine, + RTestExecution aTestExecution ) + { + CTestProgressNotifier* self = new ( ELeave ) CTestProgressNotifier( + aEngine, aTestExecution ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestProgressNotifier + + Method: ~CTestProgressNotifier + + Description: Destructor + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +CTestProgressNotifier::~CTestProgressNotifier() + { + __TRACE( KVerbose, ( _L( "CTestProgressNotifier::~CTestProgressNotifier" ) ) ); + Cancel(); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestProgressNotifier + + Method: StartL + + Description: Start active object + + Parameters: const RMessage& aMessage: in: Server message + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestProgressNotifier::StartL( const RMessage2& aMessage ) + { + __TRACE( KVerbose, ( _L( "CTestProgressNotifier::StartL" ) ) ); + // Check that this request is not pending!! + __ASSERT_ALWAYS( iState != ETestProgressPending, + iEngine->PanicClient( EReqPending, aMessage ) ); + iMessage = aMessage; + + iState = ETestProgressPending; + SetActive(); + + iTestExecution.NotifyProgress( iProgressPckg, iStatus ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestProgressNotifier + + Method: RunL + + Description: RunL handles completed requests. + + Parameters: None + + Return Values: None + + Errors/Exceptions: Leaves if WriteL leaves + Leaves if iStatus is not KErrNone or KErrEof + Leaves are handled in RunError method + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestProgressNotifier::RunL() + { + __TRACE( KVerbose, (_L("CTestProgressNotifier::RunL: iStatus=[%d]" ), iStatus.Int() )); + + iState = ETestProgressCompleted; + + // Check that request was successful or completed with acceptable error + // KErrEof is acceptable error and it means that the test case will not + // send progresses anymore (because it is closed) + if ( KErrNone == iStatus.Int() ) + { + iMessage.WriteL( 0, iProgressPckg ); + } + else if ( KErrEof != iStatus.Int() ) + { + // Leave, error will be handled in RunError + User::Leave( iStatus.Int() ); + } + + // Complete message + iMessage.Complete( iStatus.Int() ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestProgressNotifier + + Method: DoCancel + + Description: Cancel active request + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestProgressNotifier::DoCancel() + { + switch ( iState ) + { + case ETestProgressPending: + iTestExecution.CancelAsyncRequest( ETestExecutionNotifyProgress ); + iMessage.Complete( KErrCancel ); + break; + case ETestProgressIdle: + case ETestProgressCompleted: + default: + // DoCancel called in wrong state => Panic + _LIT( KTestProgressNotifier, "CTestProgressNotifier" ); + User::Panic( KTestProgressNotifier, EDoCancelDisorder ); + break; + } + iState = ETestProgressIdle; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestProgressNotifier + + Method: RunError + + Description: Handle errors. + + Parameters: TInt aError: in: Symbian OS error: Error code + + Return Values: TInt KErrNone: Always returned KErrNone + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +TInt CTestProgressNotifier::RunError( TInt aError ) + { + // Complete message with error + iMessage.Complete( aError ); + + return KErrNone; + + } + +/* +------------------------------------------------------------------------------- + + DESCRIPTION + + This module contains implementation of CTestEventNotifier class member + functions. + +------------------------------------------------------------------------------- +*/ + +// ================= MEMBER FUNCTIONS ========================================= + +/* +------------------------------------------------------------------------------- + + Class: CTestEventNotifier + + Method: CTestEventNotifier + + Description: Default constructor + + C++ default constructor can NOT contain any code, that + might leave. + + Parameters: CTestEngine* aEngine: in: Pointer to CTestEngine + RTestExecution aTestExecution: in: Handle to RTestExecution + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +CTestEventNotifier::CTestEventNotifier( CTestEngine* aEngine, + RTestExecution aTestExecution ) : + CActive( CActive::EPriorityStandard ), + iEngine( aEngine ), + iTestExecution( aTestExecution ), + iState( ETestEventIdle ), + iEventPckg( iEvent ), + iEventNotifyPckg( iEventNotify ), + iController( NULL ) + { + CActiveScheduler::Add( this ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestEventNotifier + + Method: ConstructL + + Description: Symbian OS second phase constructor + + Symbian OS default constructor can leave. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestEventNotifier::ConstructL( ) + { + __TRACE( KVerbose, ( _L( "CTestEventNotifier::ConstructL" ) ) ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestEventNotifier + + Method: NewL + + Description: Two-phased constructor. + + Parameters: CTestEngine* aEngine: in: Pointer to CTestEngine + RTestExecution aTestExecution: in: Handle to RTestExecution + + Return Values: CTestEventNotifier* : pointer to created object + + Errors/Exceptions: Leaves if construction of CTestEventNotifier fails + + Status: Approved + +------------------------------------------------------------------------------- +*/ +CTestEventNotifier* CTestEventNotifier::NewL( CTestEngine* aEngine, + RTestExecution aTestExecution ) + { + CTestEventNotifier* self = new ( ELeave ) CTestEventNotifier( + aEngine, aTestExecution ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestEventNotifier + + Method: ~CTestEventNotifier + + Description: Destructor + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +CTestEventNotifier::~CTestEventNotifier() + { + __TRACE( KVerbose, ( _L( "CTestEventNotifier::~CTestEventNotifier" ) ) ); + Cancel(); + iEventArray.ResetAndDestroy(); + iEventArray.Close(); + delete iController; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestEventNotifier + + Method: StartL + + Description: Start active object + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestEventNotifier::Start() + { + __TRACE( KVerbose, ( _L( "CTestEventNotifier::StartL" ) ) ); + // Check that this request is not pending!! + __ASSERT_ALWAYS( iState != ETestEventPending, + User::Leave( KErrAlreadyExists ) ); + + iEvent.SetType( TEventIf::EEnable ); + iState = ETestEventPending; + iTestExecution.NotifyEvent( iEventPckg, iStatus ); + SetActive(); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestEventNotifier + + Method: RunL + + Description: RunL handles completed requests. + + Parameters: None + + Return Values: None + + Errors/Exceptions: Leaves if iStatus is not KErrNone + Leaves if iState is not ETestEventPending + Leaves if some leaving method called here leaves + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestEventNotifier::RunL() + { + __TRACE( KVerbose, ( _L( "CTestEventNotifier::RunL: iStatus=[%d]" ), iStatus.Int() ) ); + + User::LeaveIfError( iStatus.Int() ); + + switch( iState ) + { + case ETestEventPending: + { + iState = ETestEventCompleted; + + switch( iEvent.Type() ) + { + case TEventIf::EReqEvent: + { + __RDEBUG( ( _L("CTestEventNotifier(ReqEvent) %S"), + &iEvent.Name() )); + if( iEngine->IsStateEventAndSet( iEvent.Name() ) ) + { + __TRACE( KVerbose, ( _L( "CTestEventNotifier::RunL: Requested Global event already set" ) ) ); + TEventIf event( TEventIf::ESetEvent, iEvent.Name(), + TEventIf::EState ); + TEventIfPckg eventPckg( event ); + TRequestStatus status; + iTestExecution.NotifyEvent( eventPckg, status ); + User::WaitForRequest( status ); + } + //add to iEventArray + HBufC* name = iEvent.Name().AllocLC(); + if( iEventArray.Append( name ) != KErrNone ) + { + User::Leave( KErrNoMemory ); + } + CleanupStack::Pop( name ); + } + break; + case TEventIf::ERelEvent: + { + __TRACE( KVerbose, ( _L( "CTestEventNotifier(RelEvent) %S" ), &iEvent.Name() ) ); + //remove from iEventArray + TInt count = iEventArray.Count(); + const TDesC& eventName = iEvent.Name(); + TInt i; + for( i = 0; i < count; i++ ) + { + TPtrC name = iEventArray[i]->Des(); + if( name == eventName ) + { + HBufC* tmp = iEventArray[i]; + iEventArray.Remove( i ); + delete tmp; + break; + } + } + // Check that event was found + if( i == count ) + { + User::Leave( KErrGeneral ); + } + } + break; + case TEventIf::ESetEvent: + { + __RDEBUG( ( _L("CTestEventNotifier(SetEvent) %S"), + &iEvent.Name() )); + iController = iEngine->CtlEventL( iEvent, iStatus ); + SetActive(); + return; + } + case TEventIf::EUnsetEvent: + { + __RDEBUG( ( _L("CTestEventNotifier(UnsetEvent) %S"), + &iEvent.Name() )); + iController = iEngine->CtlEventL( iEvent, iStatus ); + SetActive(); + return; + } + default: + { + User::Leave( KErrGeneral ); + } + } + // Set request again + Start(); + // Otherwise request is enabled again later + } + break; + case ETestEventCompleted: + __RDEBUG( ( _L("CTestEventNotifier(Complete)"))); + Start(); + break; + default: + User::Leave( KErrGeneral ); + break; + } + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestEventNotifier + + Method: DoCancel + + Description: Cancel active request + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestEventNotifier::DoCancel() + { + __TRACE( KVerbose, ( _L( "CTestEventNotifier::DoCancel" ) ) ); + + switch ( iState ) + { + case ETestEventPending: + iTestExecution.CancelAsyncRequest( ETestExecutionNotifyEvent ); + break; + case ETestEventCompleted: + delete iController; + iController = NULL; + break; + default: + // DoCancel called in wrong state => Panic + _LIT( KTestEventNotifier, "CTestEventNotifier" ); + User::Panic( KTestEventNotifier, EDoCancelDisorder ); + break; + } + + iState = ETestEventIdle; + iEventArray.ResetAndDestroy(); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestEventNotifier + + Method: RunError + + Description: Handle errors. + + Parameters: TInt aError: in: Symbian OS error: Error code + + Return Values: TInt KErrNone: Always returned KErrNone + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +TInt CTestEventNotifier::RunError( TInt aError ) + { + switch ( iState ) + { + case ETestEventPending: + if( aError != KErrCancel ) + { + __TRACE( KError, ( CStifLogger::ERed, _L( "CTestEventNotifier::RunError %d"), aError) ); + } + else + { + __TRACE( KVerbose, ( _L( "CTestEventNotifier stopped")) ); + } + + // We stop event notifier if we get error here + // Clear requested event list + iEventArray.ResetAndDestroy(); + break; + case ETestEventCompleted: + // Do not close here + __TRACE( KError, ( CStifLogger::ERed, _L( "CTestEventNotifier::RunError %d"), aError) ); + delete iController; + iController = NULL; + // forward error to testcase + iEvent.SetType( TEventIf::EEnable ); + iState = ETestEventPending; + iTestExecution.NotifyEvent( iEventPckg, iStatus, aError ); + SetActive(); + break; + default: + __TRACE( KError, ( CStifLogger::ERed, _L( "CTestEventNotifier::RunError %d"), aError) ); + // DoCancel called in wrong state => Panic + _LIT( KTestEventNotifier, "CTestEventNotifier" ); + User::Panic( KTestEventNotifier, EDoCancelDisorder ); + break; + } + + return KErrNone; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestEventNotifier + + Method: CtlEventL + + Description: Controls events + + Parameters: const TEventIf& aEvent: in: Event + TRequestStatus& aStatus: in: Request status + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestEventNotifier::CtlEvent( const TEventIf& aEvent, + TRequestStatus& aStatus ) + { + __TRACE( KVerbose, ( _L( "CTestEventNotifier::CtlEventL" ) ) ); + const TDesC& eventName = aEvent.Name(); + TInt count = iEventArray.Count(); + for( TInt i = 0; i < count; i++ ) + { + TPtrC name = iEventArray[i]->Des(); + if( name == eventName ) + { + iEventNotify.Copy( aEvent ); + iTestExecution.NotifyEvent( iEventNotifyPckg, aStatus ); + return; + } + } + } + +/* +------------------------------------------------------------------------------- + + Class: CTestEventNotifier + + Method: CheckCtlEventL + + Description: Checks if CtlEvent should be called + + Parameters: const TEventIf& aEvent: in: Event + + Return Values: ETrue: If CtlEvent sould be called. + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +TBool CTestEventNotifier::CheckCtlEvent( const TEventIf& aEvent ) + { + const TDesC& eventName = aEvent.Name(); + TInt count = iEventArray.Count(); + for( TInt i = 0; i < count; i++ ) + { + TPtrC name = iEventArray[i]->Des(); + if( name == eventName ) + { + return ETrue; + } + } + + return EFalse; + } + +/* +------------------------------------------------------------------------------- + + DESCRIPTION + + This module contains implementation of CTestEventController class member + functions. + +------------------------------------------------------------------------------- +*/ + +// ================= MEMBER FUNCTIONS ========================================= + +/* +------------------------------------------------------------------------------- + + Class: CTestEventController + + Method: CTestEventController + + Description: Default constructor + + C++ default constructor can NOT contain any code, that + might leave. + + Parameters: CTestEngine* aEngine: in: Pointer to CTestEngine + const TEventIf& aEvent: in: Event + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +CTestEventController::CTestEventController( CTestEngine* aEngine, + const TEventIf& aEvent ) : + iEngine( aEngine ), + iRequestStatus( NULL ), + iEventPckg( iEvent ), + iActiveEventCmds( 0 ) + { + iEvent.Copy( aEvent ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestEventController + + Method: ConstructL + + Description: Symbian OS second phase constructor + + Symbian OS default constructor can leave. + + Parameters: TRequestStatus* aStatus: in: Request status + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestEventController::ConstructL( TRequestStatus* aStatus ) + { + iEngine->Logger()->Log( _L( "CTestEventController::ConstructL" ) ); + + if( CheckEventsL() == 0 ) + { + // No request was pending, complete immediately + User::RequestComplete( aStatus, KErrNone ); + } + else + { + iRequestStatus = aStatus; + } + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestEventController + + Method: ConstructL + + Description: Symbian OS second phase constructor + + Symbian OS default constructor can leave. + + Parameters: RMessage& aMessage: inout: Message to be handled + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestEventController::ConstructL( RMessage2& aMessage ) + { + iEngine->Logger()->Log( _L( "CTestEventController::ConstructL" ) ); + + if( CheckEventsL() == 0 ) + { + // No request was pending, complete immediately + aMessage.Complete( KErrNone ); + } + else + { + iMessage = aMessage; + } + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestEventNotifier + + Method: NewL + + Description: Two-phased constructor. + + Parameters: CTestEngine* aEngine: in: Pointer to CTestEngine + const TEventIf& aEvent: in: Event + TRequestStatus* aStatus: in: Request status + + Return Values: CTestEventController* : pointer to created object + + Errors/Exceptions: Leaves if construction of CTestEventController fails + + Status: Approved + +------------------------------------------------------------------------------- +*/ + +CTestEventController* CTestEventController::NewL( CTestEngine* aEngine, + const TEventIf& aEvent, + TRequestStatus* aStatus ) + { + CTestEventController* self = + new ( ELeave )CTestEventController( aEngine, aEvent ); + CleanupStack::PushL( self ); + self->ConstructL( aStatus ); + CleanupStack::Pop( self ); + return self; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestEventNotifier + + Method: NewL + + Description: Two-phased constructor. + + Parameters: CTestEngine* aEngine: in: Pointer to CTestEngine + const TEventIf& aEvent: in: Event + RMessage& aMessage: inout: Message to be handled + + Return Values: CTestEventController* : pointer to created object + + Errors/Exceptions: Leaves if construction of CTestEventController fails + + Status: Approved + +------------------------------------------------------------------------------- +*/ +CTestEventController* CTestEventController::NewL( CTestEngine* aEngine, + const TEventIf& aEvent, + RMessage2& aMessage ) + { + CTestEventController* self = + new ( ELeave )CTestEventController( aEngine, aEvent ); + CleanupStack::PushL( self ); + self->ConstructL( aMessage ); + CleanupStack::Pop( self ); + return self; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestEventController + + Method: ~CTestEventController + + Description: Destructor + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ + +CTestEventController::~CTestEventController() + { + if( iEngine != NULL ) + { + if( iEngine->Logger() != NULL ) + { + iEngine->Logger()->Log( _L( "CTestEventController::~CTestEventController" ) ); + } + } + + if( iRequestStatus ) + { + // Must be completed if pending, otherwise + // CTestEventNotifier::DoCancel blocks + User::RequestComplete( iRequestStatus, KErrCancel ); + } + + iEventCallBacks.ResetAndDestroy(); + iEventCallBacks.Close(); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestEventController + + Method: CheckEventsL + + Description: Check all events. + + Parameters: None + + Return Values: TInt: Active event commands + + Errors/Exceptions: Leaves if CtlEventL leaves + Leaves if memory allocation fails + Leaves if unset event not found from pending + state event list + + Status: Approved + +------------------------------------------------------------------------------- +*/ +TInt CTestEventController::CheckEventsL() + { + iEngine->Logger()->Log( _L( "CTestEventController::CheckEventsL" ) ); + + iActiveEventCmds += CheckClientEventsL(); + iActiveEventCmds += CheckTestcaseEventsL(); + + return iActiveEventCmds; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestEventController + + Method: CheckClientEventsL + + Description: Check client events. + + Parameters: None + + Return Values: TInt: Request of pending + + Errors/Exceptions: Leaves if CtlEventL leaves + Leaves if memory allocation fails + Leaves if unset event not found from pending + state event list + + Status: Approved + +------------------------------------------------------------------------------- +*/ +TInt CTestEventController::CheckClientEventsL() + { + iEngine->Logger()->Log( _L( "CTestEventController::CheckClientEventsL" ) ); + TInt reqPending = 0; + + // Check client event requests + TInt count = iEngine->ClientEvents().Count(); + for( TInt index = 0; index < count; index++ ) + { + if( iEngine->ClientEvents()[index]->Name() == iEvent.Name() ) + { + TEventMsg* event = iEngine->ClientEvents()[index]; + if( iEvent.Type() == TEventIf::ESetEvent ) + { + // Set found event + event->Set( iEvent.EventType() ); + } + else if( iEvent.Type() == TEventIf::EUnsetEvent ) + { + // Unset found event + // Create callback for change notifier + TCallBack callBack( EventCallBack, this ); + CCallBack* eventCallBack = new (ELeave)CCallBack( callBack, + CActive::EPriorityHigh ); + CleanupStack::PushL( eventCallBack ); + + event->Unset( eventCallBack->Status() ); + reqPending++; + eventCallBack->SetActive(); + User::LeaveIfError( iEventCallBacks.Append( eventCallBack ) ); + CleanupStack::Pop( eventCallBack ); + } + break; + } + } + + return reqPending; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestEventController + + Method: CheckTestcaseEventsL + + Description: Check testcase events. + + Parameters: None + + Return Values: TInt: Request of pending + + Errors/Exceptions: Leaves if CtlEventL leaves + Leaves if memory allocation fails + Leaves if unset event not found from pending + state event list + + Status: Approved + +------------------------------------------------------------------------------- +*/ +TInt CTestEventController::CheckTestcaseEventsL() + { + TInt reqPending = 0; + TCallBack callBack( EventCallBack, this ); + CCallBack* eventCallBack = NULL; + + // Then check testcase event requests + TInt count = iEngine->TestCaseArray().Count(); + eventCallBack = new (ELeave)CCallBack( callBack, + CActive::EPriorityHigh ); + CleanupStack::PushL( eventCallBack ); + for ( TInt index = 0; index < count; index++ ) + { + + if( iEngine->TestCaseArray()[index]->CheckCtlEvent( iEvent )) + { + reqPending++; + eventCallBack->SetActive(); + iEngine->TestCaseArray()[index]->CtlEvent( iEvent, + eventCallBack->Status() ); + User::LeaveIfError( iEventCallBacks.Append( eventCallBack ) ); + CleanupStack::Pop( eventCallBack ); + eventCallBack = new (ELeave)CCallBack( callBack, + CActive::EPriorityHigh ); + CleanupStack::PushL( eventCallBack ); + } + } + CleanupStack::PopAndDestroy( eventCallBack ); + return reqPending; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestEventController + + Method: EventComplete + + Description: EventComplete handles completed event requests. + + Parameters: None + + Return Values: None + + Errors/Exceptions: + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestEventController::EventComplete() + { + iEngine->Logger()->Log( _L( "CTestEventController::EventComplete" )); + + iActiveEventCmds--; + + if( iActiveEventCmds == 0 ) + { + TInt error = KErrNone; + TInt count = iEventCallBacks.Count(); + for( TInt i=0; iiStatus.Int() != KErrNone ) + { + error = iEventCallBacks[i]->iStatus.Int(); + break; + } + } + iEventCallBacks.ResetAndDestroy(); + + // All event commands are completed + if( iRequestStatus ) + { + User::RequestComplete( iRequestStatus, error ); + } + else + { + // No request was pending, complete immediately + iMessage.Complete( error ); + } + } + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestEventController + + Method: EventCallBack + + Description: static EventCallBack handles completed event requests. + + Parameters: TAny* aTestEventController: in: Test event controller + + Return Values: TInt: returns KErrNone + + Errors/Exceptions:None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +TInt CTestEventController::EventCallBack( TAny* aTestEventController ) + { + CTestEventController* controller = + (CTestEventController*) aTestEventController; + controller->EventComplete(); + return KErrNone; + + } + + +/* +------------------------------------------------------------------------------- + + DESCRIPTION + + This module contains implementation of CTestRemoteCmdNotifier class member + functions. + +------------------------------------------------------------------------------- +*/ + +// ================= MEMBER FUNCTIONS ========================================= + +/* +------------------------------------------------------------------------------- + + Class: CTestProgressNotifier + + Method: CTestRemoteCmdNotifier + + Description: Default constructor + + C++ default constructor can NOT contain any code, that + might leave. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Draft + +------------------------------------------------------------------------------- +*/ +CTestRemoteCmdNotifier::CTestRemoteCmdNotifier( CTestEngine* aEngine, + RTestExecution aTestExecution, + CTestCaseController* aTestCaseController, + CAtsLogger& aAtsLogger ) : + CActive( CActive::EPriorityStandard ), + iEngine( aEngine ), + iTestExecution( aTestExecution ), + iState( ETestProgressIdle ), + iRemoteTypePckg( iRemoteType ), + iMsgSizePckg( iMsgSize ), + iTestCaseController( aTestCaseController ), + iAtsLogger( aAtsLogger ) + { + CActiveScheduler::Add( this ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestRemoteCmdNotifier + + Method: ConstructL + + Description: Symbian OS second phase constructor + + Symbian OS default constructor can leave. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Draft + +------------------------------------------------------------------------------- +*/ +void CTestRemoteCmdNotifier::ConstructL( ) + { + __TRACE( KVerbose, ( _L( "CTestRemoteCmdNotifier::ConstructL" ) ) ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestRemoteCmdNotifier + + Method: NewL + + Description: Two-phased constructor. + + Parameters: CTestEngine* aEngine: in: Pointer to CTestEngine + RTestExecution aTestExecution: in: Handle to RTestExecution + + Return Values: CTestRemoteCmdNotifier* : pointer to created object + + Errors/Exceptions: Leaves if construction of CTestRemoteCmdNotifier fails + + Status: Draft + +------------------------------------------------------------------------------- +*/ +CTestRemoteCmdNotifier* CTestRemoteCmdNotifier::NewL( CTestEngine* aEngine, + RTestExecution aTestExecution, + CTestCaseController* aTestCaseController, + CAtsLogger& aAtsLogger ) + { + CTestRemoteCmdNotifier* self = new ( ELeave ) CTestRemoteCmdNotifier( + aEngine, aTestExecution, aTestCaseController, aAtsLogger ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestRemoteCmdNotifier + + Method: ~CTestRemoteCmdNotifier + + Description: Destructor + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Draft + +------------------------------------------------------------------------------- +*/ +CTestRemoteCmdNotifier::~CTestRemoteCmdNotifier() + { + __TRACE( KVerbose, ( _L( "CTestRemoteCmdNotifier::~CTestRemoteCmdNotifier" ) ) ); + Cancel(); + + delete iReceivedMsg; + iReceivedMsg = 0; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestRemoteCmdNotifier + + Method: EnableReceive + + Description: Prepare to start active object + + Parameters: const RMessage& aMessage: in: Server message + + Return Values: None + + Errors/Exceptions: None + + Status: Draft + +------------------------------------------------------------------------------- +*/ +void CTestRemoteCmdNotifier::EnableReceive( const RMessage2& aMessage ) + { + __TRACE( KVerbose, ( _L( "CTestRemoteCmdNotifier::EnableReceive" ) ) ); + + iMessage = aMessage; + iMessageAvail = ETrue; + + Start( aMessage ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestRemoteCmdNotifier + + Method: GetReceivedMsg + + Description: Read received message + + Parameters: const RMessage& aMessage: in: Server message + + Return Values: None + + Errors/Exceptions: None + + Status: Draft + +------------------------------------------------------------------------------- +*/ +void CTestRemoteCmdNotifier::GetReceivedMsg( const RMessage2& aMessage ) + { + __TRACE( KVerbose, ( _L( "CTestRemoteCmdNotifier::GetReceivedMsg" ) ) ); + + TInt ret = KErrNone; + if( iReceivedMsg ) + { + TRAP( ret, aMessage.WriteL( 0, iReceivedMsg->Des() ) ); + delete iReceivedMsg; + iReceivedMsg = 0; + } + else + { + ret = KErrNotFound; + } + + // Complete message + aMessage.Complete( ret ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestRemoteCmdNotifier + + Method: StartL + + Description: Start active object + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Draft + +------------------------------------------------------------------------------- +*/ +void CTestRemoteCmdNotifier::Start( const RMessage2& aMessage ) + { + // Check that this request is not pending!! + __ASSERT_ALWAYS( iState != ETestProgressPending, + iEngine->PanicClient( EReqPending, aMessage ) ); + iState = ETestProgressPending; + SetActive(); + // Start first phase of the remote command's operations + iTestExecution.NotifyRemoteCmd( iRemoteTypePckg, + iMsgSizePckg, + iStatus ); + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestRemoteCmdNotifier + + Method: CancelReq + + Description: Cancel the request. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Draft + +------------------------------------------------------------------------------- +*/ +void CTestRemoteCmdNotifier::CancelReq() + { + if(iMessageAvail) + { + iMessageAvail = EFalse; + iMessage.Complete( KErrCancel ); + } + } + +/* +------------------------------------------------------------------------------- + + Class: CTestRemoteCmdNotifier + + Method: RunL + + Description: RunL handles completed requests. + + Parameters: None + + Return Values: None + + Errors/Exceptions: Leaves if WriteL leaves + Leaves if iStatus is not KErrNone or KErrEof + Leaves are handled in RunError method + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestRemoteCmdNotifier::RunL() + { + __TRACE( KVerbose, ( _L( "CTestRemoteCmdNotifier::StartL: iStatus=[%d]" ), iStatus.Int() ) ); + + User::LeaveIfError( iStatus.Int() ); + + iState = ETestProgressCompleted; + + TInt ret( 0 ); + switch( iRemoteType ) + { + case EStifCmdSend: // "Sending" + { + if( ( iMessageAvail == EFalse ) || + ( iMsgSize <= 0 ) ) + { + User::Leave( KErrGeneral ); + } + // Delete previous if exists + delete iReceivedMsg; + iReceivedMsg = 0; + // Create new buffer + iReceivedMsg = HBufC8::NewL( iMsgSize ); + + // Start second phase of the remote command's operations, + // buffer is read with GetReceivedMsg + TPtr8 tmp = iReceivedMsg->Des(); + ret = iTestExecution.ReadRemoteCmdInfo( tmp, iRemoteType ); + + // Writing received info to UI + iMessage.WriteL( 0, iRemoteTypePckg ); + iMessage.WriteL( 1, iMsgSizePckg ); + + // Complete message + iMessage.Complete( ret ); + iMessageAvail = EFalse; + + break; + } + case EStifCmdReboot: // "Sending" + { + TRebootParams remoteType; + TRebootParamsPckg remoteTypePckg( remoteType ); + // Start second phase of the remote command's operations + ret = iTestExecution.ReadRemoteCmdInfo( remoteTypePckg, iRemoteType ); + __TRACE( KInit, ( CStifLogger::ERed, _L("REBOOT PHONE (type %d)" ), remoteType.aType ) ); + + if( remoteType.aType == CTestModuleIf::EKernelReset ) + { + __TRACE( KInit, ( _L("Rebooting with kernel reset" ) ) ); + __TRACE( KInit, ( _L("Kernel reset implementation is ongoing, trying different reset..." ) ) ); + } + +#ifdef __WINS__ + __TRACE( KInit, ( _L("Rebooting with Process kill(WINS)" ) ) ); + RProcess thisProcess; + //thisProcess.SetSystem( ETrue ); + thisProcess.Kill( KErrNone ); + thisProcess.Close(); +#else // Hardware specific + TInt r( KErrNone ); + __TRACE( KInit, ( _L("Rebooting with reset module(HW)" ) ) ); + r = DynamicResetModule( remoteType.aType ); + if( r != KErrNone ) + { + __TRACE( KInit, ( CStifLogger::EError, _L("This reseting type is failed, trying different reset...")) ); + } +#endif // Hardware specific + + // if( !remoteType.aType == CTestModuleIf::EDefaultReset ) + // Note this change needs an error code tranceiver between reboot + // module and engine. (If reboot fails return error code, if reboot + // is default then kill process else error code returning) + + // Do process kill as a last option + __TRACE( KInit, ( _L("Rebooting with Process kill" ) ) ); + + RProcess thisProcess2; + thisProcess2.Kill( KErrNone ); + thisProcess2.Close(); + + // If this text is shown in UI something is wrong and this needs some investigation. + iEngine->ErrorPrint( 0, _L( "Reboot phone...E.g. disconnect battery!!!" ) ); + break; + } + case EStifCmdStoreState: // "Sending" + { + if( iMessageAvail == EFalse ) + { + User::Leave( KErrGeneral ); + } + TRebootStateParams remoteState; + TRebootStateParamsPckg remoteStatePckg( remoteState ); + + // Start second phase of the remote command's operations + ret = iTestExecution.ReadRemoteCmdInfo( remoteStatePckg, + iRemoteType ); + + // Get test case information(test module, test case file, etc.) + TTestInfo testInfo; + iTestCaseController->GetTestCaseInfo( testInfo ); + + // Write state informations to the file + iEngine->WriteRebootParams( testInfo, remoteState.aCode, + remoteState.aName ); + + // Write ATS loggers buffers to drive + iEngine->FlushAtsLogger(); + + // Pause test cases that there cannot make e.g. new store state + // calls. iCaseNumber is index type value so increment by one to + // get current test case. + iEngine->PauseAllTestCases(); + // Resume current test case + iTestCaseController->iTestExecution.Resume(); + + // Writing received info to UI + iMessage.WriteL( 0, iRemoteTypePckg ); + + // Complete message + iMessage.Complete( ret ); + iMessageAvail = EFalse; + break; + } + case EStifCmdGetStoredState: // "Reading, this must be done with two phase" + { + // Get test case information(test module, test case file, etc.) + TTestInfo testInfo; + iTestCaseController->GetTestCaseInfo( testInfo ); + + TGetRebootStoredParams remoteStoredState; + // Read state informations from the file + TInt errorCodeToClient = + iEngine->ReadRebootParams( testInfo, + remoteStoredState.aName, + remoteStoredState.aCode ); + + TGetRebootStoredParamsPckg remoteStoredPckg( remoteStoredState ); + + // Start second phase of the remote command's operations + ret = iTestExecution.ReadRemoteCmdInfo( remoteStoredPckg, + iRemoteType, + errorCodeToClient ); + + Start( iMessage ); // Starts active object + + break; + } + case EStifCmdMeasurement: // "Reading, this must be done with two phase" + { + TGetMeasurementOptions remoteMeasurementOptions; + remoteMeasurementOptions.iOptions = iEngine->StifMeasurement(); + + TGetMeasurementOptionsPckg remoteMeasurementPckg( remoteMeasurementOptions ); + + // Start second phase of the remote command's operations + ret = iTestExecution.ReadRemoteCmdInfo( remoteMeasurementPckg, + iRemoteType, + KErrNone ); + + Start( iMessage ); // Starts active object + + break; + } + + case EStifCmdReceive: // "Reading" + default: + User::Leave( KErrNotFound ); + break; + } + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestRemoteCmdNotifier + + Method: DoCancel + + Description: Cancel active request + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Draft + +------------------------------------------------------------------------------- +*/ +void CTestRemoteCmdNotifier::DoCancel() + { + switch ( iState ) + { + case ETestProgressPending: + iTestExecution.CancelAsyncRequest( ETestExecutionNotifyRemoteCmd ); + //iMessage.Complete( KErrCancel ); + break; + case ETestProgressIdle: + case ETestProgressCompleted: + default: + // DoCancel called in wrong state => Panic + _LIT( KTestRemoteCmdNotifier, "CTestRemoteCmdNotifier" ); + User::Panic( KTestRemoteCmdNotifier, EDoCancelDisorder ); + break; + } + iState = ETestProgressIdle; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestRemoteCmdNotifier + + Method: RunError + + Description: Handle errors. + + Parameters: TInt aError: in: Symbian OS error: Error code + + Return Values: TInt KErrNone: Always returned KErrNone + + Errors/Exceptions: None + + Status: Draft + +------------------------------------------------------------------------------- +*/ +TInt CTestRemoteCmdNotifier::RunError( TInt aError ) + { + // Complete message with error + if(iMessageAvail) + { + iMessageAvail = EFalse; + iMessage.Complete( aError ); + } + + return KErrNone; + + } + +/* +------------------------------------------------------------------------------- + + Class: CTestRemoteCmdNotifier + + Method: ResetL + + Description: Reset HW/WINS. Loads dynamically reset module by name. + + Parameters: CTestModuleIf::TRebootType aResetType: in: Reset type + + Return Values: TInt: Symbian error code. + + Errors/Exceptions: None + + Status: Proposal + +------------------------------------------------------------------------------- +*/ +TInt CTestRemoteCmdNotifier::DynamicResetModule( + CTestModuleIf::TRebootType aResetType ) + { + __TRACE( KInit, ( _L( "DynamicResetModule()" ) ) ); + RLibrary resetModule; + // Load the module + TPtrC dllName; + dllName.Set( iEngine->GetDeviceResetDllName() ); + // Loading should work with and without '.dll' extension. + TInt r = resetModule.Load( dllName ); + if ( r != KErrNone ) + { + __TRACE( KError, ( CStifLogger::EError, _L("Can't initialize reset module[%S], code = %d"), &dllName, r ) ); + return KErrNotFound; + } + else + { + // Print reset module name + __TRACE( KInit, ( _L("Loaded reset module[%S]"), &dllName ) ); + } + + + + // Get pointer to first exported function + CTestInterfaceFactory libEntry; + libEntry = (CTestInterfaceFactory) resetModule.Lookup( 1 ); + if ( libEntry == NULL ) + { + // New instance can't be created + __TRACE ( KError, ( CStifLogger::EError, _L("Can't initialize reset module, NULL libEntry" ) ) ); + return KErrNoMemory; + } + else + { + __TRACE ( KInit, ( _L("Pointer to 1st exported received"))); + } + + CStifHWReset* reset; + reset = NULL; + + // initialize test module + __TRACE ( KVerbose, (_L("Calling 1st exported at 0x%x"), (TUint32) libEntry )); + TRAPD ( err, reset = (*libEntry)() ); + + // Handle leave from test module + if ( err != KErrNone ) + { + __TRACE (KError, ( CStifLogger::EError, _L("Leave when calling 1st exported function, code %d"), err)); + return err; + } + else if ( reset == NULL ) // Handle NULL from test module init + { + __TRACE (KError, ( CStifLogger::EError, _L("NULL pointer received when constructing test module"))); + delete reset; + + // Set error codes + return KErrNoMemory; + } + else + { + __TRACE (KInit, (_L("Entrypoint successfully called, test module instance at 0x%x"), (TUint32)reset ) ); + } + + // Calls dynamically loaded reset module's method. + TInt ret = reset->DoReset( aResetType ); + if( ret != KErrNone ) + { + __TRACE (KInit, (_L("DynamicResetModule; DoReset fails with error: %d"), ret ) ); + return ret; + } + + return KErrNone; + + } + +/* +------------------------------------------------------------------------------- + + DESCRIPTION + + This module contains implementation of CTestCommandNotifier class member + functions. + +------------------------------------------------------------------------------- +*/ + +// ================= MEMBER FUNCTIONS ========================================= + +/* +------------------------------------------------------------------------------- + + Class: CTestCommandNotifier + + Method: CTestCommandNotifier + + Description: Default constructor + + C++ default constructor can NOT contain any code, that + might leave. + + Parameters: CTestEngine* aEngine: in: Pointer to CTestEngine + RTestExecution aTestExecution: in: Handle to RTestExecution + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +CTestCommandNotifier::CTestCommandNotifier(CTestEngine* aEngine, + RTestExecution aTestExecution): + CActive(CActive::EPriorityStandard), + iEngine(aEngine), + iTestExecution(aTestExecution), + iCommandPckg(iCommand) + { + CActiveScheduler::Add(this); + } + +/* +------------------------------------------------------------------------------- + + Class: CTestCommandNotifier + + Method: ConstructL + + Description: Symbian OS second phase constructor + + Symbian OS default constructor can leave. + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestCommandNotifier::ConstructL( ) + { + __TRACE(KVerbose, (_L("CTestCommandNotifier::ConstructL"))); + } + +/* +------------------------------------------------------------------------------- + + Class: CTestCommandNotifier + + Method: NewL + + Description: Two-phased constructor. + + Parameters: CTestEngine* aEngine: in: Pointer to CTestEngine + RTestExecution aTestExecution: in: Handle to RTestExecution + + Return Values: CTestCommandNotifier* : pointer to created object + + Errors/Exceptions: Leaves if construction of CTestCommandNotifier fails + + Status: Approved + +------------------------------------------------------------------------------- +*/ +CTestCommandNotifier* CTestCommandNotifier::NewL(CTestEngine* aEngine, + RTestExecution aTestExecution) + { + CTestCommandNotifier* self = new (ELeave) CTestCommandNotifier(aEngine, aTestExecution); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +/* +------------------------------------------------------------------------------- + + Class: CTestCommandNotifier + + Method: ~CTestCommandNotifier + + Description: Destructor + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +CTestCommandNotifier::~CTestCommandNotifier() + { + __TRACE(KVerbose, (_L("CTestEventNotifier::~CTestEventNotifier"))); + Cancel(); + } + +/* +------------------------------------------------------------------------------- + + Class: CTestCommandNotifier + + Method: StartL + + Description: Start active object + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestCommandNotifier::Start() + { + __TRACE(KVerbose, (_L("CTestEventNotifier::StartL"))); + + iTestExecution.NotifyCommand2(iCommandPckg, iParamsPckg, iStatus, KErrNone); + SetActive(); + } + +/* +------------------------------------------------------------------------------- + + Class: CTestCommandNotifier + + Method: RunL + + Description: RunL handles completed requests. + + Parameters: None + + Return Values: None + + Errors/Exceptions: Leaves if iStatus is not KErrNone + Leaves if iState is not ETestEventPending + Leaves if some leaving method called here leaves + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestCommandNotifier::RunL() + { + __TRACE(KVerbose, (_L("CTestCommandNotifier::RunL: iStatus=[%d]"), iStatus.Int())); + + User::LeaveIfError(iStatus.Int()); + + iEngine->ExecuteCommandL(iCommand, iParamsPckg); + + // Set request again + Start(); + } + +/* +------------------------------------------------------------------------------- + + Class: CTestCommandNotifier + + Method: DoCancel + + Description: Cancel active request + + Parameters: None + + Return Values: None + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +void CTestCommandNotifier::DoCancel() + { + __TRACE(KVerbose, (_L( "CTestEventNotifier::DoCancel"))); + + iTestExecution.CancelAsyncRequest(ETestExecutionNotifyCommand); + } + +/* +------------------------------------------------------------------------------- + + Class: CTestCommandNotifier + + Method: RunError + + Description: Handle errors. + + Parameters: TInt aError: in: Symbian OS error: Error code + + Return Values: TInt KErrNone: Always returned KErrNone + + Errors/Exceptions: None + + Status: Approved + +------------------------------------------------------------------------------- +*/ +TInt CTestCommandNotifier::RunError(TInt aError) + { + __TRACE(KError, (CStifLogger::ERed, _L("CTestCommandNotifier::RunError %d"), aError)); + return KErrNone; + } + + +// ================= OTHER EXPORTED FUNCTIONS ================================= + +// None + +// End of File