testexecmdw/tef/tef/utils/src/testserverbase.cpp
branchRCL_3
changeset 3 9397a16b6eb8
parent 1 6edeef394eb7
equal deleted inserted replaced
1:6edeef394eb7 3:9397a16b6eb8
     1 /*
       
     2 * Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  
       
    15 * Implementation of the following classes
       
    16 * CTestServer
       
    17 * n x  CTestSession Maps to RTestServ session)
       
    18 * n x  CStepControl or CPersistentStepControl (Maps to RTestSession)
       
    19 * CTestStep (1 to 1 mapping with parent)
       
    20 * CTestServer
       
    21 * Derives CServer
       
    22 * Test servers derive from this and implement the CreateTestStep() pure virtual
       
    23 * CTestSession
       
    24 * Derives CSharableSession
       
    25 * Implements the ServiceL() pure virtual and creates CStepControl object(s)
       
    26 * when a test step is opened.
       
    27 * Implements the MSessionNotify interface for callbacks from CStepControl when
       
    28 * a test step completes.
       
    29 * CStepControl
       
    30 * Derives CActive
       
    31 * Runs a test step instance in its own thread and heap
       
    32 * CTestStep
       
    33 * Derives CBase
       
    34 * Test Servers derive test steps from this
       
    35 *
       
    36 */
       
    37 
       
    38 
       
    39 
       
    40 /**
       
    41  @file TestClient.cpp
       
    42 */
       
    43 
       
    44 #include "testexecuteserverbase.h"
       
    45 #include "testserver2.h"
       
    46 #include "testexecuteserverutils.h"
       
    47 #include "testexecuteclient.h"
       
    48 #include <e32math.h>
       
    49 #include <test/wrapperutilsplugin.h>
       
    50 #include <test/tefutils.h>
       
    51 
       
    52 const TUint KDefaultHeapSize = 0x100000;
       
    53 
       
    54 //> @internalComponent
       
    55 // see the impletation below.
       
    56 void SytemWideErrToTefErr(TInt &aErr);
       
    57 /**
       
    58  * Constructor
       
    59  */
       
    60 EXPORT_C CTestServer::CTestServer() : CServer2(EPriorityStandard)
       
    61 ,	iSeed(0)
       
    62 ,	iSessionCount(0)
       
    63 	{
       
    64 	// Random seed for unique thread id's
       
    65 	iSeed = (TInt)this;
       
    66 	// Default is not to allow Server Logging
       
    67 	iLoggerStarted = EFalse;
       
    68 	}
       
    69 
       
    70 /**
       
    71  * Destructor
       
    72  */
       
    73 EXPORT_C CTestServer::~CTestServer()
       
    74 	{
       
    75 	if (iLoggerStarted)
       
    76 		{
       
    77 		// Shut down the Servers' logger instance.
       
    78 		Logger().Close();
       
    79 		}
       
    80 	}
       
    81 
       
    82 /**
       
    83  * @param aName - Reference to the Server name
       
    84  * StartL + initiate server logging
       
    85  * Servers can StartL themselves or call this to gain server logging.
       
    86  */
       
    87 EXPORT_C void CTestServer::ConstructL(const TDesC& aName)
       
    88 	 {
       
    89 	 StartL(aName);
       
    90 	 StartLoggerL();
       
    91 	 iServerName = aName;
       
    92 	 }
       
    93 
       
    94 /**
       
    95  * Will extract the script logfile name from the temporary file 'LogFileName.txt'
       
    96  * (assuming no ScheduleTest compatible logging) and then opens a logging session
       
    97  * to that file. If ScheduleTest logging is in effect then we will open ScriptEngine.htm
       
    98  * instead as the file to log to.
       
    99  */	 
       
   100 void CTestServer::StartLoggerL()
       
   101 	{
       
   102 	TDriveName defaultSysDrive(KTEFLegacySysDrive);
       
   103 	RFs fileServer;
       
   104 	TVersionName version(fileServer.Version().Name());
       
   105 	
       
   106 	RLibrary pluginLibrary;
       
   107 	CWrapperUtilsPlugin* plugin = TEFUtils::WrapperPluginNew(pluginLibrary);
       
   108 	
       
   109 	if (plugin!=NULL)
       
   110 		{
       
   111 		TDriveUnit driveUnit(plugin->GetSystemDrive());
       
   112 		defaultSysDrive.Copy(driveUnit.Name());
       
   113 		delete plugin;
       
   114 		pluginLibrary.Close();
       
   115 		}
       
   116 
       
   117 	CTestExecuteIniData* parseTestExecuteIni = NULL;
       
   118 	TBuf<KMaxTestExecuteNameLength> resultFilePath;
       
   119 	TBuf<KMaxTestExecuteNameLength> xmlFilePath;
       
   120 	TInt logMode;
       
   121 	TInt logLevel;
       
   122 
       
   123 	TRAPD(err,parseTestExecuteIni = CTestExecuteIniData::NewL(defaultSysDrive));
       
   124 	if (err == KErrNone)
       
   125 		{
       
   126 		CleanupStack::PushL(parseTestExecuteIni);
       
   127 		parseTestExecuteIni->ExtractValuesFromIni();
       
   128 		parseTestExecuteIni->GetKeyValueFromIni(KTEFHtmlKey, resultFilePath);
       
   129 		parseTestExecuteIni->GetKeyValueFromIni(KTEFXmlKey, xmlFilePath);
       
   130 		parseTestExecuteIni->GetKeyValueFromIni(KTEFLogMode, logMode);
       
   131 		parseTestExecuteIni->GetKeyValueFromIni(KTEFLogSeverityKey, logLevel);
       
   132 		}
       
   133 	else
       
   134 		{
       
   135 		TBuf<KMaxTestExecuteNameLength> testExecuteLogPath(KTestExecuteLogPath);
       
   136 		testExecuteLogPath.Replace(0, 2, defaultSysDrive);
       
   137 		resultFilePath.Copy(testExecuteLogPath);
       
   138 		xmlFilePath.Copy(testExecuteLogPath);
       
   139 		logMode = TLoggerOptions(ELogHTMLOnly);
       
   140 		logLevel = RFileFlogger::TLogSeverity(ESevrAll);
       
   141 		}
       
   142 	Logger().SetLoggerOptions(logMode);
       
   143 
       
   144 	// Initialise a handle to the file logger
       
   145 	User::LeaveIfError(Logger().Connect());
       
   146 	RFs fS;
       
   147 	User::LeaveIfError(fS.Connect());
       
   148 	CleanupClosePushL(fS);
       
   149 	RFile file;
       
   150 	TBuf<KMaxTestExecuteNameLength> xmlLogFile(xmlFilePath);
       
   151 	TBuf<KMaxTestExecuteNameLength> logFile;
       
   152 	TBuf<KMaxTestExecuteNameLength> logFileNameFile(resultFilePath);
       
   153 	logFileNameFile.Append(KTestExecuteScheduleTestLogCompatibilityNameFile);
       
   154 	if(file.Open(fS,logFileNameFile,EFileRead | EFileShareAny) != KErrNone)
       
   155 		{
       
   156 		// If LogFileName.txt is not present then we are using ScheduleTest
       
   157 		// compliant logging, any logging issued by the server will therefore
       
   158 		// go to ScriptEngine.htm
       
   159 		_LIT(KScriptEngine,"ScriptEngine");
       
   160 		logFile.Copy(KScriptEngine);
       
   161 		}
       
   162 	else
       
   163 		{
       
   164 		CleanupClosePushL(file);
       
   165 		TBuf8<KMaxTestExecuteNameLength> logFile8;
       
   166 		TInt fileSize;
       
   167 		User::LeaveIfError(file.Size(fileSize));
       
   168 		User::LeaveIfError(file.Read(logFile8,fileSize));
       
   169 		logFile.Copy(logFile8);
       
   170 		CleanupStack::Pop(&file);
       
   171 		file.Close();
       
   172 		}
       
   173 	
       
   174 	xmlLogFile.Append(logFile);
       
   175 	_LIT(KXmlExtension,".xml");
       
   176 	xmlLogFile.Append(KXmlExtension);
       
   177 	_LIT(KHtmExtension,".htm");
       
   178 	logFile.Append(KHtmExtension);
       
   179 	TBuf<KMaxTestExecuteLogFilePath> logFilePath(resultFilePath);
       
   180 	logFilePath.Append(logFile);
       
   181 	CleanupStack::Pop(&fS);
       
   182 	fS.Close();
       
   183 	
       
   184 	if (logMode == 0 || logMode == 2)
       
   185 		{
       
   186 		User::LeaveIfError(Logger().HtmlLogger().CreateLog(logFilePath,RTestExecuteLogServ::ELogModeAppend));
       
   187 		Logger().HtmlLogger().SetLogLevel(TLogSeverity(logLevel));
       
   188 		}
       
   189 		
       
   190 	if (logMode == 1 || logMode == 2)
       
   191 		{
       
   192 		User::LeaveIfError(Logger().XmlLogger().CreateLog(xmlLogFile,RFileFlogger::ELogModeAppend));
       
   193 		Logger().XmlLogger().SetLogLevel(RFileFlogger::TLogSeverity(logLevel));
       
   194 		}
       
   195 	
       
   196 	User::LeaveIfError( Logger().ShareAuto() );
       
   197 	iLoggerStarted = ETrue;
       
   198 	if (parseTestExecuteIni != NULL)
       
   199 		{
       
   200 		CleanupStack::PopAndDestroy(parseTestExecuteIni);
       
   201 		}
       
   202 	}
       
   203 	
       
   204 /**
       
   205  * Last one out switch off the lights
       
   206  * Stop the active sheduler and hence the server, if this is the last session
       
   207  */	 
       
   208 void CTestServer::SessionClosed()
       
   209 	{
       
   210 	iSessionCount--;
       
   211 	if (iSessionCount == 0)
       
   212 		CActiveScheduler::Stop();
       
   213 	}
       
   214 
       
   215 /**
       
   216  * @param RMessage - RMessage for the session open
       
   217  * Secure version
       
   218  */
       
   219 EXPORT_C CSession2* CTestServer::NewSessionL(const TVersion& /*aVersion*/,const RMessage2& /*aMessage*/) const
       
   220 	{
       
   221 	CTestSession* session = new (ELeave) CTestSession();
       
   222 	CONST_CAST(CTestServer*,this)->iSessionCount++;
       
   223 	return session;
       
   224 	}
       
   225 
       
   226 /**
       
   227  * Constructor
       
   228  */
       
   229 EXPORT_C CTestSession::CTestSession()
       
   230 :	iPersistentStepControl(NULL)
       
   231 ,	iPersistentBlockControl(NULL)
       
   232 ,	iBlockArray(NULL)
       
   233 	{
       
   234 	}
       
   235 
       
   236 /**
       
   237  * Destructor
       
   238  */
       
   239 EXPORT_C CTestSession::~CTestSession()
       
   240 	{
       
   241 	if( iBlockArray )
       
   242 		{
       
   243 		delete iBlockArray;
       
   244 		iBlockArray = NULL;
       
   245 		}	
       
   246 	
       
   247 	CTestServer* p=(CTestServer*) Server();
       
   248 	
       
   249 	//delete the persistent step
       
   250 	if(iPersistentStepControl)
       
   251 		delete iPersistentStepControl;
       
   252 	//delete the persistent block
       
   253 	if(iPersistentBlockControl)
       
   254 		delete iPersistentBlockControl;
       
   255 	// Shuts Down the server if this is the last open session
       
   256 	p->SessionClosed();
       
   257 	}
       
   258 
       
   259 /**
       
   260  * @param aMessage - Function and data for the session
       
   261  * Session was created by pure virtual CTestServer::NewSessionL()
       
   262  * Message Functions defined in TestExecuteClient.h
       
   263  * 
       
   264  * EOpenTestStep - Creates a new subsession
       
   265  * ERunTestStep - Executes the test step asynchronously
       
   266  * EAbortTestStep - Kill()'s the executing test step
       
   267  * ECloseTestStep - Free's the resource
       
   268  *
       
   269  * Secure and non-secure variants
       
   270  * There are two modes of operation:
       
   271  * Test step is opened with the shared data boolean set to FALSE:
       
   272  *		Create a new CStepControl instance and hence a new thread in its own heap
       
   273  *		Consecutive or Concurrent operation
       
   274  * Test step is opened with the shared data boolean set to TRUE:
       
   275  *		Create a CPersistentStepControl and keep reusing it, and its thread
       
   276  *		Consecutive operation only
       
   277  */
       
   278 EXPORT_C void CTestSession::ServiceL(const RMessage2& aMessage)
       
   279 	{
       
   280 	switch(aMessage.Function())
       
   281 		{
       
   282 		case EOpenTestStep :
       
   283 			{
       
   284 			// Open the test step
       
   285 			// Buffer size policed on the client side
       
   286 			TBuf<KMaxTestStepNameLength> stepName;
       
   287 			// Read the step name from the descriptor
       
   288 			TBool sharedData;
       
   289 			aMessage.ReadL(0,stepName);
       
   290 			// Find out what mode we're working in
       
   291 			sharedData = aMessage.Int1();
       
   292 			// Both types derive from base class and implement pure virtuals
       
   293 			CControlBase* stepControl = NULL;
       
   294 			if(sharedData)
       
   295 				{
       
   296 				// Shared data mode
       
   297 				// Create the instance if it doesn't exist
       
   298 				if(!iPersistentStepControl)
       
   299 					iPersistentStepControl = new (ELeave)CPersistentStepControl(*(CTestServer*)Server());
       
   300 				stepControl = iPersistentStepControl;
       
   301 				iPersistentStepControl->StepName() = stepName;
       
   302 				}
       
   303 			else
       
   304 				{
       
   305 				// Default operation. Create a new instance
       
   306 				stepControl = new (ELeave)CStepControl(*(CTestServer*)Server(),stepName);
       
   307 				}
       
   308 			// We pass back the address of the CStepControl class which is passed to
       
   309 			// us in all calls on the subsession in Message 3
       
   310 			TPtrC8 stepRef(REINTERPRET_CAST(TUint8*,&stepControl),sizeof(TInt));
       
   311 			aMessage.Write(3,stepRef);
       
   312 			aMessage.Complete(KErrNone);
       
   313 			}
       
   314 			break;
       
   315 		case EOpenTestBlock :
       
   316 			{
       
   317 			// Open the test block
       
   318 			// Buffer size policed on the client side
       
   319 			TBuf<KMaxTestExecuteNameLength> stepName;
       
   320 
       
   321 			// Find out what mode we're working in
       
   322 			TBool sharedData = aMessage.Int1();
       
   323 			// Both types derive from base class and implement pure virtuals
       
   324 			CBlockControlBase* blockControl = NULL;
       
   325 			if(sharedData)
       
   326 				{
       
   327 				// Shared data mode
       
   328 				// Create the instance if it doesn't exist
       
   329 				if(!iPersistentBlockControl)
       
   330 					iPersistentBlockControl = new (ELeave)CPersistentBlockControl(*(CTestServer*)Server());
       
   331 				blockControl = iPersistentBlockControl;
       
   332 				}
       
   333 			else
       
   334 				{
       
   335 				// Default operation. Create a new instance
       
   336 				blockControl = new (ELeave)CBlockControl(*(CTestServer*)Server());
       
   337 				}
       
   338 			// We pass back the address of the CStepControl class which is passed to
       
   339 			// us in all calls on the subsession in Message 3
       
   340 			TPtrC8 blockRef(REINTERPRET_CAST(TUint8*,&blockControl),sizeof(TInt));
       
   341 			aMessage.Write(3,blockRef);
       
   342 			aMessage.Complete(KErrNone);
       
   343 			}
       
   344 			break;
       
   345 		case ERunTestStep :
       
   346 			{
       
   347 			// Execute the test step
       
   348 			// Buffer size policed on client side
       
   349 			// Message 0 contains the test step arguments
       
   350 			// Message 1 contains a descriptor for the panic string, if the test step panics
       
   351 			TBuf<KMaxTestExecuteCommandLength> stepArgs;
       
   352 			aMessage.ReadL(0,stepArgs);
       
   353 						
       
   354 			// Get the address of our CStepControl object
       
   355 			CStepControlBase* stepControl = REINTERPRET_CAST(CStepControlBase*,aMessage.Int3());
       
   356 			// Kick off the test step
       
   357 			// Message completed when the test step completes
       
   358 			// StartL() is mode dependent pure virtual
       
   359 			TRAPD(err,stepControl->StartL(aMessage, stepArgs));
       
   360 			if(err)
       
   361 				// Complete now if we can't start the test step
       
   362 				// Client has possibly called run before waiting for last completion
       
   363 				aMessage.Complete(err);
       
   364 			}
       
   365 			break;
       
   366 		case ERunTestBlock :
       
   367 			{
       
   368 			// Execute the test step
       
   369 			// Buffer size policed on client side
       
   370 			// Message 0 contains the test step arguments
       
   371 			// Message 1 contains a descriptor for the panic string, if the test step panics
       
   372 			TBuf<KMaxTestExecuteCommandLength> blockArgs;
       
   373 			aMessage.ReadL(0,blockArgs);
       
   374 						
       
   375 			// Get the test block of commands
       
   376 			HBufC8*	itemArray = HBufC8::NewLC( aMessage.GetDesMaxLengthL(2) );
       
   377 			TPtr8	itemArrayPtr( itemArray->Des() );
       
   378 			aMessage.ReadL( 2, itemArrayPtr );
       
   379 
       
   380 			// Get the address of our CStepControl object
       
   381 			CBlockControlBase* blockControl = REINTERPRET_CAST(CBlockControlBase*,aMessage.Int3());
       
   382 			// Kick off the test step
       
   383 			// Message completed when the test step completes
       
   384 			// StartL() is mode dependent pure virtual
       
   385 			TRAPD(err,blockControl->StartL(aMessage, blockArgs, itemArrayPtr ));
       
   386 			if(err)
       
   387 				// Complete now if we can't start the test step
       
   388 				// Client has possibly called run before waiting for last completion
       
   389 				aMessage.Complete(err);
       
   390 			
       
   391 			CleanupStack::PopAndDestroy( itemArray );
       
   392 			}
       
   393 			break;
       
   394 		case EAbortTestStep :
       
   395 			{
       
   396 			CControlBase* control = REINTERPRET_CAST(CControlBase*,aMessage.Int3());
       
   397 			// Stop is mode dependent pure virtual
       
   398 			control->Stop();
       
   399 			// Complete synchronously
       
   400 			aMessage.Complete(KErrNone);
       
   401 			break;
       
   402 			}
       
   403 		case ECloseTestStep :
       
   404 			{
       
   405 			CControlBase* control = REINTERPRET_CAST(CControlBase*,aMessage.Int3());
       
   406 			// Only delete if we are in non-shared data mode
       
   407 			if(	control != iPersistentStepControl &&
       
   408 				control != iPersistentBlockControl )
       
   409 				{
       
   410 				delete control;
       
   411 				}
       
   412 			aMessage.Complete(KErrNone);
       
   413 			}
       
   414 			break;
       
   415 		default:
       
   416 			break;
       
   417 		}
       
   418 	}
       
   419 
       
   420 /**
       
   421  * @param aServer - Reference to the CTestServer base class
       
   422  * @param aStepName - The test step name
       
   423  * The Non-Shared data step control implementation
       
   424  */
       
   425 CStepControl::CStepControl(CTestServer& aServer, const TDesC& aStepName) :
       
   426 	CStepControlBase(aServer)
       
   427 	{
       
   428 	StepName() = aStepName;
       
   429 	}
       
   430 
       
   431 /**
       
   432  * Thread completion
       
   433  */
       
   434 void CStepControl::RunL()
       
   435 	{
       
   436 	// Error value if set in the test step will be saved in the Message()
       
   437 	if (Error() != KNull)
       
   438 		{
       
   439 		TBuf<KMaxTestExecuteNameLength> errorParam(KErrorEquals);
       
   440 		errorParam.Append(Error());
       
   441 		Message().Write(1,errorParam);
       
   442 		}
       
   443 
       
   444 	// If the thread panicked, pick up the panic string and return it to the client
       
   445 	// Overwrites the error value previously saved in Message()
       
   446 	if(WorkerThread().ExitType() == EExitPanic)
       
   447 		{
       
   448 		TBuf<KMaxTestExecuteNameLength> panicParam(KPanicEquals);
       
   449 		panicParam.Append(WorkerThread().ExitCategory());
       
   450 		Message().Write(1,panicParam);
       
   451 		}
       
   452 
       
   453 
       
   454 	
       
   455 	if (WorkerThread().ExitType() == EExitPanic)
       
   456 		{
       
   457 		TInt err = WorkerThread().ExitReason();
       
   458 		SytemWideErrToTefErr(err);
       
   459 		Message().Complete(err);
       
   460 		}
       
   461 	else
       
   462 		{
       
   463 		if (iStatus.Int() == KErrAbort && TimedOut())
       
   464 			{
       
   465 			if (Server().LoggerStarted())
       
   466 				{
       
   467 				Server().ERR_PRINTF1(_L("TEST IS ABOUT TO ABORT DUE TO TEF TIMEOUT"));				
       
   468 				}
       
   469 			}
       
   470 		// iStatus.Int() is the same as the thread ExitReason
       
   471 		Message().Complete(iStatus.Int());
       
   472 		}
       
   473 	
       
   474 	// Close thread handle
       
   475 	WorkerThread().Close();
       
   476 	}
       
   477 
       
   478 /**
       
   479  * Destructor
       
   480  */
       
   481 CStepControl::~CStepControl()
       
   482 	{
       
   483 	}
       
   484 
       
   485 /**
       
   486  * Step Execution module which is wrapped within UHEAP macros to trap memory leaks during execution
       
   487  * @param aStepControl - Is a generic type of class T passed as template parameter. Either CStepControl/CWorkerControl
       
   488  * for normal execution mode and persistant thread mode for concurrent execution of steps respectively
       
   489  * @param aStep - Object derived from CTestStep class for execution of test steps both in normal mode and persistent mode
       
   490  */
       
   491 template<class T>
       
   492 void ThreadStepExecutionL(T* aStepControl, CTestStep* aStep)
       
   493 	{
       
   494 	TInt loop = 0;
       
   495 	TBool simulateOOM = EFalse; //ShouldRunOOMTest();
       
   496 
       
   497 	FOREVER
       
   498 		{
       
   499 		TInt errRun = KErrNone;
       
   500 
       
   501 		// Call the CTestStep virtuals 
       
   502 		aStep->doTestStepPreambleL();
       
   503 			
       
   504 		// count cells so we can know how many we leaked
       
   505 		TInt cellsStart = User::CountAllocCells();
       
   506 		
       
   507 		if (simulateOOM)
       
   508 			{
       
   509 			__UHEAP_MARK;
       
   510 	
       
   511 			// set allocator to fail on the loop'th alloc
       
   512 			aStep->SetHeapFailNext(loop);
       
   513 			}
       
   514 		
       
   515 		aStepControl->TimedOut() = ETrue;
       
   516 		TRAP(errRun, aStep->doTestStepL());
       
   517 		if (errRun != KErrNone && !simulateOOM)
       
   518 			{
       
   519 			if (errRun == KErrAbort)
       
   520 				{
       
   521 				aStepControl->TimedOut() = EFalse;
       
   522 				}
       
   523 			aStep->doTestStepPostambleL();
       
   524 			User::Leave(errRun);
       
   525 			}
       
   526 			
       
   527 		TBool finishedCorrectly = EFalse;
       
   528 		// cancel the alloc failures
       
   529 		if (simulateOOM)
       
   530 			{
       
   531 			if ((errRun == KErrNone) && (loop >= 1))
       
   532 				{
       
   533 				// claims to have finished correctly, and we're not failing every alloc
       
   534 				finishedCorrectly = aStep->CheckForHeapFailNext();
       
   535 				}
       
   536 			aStep->ResetHeapFailNext();
       
   537 			}
       
   538 		
       
   539 		aStep->doTestStepPostambleL();
       
   540 		
       
   541 		TInt cellsEnd = User::CountAllocCells();
       
   542 			
       
   543 		if (cellsStart < cellsEnd && simulateOOM)
       
   544 			{
       
   545 			// leaked.
       
   546 			TInt leakedCells = cellsEnd - cellsStart;
       
   547 			if (aStepControl->Server().LoggerStarted())
       
   548 				{
       
   549 				aStepControl->Server().ERR_PRINTF3(_L("On loop number %d we leaked %d cells. About to cause panic."),loop,leakedCells);				
       
   550 				}
       
   551 			aStep->SetTestStepResult(EFail);
       
   552 			}
       
   553 			
       
   554 		if (simulateOOM)
       
   555 			{
       
   556 			// panic on leak (alloc nnnnnnnn)
       
   557 			__UHEAP_MARKEND;
       
   558 			}
       
   559 	
       
   560 		// check to see if we finished all OOM testing successfully
       
   561 		if ((errRun == KErrNone) && (simulateOOM) && (finishedCorrectly))
       
   562 			{
       
   563 			// test completed successfully, or the User::Leave(KErrNoMemory) was trapped by something else. 
       
   564 			// Need a cunning solution here. Hmm. Testing to see if the next alloc call fails won't work:
       
   565 			//    eg, if a test has 3 allocs, heap currently set to fail every 2nd, this would be number 4,
       
   566 			//    and if 2 was masked then we would think we are done.
       
   567 			//
       
   568 			// Fix PDEF115450, remove the line 			aStep->SetTestStepResult(EPass); and modify the information
       
   569 			// to "Out of memory test completed after %d iterations."
       
   570 			if (aStepControl->Server().LoggerStarted())
       
   571 				{
       
   572 				aStepControl->Server().INFO_PRINTF2(_L("Out of memory test completed after %d iterations."),loop);
       
   573 				}
       
   574 			break;
       
   575 			}
       
   576 
       
   577 		// check to see if we should run OOM testing.
       
   578 		if (++loop == 1)
       
   579 			{
       
   580 			// first go.
       
   581 			if (!aStep->ShouldRunOOMTest())
       
   582 				break;
       
   583 			else
       
   584 				{
       
   585 				if (aStepControl->Server().LoggerStarted())
       
   586 					{
       
   587 					aStepControl->Server().INFO_PRINTF1(_L("Test passed. About to run Out of Memory testing."));					
       
   588 					}
       
   589 				simulateOOM = ETrue;
       
   590 				aStep->IniAccessLog() = EFalse;
       
   591 				}
       
   592 			}
       
   593 		}
       
   594 	}
       
   595 
       
   596 /**
       
   597  * @param aStepControl - Pointer to the step control object which kicked us off
       
   598  * The thread code. Just drops through with no reuse.
       
   599  */
       
   600 void ThreadFuncL(CStepControl* aStepControl)
       
   601 	{
       
   602 	// Call the server pure virtual to get a step instance
       
   603 	CTestStep* step = CONST_CAST(CTestServer&,aStepControl->Server()).CreateTestStep(aStepControl->StepName());
       
   604 	if(!step)
       
   605 		User::Leave(KErrNotFound);
       
   606 	CleanupStack::PushL(step);
       
   607 	// Set up the step base class members
       
   608 	TBool sharedData = EFalse;
       
   609 	step->InitialiseL(aStepControl->Args(), aStepControl->Server().Name(), sharedData);
       
   610 
       
   611 	ThreadStepExecutionL(aStepControl, step);
       
   612 
       
   613 	// Return Error value set in test step to log result for comparison
       
   614 	if (step->TestStepError() != 0)
       
   615 		aStepControl->Error().Num(step->TestStepError());
       
   616 	// EPass is 0
       
   617 	// All the rest should be TRAP'd
       
   618 	if(step->TestStepResult())
       
   619 		User::Leave(step->TestStepResult());
       
   620 	CleanupStack::PopAndDestroy(step);
       
   621  	}
       
   622 
       
   623 /**
       
   624  * @param aParam - Pointer to a CStepControl object
       
   625  * The thread entry method
       
   626  */
       
   627 TInt ThreadFunc(TAny* aParam)
       
   628 	{
       
   629 	// Create the thread's cleanup stack
       
   630 	CTrapCleanup* cleanup = CTrapCleanup::New();
       
   631 	if(!cleanup)
       
   632 		return KErrNoMemory;
       
   633 	// Trap it and return the error code to the OS
       
   634 	TRAPD(err, ThreadFuncL(REINTERPRET_CAST(CStepControl*,aParam)));
       
   635 	SytemWideErrToTefErr(err);
       
   636 	delete cleanup;
       
   637 	cleanup = NULL;
       
   638 	return err;
       
   639 	}
       
   640 
       
   641 /**
       
   642  * @param aMessage - Keep a reference for async completion
       
   643  * @param aStepArgs - The RUN_TEST_STEP arguments
       
   644  * Secure and non-secure variants
       
   645  * Kick off the test step in its own thread
       
   646  * Pure virtual implementation
       
   647  */
       
   648 void CStepControl::StartL(const RMessage2& aMessage, const TDesC& aStepArgs)
       
   649 	{
       
   650 	if(IsActive())
       
   651 		User::Leave(KErrInUse);
       
   652 	Message() = aMessage;
       
   653 	Args().Copy(aStepArgs);
       
   654 	TBuf<8> heapSizeBuf(KNull);
       
   655 	TUint heapSize(0);
       
   656 	aMessage.ReadL(1,heapSizeBuf);
       
   657 	aMessage.Write(1,KNull);
       
   658 	TLex heapSizeLex;
       
   659 	
       
   660 	if (heapSizeBuf.Length() >=3)
       
   661 		{
       
   662 		if ( heapSizeBuf.Mid(0,2).CompareF(_L("0x")) == 0 )
       
   663 			{
       
   664 			heapSizeLex.Assign(heapSizeBuf.Mid(2));
       
   665 			}
       
   666 		else
       
   667 			{
       
   668 			heapSizeLex.Assign(heapSizeBuf);
       
   669 			}
       
   670 		heapSizeLex.Val(heapSize,EHex);
       
   671 		}
       
   672 		
       
   673 	TBuf<50> threadName;
       
   674 	// Unique thread name guaranteed if we use the this pointer plus a random number
       
   675 	// whose seed was initialised to the address of the CTestServer object
       
   676 	_LIT(KWorker,"Worker%d %d");
       
   677 	threadName.Format(KWorker,(TInt)this,Math::Rand(CONST_CAST(CTestServer&,Server()).RandSeed()));
       
   678 	// Create with own heap so system cleans up if we kill it
       
   679 	const TUint KMaxHeapSize = 0x100000;
       
   680 	const TUint KMinSize = KMinHeapSize;
       
   681 	if (heapSize < KMinSize)
       
   682 		heapSize = KMaxHeapSize;			///< Allow a 1Mb max heap
       
   683 
       
   684 	User::LeaveIfError(WorkerThread().Create(threadName, ThreadFunc, KDefaultStackSize + 0x1000,KMinHeapSize, heapSize,this, EOwnerProcess));
       
   685 	// Prime ready for completion
       
   686 	SetActive();
       
   687 	// Use the appropriate variant call to get the thread exit
       
   688 	WorkerThread().Logon(iStatus);
       
   689 	WorkerThread().Resume();
       
   690 	}
       
   691 
       
   692 /**
       
   693  * Kill the thread if it's still running
       
   694  * The async completion will be picked up as normal with a KErrAbort status
       
   695  * Pure virtual implementation
       
   696  */
       
   697 void CStepControl::Stop()
       
   698 	{
       
   699 	if(IsActive())
       
   700 		WorkerThread().Kill(KErrAbort);
       
   701 	}
       
   702 
       
   703 /**
       
   704  * @param aStepControl - Pointer to the step control object.
       
   705  * The test step thread.
       
   706  * We reuse this thread so the test steps can store persistent data in the
       
   707  * CTestServer derived class
       
   708  * The thread synchronises with its creator via the CWorkerControl class
       
   709  * Implementation of the shared data mode control object
       
   710  */
       
   711 void PersistentThreadFuncL(CWorkerControl* aControl)
       
   712 	{
       
   713 	// Thread entry is sync'd with a semaphore
       
   714 	// Caller will Wait on this
       
   715 	// Also set our main sync treq to pending.
       
   716 	// It's completed to let us go in and execute the test step code.
       
   717 	aControl->WorkerStatus() = KRequestPending;
       
   718 	aControl->Semaphore().Signal();
       
   719 	// Go into the main test step execution loop
       
   720 	for(;;)
       
   721 		{
       
   722 		User::WaitForRequest(aControl->WorkerStatus());
       
   723 		// Check
       
   724 		if(aControl->WorkerStatus().Int() == KErrAbort)
       
   725 			User::Leave(KErrAbort);
       
   726 		CTestStep* step = CONST_CAST(CTestServer&,aControl->Server()).CreateTestStep(aControl->StepName());
       
   727 		if(!step)
       
   728 			User::Leave(KErrNotFound);
       
   729 		CleanupStack::PushL(step);
       
   730 		// Set up the step base class members
       
   731 		TBool sharedData = ETrue;
       
   732 		step->InitialiseL(aControl->Args(), aControl->Server().Name(), sharedData);
       
   733 
       
   734 		ThreadStepExecutionL(aControl, step);
       
   735 
       
   736 		// Pick up the final result
       
   737 		// Set it in the controlling class
       
   738 		aControl->Result() = step->TestStepResult();
       
   739 		TBuf<KMaxTestExecuteNameLength> lError;
       
   740 		if (step->TestStepError() != 0)
       
   741 			{
       
   742 			lError.Num(step->TestStepError());
       
   743 			if (lError != KNull)
       
   744 				{
       
   745 				lError.Insert(0,KErrorEquals);
       
   746 				aControl->PersistentError().Copy(lError);
       
   747 				}
       
   748 			}
       
   749 		CleanupStack::PopAndDestroy(step);
       
   750 		// Set our status for the wait at the top of the loop
       
   751 		aControl->WorkerStatus() = KRequestPending;
       
   752 		// Signal the status that our creator will be waiting on
       
   753 		// Creator's thread handle in the control class
       
   754 		TRequestStatus* status = &aControl->Status();
       
   755 		aControl->ControllerThread().RequestComplete(status,KErrNone);
       
   756 		}
       
   757  	}
       
   758 
       
   759 /**
       
   760  * @param aParam - Pointer to a CTestStep control object
       
   761  * The thread entry method
       
   762  */
       
   763 TInt PersistentThreadFunc(TAny* aParam)
       
   764 	{
       
   765 	// Create the thread's cleanup stack
       
   766 	CTrapCleanup* cleanup = CTrapCleanup::New();
       
   767 	
       
   768 	if(!cleanup)
       
   769 		return KErrNoMemory;
       
   770 	// Trap it and return the error code to the OS
       
   771 	//defect 116046
       
   772 	CWorkerControl* workControl = REINTERPRET_CAST(CWorkerControl*,aParam);
       
   773 	workControl->SetCleanupPtr(cleanup);
       
   774 	TRAPD(err, PersistentThreadFuncL(workControl));
       
   775 	//END defect 116046
       
   776 	SytemWideErrToTefErr(err);
       
   777 	delete cleanup;
       
   778 	cleanup = NULL;
       
   779 	return err;
       
   780 	}
       
   781 
       
   782 /**
       
   783  * @param aServer - Reference to the CTestServer derived class
       
   784  * Constructor
       
   785  */
       
   786 CPersistentStepControl::CPersistentStepControl(CTestServer& aServer) :
       
   787 	CStepControlBase(aServer),
       
   788 	iInitialised(EFalse)
       
   789 	{ 
       
   790 	}
       
   791 
       
   792 /**
       
   793  * @param aMessage - Client's message for completion
       
   794  * @param aStepArgs - Arguments to the RUN_xxx_STEP_COMMAND's
       
   795  * Implementation of base class pure virtual.
       
   796  * Necessarily complex because of thread reuse. Instantiates 2 classes:
       
   797  * WorkerMonitor class and WorkerControl class
       
   798  * WorkerMonitor picks up thread exit and WorkerControl picks up test step
       
   799  * return value.
       
   800  */
       
   801 void CPersistentStepControl::StartL(const RMessage2& aMessage,const TDesC& aStepArgs)
       
   802 	{
       
   803 	if(IsActive())
       
   804 		User::Leave(KErrInUse);
       
   805 	Message() = aMessage;
       
   806 	Args().Copy(aStepArgs);
       
   807 	// Check to see if we're reusing the worker thread and classes
       
   808 	if(!iInitialised)
       
   809 		{
       
   810 		// Need to construct the monitor and controller classes
       
   811 		// They are both constructed with a reference to our iStatus
       
   812 		// Either of them can complete us. We check their Active flags in our RunL()
       
   813 		iWorkerControl = new (ELeave) CWorkerControl(Server(),iStatus);		
       
   814 		// The worker thread needs our thread handle to RequestComplete us
       
   815 		User::LeaveIfError(iWorkerControl->ControllerThread().Duplicate(RThread()));
       
   816 		// Worker thread entry is sync'd with a semaphore.
       
   817 		User::LeaveIfError(iWorkerControl->Semaphore().CreateLocal(0));
       
   818 		TBuf<50> threadName;
       
   819 		// Unique thread name guaranteed if we use the this pointer plus a random number
       
   820 		// whose seed was initialised to the address of the CTestServer object
       
   821 		// Create in our heap.
       
   822 		_LIT(KWorker,"Worker%d %d");
       
   823 		threadName.Format(KWorker,(TInt)this,Math::Rand(CONST_CAST(CTestServer&,Server()).RandSeed()));
       
   824 		User::LeaveIfError(WorkerThread().Create(threadName,PersistentThreadFunc, KDefaultStackSize + 0x1000,NULL,iWorkerControl, EOwnerProcess));
       
   825 		iWorkerMonitor = new (ELeave) CWorkerMonitor(iStatus);
       
   826 		}
       
   827 	// Worker thread needs the step arguments and the step name
       
   828 	iWorkerControl->Args().Set(Args());
       
   829 	iWorkerControl->StepName().Set(StepName());
       
   830 	// Set this object ready for completion by either the monitor or controller objects
       
   831 	Prime();
       
   832 	// Set the child monitor and control objects ready for completion
       
   833 	iWorkerMonitor->SetActive();
       
   834 	iWorkerControl->Prime();
       
   835 	// Use the monitor object to pick up thread exit
       
   836 	// This should only happen for panic, leave and abort following the Stop() call
       
   837 	WorkerThread().Rendezvous(iWorkerMonitor->Status());
       
   838 	if(!iInitialised)
       
   839 		{
       
   840 		// Start the thread and sync up via the semaphore
       
   841 		WorkerThread().Resume();
       
   842 		iWorkerControl->Semaphore().Wait();
       
   843 		iWorkerControl->Semaphore().Close();
       
   844 		iInitialised = ETrue;
       
   845 		}
       
   846 	// Worker thread will be at the top of its loop waiting to execute
       
   847 	// the test step virtuals.
       
   848 	// Issue the request then it will drop through
       
   849 	TRequestStatus* status = &iWorkerControl->WorkerStatus();
       
   850 	WorkerThread().RequestComplete(status,KErrNone);
       
   851 	}
       
   852 
       
   853 /**
       
   854  * Destructor
       
   855  */
       
   856 CPersistentStepControl::~CPersistentStepControl()
       
   857 	{
       
   858 	// Only need to clean up in the initialised state
       
   859 	if(!iInitialised)
       
   860 		return;
       
   861 
       
   862 	// Check both objects
       
   863 	// Neither of them should be active, but just in case
       
   864 	if(iWorkerMonitor->IsActive())
       
   865 		{
       
   866 		// Cancelling means we don't get stray events
       
   867 		WorkerThread().RendezvousCancel(iWorkerMonitor->Status());
       
   868 		// Need to cancel the objeect itself
       
   869 		iWorkerMonitor->Cancel();
       
   870 		}
       
   871 	if(iWorkerControl->IsActive())
       
   872 		{
       
   873 		// Complete the request then cancel
       
   874 		TRequestStatus* status = &iWorkerControl->Status();
       
   875 		User::RequestComplete(status,KErrNone);
       
   876 		iWorkerControl->Cancel();
       
   877 		}
       
   878 
       
   879 	// The worker thread will currently be blocked on its TRequestStatus at the top
       
   880 	// of its loop.
       
   881 	// Signal the status with KErrAbort and the thread will check this value and leave.
       
   882 	// If we Kill the thread then the cleanup stack for the thread is orphaned.
       
   883 	// PersistentThreadFuncL() TRAP's the leave.
       
   884 	// We logon and catch the thread exit.
       
   885 	TRequestStatus status = KRequestPending;
       
   886 	WorkerThread().Rendezvous(status);
       
   887 	TRequestStatus* workerStatus = &iWorkerControl->WorkerStatus();
       
   888 	WorkerThread().RequestComplete(workerStatus,KErrAbort);
       
   889 	User::WaitForRequest(status);
       
   890 	// Close both handles
       
   891 	WorkerThread().Close();				
       
   892 	iWorkerControl->ControllerThread().Close();
       
   893 
       
   894 	delete iWorkerControl;
       
   895 	delete iWorkerMonitor;
       
   896 	}
       
   897 
       
   898 /**
       
   899  * Necessarily complex because of the two sources of completion
       
   900  * We can tell which one completed us by checking their iActive members
       
   901  */
       
   902 void CPersistentStepControl::RunL()
       
   903 	{
       
   904 	if (iWorkerControl->PersistentError() != KNull)
       
   905 		{
       
   906 		TBuf<KMaxTestExecuteNameLength> errorParam;
       
   907 		errorParam.Copy(iWorkerControl->PersistentError()); // Error Value returned as Panic Result
       
   908 		Message().Write(1,errorParam);
       
   909 		iWorkerControl->PersistentError().Copy(KNull);
       
   910 		}
       
   911 	TInt ret = KErrNone;
       
   912 	// Check which of the child objects completed us
       
   913 	if(!iWorkerMonitor->IsActive())
       
   914 		{
       
   915 		// Unexpected exit from the worker thread
       
   916 		iInitialised = EFalse;// this also make ~CPersistentStepControl not to delete twice.
       
   917 		// Pick up the exit reason and panic code if it exists
       
   918 		if(WorkerThread().ExitType() == EExitPanic)
       
   919 			{
       
   920 			TBuf<KMaxTestExecuteNameLength> panicParam(KPanicEquals);
       
   921 				panicParam.Append(WorkerThread().ExitCategory()); // Panic Value returned as Result
       
   922 
       
   923 			//START defect 116046, Cleanup memories.
       
   924 			//iWorkerControl->Cleanup();
       
   925 			//END defect 116046
       
   926 				
       
   927 			Message().Write(1,panicParam);
       
   928 			}
       
   929 			
       
   930 		ret = WorkerThread().ExitReason();
       
   931 		
       
   932 		if (WorkerThread().ExitType() == EExitPanic)
       
   933 			{
       
   934 			SytemWideErrToTefErr(ret);
       
   935 			}		
       
   936 		if (ret == KErrAbort && iWorkerControl->TimedOut())
       
   937 			{
       
   938 			if (Server().LoggerStarted())
       
   939 				{
       
   940 				Server().ERR_PRINTF1(_L("TEST IS ABOUT TO ABORT DUE TO TEF TIMEOUT"));				
       
   941 				}
       
   942 			}
       
   943 
       
   944 		// We need to complete and cancel the other request so we don't have stray events
       
   945 		TRequestStatus* status = &iWorkerControl->Status();
       
   946 		User::RequestComplete(status,KErrNone);
       
   947 		iWorkerControl->Cancel();
       
   948 		// Free the resource in the worker control object
       
   949 		iWorkerControl->ControllerThread().Close();
       
   950 		WorkerThread().Close();
       
   951 		delete iWorkerControl;
       
   952 		iWorkerControl = NULL;
       
   953 		delete iWorkerMonitor;
       
   954 		iWorkerMonitor = NULL;
       
   955 		// Next time in to StartL() we create them from cleana
       
   956 		}
       
   957 	else if(!iWorkerControl->IsActive())
       
   958 		{
       
   959 		// Normal test step completion
       
   960 		// We can reuse the thread next time into StartL()
       
   961 		// The thread will be blocking on iWorkerStatus
       
   962 		// We need to cancel the other object
       
   963 		WorkerThread().RendezvousCancel(iWorkerMonitor->Status());
       
   964 		iWorkerMonitor->Cancel();
       
   965 		// Retrieve the test result
       
   966 		ret = iWorkerControl->Result();
       
   967 		SytemWideErrToTefErr(ret);
       
   968 		}
       
   969 	else
       
   970 		// Unexpected
       
   971 		{
       
   972 		ret = iStatus.Int();
       
   973 		}
       
   974 	// Complete back to the client
       
   975 	Message().Complete(ret);
       
   976 	}
       
   977 
       
   978 /**
       
   979  * Abort due to timeout
       
   980  * The worker monitor object will pick up the thread exit
       
   981  */
       
   982 void CPersistentStepControl::Stop()
       
   983 	{
       
   984 	if(iWorkerMonitor->IsActive())
       
   985 		{
       
   986 		WorkerThread().Kill(KErrAbort);
       
   987 		}
       
   988 	}
       
   989 
       
   990 
       
   991 CBlockControlBase::~CBlockControlBase()
       
   992 	{
       
   993 	if( iBlockArray )
       
   994 		{
       
   995 		delete iBlockArray;
       
   996 		iBlockArray = NULL;	
       
   997 		}
       
   998 	}
       
   999 	
       
  1000 TTEFItemArray* CBlockControlBase::BlockArray() const
       
  1001 	{
       
  1002 	return iBlockArray;
       
  1003 	}
       
  1004 
       
  1005 void CBlockControlBase::CreateBlockArrayL( const TDesC8& aBlockArrayPckg )
       
  1006 	{
       
  1007 	if( iBlockArray )
       
  1008 		{
       
  1009 		delete iBlockArray;
       
  1010 		iBlockArray = NULL;
       
  1011 		}
       
  1012 	
       
  1013 	TTEFItemPkgBuf	itemPckgBuf;
       
  1014 	TInt count = aBlockArrayPckg.Size()/itemPckgBuf.Size();
       
  1015 	iBlockArray = new (ELeave) TTEFItemArray( count );
       
  1016 	TInt pos = 0;
       
  1017 	for( TInt i=0; i<count; i++ )
       
  1018 		{
       
  1019 		itemPckgBuf.Copy(aBlockArrayPckg.Mid(pos, itemPckgBuf.Size()));
       
  1020 		pos += itemPckgBuf.Size();
       
  1021 		iBlockArray->AppendL( itemPckgBuf() );
       
  1022 		}
       
  1023 	}
       
  1024 	
       
  1025 HBufC8* CBlockControlBase::CreateBlockArrayPckgLC()
       
  1026 	{
       
  1027 	TInt count = iBlockArray->Count();
       
  1028 	TTEFItemPkgBuf	itemPckgBuf;
       
  1029 	HBufC8* blockArrayPckg = HBufC8::NewLC( count * itemPckgBuf.Size() );
       
  1030 	TPtr8	ptr( blockArrayPckg->Des() );
       
  1031 	for( TInt i=0; i<count; i++ )
       
  1032 		{
       
  1033 		itemPckgBuf = iBlockArray->At(i);
       
  1034 		ptr.Append( itemPckgBuf );
       
  1035 		}
       
  1036 	
       
  1037 	return blockArrayPckg;
       
  1038 	}
       
  1039 
       
  1040 CBlockControl::CBlockControl(CTestServer& aServer)
       
  1041 :	CBlockControlBase(aServer)
       
  1042 	{
       
  1043 	}
       
  1044 	
       
  1045 CBlockControl::~CBlockControl()
       
  1046 	{
       
  1047 	}
       
  1048 
       
  1049 void CBlockControl::RunL()
       
  1050 	{
       
  1051 	// Write back the test block
       
  1052 	HBufC8*	blockArrayPckg = CreateBlockArrayPckgLC();
       
  1053 	TPtr8	blockArrayPtr(blockArrayPckg->Des());
       
  1054 	Message().WriteL( 2, blockArrayPtr );
       
  1055 	CleanupStack::PopAndDestroy(blockArrayPckg);
       
  1056 	
       
  1057 	// If the thread panicked, pick up the panic string and return it to the client
       
  1058 	// Overwrites the error value previously saved in Message()
       
  1059 	if(WorkerThread().ExitType() == EExitPanic)
       
  1060 		{
       
  1061 		TBuf<KMaxTestExecuteNameLength> panicParam(KPanicEquals);
       
  1062 		TPtrC	panicCat = WorkerThread().ExitCategory(); // Panic Value returned as Result
       
  1063 		if( panicCat.Length() == 0 )
       
  1064 			{
       
  1065 			panicParam.Append(_L("NULL"));
       
  1066 			}
       
  1067 		panicParam.Append( panicCat );
       
  1068 		Message().Write(1,panicParam);
       
  1069 		}
       
  1070 
       
  1071 	if (WorkerThread().ExitType() == EExitPanic)
       
  1072 		{
       
  1073 		TInt err = WorkerThread().ExitReason();
       
  1074 		SytemWideErrToTefErr(err);
       
  1075 		Message().Complete(err);
       
  1076 		}
       
  1077 	else
       
  1078 		{
       
  1079 		if (iStatus.Int() == KErrAbort && TimedOut())
       
  1080 			{
       
  1081 			if (Server().LoggerStarted())
       
  1082 				{
       
  1083 				Server().ERR_PRINTF1(_L("TEST IS ABOUT TO ABORT DUE TO TEF TIMEOUT"));				
       
  1084 				}
       
  1085 			}
       
  1086 		// iStatus.Int() is the same as the thread ExitReason
       
  1087 		Message().Complete(iStatus.Int());
       
  1088 		}
       
  1089 	
       
  1090 	// Close thread handle
       
  1091 	WorkerThread().Close();
       
  1092 	}
       
  1093 
       
  1094 
       
  1095 void ThreadBlockFuncL(CBlockControl* aBlockControl)
       
  1096 	{
       
  1097 	// Call the server pure virtual to get a step instance
       
  1098 	CTestBlockController* block = REINTERPRET_CAST(CTestServer2&,aBlockControl->Server()).CreateTestBlock();
       
  1099 	if(!block)
       
  1100 		{
       
  1101 		User::Leave(KErrNotFound);
       
  1102 		}
       
  1103 	CleanupStack::PushL(block);
       
  1104 
       
  1105 	// Set up the block base class members
       
  1106 	TBool sharedData = EFalse;
       
  1107 	block->InitialiseL(aBlockControl->Args(), aBlockControl->Server().Name(), sharedData);
       
  1108 	block->SetBlockArray(aBlockControl->BlockArray());
       
  1109 	block->SetSharedData( REINTERPRET_CAST(CTestServer2*, &aBlockControl->Server() ));
       
  1110 
       
  1111 	ThreadStepExecutionL(aBlockControl, block);
       
  1112 
       
  1113 	// All the rest should be TRAP'd
       
  1114 	if( block->TestStepResult() )
       
  1115 		{
       
  1116 		User::Leave( block->TestStepResult() );
       
  1117 		}
       
  1118 	
       
  1119 	CleanupStack::PopAndDestroy(block);
       
  1120  	}
       
  1121 
       
  1122 TInt ThreadBlockFunc(TAny* aParam)
       
  1123 	{
       
  1124 	// Create the thread's cleanup stack
       
  1125 	CTrapCleanup* cleanup = CTrapCleanup::New();
       
  1126 	if(!cleanup)
       
  1127 		return KErrNoMemory;
       
  1128 	// Trap it and return the error code to the OS
       
  1129 	TRAPD(err, ThreadBlockFuncL(REINTERPRET_CAST(CBlockControl*,aParam)));
       
  1130 	SytemWideErrToTefErr(err);
       
  1131 	delete cleanup;
       
  1132 	cleanup = NULL;
       
  1133 	return err;
       
  1134 	}
       
  1135 
       
  1136 void CBlockControl::StartL(const RMessage2& aMessage,const TDesC& aArgs, const TDesC8& aBlockArrayPckg)
       
  1137 	{
       
  1138 	if(IsActive())
       
  1139 		{
       
  1140 		User::Leave(KErrInUse);
       
  1141 		}
       
  1142 
       
  1143 	Message() = aMessage;
       
  1144 	Args().Copy(aArgs);
       
  1145 	TBuf<8> heapSizeBuf(KNull);
       
  1146 	TUint heapSize(0);
       
  1147 	aMessage.ReadL(1,heapSizeBuf);
       
  1148 	aMessage.Write(1,KNull);
       
  1149 	TLex heapSizeLex;
       
  1150 	
       
  1151 	if (heapSizeBuf.Length() >=3)
       
  1152 		{
       
  1153 		if ( heapSizeBuf.Mid(0,2).CompareF(_L("0x")) == 0 )
       
  1154 			{
       
  1155 			heapSizeLex.Assign(heapSizeBuf.Mid(2));
       
  1156 			}
       
  1157 		else
       
  1158 			{
       
  1159 			heapSizeLex.Assign(heapSizeBuf);
       
  1160 			}
       
  1161 		heapSizeLex.Val(heapSize,EHex);
       
  1162 		}
       
  1163 
       
  1164 	// Set the BlockArray so it can be passed and used by the TestBlockController
       
  1165 	CreateBlockArrayL( aBlockArrayPckg );
       
  1166 	
       
  1167 	// Unique thread name guaranteed if we use the this pointer plus a random number
       
  1168 	// whose seed was initialised to the address of the CTestServer object
       
  1169 	TBuf<50> threadName;
       
  1170 	_LIT(KWorker,"Worker%d %d");
       
  1171 	threadName.Format(KWorker,(TInt)this,Math::Rand(CONST_CAST(CTestServer&,Server()).RandSeed()));
       
  1172 
       
  1173 	// Create with own heap so system cleans up if we kill it
       
  1174 	if( (TInt)heapSize < KMinHeapSize )
       
  1175 		{
       
  1176 		heapSize = KDefaultHeapSize;			///< Allow a 1Mb max heap
       
  1177 		}
       
  1178 
       
  1179 	User::LeaveIfError(WorkerThread().Create(threadName, ThreadBlockFunc, KDefaultStackSize + 0x1000,KMinHeapSize, heapSize, this, EOwnerProcess));
       
  1180 
       
  1181 	// Prime ready for completion
       
  1182 	SetActive();
       
  1183 	// Use the appropriate variant call to get the thread exit
       
  1184 	WorkerThread().Logon(iStatus);
       
  1185 	WorkerThread().Resume();
       
  1186 	}
       
  1187 	
       
  1188 void CBlockControl::Stop()
       
  1189 	{
       
  1190 	if(IsActive())
       
  1191 		{
       
  1192 		WorkerThread().Kill(KErrAbort);
       
  1193 		}
       
  1194 	}
       
  1195 	
       
  1196 CPersistentBlockControl::CPersistentBlockControl(CTestServer& aServer)
       
  1197 :	CBlockControlBase(aServer)
       
  1198 ,	iWorkerControl(NULL)
       
  1199 ,	iWorkerMonitor(NULL)
       
  1200 ,	iInitialised(EFalse)
       
  1201 	{ 
       
  1202 	}
       
  1203 	
       
  1204 CPersistentBlockControl::~CPersistentBlockControl()
       
  1205 	{
       
  1206 
       
  1207 	// Only need to clean up in the initialised state
       
  1208 	if(!iInitialised)
       
  1209 		return;
       
  1210 
       
  1211 	// Check both objects
       
  1212 	// Neither of them should be active, but just in case
       
  1213 	if(iWorkerMonitor->IsActive())
       
  1214 		{
       
  1215 		// Cancelling means we don't get stray events
       
  1216 		WorkerThread().RendezvousCancel(iWorkerMonitor->Status());
       
  1217 		// Need to cancel the objeect itself
       
  1218 		iWorkerMonitor->Cancel();
       
  1219 		}
       
  1220 	if(iWorkerControl->IsActive())
       
  1221 		{
       
  1222 		// Complete the request then cancel
       
  1223 		TRequestStatus* status = &iWorkerControl->Status();
       
  1224 		User::RequestComplete(status,KErrNone);
       
  1225 		iWorkerControl->Cancel();
       
  1226 		}
       
  1227 
       
  1228 	// The worker thread will currently be blocked on its TRequestStatus at the top
       
  1229 	// of its loop.
       
  1230 	// Signal the status with KErrAbort and the thread will check this value and leave.
       
  1231 	// If we Kill the thread then the cleanup stack for the thread is orphaned.
       
  1232 	// PersistentThreadFuncL() TRAP's the leave.
       
  1233 	// We logon and catch the thread exit.
       
  1234 	TRequestStatus status = KRequestPending;
       
  1235 	WorkerThread().Rendezvous(status);
       
  1236 	TRequestStatus* workerStatus = &iWorkerControl->WorkerStatus();
       
  1237 	WorkerThread().RequestComplete(workerStatus,KErrAbort);
       
  1238 	User::WaitForRequest(status);
       
  1239 	// Close both handles
       
  1240 	WorkerThread().Close();				
       
  1241 	iWorkerControl->ControllerThread().Close();
       
  1242 
       
  1243 	delete iWorkerControl;
       
  1244 	delete iWorkerMonitor;
       
  1245 	}
       
  1246 
       
  1247 void PersistentThreadBlockFuncL(CBlockWorkerControl* aControl)
       
  1248 	{
       
  1249 	// Thread entry is sync'd with a semaphore
       
  1250 	// Caller will Wait on this
       
  1251 	// Also set our main sync treq to pending.
       
  1252 	// It's completed to let us go in and execute the test step code.
       
  1253 	aControl->WorkerStatus() = KRequestPending;
       
  1254 	aControl->Semaphore().Signal();
       
  1255 	// Go into the main test step execution loop
       
  1256 	for(;;)
       
  1257 		{
       
  1258 		User::WaitForRequest(aControl->WorkerStatus());
       
  1259 		// Check
       
  1260 		if(aControl->WorkerStatus().Int() == KErrAbort)
       
  1261 			User::Leave(KErrAbort);
       
  1262 		CTestBlockController* block = REINTERPRET_CAST(CTestServer2&, aControl->Server()).CreateTestBlock();
       
  1263 		if(!block)
       
  1264 			User::Leave(KErrNotFound);
       
  1265 		CleanupStack::PushL(block);
       
  1266 		// Set up the step base class members
       
  1267 		TBool sharedData = ETrue;
       
  1268 		block->InitialiseL(aControl->Args(), aControl->Server().Name(), sharedData);
       
  1269 		
       
  1270 		block->SetBlockArray( aControl->BlockArray() );
       
  1271 		block->SetSharedData( REINTERPRET_CAST(CTestServer2*, &aControl->Server()) );
       
  1272 
       
  1273 		ThreadStepExecutionL(aControl, block);
       
  1274 
       
  1275 		// Pick up the final result
       
  1276 		// Set it in the controlling class
       
  1277 		aControl->Result() = block->TestStepResult();
       
  1278 		TBuf<KMaxTestExecuteNameLength> lError;
       
  1279 		if (block->TestStepError() != 0)
       
  1280 			lError.Num(block->TestStepError());
       
  1281 		if (lError != KNull)
       
  1282 			{
       
  1283 			lError.Insert(0,KErrorEquals);
       
  1284 			aControl->PersistentError().Copy(lError);
       
  1285 			}
       
  1286 		CleanupStack::PopAndDestroy(block);
       
  1287 		// Set our status for the wait at the top of the loop
       
  1288 		aControl->WorkerStatus() = KRequestPending;
       
  1289 		// Signal the status that our creator will be waiting on
       
  1290 		// Creator's thread handle in the control class
       
  1291 		TRequestStatus* status = &aControl->Status();
       
  1292 		aControl->ControllerThread().RequestComplete(status,KErrNone);
       
  1293 		}
       
  1294  	}
       
  1295  
       
  1296 TInt PersistentThreadBlockFunc(TAny* aParam)
       
  1297 	{
       
  1298 	// Create the thread's cleanup stack
       
  1299 	CTrapCleanup* cleanup = CTrapCleanup::New();
       
  1300 	if(!cleanup)
       
  1301 		return KErrNoMemory;
       
  1302 	// Trap it and return the error code to the OS
       
  1303 	TRAPD(err, PersistentThreadBlockFuncL(REINTERPRET_CAST(CBlockWorkerControl*,aParam)));
       
  1304 	SytemWideErrToTefErr(err);
       
  1305 	delete cleanup;
       
  1306 	cleanup = NULL;
       
  1307 	return err;
       
  1308 	}
       
  1309  	
       
  1310 void CPersistentBlockControl::StartL(const RMessage2& aMessage,const TDesC& aStepArgs, const TDesC8& aBlockArrayPckg)
       
  1311 	{
       
  1312 	if(IsActive())
       
  1313 		User::Leave(KErrInUse);
       
  1314 	Message() = aMessage;
       
  1315 	Args().Copy(aStepArgs);
       
  1316 	
       
  1317 	// Set the BlockArray so it can be passed and used by the TestBlockController
       
  1318 	// Set the BlockArray so it can be passed and used by the TestBlockController
       
  1319 	CreateBlockArrayL( aBlockArrayPckg );
       
  1320 	
       
  1321 	// Check to see if we're reusing the worker thread and classes
       
  1322 	if(!iInitialised)
       
  1323 		{
       
  1324 		// Need to construct the monitor and controller classes
       
  1325 		// They are both constructed with a reference to our iStatus
       
  1326 		// Either of them can complete us. We check their Active flags in our RunL()
       
  1327 		iWorkerControl = new (ELeave) CBlockWorkerControl(Server(),iStatus);
       
  1328 		// The worker thread needs our thread handle to RequestComplete us
       
  1329 		User::LeaveIfError(iWorkerControl->ControllerThread().Duplicate(RThread()));
       
  1330 		// Worker thread entry is sync'd with a semaphore.
       
  1331 		User::LeaveIfError(iWorkerControl->Semaphore().CreateLocal(0));
       
  1332 		TBuf<50> threadName;
       
  1333 		// Unique thread name guaranteed if we use the this pointer plus a random number
       
  1334 		// whose seed was initialised to the address of the CTestServer object
       
  1335 		// Create in our heap.
       
  1336 		_LIT(KWorker,"Worker%d %d");
       
  1337 		threadName.Format(KWorker,(TInt)this,Math::Rand(CONST_CAST(CTestServer&,Server()).RandSeed()));
       
  1338 		User::LeaveIfError(WorkerThread().Create(threadName,PersistentThreadBlockFunc, KDefaultStackSize + 0x1000,NULL,iWorkerControl, EOwnerProcess));
       
  1339 		iWorkerMonitor = new (ELeave) CWorkerMonitor(iStatus);
       
  1340 		}
       
  1341 
       
  1342 	// Set the Block Array
       
  1343 	iWorkerControl->SetBlockArray( BlockArray() );
       
  1344 	
       
  1345 	// Worker thread needs the step arguments and the step name
       
  1346 	iWorkerControl->Args().Set(Args());
       
  1347 
       
  1348 	// Set this object ready for completion by either the monitor or controller objects
       
  1349 	Prime();
       
  1350 	// Set the child monitor and control objects ready for completion
       
  1351 	iWorkerMonitor->SetActive();
       
  1352 	iWorkerControl->Prime();
       
  1353 	// Use the monitor object to pick up thread exit
       
  1354 	// This should only happen for panic, leave and abort following the Stop() call
       
  1355 	WorkerThread().Rendezvous(iWorkerMonitor->Status());
       
  1356 	if(!iInitialised)
       
  1357 		{
       
  1358 		// Start the thread and sync up via the semaphore
       
  1359 		WorkerThread().Resume();
       
  1360 		iWorkerControl->Semaphore().Wait();
       
  1361 		iWorkerControl->Semaphore().Close();
       
  1362 		iInitialised = ETrue;
       
  1363 		}
       
  1364 	// Worker thread will be at the top of its loop waiting to execute
       
  1365 	// the test step virtuals.
       
  1366 	// Issue the request then it will drop through
       
  1367 	TRequestStatus* status = &iWorkerControl->WorkerStatus();
       
  1368 	WorkerThread().RequestComplete(status,KErrNone);
       
  1369 	}
       
  1370 	
       
  1371 void CPersistentBlockControl::RunL()
       
  1372 	{
       
  1373 	// Write back the test block
       
  1374 	HBufC8*	blockArrayPckg = CreateBlockArrayPckgLC();
       
  1375 	TPtr8	blockArrayPtr(blockArrayPckg->Des());
       
  1376 	Message().WriteL( 2, blockArrayPtr );
       
  1377 	CleanupStack::PopAndDestroy(blockArrayPckg);
       
  1378 	
       
  1379 	if (iWorkerControl->PersistentError() != KNull)
       
  1380 		{
       
  1381 		TBuf<KMaxTestExecuteNameLength> errorParam;
       
  1382 		errorParam.Copy(iWorkerControl->PersistentError()); // Error Value returned as Panic Result
       
  1383 		Message().Write(1,errorParam);
       
  1384 		iWorkerControl->PersistentError().Copy(KNull);
       
  1385 		}
       
  1386 	TInt ret = KErrNone;
       
  1387 	// Check which of the child objects completed us
       
  1388 	if(!iWorkerMonitor->IsActive())
       
  1389 		{
       
  1390 		// Unexpected exit from the worker thread
       
  1391 		iInitialised = EFalse;// this also make ~CPersistentBlockControl not to delete twice.
       
  1392 		// Pick up the exit reason and panic code if it exists
       
  1393 		if(WorkerThread().ExitType() == EExitPanic)
       
  1394 			{
       
  1395 			TBuf<KMaxTestExecuteNameLength> panicParam(KPanicEquals);
       
  1396 			TPtrC	panicCat = WorkerThread().ExitCategory(); // Panic Value returned as Result
       
  1397 			if( panicCat.Length() == 0 )
       
  1398 				{
       
  1399 				panicParam.Append(_L("NULL"));
       
  1400 				}
       
  1401 			panicParam.Append( panicCat );
       
  1402 			Message().Write(1,panicParam);
       
  1403 			}
       
  1404 			
       
  1405 		ret = WorkerThread().ExitReason();
       
  1406 		
       
  1407 		if (WorkerThread().ExitType() == EExitPanic)
       
  1408 			{
       
  1409 			SytemWideErrToTefErr(ret);
       
  1410 			}
       
  1411 		if (ret == KErrAbort && iWorkerControl->TimedOut())
       
  1412 			{
       
  1413 			if (Server().LoggerStarted())
       
  1414 				{
       
  1415 				Server().ERR_PRINTF1(_L("TEST IS ABOUT TO ABORT DUE TO TEF TIMEOUT"));				
       
  1416 				}
       
  1417 			}
       
  1418 
       
  1419 		// We need to complete and cancel the other request so we don't have stray events
       
  1420 		TRequestStatus* status = &iWorkerControl->Status();
       
  1421 		User::RequestComplete(status,KErrNone);
       
  1422 		iWorkerControl->Cancel();
       
  1423 		// Free the resource in the worker control object
       
  1424 		iWorkerControl->ControllerThread().Close();
       
  1425 		WorkerThread().Close();
       
  1426 		delete iWorkerControl;
       
  1427 		iWorkerControl = NULL;
       
  1428 		delete iWorkerMonitor;
       
  1429 		iWorkerMonitor = NULL;
       
  1430 		// Next time in to StartL() we create them from cleana
       
  1431 		}
       
  1432 	else if(!iWorkerControl->IsActive())
       
  1433 		{
       
  1434 		// Normal test step completion
       
  1435 		// We can reuse the thread next time into StartL()
       
  1436 		// The thread will be blocking on iWorkerStatus
       
  1437 		// We need to cancel the other object
       
  1438 		WorkerThread().RendezvousCancel(iWorkerMonitor->Status());
       
  1439 		iWorkerMonitor->Cancel();
       
  1440 		// Retrieve the test result
       
  1441 		ret = iWorkerControl->Result();
       
  1442 		SytemWideErrToTefErr(ret);
       
  1443 		}
       
  1444 	else
       
  1445 		// Unexpected
       
  1446 		{
       
  1447 		ret = iStatus.Int();
       
  1448 		}
       
  1449 	// Complete back to the client
       
  1450 	Message().Complete(ret);
       
  1451 	}
       
  1452 
       
  1453 void CPersistentBlockControl::Stop()
       
  1454 	{
       
  1455 	if(iWorkerMonitor->IsActive())
       
  1456 		{
       
  1457 		WorkerThread().Kill(KErrAbort);
       
  1458 		}
       
  1459 	}
       
  1460 
       
  1461 /**
       
  1462  * //> @internalComponent
       
  1463  * @param aErr - Reference to the error number
       
  1464  * this delling with Leave or set result  error number conflict with sys wide numbers[-1,-49]
       
  1465  */
       
  1466 void SytemWideErrToTefErr(TInt &aErr)
       
  1467 {
       
  1468     switch (aErr)
       
  1469     	{
       
  1470     	case KErrInUse:
       
  1471     		{
       
  1472     		aErr = KErrTestExecuteInUse;
       
  1473     		}
       
  1474     		break;
       
  1475     	case KErrServerBusy:
       
  1476     		{
       
  1477     		aErr = KErrTestExecuteServerBusy;
       
  1478     		}
       
  1479     		break;
       
  1480     	};
       
  1481     return;
       
  1482 }