sl@0: // Copyright (c) 2007-2009 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 "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: #include sl@0: #include "Thelpers.h" sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include "TestUtils.h" sl@0: sl@0: _LIT(KTestName, "Task Scheduler Robustness Test"); sl@0: _LIT(KTaskScheduler, "schexe"); sl@0: sl@0: RTest TheTest(KTestName); sl@0: sl@0: typedef CArrayFixFlat CTaskInfoArray; sl@0: typedef CArrayFixFlat CSchItemRefArray; sl@0: typedef CArrayFixFlat CSchConditionArray; sl@0: sl@0: static RScheduler TheScheduler; sl@0: static CTrapCleanup* TheCleanup; sl@0: static RFs TheFsSession; sl@0: sl@0: const TInt KTestKey1 = 1; sl@0: sl@0: _LIT(KSeparator, "|"); // Invalid filepath char used to separate filenames sl@0: sl@0: // This function launches the TPropertyDefine process which sl@0: // has WriteDeviceData Capabilities enabling it to create the P&S sl@0: // variables used by this test. sl@0: static void LaunchHelperL(TUid aCategory, TInt aKey, TInt aAttr) sl@0: { sl@0: _LIT(KConditionHelper, "TPropertyDefine"); sl@0: TRequestStatus stat; sl@0: RProcess p; sl@0: sl@0: TBuf<32> args; sl@0: args.AppendNum(aCategory.iUid); sl@0: args.Append(KSeparator); sl@0: args.AppendNum(aKey); sl@0: args.Append(KSeparator); sl@0: args.AppendNum(aAttr); sl@0: sl@0: User::LeaveIfError(p.Create(KConditionHelper, args,EOwnerProcess)); sl@0: sl@0: // Asynchronous logon: completes when process terminates with process exit code sl@0: p.Logon(stat); sl@0: p.Resume(); sl@0: sl@0: User::WaitForRequest(stat); sl@0: TInt exitReason = p.ExitReason(); sl@0: p.Close(); sl@0: User::LeaveIfError(exitReason); sl@0: } sl@0: sl@0: sl@0: static void CreateTestVariables() sl@0: { sl@0: LaunchHelperL(KUidSystemCategory, KTestKey1,RProperty::EInt); sl@0: } sl@0: sl@0: static void ResetVariablesL(TInt aKey1Val) sl@0: { sl@0: User::LeaveIfError(RProperty::Set(KUidSystemCategory, KTestKey1,aKey1Val)); sl@0: } sl@0: sl@0: sl@0: // single condition with default time set to 1 year in the future sl@0: static TInt CreateScheduleL(TSchedulerItemRef& aRef, sl@0: RScheduler& aScheduler, sl@0: const TUid& aConditionUID, sl@0: TUint aConditionUInt) sl@0: { sl@0: aRef.iName = _L("Schedule created using CreateScheduleSingle"); sl@0: sl@0: CSchConditionArray* conditionList = new (ELeave) CSchConditionArray(1); sl@0: CleanupStack::PushL(conditionList); sl@0: sl@0: //create a single condition sl@0: TTaskSchedulerCondition condition1; sl@0: condition1.iCategory = aConditionUID; sl@0: condition1.iKey = aConditionUInt; sl@0: condition1.iState = 10; sl@0: condition1.iType = TTaskSchedulerCondition::EEquals; sl@0: sl@0: conditionList->AppendL(condition1); sl@0: sl@0: //create a persistent schedule sl@0: TTime time = SchSvrHelpers::TimeBasedOnOffset(0, 0, 0, 0, 0, 1); //1 year in the future sl@0: TInt res = aScheduler.CreatePersistentSchedule(aRef, *conditionList, time); sl@0: CleanupStack::PopAndDestroy(); // conditionList sl@0: return res; sl@0: } sl@0: sl@0: //Add a single task to a schedule sl@0: static TInt AddTaskToScheduleL(const TDesC& aName, sl@0: TInt& aNewId, sl@0: TInt aScheduleId, sl@0: RScheduler& aScheduler) sl@0: { sl@0: TTaskInfo taskInfo; sl@0: taskInfo.iTaskId = aNewId; sl@0: taskInfo.iName = aName; sl@0: taskInfo.iPriority = 2; sl@0: taskInfo.iRepeat = 0; sl@0: HBufC* data = _L("the data").AllocLC(); sl@0: TInt res = aScheduler.ScheduleTask(taskInfo, *data, aScheduleId); sl@0: aNewId = taskInfo.iTaskId; sl@0: sl@0: CleanupStack::PopAndDestroy(); // data sl@0: return res; sl@0: } sl@0: sl@0: sl@0: static TInt ScheduleTaskL() sl@0: { sl@0: //reset the p&s variables before creating the schedule sl@0: ResetVariablesL(0); sl@0: sl@0: //Create a schedule sl@0: TSchedulerItemRef ref1; sl@0: TheTest.Printf(_L("Create a schedule\n")); sl@0: TInt res = CreateScheduleL(ref1, TheScheduler, KUidSystemCategory, KTestKey1); sl@0: TEST2(res, KErrNone); sl@0: sl@0: //Add task to the schedule sl@0: TInt task1 = 0; sl@0: _LIT(KName1, "Test Task"); sl@0: TheTest.Printf(_L("Schedule a task\n")); sl@0: sl@0: res = AddTaskToScheduleL(KName1, task1, ref1.iHandle, TheScheduler); sl@0: TEST2(res, KErrNone); sl@0: sl@0: return res; sl@0: } sl@0: sl@0: static void ExecuteTaskL() sl@0: { sl@0: TheTest.Printf(_L("Execute Task\n")); sl@0: //Set property causing schedule to be run sl@0: User::LeaveIfError(RProperty::Set(KUidSystemCategory, KTestKey1,10)); sl@0: sl@0: //Pause to wait for the task to be executed sl@0: SchSvrHelpers::Pause(TheTest, 2); sl@0: sl@0: } sl@0: sl@0: static TInt ScheduleAndExecuteTaskL() sl@0: { sl@0: TInt res = ScheduleTaskL(); sl@0: sl@0: ExecuteTaskL(); sl@0: sl@0: return res; sl@0: } sl@0: sl@0: LOCAL_C void AddTaskFunctionL() sl@0: { sl@0: RScheduler localScheduler; sl@0: // Connect to the server sl@0: TInt res = localScheduler.Connect(); sl@0: TEST2(res, KErrNone); sl@0: //Schedule a task and execute it sl@0: //reset the p&s variables before creating the schedule sl@0: ResetVariablesL(0); sl@0: sl@0: //Create a schedule sl@0: TSchedulerItemRef ref1; sl@0: ref1.iName = _L("Schedule created using CreateScheduleSingle"); sl@0: CSchConditionArray* conditionList = new (ELeave) CSchConditionArray(1); sl@0: CleanupStack::PushL(conditionList); sl@0: sl@0: //create a single condition sl@0: TTaskSchedulerCondition condition1; sl@0: condition1.iCategory = KUidSystemCategory; sl@0: condition1.iKey = KTestKey1; sl@0: condition1.iState = 10; sl@0: condition1.iType = TTaskSchedulerCondition::EEquals; sl@0: sl@0: conditionList->AppendL(condition1); sl@0: sl@0: //create a persistent schedule sl@0: TTime time = SchSvrHelpers::TimeBasedOnOffset(0, 0, 0, 0, 0, 1); //1 year in the future sl@0: res = localScheduler.CreatePersistentSchedule(ref1, *conditionList, time); sl@0: CleanupStack::PopAndDestroy(); // conditionList sl@0: sl@0: //Add task to the schedule sl@0: TInt task1 = 0; sl@0: _LIT(KName1, "Test Task"); sl@0: sl@0: TTaskInfo taskInfo; sl@0: taskInfo.iTaskId = task1; sl@0: taskInfo.iName = KName1; sl@0: taskInfo.iPriority = 2; sl@0: taskInfo.iRepeat = 0; sl@0: HBufC* data = _L("the data").AllocLC(); sl@0: sl@0: TInt ret = localScheduler.ScheduleTask(taskInfo, *data, ref1.iHandle); sl@0: TEST2(ret, 0);//EPanicNotRegistered == 0 sl@0: sl@0: task1 = taskInfo.iTaskId; sl@0: sl@0: CleanupStack::PopAndDestroy(); // data sl@0: sl@0: //Tidying up so next test will be clear. sl@0: SchSvrHelpers::DeleteAllSchedulesL(localScheduler); sl@0: sl@0: localScheduler.Close(); sl@0: } sl@0: sl@0: // Helper function for DEF124488 sl@0: LOCAL_C TInt TestPanicThread(TAny*) sl@0: { sl@0: CTrapCleanup* cleanup = CTrapCleanup::New(); sl@0: if(!cleanup) sl@0: return KErrNoMemory; sl@0: sl@0: sl@0: TRAPD(err,AddTaskFunctionL()) sl@0: TEST2(err,KErrNone); sl@0: sl@0: delete cleanup; sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: @SYMTestCaseID SYSLIB-SCHSVR-CT-3369 sl@0: @SYMTestCaseDesc Test deletion of temporary files with non existent client sl@0: @SYMTestPriority High sl@0: @SYMTestActions Schedule a task with a client that does not exist. sl@0: Ensure that all temporary files are deleted after sl@0: schedule excecutes sl@0: @SYMTestExpectedResults All temporary files should be deleted by task scheduler sl@0: @SYMDEF PDEF101876 sl@0: */ sl@0: static void DoTest1L() sl@0: { sl@0: TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SCHSVR-CT-3369 Test handling of non existent client ")); sl@0: // Connect to the server sl@0: TheTest.Next(_L("===== Connect to Scheduler =====")); sl@0: TInt res = TheScheduler.Connect(); sl@0: TEST2(res, KErrNone); sl@0: sl@0: // Register a client with the server - this client does not exist sl@0: TheTest.Next(_L("===== Registering Client =====")); sl@0: res = SchSvrHelpers::RegisterNonExistentClient(TheScheduler); sl@0: TEST2(res, KErrNone); sl@0: sl@0: //Schedule a task and execute it sl@0: ScheduleAndExecuteTaskL(); sl@0: sl@0: // Check for left task files after scheduled tasks completed sl@0: // To access private data cage, uses SchSvrHelplers::CheckTaskFilesL() sl@0: TheTest.Next(_L("Now checking no files left when tasks completed")); sl@0: TInt err = SchSvrHelpers::CheckTaskFilesL(); sl@0: sl@0: // If there's any task files left, test fails with error code KErrGeneral sl@0: TEST(err == KErrNone); sl@0: TheTest.Next(_L("All files deleted as expected...")); sl@0: sl@0: //Tidying up so next test will be clear. sl@0: TheTest.Next(_L("Delete all schedules")); sl@0: SchSvrHelpers::DeleteAllSchedulesL(TheScheduler); sl@0: sl@0: TheScheduler.Close(); sl@0: sl@0: } sl@0: sl@0: /** sl@0: @SYMTestCaseID SYSLIB-SCHSVR-CT-3370 sl@0: @SYMTestCaseDesc Test deletion of temporary files with faulty client sl@0: @SYMTestPriority High sl@0: @SYMTestActions Schedule a task with a client that panics and does not sl@0: release the temporary file handle. sl@0: Ensure that all temporary files are deleted after schedule excecutes sl@0: @SYMTestExpectedResults All temporary files should be deleted by task scheduler sl@0: @SYMDEF PDEF101876 sl@0: */ sl@0: static void DoTest2L() sl@0: { sl@0: TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SCHSVR-CT-3370 Test handling of panicing client ")); sl@0: sl@0: // Connect to the server sl@0: TheTest.Next(_L("===== Connect to Scheduler =====")); sl@0: TInt res = TheScheduler.Connect(); sl@0: TEST2(res, KErrNone); sl@0: sl@0: // Register a client with the server - this client panics sl@0: //after calling RFile::AdoptFromClient sl@0: TheTest.Next(_L("===== Registering Client =====")); sl@0: res = SchSvrHelpers::RegisterPanicingClient(TheScheduler); sl@0: TEST2(res, KErrNone); sl@0: sl@0: //Schedule a task and execute it - we expect the client to panic sl@0: ScheduleAndExecuteTaskL(); sl@0: sl@0: // Check for left task files after scheduled tasks completed sl@0: // To access private data cage, uses SchSvrHelplers::CheckTaskFilesL() sl@0: TheTest.Next(_L("Now checking no files left when tasks completed")); sl@0: TInt err = SchSvrHelpers::CheckTaskFilesL(); sl@0: sl@0: // If there's any task files left, test fails with error code KErrGeneral sl@0: TEST(err == KErrNone); sl@0: sl@0: TheTest.Next(_L("All files deleted as expected...")); sl@0: sl@0: //Tidying up so next test will be clear. sl@0: TheTest.Next(_L("Delete all schedules")); sl@0: SchSvrHelpers::DeleteAllSchedulesL(TheScheduler); sl@0: sl@0: TheScheduler.Close(); sl@0: } sl@0: sl@0: /** sl@0: @SYMTestCaseID SYSLIB-SCHSVR-CT-3371 sl@0: @SYMTestCaseDesc Test deletion of temporary files on task scheduler startup sl@0: @SYMTestPriority High sl@0: @SYMTestActions Create temporary files in the task schedulers private data cage. sl@0: Start the task scheduler and verify that these files are deleted. sl@0: @SYMTestExpectedResults All temporary files should be deleted by task scheduler on startup sl@0: @SYMDEF PDEF101876 sl@0: */ sl@0: static void DoTest3L() sl@0: { sl@0: TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SCHSVR-CT-3371 Test deletion of temporary files on startup ")); sl@0: sl@0: //Connect to the scheduler sl@0: TInt res = TheScheduler.Connect(); sl@0: TEST2(res, KErrNone); sl@0: sl@0: // Kill the server to ensure we restart it when we connect sl@0: res = CleanupHelpers::KillProcess(KTaskScheduler); sl@0: TEST2(res, KErrNone); sl@0: TheScheduler.Close(); sl@0: sl@0: // Create task files to test cleanup sl@0: // To access private data cage, uses SchSvrHelplers::CreateTaskFilesL() sl@0: TheTest.Next(_L("Creating dummy task files")); sl@0: res = SchSvrHelpers::CreateTaskFilesL(); sl@0: sl@0: //Restart the scheduler which should clean up temp files on startup sl@0: TheTest.Next(_L("===== Connect to Scheduler =====")); sl@0: res = TheScheduler.Connect(); sl@0: TEST2(res, KErrNone); sl@0: sl@0: //wait for the server to start up sl@0: SchSvrHelpers::Pause(TheTest, 2); sl@0: sl@0: TheScheduler.Close(); sl@0: sl@0: // Check for left task files after scheduled tasks completed sl@0: // To access private data cage, uses SchSvrHelplers::CheckTaskFilesL() sl@0: TheTest.Next(_L("Now checking no files left after task scheduler starts")); sl@0: res = SchSvrHelpers::CheckTaskFilesL(); sl@0: sl@0: TEST2(res, KErrNone); sl@0: sl@0: TheTest.Next(_L("All files deleted as expected...")); sl@0: } sl@0: sl@0: /** sl@0: @SYMTestCaseID SYSLIB-SCHSVR-CT-3402 sl@0: @SYMTestCaseDesc Test memory cleanup on Task Scheduler exit sl@0: @SYMTestPriority High sl@0: @SYMTestActions Start the scheduler and register a client. sl@0: Execute a schedule and then terminate the scheduler. sl@0: When the scheduler is restarted it should exit as there are no sl@0: pending schedules. On exit all allocated memory should be freed sl@0: @SYMTestExpectedResults All allocated memory should be freed when the scheduler exits sl@0: @SYMDEF DEF102414 sl@0: */ sl@0: static void DoTest4L() sl@0: { sl@0: __UHEAP_MARK; sl@0: TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SCHSVR-CT-3402 Test memory cleanup on Task Scheduler exit ")); sl@0: sl@0: // Connect to the server sl@0: TheTest.Next(_L("===== Connect to Scheduler =====")); sl@0: TInt res = TheScheduler.Connect(); sl@0: TEST2(res, KErrNone); sl@0: sl@0: // Register a client with the server sl@0: TheTest.Next(_L("===== Registering Client =====")); sl@0: res = SchSvrHelpers::RegisterClientL(TheScheduler); sl@0: TEST2(res, KErrNone); sl@0: sl@0: //Schedule a task and execute it sl@0: ScheduleAndExecuteTaskL(); sl@0: sl@0: // Kill the server sl@0: res = CleanupHelpers::KillProcess(KTaskScheduler); sl@0: TEST2(res, KErrNone); sl@0: sl@0: TheScheduler.Close(); sl@0: sl@0: //Restarting with a registered client and no schedule should sl@0: //cause the server to exit. Ther server should free all allocated sl@0: //memory. If all memory is not freed, heap check macros within sl@0: // the task scheduler code will cause a panic sl@0: SchSvrHelpers::LaunchTaskSchedulerL(); sl@0: sl@0: //wait for the server to exit sl@0: SchSvrHelpers::Pause(TheTest, 2); sl@0: sl@0: //Verify that the server has already exited - there are two valid sl@0: //error codes depending on how quickly the process is cleaned up sl@0: //KErrDied - Process is dead but hasn't been cleaned up yet by the kernel sl@0: //KErrNotFound - Process has been cleaned up sl@0: res = CleanupHelpers::KillProcess(KTaskScheduler); sl@0: sl@0: TEST((res == KErrDied)||(res == KErrNotFound)); sl@0: sl@0: __UHEAP_MARKEND; sl@0: sl@0: TheTest.Next(_L("All memory freed...")); sl@0: } sl@0: sl@0: sl@0: /** sl@0: @SYMTestCaseID SYSLIB-SCHSVR-CT-3412 sl@0: @SYMTestCaseDesc Test Task Scheduler startup with pending schedule sl@0: @SYMTestPriority High sl@0: @SYMTestActions Start the scheduler and register a client. sl@0: Create a scheduled task and then terminate the scheduler without executing the task. sl@0: When the scheduler is restarted it should not exit as there is a sl@0: pending schedule. Verify that the scheduler is still active by executing sl@0: the schedule sl@0: @SYMTestExpectedResults The task scheduler should not exit and the schedule should execute sl@0: @SYMDEF DEF102414 sl@0: */ sl@0: static void DoTest5L() sl@0: { sl@0: __UHEAP_MARK; sl@0: TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SCHSVR-CT-3412 Test Task Scheduler startup with pending schedule ")); sl@0: sl@0: // Connect to the server sl@0: TheTest.Next(_L("===== Connect to Scheduler =====")); sl@0: TInt res = TheScheduler.Connect(); sl@0: TEST2(res, KErrNone); sl@0: sl@0: // Register a client with the server sl@0: TheTest.Next(_L("===== Registering Client =====")); sl@0: res = SchSvrHelpers::RegisterClientL(TheScheduler); sl@0: TEST2(res, KErrNone); sl@0: sl@0: //Schedule a task sl@0: ScheduleTaskL(); sl@0: sl@0: // Kill the server sl@0: res = CleanupHelpers::KillProcess(KTaskScheduler); sl@0: TEST2(res, KErrNone); sl@0: TheScheduler.Close(); sl@0: sl@0: TheTest.Next(_L("Create Task notification semaphore")); sl@0: //initialise task notification semaphore sl@0: STaskSemaphore sem; sl@0: sem.CreateL(); sl@0: sl@0: //Restart the scheduler - task scheduler should not exit as there is a sl@0: //pending schedule sl@0: res = SchSvrHelpers::LaunchTaskSchedulerL(); sl@0: TEST2(res, KErrNone); sl@0: sl@0: //Execute task and wait for it to run - this would not succeed sl@0: //if task scheduler had exited above sl@0: ExecuteTaskL(); sl@0: TEST2(STaskSemaphore::WaitL(KDefaultTimeout), KErrNone); sl@0: sl@0: //Kill the process and verify that the scheduler was active sl@0: //If the task scheduler isnt active when we try to kill it sl@0: //KillProcess would return KErrDied sl@0: res = CleanupHelpers::KillProcess(KTaskScheduler); sl@0: TEST2(res, KErrNone); sl@0: sl@0: //close handle to semaphore sl@0: sem.Close(); sl@0: sl@0: __UHEAP_MARKEND; sl@0: sl@0: } sl@0: sl@0: /** sl@0: @SYMTestCaseID SYSLIB-SCHSVR-CT-4010 sl@0: @SYMTestCaseDesc Test that adding a task using an unregistered client panics the client and does not crash the server. sl@0: @SYMTestPriority High sl@0: @SYMTestActions Schedule a task with a client that has not been registered. sl@0: @SYMTestExpectedResults Client should be panicked. sl@0: @SYMDEF DEF124488 sl@0: */ sl@0: static void DoTest6L() sl@0: { sl@0: TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SCHSVR-CT-4010 Test handling of unregistered client Should Panic Client thread ")); sl@0: sl@0: RThread testThread; sl@0: _LIT(KThreadName, "PanicClientThread"); sl@0: sl@0: testThread.Create(KThreadName, TestPanicThread, KDefaultStackSize, 0x1000, 0x100000, NULL); sl@0: sl@0: TRequestStatus requestStatus; sl@0: // Request notification when the thread terminates sl@0: testThread.Logon(requestStatus); sl@0: sl@0: TBool justInTime=User::JustInTime(); sl@0: User::SetJustInTime(EFalse); sl@0: // Let the thread execute sl@0: testThread.Resume(); sl@0: sl@0: // Wait for termination sl@0: User::WaitForRequest(requestStatus); sl@0: User::SetJustInTime(justInTime); sl@0: sl@0: TEST2(testThread.ExitReason(), 0); sl@0: testThread.Close(); sl@0: sl@0: } sl@0: sl@0: static TInt RunTestsL() sl@0: { sl@0: TheTest.Next(_L("Delete old files")); sl@0: SchSvrHelpers::DeleteScheduleFilesL(); sl@0: sl@0: //create P&S variables for the test sl@0: CreateTestVariables(); sl@0: sl@0: TheTest.Next(_L("Start tests")); sl@0: sl@0: CActiveScheduler* scheduler = new (ELeave) CActiveScheduler(); sl@0: CleanupStack::PushL(scheduler); sl@0: CActiveScheduler::Install(scheduler); sl@0: sl@0: DoTest1L(); sl@0: DoTest2L(); sl@0: DoTest3L(); sl@0: DoTest4L(); sl@0: DoTest5L(); sl@0: DoTest6L(); sl@0: sl@0: TheTest.Next(_L("Tidying up")); sl@0: CleanupStack::PopAndDestroy(scheduler); sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: GLDEF_C TInt E32Main() sl@0: { sl@0: __UHEAP_MARK; sl@0: TheTest.Start(_L("TC_TSCH_ROBUSTNESS")); sl@0: TheTest.Title(); sl@0: TheCleanup = CTrapCleanup::New(); sl@0: sl@0: //If the previous test fails, SCHSVR.exe may stay in memory. sl@0: TRAPD(error,CleanupHelpers::TestCleanupL()); sl@0: TEST2(error, KErrNone); sl@0: TheTest(TheFsSession.Connect() == KErrNone);; sl@0: TRAP(error, RunTestsL()); sl@0: TEST2(error, KErrNone); sl@0: TRAP(error,CleanupHelpers::TestCleanupL()); sl@0: TEST2(error, KErrNone); sl@0: delete TheCleanup; sl@0: sl@0: TheFsSession.Close(); sl@0: TheTest.End(); sl@0: TheTest.Close(); sl@0: __UHEAP_MARKEND; sl@0: sl@0: return KErrNone; sl@0: }