diff -r 000000000000 -r f979ecb2b13e pimappservices/calendar/tsrc/tcal_notification.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pimappservices/calendar/tsrc/tcal_notification.cpp Tue Feb 02 10:12:19 2010 +0200 @@ -0,0 +1,601 @@ +// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include "caltestlib.h" +#include +#include +#include +#include + +LOCAL_D RTest test(_L("tcal_notification")); + +_LIT8(KEntryGuid, "A_DUMMY_GUID"); +_LIT(KCalendarFile1, "tcal_notification1"); +_LIT(KCalendarFile2, "tcal_notification2"); +_LIT(KSemName, "TCAL_NOTIFICATION_SEM"); + +LOCAL_D const TInt KMaxHeapSize = 0x20000; + +class CTestApp : public CBase + { +public: + virtual void RunTestL() = 0; + ~CTestApp(); + +protected: + CCalTestLibrary* iTestLib; + CPeriodic* iTimer; + }; + +CTestApp::~CTestApp() + { + if (iTimer) + { + iTimer->Cancel(); + } + delete iTimer; + delete iTestLib; + } + + +class CNotificationTestManager : public CTestApp, public MCalChangeCallBack + { +public: + void InitialiseL(); + static TInt StopWaitingForNotification(TAny* ); + void DoStopWaitingForNotification(); + void RunTestL(); + + // from MCalChangeCallBack + void CalChangeNotification(TChangeEntryType aChangeEntryType); + +public: + enum TCallBackState + { + ENotStarted = 0, + EWaitingForAddApptInRange, + EWaitingForAddApptOutRange, + EWaitingForAddTodoInRange, + EWaitingForAddTodoOutRange, + ENotificationReceived, + EWaitingToDeleteAppt, + EWaitingToDeleteTodo, + }; + +private: + TCallBackState iState; + }; + + +class CTestAppModifier : public CTestApp + { +public: + void RunTestL(); + static TInt RunTestThread(TAny* aArgs); + +private: + void StoreAndDestroyEntryL(CCalEntry* aEntry); + CCalEntry* CreateEntryL(CCalEntry::TType aType, TTime aTime); + void ClearEntryL(); + }; + + +//CNotificationTestManager------------------------------------------------------------------------- + +TInt CNotificationTestManager::StopWaitingForNotification(TAny* aPtr) + { + CNotificationTestManager* manager = static_cast(aPtr); + + if (manager) + { + manager->DoStopWaitingForNotification(); + } + + CActiveScheduler::Stop(); + + return KErrNone; + } + + +void CNotificationTestManager::DoStopWaitingForNotification() + { + test.Printf(_L("No notification received\n")); + + iTimer->Cancel(); + } + + +// callback function for change notification +void CNotificationTestManager::CalChangeNotification(TChangeEntryType aChangeEntryType) + { + test.Printf(_L("Notification received - type = %d\n"), aChangeEntryType); + + switch (iState) + { + case EWaitingForAddApptInRange: + case EWaitingToDeleteAppt: + __ASSERT_ALWAYS(aChangeEntryType == EChangeEntryEvent, User::Invariant()); + break; + case EWaitingForAddTodoInRange: + case EWaitingToDeleteTodo: + __ASSERT_ALWAYS(aChangeEntryType != EChangeEntryEvent, User::Invariant()); + break; + case EWaitingForAddApptOutRange: + case EWaitingForAddTodoOutRange: + test.Printf(_L("Got call back from an out-of-range entry!!\n")); + test(0); + break; + default: + break; + } + + iTimer->Cancel(); + iState = ENotificationReceived; + + CActiveScheduler::Stop(); + } + + +void CNotificationTestManager::InitialiseL() + { + iTestLib = CCalTestLibrary::NewL(); + + test.Printf(_L("Opening calendar file...\n")); + + iTestLib->ReplaceFileL(KCalendarFile2()); + iTestLib->OpenFileL(KCalendarFile2()); + + // force creation of a CEntryView object + test.Printf(_L("Opening entry view...\n")); + + iTestLib->AsynCGetEntryViewL(); + CActiveScheduler::Start(); + } + + + +void CNotificationTestManager::RunTestL() + { + TInt err; + + test.Next(_L("Running Notification Test\n")); + + iTestLib = CCalTestLibrary::NewL(); + iTestLib->ReplaceFileL(KCalendarFile1()); + test.Printf(_L("Opening calendar file...\n")); + iTestLib->OpenFileL(KCalendarFile1()); + + // force creation of a CEntryView object + test.Printf(_L("Opening entry view...\n")); + iTestLib->SynCGetEntryViewL(); + + iTimer = CPeriodic::NewL(CActive::EPriorityStandard); + const TTimeIntervalMicroSeconds32 KWait1second(1000000); // 1 second + + // set up notification (all entries in 2005) + TTime startTime(TDateTime(2005, EJanuary, 0, 0, 0, 0, 0)); // 1 Jan 05 + TTime endTime(startTime + TTimeIntervalYears(1)); // 1 Jan 06 + iTestLib->GetSession().StartChangeNotification(this, EChangeEntryAll, ETrue, startTime, endTime); + + + // Create another thread to test the change callback. + test.Printf(_L("Setting up other thread for modifier object...\n")); + RThread otherThread; + TName threadName = _L("TestModifierThread"); + err = otherThread.Create(threadName, CTestAppModifier::RunTestThread, KDefaultStackSize, + KMinHeapSize, KMaxHeapSize, NULL, EOwnerProcess); + if (err != KErrNone) + { + User::Panic(_L("Thread's not been created"), err); + } + + // Create a semaphore + TName semName; + semName.Append(KSemName); + + RSemaphore sem; + err = sem.CreateGlobal(semName, 0); + if (err == KErrAlreadyExists) + { + sem.OpenGlobal(semName); + } + + // add appt within time range + + test.Next(_L("Add an appointment within the notification time range")); + + iState = EWaitingForAddApptInRange; + + // CNotificationTestManager::RunTestL hands over execution to the function + // CTestAppModifier::RunTestL in the other thread for it to make + // changes. The manager waits until the modifier has done what it + // needs to and then signals the manager. + // + // See "// Sync point 1" comments to trace back and forth between + // the two functions. + + otherThread.Resume(); + sem.Wait(); // Sync point 1 + iTimer->Start(KWait1second, KWait1second, TCallBack(StopWaitingForNotification, this)); + CActiveScheduler::Start(); + test(iState == ENotificationReceived); // check callback notification was received for adding appt + + test.Next(_L("Delete this appointment")); + + iState = EWaitingToDeleteAppt; + otherThread.Resume(); + sem.Wait(); // Sync point 2 + iTimer->Start(KWait1second, KWait1second, TCallBack(StopWaitingForNotification, this)); + CActiveScheduler::Start(); + test(iState == ENotificationReceived); // check callback notification was received for delete + + // add appt outside time range + + test.Next(_L("Add an appointment outside the notification time range")); + + iState = EWaitingForAddApptOutRange; + otherThread.Resume(); + sem.Wait(); // Sync point 3 + iTimer->Start(KWait1second, KWait1second, TCallBack(StopWaitingForNotification, this)); + CActiveScheduler::Start(); + test(iState != ENotificationReceived); // check callback notification was NOT received for adding appt + + test.Next(_L("Delete this appointment")); + + iState = EWaitingToDeleteAppt; + otherThread.Resume(); + sem.Wait(); // Sync point 4 + iTimer->Start(KWait1second, KWait1second, TCallBack(StopWaitingForNotification, this)); + CActiveScheduler::Start(); + test(iState != ENotificationReceived); // check callback notification was NOT received for delete + + // notification should now be disabled by the other thread + + // add todo within time range + + test.Next(_L("Disable change notification then add a todo within the notification time range")); + + iState = EWaitingForAddTodoInRange; + otherThread.Resume(); + sem.Wait(); // Sync point 5 + iTimer->Start(KWait1second, KWait1second, TCallBack(StopWaitingForNotification, this)); + CActiveScheduler::Start(); + test(iState != ENotificationReceived); // check callback notification was NOT received (disabled notification) + + // notification should now be re-enabled by the other thread + + test.Next(_L("Re-enable change notification")); + + otherThread.Resume(); + sem.Wait(); // Sync point 6 + iTimer->Start(KWait1second, KWait1second, TCallBack(StopWaitingForNotification, this)); + CActiveScheduler::Start(); + test(iState == ENotificationReceived); // check callback notification was received for todo added during disable + + test.Next(_L("Delete this todo")); + + iState = EWaitingToDeleteTodo; + otherThread.Resume(); + sem.Wait(); // Sync point 7 + iTimer->Start(KWait1second, KWait1second, TCallBack(StopWaitingForNotification, this)); + CActiveScheduler::Start(); + test(iState == ENotificationReceived); // check callback notification was received for delete + + // add todo out of time range + + test.Next(_L("Add a todo entry outside the notification time range")); + + iState = EWaitingForAddTodoOutRange; + otherThread.Resume(); + sem.Wait(); // Sync point 8 + iTimer->Start(KWait1second, KWait1second, TCallBack(StopWaitingForNotification, this)); + CActiveScheduler::Start(); + test(iState != ENotificationReceived); // check callback notification was NOT received for adding todo + + test.Next(_L("Delete this todo")); + + iState = EWaitingToDeleteTodo; + otherThread.Resume(); + sem.Wait(); // Sync point 9 + iTimer->Start(KWait1second, KWait1second, TCallBack(StopWaitingForNotification, this)); + CActiveScheduler::Start(); + test(iState != ENotificationReceived); // check callback notification was NOT received for delete + + otherThread.Resume(); // allow the thread to tidy up; + sem.Wait(); + + otherThread.Close(); + sem.Close(); + + iTestLib->GetSession().StopChangeNotification(); + } + + + +//CTestAppModifier------------------------------------------------------------------------ + +// this function deletes all entries with the UID used in this test harness +void CTestAppModifier::ClearEntryL() + { + CDesC8Array* uidArray = new (ELeave) CDesC8ArrayFlat(1); + CleanupStack::PushL(uidArray); + + uidArray->AppendL(KEntryGuid()); + iTestLib->SynCGetEntryViewL().DeleteL(*uidArray); + + CleanupStack::PopAndDestroy(uidArray); + } + +// this function creates an entries with the type and time specified +CCalEntry* CTestAppModifier::CreateEntryL(CCalEntry::TType aType, TTime aTime) + { + HBufC8* guid1 = KEntryGuid().AllocLC(); + CCalEntry* entry = CCalEntry::NewL(aType, guid1, CCalEntry::EMethodNone, 0); + CleanupStack::Pop(guid1); + + TCalTime calTime1; + TCalTime calTime2; + calTime1.SetTimeLocalL(aTime); + calTime2.SetTimeLocalL(aTime + TTimeIntervalHours(1)); + entry->SetStartAndEndTimeL(calTime1, calTime2); + + return entry; + } + +// this function stores an entry then deletes it +void CTestAppModifier::StoreAndDestroyEntryL(CCalEntry* aEntry) + { + CleanupStack::PushL(aEntry); + + RPointerArray entriesToAdd; + CleanupClosePushL(entriesToAdd); + + entriesToAdd.AppendL(aEntry); + + TInt successfulAdd(0); + iTestLib->SynCGetEntryViewL().StoreL(entriesToAdd, successfulAdd); + + test(successfulAdd == entriesToAdd.Count()); + + CleanupStack::PopAndDestroy(); // entriesToAdd.Close() + CleanupStack::PopAndDestroy(aEntry); + } + +TInt CTestAppModifier::RunTestThread(TAny* /*aArgs*/) + { + CTrapCleanup* trapCleanup = CTrapCleanup::New(); + CActiveScheduler* scheduler = new CActiveScheduler; + if ( ! scheduler) + { + return KErrNoMemory; + } + CActiveScheduler::Install(scheduler); + + // Create a semaphore + TName semName; + semName.Append(KSemName); + + RSemaphore sem; + TInt err = sem.CreateGlobal(semName, 0); + if (err == KErrAlreadyExists) + { + sem.OpenGlobal(semName); + } + + CTestAppModifier* modifier = new CTestAppModifier; + if ( ! modifier) + { + return KErrNoMemory; + } + TRAP(err, modifier->RunTestL()); + + delete modifier; + delete scheduler; + delete trapCleanup; + + sem.Signal(); + sem.Close(); + return err; + } + +void CTestAppModifier::RunTestL() + { + RThread thisThread; + thisThread.Duplicate(RThread()); // get a handle to the current thread + + + iTestLib = CCalTestLibrary::NewL(); + iTestLib->OpenFileL(KCalendarFile1()); + + // force creation of a CEntryView object + iTestLib->SynCGetEntryViewL(); + + // Create a semaphore + TName semName; + semName.Append(KSemName); + + RSemaphore sem; + TInt err = sem.CreateGlobal(semName, 0); + if (err == KErrAlreadyExists) + { + sem.OpenGlobal(semName); + } + + // The function CNotificationTestManager::RunTestL hands over execution + // from the other thread to CTestAppModifier::RunTestL for it to + // make changes. The manager waits until the modifier has done + // what it needs to and then signals the manager. + // + // See "// Sync point 1" comments to trace back and forth between + // the two functions. + + // Sync point 1 + // add appt within time range + TTime startTime(TDateTime(2005, EJanuary, 0, 0, 0, 0, 0)); // 1 Jan 05 + TTime endTime(startTime + TTimeIntervalYears(1)); // 1 Jan 06 + CCalEntry* apptInRange = CreateEntryL(CCalEntry::EAppt, startTime + TTimeIntervalDays(5)); + StoreAndDestroyEntryL(apptInRange); + sem.Signal(); + thisThread.Suspend(); + + // Sync point 2 + // delete it + ClearEntryL(); + sem.Signal(); + thisThread.Suspend(); + + // Sync point 3 + // add appt outside time range + CCalEntry* apptOutOfRange = CreateEntryL(CCalEntry::EAppt, startTime - TTimeIntervalMonths(3)); + StoreAndDestroyEntryL(apptOutOfRange); + sem.Signal(); + thisThread.Suspend(); + + // Sync point 4 + // delete it + ClearEntryL(); + sem.Signal(); + thisThread.Suspend(); + + // Sync point 5 + iTestLib->GetSession().DisableChangeBroadcast(); + + // add todo within time range + CCalEntry* disableAppt = CreateEntryL(CCalEntry::ETodo, startTime + TTimeIntervalDays(5)); + StoreAndDestroyEntryL(disableAppt); + sem.Signal(); + thisThread.Suspend(); + + // Sync point 6 + iTestLib->GetSession().EnableChangeBroadcast(); + sem.Signal(); + thisThread.Suspend(); + + // Sync point 7 + // delete it + ClearEntryL(); + sem.Signal(); + thisThread.Suspend(); + + // Sync point 8 + // add todo out of time range + + CCalEntry* todoOutRange = CreateEntryL(CCalEntry::ETodo, endTime + TTimeIntervalHours(4)); + StoreAndDestroyEntryL(todoOutRange); + sem.Signal(); + thisThread.Suspend(); + + // Sync point 9 + // delete it + ClearEntryL(); + sem.Signal(); + thisThread.Suspend(); + + sem.Close(); + } + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * DoTestL() + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +static void DoTestL() + { + CNotificationTestManager* testManager = new (ELeave) CNotificationTestManager(); + CleanupStack::PushL(testManager); + + + TPerformanceTimer timer(test); + timer.Start(); + + + // Run the test suite + + // initialise the calendar file + testManager->RunTestL(); + + + timer.Stop(); + test.Printf(_L("Done\n")); + // printout performance time + timer.PrintOut(); + + + CleanupStack::PopAndDestroy(testManager); + + + //Test code added for DEF063285 + test.Next(_L("To initialise CalenderProgressObserver,Entryview,CalSession...")); + + test.Next(_L("...and destroy entryview before it is built completely...")); + + test.Next(_L("...to check any asynchronous operation is cancelled")); + + + testManager = new (ELeave) CNotificationTestManager(); + CleanupStack::PushL(testManager); + + //Intialise CalenderProgressObserver,Entryview,CalSession + TRAPD(err, testManager->InitialiseL()); + test(err == KErrNone); + + //After initialising try to destroy CalenderProgressObserver which contains entryview + //and session to check any asynchronous operation is cancelled if the entryview is not built completely + CleanupStack::PopAndDestroy(testManager); + } + + +/** + +@SYMTestCaseID PIM-TCAL-NOTIFICATION-0001 + +*/ + +TInt E32Main() + { + __UHEAP_MARK; + + test.Start(_L("@SYMTESTCaseID:PIM-TCAL-NOTIFICATION-0001 Calendar Interim API Notification test suite")); + + test.Title(); + + CTrapCleanup* trapCleanup = CTrapCleanup::New(); + if (!trapCleanup) + { + return KErrNoMemory; + } + + CActiveScheduler* scheduler = new CActiveScheduler(); + if (!scheduler) + { + delete trapCleanup; + return KErrNoMemory; + } + CActiveScheduler::Install(scheduler); + + TRAPD(ret, DoTestL()); + test(ret == KErrNone); + + delete scheduler; + delete trapCleanup; + + test.End(); + test.Close(); + + __UHEAP_MARKEND; + + return (KErrNone); + } +