cryptoservices/certificateandkeymgmt/tcertstore/tcertstoreconcurrent.cpp
changeset 8 35751d3474b7
parent 0 2c201484c85f
child 102 deec7e509f66
--- a/cryptoservices/certificateandkeymgmt/tcertstore/tcertstoreconcurrent.cpp	Tue Jul 21 01:04:32 2009 +0100
+++ b/cryptoservices/certificateandkeymgmt/tcertstore/tcertstoreconcurrent.cpp	Thu Sep 10 14:01:51 2009 +0300
@@ -1,389 +1,389 @@
-/*
-* Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
-* All rights reserved.
-* This component and the accompanying materials are made available
-* under the terms of the License "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: 
-*
-*/
-
-
-#include "tscripttests.h"
-#include "t_testhandler.h"
-#include "t_certstoretests.h"
-#include "t_certstoreactions.h"
-
-#include <e32std.h>
-#include <f32file.h>
-#include <ECom.h>
-
-
-///////////////
-
-#include "t_testsetup.h"
-#include "t_testactionspec.h"
-#include "t_input.h"
-#include "t_certstoreactionmemfail.h"
-#include "tcancel.h"
-#include "t_message.h"
-#include "tScriptSetup.h"
-#include "tHardcodedSetup.h"
-#include "t_testhandler.h"
-#include "t_output.h"
-#include "tTestSpec.h"
-#include "Ttesthandlersettings.h"
-
-/**
-*	--------------------------------------
-*	How this test works:
-*	--------------------------------------
-*
-*	RUN THIS TEST IN CONFIGURATION 1 (FILECERTSTORE.DLL SHOULD BE THE ONLY 
-*	ECOM PLUGIN IN Z:\SYSTEM\LIBS\PLUGINS).  IF WAPCERTSTORE.DLL IS PRESENT
-*	THIS TEST WILL HANG!!!
-*
-*	This test is designed to stress concurrent access to the filecertstore
-*	by multiple threads, and to check that the integrity of the store is
-*	retained.
-*
-*	The test consists of 3 scripts (certstoreconcurrent1-3.txt) which test various
-*	possible accesses to the filebased store (cert add, delete, set trust, applications
-*	and certificate retreival.  There are 27 possible ways to combine the 3 scripts.
-*	For each of these combinations, 3 threads are started and each is assigned a
-*	separate test handler and one of the scripts for that combination.  The threads
-*	then run together, accessing the store concurrently. 
-*	
-*	BECAUSE THE THREADS ARE RUNNING CONCURRENTLY, IT IS NOT POSSIBLE TO PREDICT
-*	THE RESULTS OF EACH TEST, EG IT IS NOT POSSIBLE TO DETERMINE WHETHER THE 
-*	CERTIFICATE THAT ONE THREAD WISHES TO DELETE IS ACTUALLY PRESENT IN THE STORE
-*	AT THAT TIME, SINCE ANOTHER THREAD MAY HAVE REMOVED IT.  BECAUSE OF THIS 
-*	THE SCRIPTS ARE MARKED WITH A testconcurrent FLAG TO INDICATE THAT THE FAIL
-*	RESULTS SHOULD BE DISREGARDED.  The results for each script are written to a
-*	separate file in EPOC directory \tcertstoreconcurrent\ on system drive thus by the end of the
-*	the test there are 81 such log files in the directory.
-*
-*	Following the 27 combinations of 3 threads, the test then runs a standard
-*	tcertstore test using one of the scripts used in general certstore testing
-*	(the script is determined by the command line for the entire test).  This
-*	runs in a single thread so results can be predicted.  Thus we check that 
-*	filecertstore integrity is maintained.  The log file for these tests are
-*	placed in EPOC system drive and should be inspected for errors as part of the
-*	testing procedure.
-*
-*	Thus to run these tests, the following command line should be used:
-*	tcertstoreconcurrent \tcertstore\scripts\unifiedcertstore2-conf1.txt \tcertstoreconcurrent1.log
-*	,the script and log file being on system drive.This runs script unifiedcertstore2-conf1 after the 
-*	threaded tests and logs	the test results to tcertstoreconcurrent1.log
-*/
-
-//	3 scripts available, switch between them
-const static TText* scripts[] = {	_S("dummy for zero element"),
-									_S("\\tcertstoreconcurrent\\scripts\\certstoreconcurrent1.txt"), 
-									_S("\\tcertstoreconcurrent\\scripts\\certstoreconcurrent2.txt"),
-									_S("\\tcertstoreconcurrent\\scripts\\certstoreconcurrent3.txt")};
-
-
-const TInt KMaxIterations = 27;
-
-const TInt scriptCombinations[] = {	1,1,1,	1,1,2,	1,1,3,
-									1,2,1,	1,2,2,	1,2,3,
-									1,3,1,	1,3,2,	1,3,3,
-									2,1,1,	2,1,2,	2,1,3,
-									2,2,1,	2,2,2,	2,2,3,
-									2,3,1,	2,3,2,	2,3,3,
-									3,1,1,	3,1,2,	3,1,3,
-									3,2,1,	3,2,2,	3,2,3,
-									3,3,1,	3,3,2,	3,3,3};
-
-class TThreadData
-	{
-public:
-	void InitialiseL(TInt aIteration, TInt aScriptNum);
-public:	
-	TPtrC iScriptFile;
-	TFileName iLogFile;
-	};
-
-void TThreadData::InitialiseL(TInt aIteration, TInt aThreadNum)
-	{
-	ASSERT(aIteration >= 0 && aIteration < KMaxIterations);
-	ASSERT(aThreadNum >= 1 && aThreadNum <= 3);
-
-	TInt script = scriptCombinations[aIteration * 3 + aThreadNum - 1];		
-	
-	// Set script file
-	TDriveUnit sysDrive (RFs::GetSystemDrive());
-	TDriveName sysdriveName (sysDrive.Name());
-	TBuf <60> scriptFile (sysdriveName);
-	scriptFile.Append(scripts[script]);
-	iScriptFile.Set(scriptFile);
-
-	// Set log file
-	iLogFile.Zero();
-	TBuf<80> scriptName (sysdriveName);
-	scriptName.Append(_L("\\tcertstoreconcurrent\\iteration%02d_thread%d_script%d.txt"));
-	TBuf<80> buf ;
-	buf.Format(scriptName,aIteration, aThreadNum, script); 
-	iLogFile.Append(buf);
-	}
-
-
-LOCAL_C TInt ThreadEntryPoint(TAny* aArg)
-{
-	__UHEAP_MARK;
-
-	CTrapCleanup* cleanup=CTrapCleanup::New();
-
-	TThreadData* data = static_cast<TThreadData*>(aArg);
-	ASSERT(data);
-
-	TRAPD(r, DoTests(data->iScriptFile, data->iLogFile, ETrue));
-	//TRAPD(r, PerformTests(TestTypes(), data->iScriptFile, data->iLogFile));
-
-	ASSERT( (r==KErrNone) || (r==KErrInUse) );
-
-	delete cleanup;
-	
-	__UHEAP_MARKEND;
-
-	return (r);
-}
-
-/** Start a thread. */
-LOCAL_D void StartThreadL(RThread& aThread, TThreadData& aData, TInt aIteration, TInt aThreadNum, TRequestStatus& aStatus)
-	{
-	aData.InitialiseL(aIteration, aThreadNum);
-
-	TBuf<32> threadName;
-	threadName.Format(_L("iteration%02d_thread%d"), aIteration, aThreadNum);
-	
-	RHeap* heap = User::ChunkHeap(NULL, KMinHeapSize, 0x100000);
-	User::LeaveIfNull(heap);
-	User::LeaveIfError(aThread.Create(threadName, ThreadEntryPoint, KDefaultStackSize, heap, (TAny*)&aData));	
-	aStatus = KRequestPending;
-	aThread.Logon(aStatus);
-	aThread.Resume();
-	}
-
-//	Kicks off each thread for multiple concurrent certstore access
-LOCAL_D TBool DoThreadedTestsL(CConsoleBase* console, HBufC* logFileName, TBool wait)
-{
- 	RFs myfs;
- 	CleanupClosePushL(myfs);
- 
- 	RFile logfile;
- 	CleanupClosePushL(logfile);
- 
- 	Output* out;
- 	
- 	User::LeaveIfError(myfs.Connect());
- 	User::LeaveIfError(logfile.Replace(myfs, *logFileName, EFileWrite));
- 
- 	out = new (ELeave) FileOutput(logfile);
- 	CleanupStack::PushL(out);
-
-	TInt failureCount = 0;
-	
-	for (TInt i = 0 ; i < KMaxIterations; ++i)
-		{
-		console->Printf(_L("Iteration %d \n"), i);
-		out->writeNewLine();
-		out->writeString(_L("Iteration "));
-		out->writeNum(i);
-		out->writeNewLine();
-
-		RThread thread1;
-		TThreadData data1;
-		TRequestStatus status1;
-		StartThreadL(thread1, data1, i, 1, status1);
-
-		RThread thread2;
-		TThreadData data2;
-		TRequestStatus status2;
-		StartThreadL(thread2, data2, i, 2, status2);
-
-		RThread thread3;
-		TThreadData data3;
-		TRequestStatus status3;
-		StartThreadL(thread3, data3, i, 3, status3);
-		
-		User::WaitForRequest(status1);
-		User::WaitForRequest(status2);
-		User::WaitForRequest(status3);
-
-		TExitType exit1 = thread1.ExitType();
-		TExitType exit2 = thread2.ExitType();
-		TExitType exit3 = thread3.ExitType();
-		
-		if (exit1 != EExitKill) 
-			{
-			console->Printf(_L("ERROR: Thread 1 exited with exit type: %d \n"), exit1);
- 			out->writeString(_L("ERROR: Thread 1 exited with exit type: "));
-			out->writeNum(exit1);
-	 		out->writeNewLine();
-			failureCount++;
-			}
-		if (exit2 != EExitKill) 		
-			{
-			console->Printf(_L("ERROR: Thread 2 exited with exit type: %d \n"), exit2);
- 			out->writeString(_L("ERROR: Thread 2 exited with exit type: "));
-			out->writeNum(exit2);
-	 		out->writeNewLine();			
-			failureCount++;
-			}
-		if (exit3 != EExitKill) 
-			{
-			console->Printf(_L("ERROR: Thread 3 exited with exit type: %d \n"), exit3);
- 			out->writeString(_L("ERROR: Thread 2 exited with exit type: "));
-			out->writeNum(exit3);
-	 		out->writeNewLine();			
-			failureCount++;
-			}
-				
-		thread1.Heap()->Close();
-		thread2.Heap()->Close();
-		thread3.Heap()->Close();
-		
-		thread1.Close();
-		thread2.Close();
-		thread3.Close(); 
-
-		User::LeaveIfError(status1.Int());
-		User::LeaveIfError(status2.Int());
-		User::LeaveIfError(status3.Int());		
-	}
-	if (failureCount > 0) 
- 		{
- 		out->writeNewLine();
-		console->Printf(_L("\n %d tests failed out of %d \n"), failureCount, (KMaxIterations*3));
- 		out->writeNewLine();
- 		out->writeNum(failureCount);
- 		out->writeString(_L(" tests failed out of "));
- 		out->writeNum(KMaxIterations*3);
- 		out->writeNewLine();		
- 		}
- 	if (wait) 
- 		{
-		console->Printf(_L("\n Press any key to continue \n"));		
-		console->Getch();
- 		}
- 	CleanupStack::PopAndDestroy(out);
- 	CleanupStack::PopAndDestroy(&logfile);
- 	CleanupStack::PopAndDestroy(&myfs); 	
- 	if (failureCount>0) 
- 		{
- 		return EFalse;
- 		}
- 	return ETrue;
-}
-
-
-/**
- * Extracts the nPos command line argument.
- */
-LOCAL_D HBufC* GetArgument(TInt nPos)
-	{
-	HBufC *argv = HBufC::NewLC(User::CommandLineLength());
-	TPtr cmd(argv->Des());
-	User::CommandLine(cmd);
-
-	TLex arguments(cmd);
-
-	// finds nth parameter 
-	while(nPos && !arguments.Eos())
-		{
-		TPtrC token = arguments.NextToken();
-		if(token.Length() > 0)		
-			nPos--;
-		}
-
-	HBufC* result = NULL;
-	if(!arguments.Eos())
-		{
-		TPtrC testfile(arguments.NextToken());
-
-		if(testfile.Length() > 0)
-			result = testfile.AllocL();
-		};
-
-	// no parameter found, but must return something so..
-	if(!result)
-		result = HBufC::NewL(0);
-
-	CleanupStack::PopAndDestroy(argv);
-
-	return result;
-	}
-
-/**
- * This function sets up a console, a log file and checks
- * whether we need to wait for a key pressed after test 
- * completion.
- * First DoThreadedTestsL is called, if everything is ok
- * it return ETrue and we move on to the standard tests.
- * If something went amiss (return EFalse) we skip 
- * the standard test and return. 
- */
-LOCAL_D void SetupAndRunTests() 
-{
-
-	CConsoleBase* console = Console::NewL(_L("Test code"), TSize(KConsFullScreen, KConsFullScreen));
-	
-	HBufC* logFile = GetArgument(1);
-	
-	if (logFile->Length()==0) 
-		{
-		_LIT(defaultLog, "\\tcertstore.log");
-		TDriveUnit sysDrive (RFs::GetSystemDrive());
-		TDriveName sysdriveName (sysDrive.Name());
-		TBuf <18> fileName (sysdriveName);
-		fileName.Append(defaultLog);
-		logFile->ReAlloc(18);
-		TPtr16 plog = logFile->Des();
-		plog.Append(fileName);
-		}
-		
-	HBufC* wait = GetArgument(2);
-
-	TBool waitAfterCompletion = EFalse;
-	if (wait->Find(_L("-w")) != KErrNotFound) 
-		{
-		waitAfterCompletion = ETrue;
-		}
-	
-	TBool res = EFalse;	
-	TRAPD(err, res = DoThreadedTestsL(console, logFile, waitAfterCompletion));
-	
-	if (res) 
-		{
-		// Now run a normal tcertstore test to check store integrity
-		TRAP(err, DoTests());
-		}
-		
-	delete console;
-	delete wait;
-	delete logFile;
-}
-
-GLDEF_C TInt E32Main()
-{
-	__UHEAP_MARK;
-	CTrapCleanup* cleanup=CTrapCleanup::New();
-	
-	TRAPD(err, SetupAndRunTests());
-	
-	REComSession::FinalClose();
-
-	delete cleanup;
-
-	__UHEAP_MARKEND;
-	return 0;
-}
+/*
+* Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "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: 
+*
+*/
+
+
+#include "tscripttests.h"
+#include "t_testhandler.h"
+#include "t_certstoretests.h"
+#include "t_certstoreactions.h"
+
+#include <e32std.h>
+#include <f32file.h>
+#include <ecom/ecom.h>
+
+
+///////////////
+
+#include "t_testsetup.h"
+#include "t_testactionspec.h"
+#include "t_input.h"
+#include "t_certstoreactionmemfail.h"
+#include "tcancel.h"
+#include "t_message.h"
+#include "tScriptSetup.h"
+#include "tHardcodedSetup.h"
+#include "t_testhandler.h"
+#include "t_output.h"
+#include "tTestSpec.h"
+#include "Ttesthandlersettings.h"
+
+/**
+*	--------------------------------------
+*	How this test works:
+*	--------------------------------------
+*
+*	RUN THIS TEST IN CONFIGURATION 1 (FILECERTSTORE.DLL SHOULD BE THE ONLY 
+*	ECOM PLUGIN IN Z:\SYSTEM\LIBS\PLUGINS).  IF WAPCERTSTORE.DLL IS PRESENT
+*	THIS TEST WILL HANG!!!
+*
+*	This test is designed to stress concurrent access to the filecertstore
+*	by multiple threads, and to check that the integrity of the store is
+*	retained.
+*
+*	The test consists of 3 scripts (certstoreconcurrent1-3.txt) which test various
+*	possible accesses to the filebased store (cert add, delete, set trust, applications
+*	and certificate retreival.  There are 27 possible ways to combine the 3 scripts.
+*	For each of these combinations, 3 threads are started and each is assigned a
+*	separate test handler and one of the scripts for that combination.  The threads
+*	then run together, accessing the store concurrently. 
+*	
+*	BECAUSE THE THREADS ARE RUNNING CONCURRENTLY, IT IS NOT POSSIBLE TO PREDICT
+*	THE RESULTS OF EACH TEST, EG IT IS NOT POSSIBLE TO DETERMINE WHETHER THE 
+*	CERTIFICATE THAT ONE THREAD WISHES TO DELETE IS ACTUALLY PRESENT IN THE STORE
+*	AT THAT TIME, SINCE ANOTHER THREAD MAY HAVE REMOVED IT.  BECAUSE OF THIS 
+*	THE SCRIPTS ARE MARKED WITH A testconcurrent FLAG TO INDICATE THAT THE FAIL
+*	RESULTS SHOULD BE DISREGARDED.  The results for each script are written to a
+*	separate file in EPOC directory \tcertstoreconcurrent\ on system drive thus by the end of the
+*	the test there are 81 such log files in the directory.
+*
+*	Following the 27 combinations of 3 threads, the test then runs a standard
+*	tcertstore test using one of the scripts used in general certstore testing
+*	(the script is determined by the command line for the entire test).  This
+*	runs in a single thread so results can be predicted.  Thus we check that 
+*	filecertstore integrity is maintained.  The log file for these tests are
+*	placed in EPOC system drive and should be inspected for errors as part of the
+*	testing procedure.
+*
+*	Thus to run these tests, the following command line should be used:
+*	tcertstoreconcurrent \tcertstore\scripts\unifiedcertstore2-conf1.txt \tcertstoreconcurrent1.log
+*	,the script and log file being on system drive.This runs script unifiedcertstore2-conf1 after the 
+*	threaded tests and logs	the test results to tcertstoreconcurrent1.log
+*/
+
+//	3 scripts available, switch between them
+const static TText* scripts[] = {	_S("dummy for zero element"),
+									_S("\\tcertstoreconcurrent\\scripts\\certstoreconcurrent1.txt"), 
+									_S("\\tcertstoreconcurrent\\scripts\\certstoreconcurrent2.txt"),
+									_S("\\tcertstoreconcurrent\\scripts\\certstoreconcurrent3.txt")};
+
+
+const TInt KMaxIterations = 27;
+
+const TInt scriptCombinations[] = {	1,1,1,	1,1,2,	1,1,3,
+									1,2,1,	1,2,2,	1,2,3,
+									1,3,1,	1,3,2,	1,3,3,
+									2,1,1,	2,1,2,	2,1,3,
+									2,2,1,	2,2,2,	2,2,3,
+									2,3,1,	2,3,2,	2,3,3,
+									3,1,1,	3,1,2,	3,1,3,
+									3,2,1,	3,2,2,	3,2,3,
+									3,3,1,	3,3,2,	3,3,3};
+
+class TThreadData
+	{
+public:
+	void InitialiseL(TInt aIteration, TInt aScriptNum);
+public:	
+	TPtrC iScriptFile;
+	TFileName iLogFile;
+	};
+
+void TThreadData::InitialiseL(TInt aIteration, TInt aThreadNum)
+	{
+	ASSERT(aIteration >= 0 && aIteration < KMaxIterations);
+	ASSERT(aThreadNum >= 1 && aThreadNum <= 3);
+
+	TInt script = scriptCombinations[aIteration * 3 + aThreadNum - 1];		
+	
+	// Set script file
+	TDriveUnit sysDrive (RFs::GetSystemDrive());
+	TDriveName sysdriveName (sysDrive.Name());
+	TBuf <60> scriptFile (sysdriveName);
+	scriptFile.Append(scripts[script]);
+	iScriptFile.Set(scriptFile);
+
+	// Set log file
+	iLogFile.Zero();
+	TBuf<80> scriptName (sysdriveName);
+	scriptName.Append(_L("\\tcertstoreconcurrent\\iteration%02d_thread%d_script%d.txt"));
+	TBuf<80> buf ;
+	buf.Format(scriptName,aIteration, aThreadNum, script); 
+	iLogFile.Append(buf);
+	}
+
+
+LOCAL_C TInt ThreadEntryPoint(TAny* aArg)
+{
+	__UHEAP_MARK;
+
+	CTrapCleanup* cleanup=CTrapCleanup::New();
+
+	TThreadData* data = static_cast<TThreadData*>(aArg);
+	ASSERT(data);
+
+	TRAPD(r, DoTests(data->iScriptFile, data->iLogFile, ETrue));
+	//TRAPD(r, PerformTests(TestTypes(), data->iScriptFile, data->iLogFile));
+
+	ASSERT( (r==KErrNone) || (r==KErrInUse) );
+
+	delete cleanup;
+	
+	__UHEAP_MARKEND;
+
+	return (r);
+}
+
+/** Start a thread. */
+LOCAL_D void StartThreadL(RThread& aThread, TThreadData& aData, TInt aIteration, TInt aThreadNum, TRequestStatus& aStatus)
+	{
+	aData.InitialiseL(aIteration, aThreadNum);
+
+	TBuf<32> threadName;
+	threadName.Format(_L("iteration%02d_thread%d"), aIteration, aThreadNum);
+	
+	RHeap* heap = User::ChunkHeap(NULL, KMinHeapSize, 0x100000);
+	User::LeaveIfNull(heap);
+	User::LeaveIfError(aThread.Create(threadName, ThreadEntryPoint, KDefaultStackSize, heap, (TAny*)&aData));	
+	aStatus = KRequestPending;
+	aThread.Logon(aStatus);
+	aThread.Resume();
+	}
+
+//	Kicks off each thread for multiple concurrent certstore access
+LOCAL_D TBool DoThreadedTestsL(CConsoleBase* console, HBufC* logFileName, TBool wait)
+{
+ 	RFs myfs;
+ 	CleanupClosePushL(myfs);
+ 
+ 	RFile logfile;
+ 	CleanupClosePushL(logfile);
+ 
+ 	Output* out;
+ 	
+ 	User::LeaveIfError(myfs.Connect());
+ 	User::LeaveIfError(logfile.Replace(myfs, *logFileName, EFileWrite));
+ 
+ 	out = new (ELeave) FileOutput(logfile);
+ 	CleanupStack::PushL(out);
+
+	TInt failureCount = 0;
+	
+	for (TInt i = 0 ; i < KMaxIterations; ++i)
+		{
+		console->Printf(_L("Iteration %d \n"), i);
+		out->writeNewLine();
+		out->writeString(_L("Iteration "));
+		out->writeNum(i);
+		out->writeNewLine();
+
+		RThread thread1;
+		TThreadData data1;
+		TRequestStatus status1;
+		StartThreadL(thread1, data1, i, 1, status1);
+
+		RThread thread2;
+		TThreadData data2;
+		TRequestStatus status2;
+		StartThreadL(thread2, data2, i, 2, status2);
+
+		RThread thread3;
+		TThreadData data3;
+		TRequestStatus status3;
+		StartThreadL(thread3, data3, i, 3, status3);
+		
+		User::WaitForRequest(status1);
+		User::WaitForRequest(status2);
+		User::WaitForRequest(status3);
+
+		TExitType exit1 = thread1.ExitType();
+		TExitType exit2 = thread2.ExitType();
+		TExitType exit3 = thread3.ExitType();
+		
+		if (exit1 != EExitKill) 
+			{
+			console->Printf(_L("ERROR: Thread 1 exited with exit type: %d \n"), exit1);
+ 			out->writeString(_L("ERROR: Thread 1 exited with exit type: "));
+			out->writeNum(exit1);
+	 		out->writeNewLine();
+			failureCount++;
+			}
+		if (exit2 != EExitKill) 		
+			{
+			console->Printf(_L("ERROR: Thread 2 exited with exit type: %d \n"), exit2);
+ 			out->writeString(_L("ERROR: Thread 2 exited with exit type: "));
+			out->writeNum(exit2);
+	 		out->writeNewLine();			
+			failureCount++;
+			}
+		if (exit3 != EExitKill) 
+			{
+			console->Printf(_L("ERROR: Thread 3 exited with exit type: %d \n"), exit3);
+ 			out->writeString(_L("ERROR: Thread 2 exited with exit type: "));
+			out->writeNum(exit3);
+	 		out->writeNewLine();			
+			failureCount++;
+			}
+				
+		thread1.Heap()->Close();
+		thread2.Heap()->Close();
+		thread3.Heap()->Close();
+		
+		thread1.Close();
+		thread2.Close();
+		thread3.Close(); 
+
+		User::LeaveIfError(status1.Int());
+		User::LeaveIfError(status2.Int());
+		User::LeaveIfError(status3.Int());		
+	}
+	if (failureCount > 0) 
+ 		{
+ 		out->writeNewLine();
+		console->Printf(_L("\n %d tests failed out of %d \n"), failureCount, (KMaxIterations*3));
+ 		out->writeNewLine();
+ 		out->writeNum(failureCount);
+ 		out->writeString(_L(" tests failed out of "));
+ 		out->writeNum(KMaxIterations*3);
+ 		out->writeNewLine();		
+ 		}
+ 	if (wait) 
+ 		{
+		console->Printf(_L("\n Press any key to continue \n"));		
+		console->Getch();
+ 		}
+ 	CleanupStack::PopAndDestroy(out);
+ 	CleanupStack::PopAndDestroy(&logfile);
+ 	CleanupStack::PopAndDestroy(&myfs); 	
+ 	if (failureCount>0) 
+ 		{
+ 		return EFalse;
+ 		}
+ 	return ETrue;
+}
+
+
+/**
+ * Extracts the nPos command line argument.
+ */
+LOCAL_D HBufC* GetArgument(TInt nPos)
+	{
+	HBufC *argv = HBufC::NewLC(User::CommandLineLength());
+	TPtr cmd(argv->Des());
+	User::CommandLine(cmd);
+
+	TLex arguments(cmd);
+
+	// finds nth parameter 
+	while(nPos && !arguments.Eos())
+		{
+		TPtrC token = arguments.NextToken();
+		if(token.Length() > 0)		
+			nPos--;
+		}
+
+	HBufC* result = NULL;
+	if(!arguments.Eos())
+		{
+		TPtrC testfile(arguments.NextToken());
+
+		if(testfile.Length() > 0)
+			result = testfile.AllocL();
+		};
+
+	// no parameter found, but must return something so..
+	if(!result)
+		result = HBufC::NewL(0);
+
+	CleanupStack::PopAndDestroy(argv);
+
+	return result;
+	}
+
+/**
+ * This function sets up a console, a log file and checks
+ * whether we need to wait for a key pressed after test 
+ * completion.
+ * First DoThreadedTestsL is called, if everything is ok
+ * it return ETrue and we move on to the standard tests.
+ * If something went amiss (return EFalse) we skip 
+ * the standard test and return. 
+ */
+LOCAL_D void SetupAndRunTests() 
+{
+
+	CConsoleBase* console = Console::NewL(_L("Test code"), TSize(KConsFullScreen, KConsFullScreen));
+	
+	HBufC* logFile = GetArgument(1);
+	
+	if (logFile->Length()==0) 
+		{
+		_LIT(defaultLog, "\\tcertstore.log");
+		TDriveUnit sysDrive (RFs::GetSystemDrive());
+		TDriveName sysdriveName (sysDrive.Name());
+		TBuf <18> fileName (sysdriveName);
+		fileName.Append(defaultLog);
+		logFile->ReAlloc(18);
+		TPtr16 plog = logFile->Des();
+		plog.Append(fileName);
+		}
+		
+	HBufC* wait = GetArgument(2);
+
+	TBool waitAfterCompletion = EFalse;
+	if (wait->Find(_L("-w")) != KErrNotFound) 
+		{
+		waitAfterCompletion = ETrue;
+		}
+	
+	TBool res = EFalse;	
+	TRAPD(err, res = DoThreadedTestsL(console, logFile, waitAfterCompletion));
+	
+	if (res) 
+		{
+		// Now run a normal tcertstore test to check store integrity
+		TRAP(err, DoTests());
+		}
+		
+	delete console;
+	delete wait;
+	delete logFile;
+}
+
+GLDEF_C TInt E32Main()
+{
+	__UHEAP_MARK;
+	CTrapCleanup* cleanup=CTrapCleanup::New();
+	
+	TRAPD(err, SetupAndRunTests());
+	
+	REComSession::FinalClose();
+
+	delete cleanup;
+
+	__UHEAP_MARKEND;
+	return 0;
+}