imagingtestenv/imagingtestfw/Source/TestFrameworkClient/TestStep.cpp
changeset 0 5752a19fdefe
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/imagingtestenv/imagingtestfw/Source/TestFrameworkClient/TestStep.cpp	Wed Aug 25 12:29:52 2010 +0300
@@ -0,0 +1,1164 @@
+// Copyright (c) 2002-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:
+//
+
+// EPOC includes
+#include <e32base.h>
+
+// Test system includes
+#include <testframework.h>
+#include "TestIniData.h"
+#include "asyncscheduler.h"
+
+// do not export if Unit Testing
+#if defined (__TSU_TESTFRAMEWORK__)
+#undef EXPORT_C
+#define EXPORT_C
+#endif
+
+static const TUint16*const KVerdictString[] = // must match up with TVerdict
+	{
+	_S("EPass"),
+	_S("EFail"),
+	_S("EInconclusive"),
+	_S("ETestSuiteError"),
+	_S("EAbort"),
+	_S("EKnownFailure")
+	};
+
+/**
+ *
+ * Test step constructor.
+ *
+ * @xxxx
+ *
+ */
+EXPORT_C RTestStep::RTestStep()
+	{
+	iTestStepResult = EPass;
+	iTestStepName.Zero();
+	iSuite = NULL;
+	iConfigData = NULL;
+	iConfigDataAvailable = EFalse;
+	iStackSize = KTestStackSize;
+	iHeapSize = KMaxTestThreadHeapSize;
+
+	// NB : RTestStep has no destructor
+	}
+
+/**
+ *
+ * CBase compatibility functionality.
+ *
+ * @xxxx
+ *
+ */
+
+
+EXPORT_C TAny* RTestStep::operator new(TUint aSize, TAny* aBase) __NO_THROW
+	{
+	Mem::FillZ(aBase,aSize);
+	return(aBase);
+	}
+
+
+EXPORT_C TAny* RTestStep::operator new(TUint aSize, TLeave)
+	{
+	return newL(aSize);		// will leave on alloc failure
+	}
+
+EXPORT_C TAny* RTestStep::operator new(TUint aSize) __NO_THROW
+	{
+	TAny* pM=User::Alloc(aSize);
+	if (pM)
+		Mem::FillZ(pM,aSize);
+	return(pM);
+	}
+
+EXPORT_C TAny* RTestStep::newL(TUint aSize)
+	{
+	TAny* pM=User::AllocL(aSize);
+	Mem::FillZ(pM,aSize);
+	return pM;
+	}
+
+EXPORT_C TAny* RTestStep::operator new(TUint aSize,TUint anExtraSize) __NO_THROW
+	{
+	aSize+=anExtraSize;
+	TAny *pM=User::Alloc(aSize);
+	if (pM)
+		Mem::FillZ(pM,aSize);
+	return(pM);
+	}
+
+/**
+ *
+ * Pre-preamble for all test steps. This grows the cleanup stack to
+ * allow for allocation errors.
+ *
+ * @xxxx
+ *
+ */
+EXPORT_C void RTestStep::PreOpenL()
+	{
+	TAny* dummyPtr = NULL;
+	for(TInt i = 0 ; i < 20 ; i++)
+		CleanupStack::PushL(dummyPtr); // Grow the cleanup stack.
+	CleanupStack::PopAndDestroy(20);
+	}
+
+/**
+ *
+ * Default empty implementation of OpenL (preamble).
+ * Test steps can override this to implement required code.
+ *
+ * @return	"TVerdict"
+ *			Result of preamble (should only be EPass or EInconclusive)
+ *
+ * @xxxx
+ *
+ */
+EXPORT_C TVerdict RTestStep::OpenL()
+	{
+	// for backward compatibility with CTestStep
+	return DoTestStepPreambleL();
+	}
+
+/**
+ *
+ * Default empty implementation of CleanupAfterOpenFail (preamble cleanup).
+ * Test steps can override this to implement required code.
+ *
+ * @xxxx
+ *
+ */
+EXPORT_C void RTestStep::CleanupAfterOpenFail()
+	{
+	// default empty implementation
+	// a step should implement its own method if required
+	}
+
+/**
+ *
+ * Default empty implementation of Close (postamble)
+ * Test steps can override this to implement required code.
+ *
+ * NB this does NOT leave - any leaves should be trapped and panicked.
+ *
+ * @xxxx
+ *
+ */
+EXPORT_C void RTestStep::Close()
+	{
+	// for backward compatibility with CTestStep
+	_LIT(KPanicStr, "RTestStep::Close");
+	TVerdict ver = EPass;
+	TRAPD(err, ver = DoTestStepPostambleL());
+	if(err != KErrNone)
+		User::Panic(KPanicStr, 0);
+	// any DoTestStepPostambleL() which returns EInconclusive should be panicked
+ 	if(ver != EPass)
+		User::Panic(KPanicStr, 1);
+
+	}
+
+/**
+ *
+ * Set the test suite
+ *
+ * @param	"CTestSuite*"
+ *			The test suite
+ *
+ * @xxxx
+ *
+ */
+EXPORT_C void RTestStep::SetSuite(CTestSuite* aSuite)
+	{
+	iSuite = aSuite;
+	}
+
+/**
+ *
+ * Set the test result
+ *
+ * @param	"TVerdict"
+ *			The test result
+ *
+ * @xxxx
+ *
+ */
+EXPORT_C void RTestStep::SetResult(TVerdict aResult)
+	{
+	iTestStepResult = aResult;
+	}
+
+/**
+ *
+ * Get the step name
+ *
+ * @return	"TPtrC"
+ *			The step name
+ *
+ * @xxxx
+ *
+ */
+EXPORT_C TPtrC RTestStep::StepName() const
+	{
+	return iTestStepName;
+	}
+
+/**
+ *
+ * General logging function for test steps.
+ *
+ * @param	"TRefByValue<const TDesC16> aFmt"
+ *			Printf-style aFmt.
+ *
+ * @param	"..."
+ *			Variable print parameters
+ *
+ * @xxxx
+ *
+ */
+EXPORT_C void RTestStep::Log(TRefByValue<const TDesC16> aFmt, ...)
+	{
+    
+	VA_LIST aList;
+	VA_START(aList, aFmt);
+
+	TIntegrationTestLog16Overflow iOverflow16;
+
+	// decode formatted data for display on console
+	TBuf<KMaxLogLineLength> lineBuf;
+	lineBuf.AppendFormatList(aFmt, aList, &iOverflow16);
+
+	// send the data to the log system via the suite
+	iSuite->Log(_L("%S"),&lineBuf);
+
+	VA_END(aList); 
+
+	}
+
+/**
+ *
+ * General logging function for test steps, with severity.
+ *
+ * @param	"TInt aSeverity"
+ *			Severity level required to log
+ *
+ * @param	"TRefByValue<const TDesC16> aFmt"
+ *			Printf-style aFmt.
+ *
+ * @param	"..."
+ *			Variable print parameters
+ *
+ * @xxxx
+ *
+ */
+EXPORT_C void RTestStep::Log( TInt aSeverity, TRefByValue<const TDesC16> aFmt, ... )
+{
+	VA_LIST aList;
+	VA_START(aList, aFmt);
+
+	TIntegrationTestLog16Overflow iOverflow16;
+
+	// decode formatted data for display on console
+	TBuf<KMaxLogLineLength> lineBuf;
+	lineBuf.AppendFormatList(aFmt, aList, &iOverflow16);
+
+	// send the data to the log system via the suite
+	if(LogSeverity::IsActive(aSeverity, iSuite->Severity()))
+		iSuite->Log(aSeverity, _L("%S"),&lineBuf);
+
+	VA_END(aList); 
+}
+
+/**
+ *
+ * Traceable logging function for test steps.
+ *
+ * @param	"const TText8* aFile"
+ *			Source code file name
+ *
+ * @param	"TInt aLine"
+ *			Source code line
+ *
+ * @param	"TInt aSeverity"
+ *			Severity level required to log
+ *
+ * @param	"TRefByValue<const TDesC16> aFmt"
+ *			Printf-style format.
+ *
+ * @param	"..."
+ *			Variable print parameters
+ *
+ * @xxxx
+ *
+ */
+EXPORT_C void RTestStep::LogExtra(const TText8* aFile, TInt aLine, TInt aSeverity,
+		TRefByValue<const TDesC16> aFmt,...)
+	{
+	VA_LIST aList;
+	VA_START(aList, aFmt);
+
+	TIntegrationTestLog16Overflow iOverflow16;
+
+	// decode formatted data for display on console
+	TBuf<KMaxLogLineLength> lineBuf;
+	lineBuf.AppendFormatList(aFmt, aList, &iOverflow16);
+
+	// send the data to the log system via the suite
+	if(LogSeverity::IsActive(aSeverity, iSuite->Severity()))
+		iSuite->LogExtra(aFile, aLine, aSeverity, lineBuf);
+
+	VA_END(aList); 
+	}
+	
+/**
+Set default paramSet
+Test steps can use this when looking up configs, to provide a level of script control
+*/
+void RTestStep::SetDefaultParamSet(const TDesC& aParamSet)
+	{
+	iDefaultParamSet.Set(aParamSet);
+	}
+
+/**
+ *
+ * Load a configuration file.
+ * If successful, data member iConfigDataAvailable is set.
+ *
+ * @param	"TPtrC aConfig"
+ *			The configuration file name.
+ *
+ * @xxxx
+ *
+ */
+EXPORT_C void RTestStep::LoadConfig(const TDesC& aConfig)
+	{
+
+	// if a config file supplied then use
+	if (aConfig.Length() != 0)
+		{
+
+		// get the full pathname default drive name and extension
+		_LIT(KRelated,"C:\\config.ini"); 
+		TParse configFileName;
+		TInt returnCode = configFileName.Set(aConfig, &KRelated, NULL);
+
+		if (returnCode != KErrNone)
+			{
+			// error opening FileManager
+			ERR_PRINTF2(_L("Error opening config file %S"), &(configFileName.FullName())); 
+			}
+
+		// create and load the CTestIniData object
+		TRAPD(r, iConfigData = CTestIniData::NewL(configFileName.FullName()));
+		
+		// check if loaded ok
+		if (r == KErrNone)
+			{
+			// loaded ok
+			iConfigDataAvailable = ETrue;
+			}
+		else
+			{
+			// failed to load
+			iConfigDataAvailable = EFalse;
+			iConfigData = NULL;
+
+			// report error 
+			TPtrC errortxt = CLog::EpocErrorToText(r);
+			ERR_PRINTF2(_L("Failed to load config data file - error %S"), &errortxt);
+			}
+		}
+	}
+
+/**
+ *
+ * Unload any existing configuration data.
+ *
+ * @xxxx
+ *
+ */
+EXPORT_C void RTestStep::UnloadConfig()
+	{
+	iConfigDataAvailable = EFalse;
+
+	// clean up Config data object
+	delete iConfigData;
+	iConfigData = NULL;
+
+	}
+
+/**
+ *
+ * Check the config file for a boolean value
+ *
+ * @param	"const TDesC &aSectName"
+ *			Section name to check in
+ *
+ * @param	"const TDesC &aKeyName"
+ *			Key name to check for
+ *
+ * @param	"Bool &aResult"
+ *			TBool returned from config file
+ *
+ * @return	"TBool"
+ *			Result (ETrue if found)
+ *
+ * @xxxx
+ *
+ */
+EXPORT_C TBool RTestStep::GetBoolFromConfig(const TDesC &aSectName, const TDesC &aKeyName, TBool &aResult)
+	{
+	// check file available
+	if (!iConfigDataAvailable)
+		{
+		ERR_PRINTF1(_L("No config file available"));
+		return EFalse;
+		}
+
+	TBool ret = EFalse;
+	TPtrC result;
+
+	// get the value 
+	ret = iConfigData->FindVar(aSectName, aKeyName, result);
+
+	// if failed to decode display error
+	if (!ret) 
+		{
+		// display error message
+		ERR_PRINTF3(_L("Failed to read section:%S key:%S "),
+				&aSectName, &aKeyName );
+
+		// return fail
+		return EFalse;
+		}
+
+	// set result as a TBool
+	if (result.FindF(_L("true")) == KErrNotFound)
+		aResult = EFalse;
+	else
+		aResult = ETrue;
+	// return success
+	return ETrue;
+	}
+
+/**
+ *
+ * Check the config file for a TInt value
+ *
+ * @param	"const TDesC &aSectName"
+ *			Section name to check in
+ *
+ * @param	"const TDesC &aKeyName"
+ *			Key name to check for
+ *
+ * @param	"TInt &aResult"
+ *			TInt returned from config file
+ *
+ * @return	"TBool"
+ *			Result (ETrue if found)
+ *
+ * @xxxx
+ *
+ */
+EXPORT_C TBool RTestStep::GetIntFromConfig(const TDesC &aSectName, const TDesC &aKeyName, TInt &aResult)
+	{
+	// check file available
+	if ( !iConfigDataAvailable )
+		{
+		ERR_PRINTF1(_L("No config file available"));
+		return EFalse;
+		}	
+
+	TBool ret = EFalse;
+	TPtrC result;
+
+	// get the value 
+	ret = iConfigData->FindVar(aSectName, aKeyName, result);
+
+	// if failed to decode display error
+	if (!ret) 
+		{
+		// display error message
+		ERR_PRINTF3(_L("Failed to read section:%S key:%S "),
+				&aSectName, &aKeyName );
+
+		// return fail
+		return EFalse;
+		}
+
+	// use TLex to convert to a TInt
+	TLex lex(result);
+	if (lex.Val(aResult) == KErrNone)
+		return ETrue;
+	else
+		return EFalse;
+}
+
+/**
+ *
+ * Check the config file for a string TPtr value
+ *
+ * @param	"const TDesC &aSectName"
+ *			Section name to check in
+ *
+ * @param	"const TDesC &aKeyName"
+ *			Key name to check for
+ *
+ * @param	"TPtrC &aResult"
+ *			String returned from config file
+ *
+ * @return	"TBool"
+ *			Result (ETrue if found)
+ *
+ * @xxxx
+ *
+ */
+EXPORT_C TBool RTestStep::GetStringFromConfig(const TDesC &aSectName, const TDesC &aKeyName, TPtrC &aResult)
+	{
+	// check file available
+	if (!iConfigDataAvailable)
+		{
+		ERR_PRINTF1(_L("No config file available"));
+		return EFalse;
+		}	
+
+	// get the value 
+	TBool ret = iConfigData->FindVar(aSectName, aKeyName, aResult);
+
+	// if failed to decode display error
+	if (ret == EFalse) 
+		{
+		ERR_PRINTF3(_L("Failed to read section:%S key:%S "),
+				&aSectName, &aKeyName );
+		}
+
+	return ret;
+}
+
+/**
+ * Reads the value present from the test steps ini file within the mentioned section name and key name
+ * Copies the value to the TInt reference passed in
+ * @param aSectName - Section within the test steps ini file
+ * @param aKeyName - Name of a key within a section
+ * @return aResult - The integer value of the Hex input
+ * @return TBool - ETrue for found, EFalse for not found 
+ */	
+EXPORT_C TBool RTestStep::GetHexFromConfig(const TDesC &aSectName,const TDesC &aKeyName,TInt &aResult)
+	{
+	TPtrC result;
+	if(!iConfigData)
+		return EFalse;
+	if(!iConfigData->FindVar(aSectName, aKeyName, result))
+		return EFalse;
+	TLex lex(result);
+	TInt err = lex.Val((TUint &)aResult, EHex);
+	if(err)
+		return EFalse;
+	
+	return(ETrue);
+	}
+	
+/**
+ *
+ * Default empty implementation of DoTestStepPreambleL.
+ * Test steps can override this to implement required code.
+ *
+ * @return	"TVerdict"
+ *			Result of preamble (should only be EPass or EInconclusive)
+ *
+ * @xxxx
+ *
+ */
+// for backward compatibility with CTestStep
+EXPORT_C TVerdict RTestStep::DoTestStepPreambleL()
+	{
+	return EPass;
+	}
+
+/**
+ *
+ * Default empty implementation of DoTestStepPostambleL.
+ * Test steps can override this to implement required code.
+ *
+ * @return	"TVerdict"
+ *			Result of postamble (should only be EPass or EInconclusive)
+ *
+ * @xxxx
+ *
+ */
+// for backward compatibility with CTestStep
+EXPORT_C TVerdict RTestStep::DoTestStepPostambleL()
+	{
+	return EPass;
+	}
+
+/**
+ *
+ * Traceable Boolean condition tester.
+ * If the condition is not true, record an error.
+ *
+ * @param	"TBool aCondition"
+ *			Condition to be checked
+ *
+ * @param	"const TText8* aFile"
+ *			Source code file name
+ *
+ * @param	"TInt aLine"
+ *			Source code line
+ *
+ * @xxxx
+ *
+ */
+EXPORT_C void RTestStep::TestBooleanTrue(TBool aCondition, const TText8* aFile, TInt aLine)
+	{
+
+	// check condition
+	if (aCondition)
+		return;
+
+	// this is only relevant if the current result is pass
+	if (iTestStepResult == EPass)
+		iTestStepResult = EFail;
+
+	// convert filename for log
+	TBuf<KMaxLogFilenameLength> fileName;
+	TPtrC8 fileName8(aFile);
+	fileName.Copy(fileName8);  // TText8->TBuf16
+
+	// display a log message
+ 	ERR_PRINTF3(_L("Test Failed in file:%S line:%d"), &fileName, aLine);
+
+	}
+
+/**
+ *
+ * Traceable Boolean condition tester.
+ * If the condition is not true, record an error and leave.
+ *
+ * @param	"TBool aCondition"
+ *			Condition to be checked
+ *
+ * @param	"const TText8* aFile"
+ *			Source code file name
+ *
+ * @param	"TInt aLine"
+ *			Source code line
+ *
+ * @xxxx
+ *
+ */
+EXPORT_C void RTestStep::TestBooleanTrueL(TBool aCondition, const TText8* aFile, TInt aLine)
+	{
+
+	// check condition
+	if (aCondition)
+		return;
+
+	// this is only relevant if the current result is pass
+	if (iTestStepResult == EPass)
+		iTestStepResult = EFail;
+
+	// convert filename for log
+	TBuf<KMaxLogFilenameLength> fileName;
+	TPtrC8 fileName8(aFile);
+	fileName.Copy(fileName8);  // TText8->TBuf16
+
+	// display a log message
+ 	ERR_PRINTF3(_L("Test Failed in file:%S line:%d"), &fileName, aLine);
+
+	// leave with error code
+	User::Leave(KTestErrorCode);
+
+	}
+
+/**
+ *
+ * Traceable Boolean condition tester.
+ * If the condition is not true, record an error with the supplied 
+ * error code, and leave.
+ *
+ * @param	"TBool aCondition"
+ *			Condition to be checked
+ *
+ * @param	"TInt aErrorCode"
+ *			Supplied error code
+ *
+ * @param	"const TText8* aFile"
+ *			Source code file name
+ *
+ * @param	"TInt aLine"
+ *			Source code line
+ *
+ * @xxxx
+ *
+ */
+EXPORT_C void RTestStep::TestBooleanTrueWithErrorCodeL(TBool aCondition, TInt aErrorCode, const TText8* aFile, TInt aLine)
+	{
+	// check condition
+	if (aCondition)
+		return;
+
+	// this is only relevant if the current result is pass
+	if (iTestStepResult == EPass)
+		iTestStepResult = EFail;
+
+	// convert filename for log
+	TBuf<KMaxLogFilenameLength> fileName;
+	TPtrC8 fileName8(aFile);
+	fileName.Copy(fileName8);  // TText8->TBuf16
+
+	// get the error text
+	TPtrC errortxt = CLog::EpocErrorToText(aErrorCode);
+
+	// display a log message
+	ERR_PRINTF4(_L("Test Failed with error:%S in file:%S line:%d"),
+			&errortxt, &fileName, aLine);
+
+	// leave with error code
+	User::Leave(aErrorCode);
+	
+	}
+
+/**
+ *
+ * Traceable Boolean condition tester.
+ * If the condition is not true, record an error with the supplied 
+ * error code.
+ *
+ * @param	"TBool aCondition"
+ *			Condition to be checked
+ *
+ * @param	"TInt aErrorCode"
+ *			Supplied error code
+ *
+ * @param	"const TText8* aFile"
+ *			Source code file name
+ *
+ * @param	"TInt aLine"
+ *			Source code line
+ *
+ * @xxxx
+ *
+ */
+EXPORT_C void RTestStep::TestBooleanTrueWithErrorCode(TBool aCondition, TInt aErrorCode, const TText8* aFile, TInt aLine)
+	{
+	// check condition
+	if (aCondition)
+		return;
+
+	// this is only relevant if the current result is pass
+	if (iTestStepResult == EPass)
+		iTestStepResult = EFail;
+
+	// convert filename for log
+	TBuf<KMaxLogFilenameLength> fileName;
+	TPtrC8 fileName8(aFile);
+	fileName.Copy(fileName8);  // TText8->TBuf16
+
+	// get the error text
+	TPtrC errortxt = CLog::EpocErrorToText(aErrorCode);
+
+	// display a log message
+	ERR_PRINTF4(_L("Test Failed with error:%S in file:%S line:%d"),
+			&errortxt, &fileName, aLine);
+	}
+
+/**
+ *
+ * Traceable checkpoint tester.
+ * If the value does not match expected, record an error with supplied
+ * text string, and leave.
+ *
+ * @param	"TInt aVal"
+ *			Value to be checked
+ *
+ * @param	"TInt aExpectedVal"
+ *			Value expected
+ *
+ * @param	"const TDesC& aText"
+ *			Supplied text string
+ *
+ * @param	"const TText8* aFile"
+ *			Source code file name
+ *
+ * @param	"TInt aLine"
+ *			Source code line
+ *
+ * @xxxx
+ *
+ */
+EXPORT_C void RTestStep::TestCheckPointCompareL(TInt aVal, TInt aExpectedVal, 
+												  const TDesC& aText, const TText8* aFile, TInt aLine)
+	{
+	if(aVal != aExpectedVal)
+		{
+		// this is only relevant if the current result is pass
+		if (iTestStepResult == EPass)
+			iTestStepResult = EFail;
+
+		// convert filename for log
+		TBuf<KMaxLogFilenameLength> fileName;
+		TPtrC8 fileName8(aFile);
+		fileName.Copy(fileName8);  // TText8->TBuf16
+
+		ERR_PRINTF6(_L("FAILED test:  Val = %d Exp Val = %d %S in file:%S line:%d"), 
+			aVal, aExpectedVal, &aText, &fileName, aLine);
+
+		User::Leave(aVal);
+		}
+	}
+
+/** 
+ *
+ * Accessors for stack / heap size
+ *
+ * NB - These can only be set from within the RTestStep derived constructor itself - there
+ * are no setter accessors.
+ *
+ * @xxxx
+ *
+ */
+EXPORT_C TInt RTestStep::StackSize() const
+{
+	return iStackSize;
+}
+
+EXPORT_C TInt RTestStep::HeapSize() const
+{
+	return iHeapSize;
+}
+
+
+/** 
+ *
+ * Virtual destructor for CTestStep
+ * Provided for backward compatibility ONLY
+ *
+ * @xxxx
+ *
+ */
+EXPORT_C CTestStep::~CTestStep()
+{
+}
+
+//
+// RAsyncTestStep
+//
+
+EXPORT_C RAsyncTestStep::RAsyncTestStep():
+	iReason (KErrNone),
+	iResult (EPass),
+	iStartAO (NULL),
+	iActiveSchedulerWait (NULL),
+	iStarted (EFalse)
+	{
+	}
+
+EXPORT_C TVerdict RAsyncTestStep::DoTestStepL()
+	{
+	// allow recalls to same test step (?), so re-initialise the basic variables. Can't delete
+	// as if in that case, old heap would be dead
+	iReason = KErrNone;
+	iResult = EPass;
+	iScheduler = NULL;
+	iActiveSchedulerWait = NULL;
+	
+	iScheduler = new (ELeave) CAsyncTestActiveScheduler(*this);	
+	CActiveScheduler::Install(iScheduler);
+	iActiveSchedulerWait = new (ELeave) CActiveSchedulerWait();
+	
+	// arrange for DoCallBack() to be called as the first thing. Use low priority to reduce
+	// the overhead of an extra AO on everything else
+	TCallBack callback (CallBack, this);
+	iStartAO = NULL;
+	iStartAO = new (ELeave) CAsyncCallBack (callback, CActive::EPriorityIdle); 
+	iStartAO->Call();
+	
+	iStarted = ETrue; // obviously do this before we start, as can't once it is
+	iActiveSchedulerWait->Start();
+	return CheckTestResult();
+	}
+
+EXPORT_C TVerdict RAsyncTestStep::DoTestStepPostambleL()
+	{
+	CloseTest();
+	delete iStartAO; // no need to Cancel 
+	iStartAO = NULL;
+	delete iActiveSchedulerWait;
+	iActiveSchedulerWait = NULL;
+	delete iScheduler; 
+	iScheduler = NULL;
+	return EPass;
+	}
+	
+EXPORT_C void RAsyncTestStep::StopTest()
+	{
+	StopTest(KErrNone);
+	}
+	
+EXPORT_C void RAsyncTestStep::StopTest(TInt aReason)
+	{
+	TVerdict resultToUse = (aReason==KErrNone) ? EPass : EFail;
+	StopTest (aReason, resultToUse);
+	}
+
+EXPORT_C void RAsyncTestStep::StopTest(TInt aReason, TVerdict aResult)
+	{
+	// note if stop is called multiple times, we record last
+	// non-KErrNone reason and last non-Pass result, but only actually stop once
+	if (aReason!=KErrNone)
+		{
+		iReason = aReason;		
+		}
+	SetResult(aResult);
+	if (iStarted)
+		{
+		iStarted = EFalse;
+		iActiveSchedulerWait->AsyncStop();
+		}
+	}
+	
+EXPORT_C TInt RAsyncTestStep::Reason() const
+	{
+	return iReason;
+	}
+	
+EXPORT_C TVerdict RAsyncTestStep::Result() const
+	{
+	return iResult;
+	}
+	
+void RAsyncTestStep::SetResult(TVerdict aResult)
+	{
+	// remember the last non-Pass result
+	if (aResult!=EPass)
+		{
+		iResult = aResult;
+		}	
+	}
+	
+EXPORT_C TVerdict RAsyncTestStep::CheckTestResult()
+	{
+	TVerdict result = Result();
+	
+	if (result!=EPass) // if the result is a Pass, even if error is too we treat as test pass
+		{
+		INFO_PRINTF3(_L("Failed test with error %d, result %s"), Reason(), KVerdictString[result]);
+		}
+	return result;
+	}
+
+TInt RAsyncTestStep::CallBack(TAny* aPtr)
+	{
+	RAsyncTestStep* self = static_cast<RAsyncTestStep*> (aPtr);
+	self->DoCallBack(); // if this fails, it will stop itself
+	return KErrNone;
+	}
+	
+void RAsyncTestStep::DoCallBack()
+	{
+	TRAPD(error, KickoffTestL()); 
+	if (error!=KErrNone)
+		{
+		StopTest(error); // if kickoff fails, we stop here
+		}	
+	}
+
+void RAsyncTestStep::HandleError(TInt aError)
+	{
+	INFO_PRINTF2(_L("ActiveScheduler::Error(%d)"), aError);
+	StopTest(aError);
+	}
+	
+//
+// CBusyTestUnit
+//
+
+CBusyTestUnit::CBusyTestUnit():
+		iPercentBusy(0), iThreadPriority(EPriorityNormal)
+	{
+	// non exported default constructor to enforce non-derivation
+	}
+
+CBusyTestUnit::CBusyTestUnit(TInt aPercentBusy, TThreadPriority aThreadPriority):
+		iPercentBusy(aPercentBusy), iThreadPriority(aThreadPriority)
+	{
+	ASSERT(aPercentBusy>=0 && aPercentBusy<=100); // assume this
+	}
+	
+void CBusyTestUnit::ConstructL()
+	{
+	}
+	
+EXPORT_C CBusyTestUnit* CBusyTestUnit::NewLC(TInt aPercentBusy, TThreadPriority aThreadPriority)
+	{
+	CBusyTestUnit* self = new (ELeave) CBusyTestUnit(aPercentBusy, aThreadPriority);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;
+	}
+	
+EXPORT_C CBusyTestUnit* CBusyTestUnit::NewL(TInt aPercentBusy, TThreadPriority aThreadPriority)
+	{
+	CBusyTestUnit* self = NewLC(aPercentBusy, aThreadPriority);
+	CleanupStack::Pop(self);
+	return self;
+	}
+	
+CBusyTestUnit::~CBusyTestUnit()
+	{
+	Stop();
+	}
+	
+EXPORT_C void CBusyTestUnit::Stop()
+	{
+	if (iTimer)
+		{
+		iTimer->Cancel();
+		delete iTimer;
+		iTimer=NULL;
+		}
+	if (iChildThread.Handle())
+		{
+		// child thread created, so kill
+		iChildThread.Kill(0);
+		iChildThread.Close();
+		}
+	}
+	
+EXPORT_C TInt CBusyTestUnit::Start()
+	{
+	return Start(0);	
+	}
+	
+EXPORT_C TInt CBusyTestUnit::Start(TTimeIntervalMicroSeconds aRunFor)
+	{
+	return Start(0, aRunFor);
+	}
+	
+EXPORT_C TInt CBusyTestUnit::Start(TTimeIntervalMicroSeconds32 aDelayFor, TTimeIntervalMicroSeconds aRunFor)
+	{
+	iRunFor = aRunFor;
+	if (!aDelayFor.Int())
+		{
+		// run immediately
+		return RunThread();
+		}
+	else
+		{
+		iTimer = CPeriodic::NewL(CActive::EPriorityHigh);
+		TCallBack callback(StaticTimerCallback, this);
+		iTimer->Start(aDelayFor, 0, callback);
+		return KErrNone;
+		}
+	}
+	
+TInt CBusyTestUnit::StaticTimerCallback(TAny* aPtr)
+	{
+	CBusyTestUnit* self = static_cast<CBusyTestUnit*>(aPtr);
+	return self->TimerCallback();
+	}
+	
+TInt CBusyTestUnit::TimerCallback()
+	{
+	// called on timer callback, so assume iTimer!
+	ASSERT(iTimer);
+	// first stop and delete timer - don't need again this run
+	iTimer->Cancel();
+	// then kick off the thread
+	TInt error = RunThread(); 
+	// now delete the timer - do now as we've been called back by it!
+	delete iTimer;
+	iTimer = NULL;
+	return error; // any error will stop the test, in theory
+	}
+	
+TInt CBusyTestUnit::RunThread()
+	{
+	TAny* paramPtr = this;
+	TInt error = iChildThread.Create(KNullDesC, StartThread, 
+					KDefaultStackSize, NULL, paramPtr, EOwnerThread);
+	if (!error)
+		{
+		iChildThread.SetPriority(iThreadPriority);
+		iChildThread.Resume();
+		}
+	return error;
+	}
+	
+TInt CBusyTestUnit::StartThread(TAny* aPtr)
+	{
+	CBusyTestUnit* self = static_cast<CBusyTestUnit*>(aPtr);
+	if (self)
+		{
+		self->ThreadFunction();
+		}
+	return KErrNone;
+	}
+	
+void CBusyTestUnit::ThreadFunction()
+	{
+	// this runs in a separate thread and tries to use lots of CPU time up to percentage
+	// nominally we run busy for loops for iPercentBusy/100ms, and then wait for rest of the
+	// 100ms using User::After(). We keep doing this until we reach the target time, if there is
+	// one
+	
+	const TInt KDefaultLoop = 10000;
+	TTime timeAtStart; 
+	timeAtStart.UniversalTime(); // time of start
+	
+	const TInt KLoopInterval =100000; // 100ms - loop time
+	TTimeIntervalMicroSeconds32 busyInterval(KLoopInterval*iPercentBusy/100); // how much of loop time to be busy
+	TTimeIntervalMicroSeconds32 quietInterval(KLoopInterval-busyInterval.Int()); // how much of loop time to be quiet
+	
+	while (ETrue)
+		{
+		// the interval, for loops for the busy bit and then a User::After()
+		TTime startOfInterval;
+		startOfInterval.UniversalTime();
+		while (ETrue)
+			{
+			// the busy bit - iBusyVariable is volatile so should never be optimised out
+			for (TInt i=0; i<KDefaultLoop; i++)
+				{
+				iBusyVariable = i;
+				}
+			TTime now;
+			now.UniversalTime();
+			if (startOfInterval + busyInterval < now)
+				{
+				// we're passed the time
+				break;
+				}
+			}
+		User::After(quietInterval);		
+			
+		if (iRunFor.Int64())
+			{
+			// check to see if we are passed the interval given at Start()
+			TTime now;
+			now.UniversalTime();
+			if (timeAtStart + iRunFor < now)
+				{
+				// we're passed the time
+				break;
+				}
+			}
+		}
+	}
+