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