--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lowlevellibsandfws/pluginfw/Framework/ResolverTest/t_resolvercache.cpp Tue Feb 02 02:01:42 2010 +0200
@@ -0,0 +1,1433 @@
+// Copyright (c) 2008-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:
+// This file contains test classes and their implementations
+// to test production class CCustomResolverCache.
+//
+//
+
+#include <e32test.h>
+#include <f32file.h>
+#include <hal.h>
+#include <bautils.h>
+#include <babitflags.h>
+#include <babackup.h>
+#include <startup.hrh>
+#include <ecom/resolver.h>
+#include "EComErrorCodes.h"
+#include "EComUidCodes.h"
+#include "ImplementationInformation.h"
+#include "RegistryData.h"
+#include "Registrar.h"
+#include "RegistrarObserver.h"
+#include "../EcomTestUtils/EcomTestUtils.h"
+#include <swi/swispubsubdefs.h>
+#include "../EcomTestUtils/TPropertyManager.h"
+#include "EComPatchDataConstantv2.h"
+#include "RegistryResolveTransaction.h" // ecom3 code
+#include "callback.h"
+#include "resolvercache.h"
+#include "EComServer.h"
+
+
+const TInt KOneSecond = 1000000;
+const TInt KHalfSecond = KOneSecond / 2;
+// Use this timeout to wait for events occuring within a few seconds.
+const TInt KIndefiniteWait = KOneSecond * 20;
+
+LOCAL_D RTest test(_L("t_resolvercache.exe"));
+
+LOCAL_D RFs TheFs;
+LOCAL_D CTrapCleanup* TheTrapCleanup = NULL;
+class CDerivedActiveScheduler;
+LOCAL_D CDerivedActiveScheduler* TheActiveScheduler = NULL;
+
+
+// custom resolvers available for testing.
+// 200126cd, A0001346 and A0001347 are allocated outside the
+// ECOM Uid Allocations.doc
+const TUid KDummyResolverUid2 = {0xA0001346};
+const TUid KDummyResolverUid3 = {0xA0001347};
+const TUid KExampleResolverUid = {0x10009DD0};
+const TUid KMyResolverUid = {0x10009E12};
+const TUid KDummyResolverUid1 = {0x200126CD};
+
+// The custom resolver in RAMOnly dir
+_LIT(KDummyRscInC, "c:\\resource\\plugins\\dummycustomresolver1.rsc");
+_LIT(KDummyDllInC, "c:\\sys\\bin\\dummycustomresolver1.dll");
+
+_LIT(KDummyRscInZ, "z:\\ramonly\\dummycustomresolver1.rsc");
+_LIT(KDummyDllInZ, "z:\\ramonly\\dummycustomresolver1.dll");
+
+// This pair is to upgrade a resolver DLL.
+// NB: to supersede a Z: drive plugin, the C: DLL must have the
+// same name as the one in z: drive. Hence the '2' is dropped.
+_LIT(KDllUpgradeInZ, "z:\\ramonly\\cachedcustomresolver2.dll");
+_LIT(KDllUpgradeInC, "c:\\sys\\bin\\cachedcustomresolver.dll");
+
+_LIT(KRscUpgradeInZ, "z:\\ramonly\\cachedcustomresolver2.rsc");
+_LIT(KRscUpgradeInC, "c:\\resource\\plugins\\cachedcustomresolver.rsc");
+
+/** User::AfterHighRes is not a reliable mechanism to wait
+for async events. Especially when we have 4 different timers
+firing within a span of 4 s. Hence this harness intercepts
+and inserts callbacks in the notification sources and set
+the following flag to indicate what event has occured. */
+LOCAL_D TBitFlags32 AsyncEvents = 0;
+
+/** enum to identify different async events */
+enum TAsyncEventId
+ {
+ EAsyncEvent_Unknown = 0,
+ EAsyncEvent_ImplUpgrade,
+ EAsyncEvent_SwiStart,
+ EAsyncEvent_SwiEnd,
+ EAsyncEvent_BurStart,
+ EAsyncEvent_BurEnd,
+ EAsyncEvent_CacheTimer,
+ EAsyncEvent_HaltTimer
+ };
+
+//
+// maps callback data to enum TAsyncEventId.
+LOCAL_C TAsyncEventId CallbackDataToEventId(TInt aEvent, TAny* aData)
+ {
+ TAsyncEventId ret = EAsyncEvent_Unknown;
+ TCallBackState* state = static_cast<TCallBackState*>(aData);
+ if (aEvent == ECallBackId_SwiEvent)
+ {
+ if (*state == ECallBackState_EventStart)
+ {
+ ret = EAsyncEvent_SwiStart;
+ }
+ else // treat all unexpected states as SWI end!
+ {
+ ret = EAsyncEvent_SwiEnd;
+ }
+ }
+ else if (aEvent == ECallBackId_BurEvent)
+ {
+ if (*state == ECallBackState_EventStart)
+ {
+ ret = EAsyncEvent_BurStart;
+ }
+ else // treat all unexpected states as BUR finish!
+ {
+ ret = EAsyncEvent_BurEnd;
+ }
+ }
+ else if (aEvent == ECallBackId_ImplUpgrade)
+ {
+ ret = EAsyncEvent_ImplUpgrade;
+ }
+ return ret;
+ }
+
+// beginningOfTest is set when this harness is run.
+LOCAL_D TTime beginningOfTest;
+LOCAL_C void WaitForLazyUnloadingL()
+ {
+ TTime now;
+ now.UniversalTime();
+
+ TTimeIntervalSeconds n;
+ User::LeaveIfError(now.SecondsFrom(beginningOfTest, n));
+ const TInt KLazyDllUnloadPeriod = 150; // actual is 2 minutes
+ TInt secondsToWait = KLazyDllUnloadPeriod - n.Int();
+ test.Printf(_L("Amount to wait for lazy unload is %d seconds.\n"), secondsToWait);
+ if (secondsToWait > 0)
+ {
+ User::After(KOneSecond * secondsToWait);
+ }
+ }
+
+// Copies the Plugins to specific folder for testing purpose
+LOCAL_C void CopyPluginsL()
+ {
+ EComTestUtils::FileManCopyFileL(KDummyRscInZ, KDummyRscInC);
+ EComTestUtils::FileManCopyFileL(KDummyDllInZ, KDummyDllInC);
+ }
+
+// Deleting plugin from the RAM for cleanup purpose
+LOCAL_C void DeleteTestPlugin()
+ {
+ TRAP_IGNORE(EComTestUtils::FileManDeleteFileL(KDummyRscInC));
+ TRAP_IGNORE(EComTestUtils::FileManDeleteFileL(KDummyDllInC));
+
+ TRAP_IGNORE(EComTestUtils::FileManDeleteFileL(KRscUpgradeInC));
+ TRAP_IGNORE(EComTestUtils::FileManDeleteFileL(KDllUpgradeInC));
+ }
+
+// utility to help cast TTimeIntervalMicroSeconds to TInt
+LOCAL_C TInt CalcElapsedMicroseconds(const TTime& aStart)
+ {
+ TTime now;
+ now.UniversalTime();
+ TTimeIntervalMicroSeconds timediff = now.MicroSecondsFrom(aStart);
+ return I64LOW( timediff.Int64() );
+ }
+
+/** Need a CActive to wait for various change notifications. */
+class CHaltTimer : public CTimer
+ {
+public:
+ CHaltTimer(TInt aPriority);
+ ~CHaltTimer();
+ void ConstructL();
+ void StartTimer(TInt aTimeInterval);
+
+private:
+ void RunL();
+ };
+
+CHaltTimer::CHaltTimer(TInt aPriority)
+ : CTimer(aPriority)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+CHaltTimer::~CHaltTimer()
+ {
+ Cancel();
+ }
+
+void CHaltTimer::ConstructL()
+ {
+ CTimer::ConstructL();
+ }
+
+void CHaltTimer::StartTimer(TInt aTimeInterval)
+ {
+ After(aTimeInterval);
+ }
+
+void CHaltTimer::RunL()
+ {
+ AsyncEvents.Set(EAsyncEvent_HaltTimer);
+ CActiveScheduler::Stop();
+ }
+
+/** Avoid E32User::Case 47 panic in OOM test */
+class CDerivedActiveScheduler : public CActiveScheduler
+ {
+public:
+ virtual void Error(TInt aError) const;
+ };
+
+void CDerivedActiveScheduler::Error(TInt aError) const
+ {
+ Halt(aError);
+ }
+
+/** friend class to access private members of CEComServer */
+class TEComServer_StateAccessor
+ {
+public:
+ static void InterceptCallbacks(CEComServer& aEComServer, TCallBackWithArg aCb);
+ static CCustomResolverCache* GetResolverCache(CEComServer& aEComServer);
+ };
+
+/** Test class for object CCustomResolverCache.
+*/
+class CCustomResolverCacheTest : public CBase
+ {
+public:
+ typedef void (CCustomResolverCacheTest::*ClassFuncPtrL) (void);
+
+ virtual ~CCustomResolverCacheTest();
+ static CCustomResolverCacheTest* NewL();
+ static void RunAllTestsL();
+ static TInt InterceptCacheMgrCallback(TAny* aObj, TInt aEvent, TAny* aData);
+ static TInt CacheTimeoutCallback(TAny* aObj, TInt aEvent, TAny* aData);
+
+private:
+ CCustomResolverCacheTest();
+ void ConstructL();
+
+ static void DoBasicTestL(ClassFuncPtrL aTestFunc);
+ static void DoOOMTestL(ClassFuncPtrL aTestFunc);
+
+ // Test cases
+ void TestUpgradingCachedResolverL();
+ void TestDeletingCachedResolverL();
+
+ void TestCacheQueueFullPattern1L();
+ void TestCacheQueueFullPattern2L();
+ void TestCacheQueueFullPattern3L();
+ void DoQueueFullTestL(const RArray<TUid>& aResolverList);
+
+ void TestCounterWrapAroundL();
+ void TestCacheTimerAccuracyL();
+ void TestTimestampUpdateOnCacheHitL();
+ void TestSWIDisableRwResolverCachingL();
+ void TestBurDisableRwResolverCachingL();
+ void TestClockChangeHasNoEffectOnCacheTimeoutL();
+ void TestCacheSizeZeroL();
+ void TestCacheTimeoutZeroL();
+ void TestResolverWithBadProxyTable();
+
+ // utilities
+ TBool UseResolverCheckVersionL(TUid aResolverUid,
+ TInt aVersion = 0);
+ void YieldToOtherCActive(TInt aMicroSeconds);
+ void WaitAsyncL(TInt aNumSeconds);
+ TBool WaitForEvict(TUid aResolverUid);
+
+ // access private data of CCustomResolverCache
+ TInt CacheSize();
+ TBool HasResolverUid(TUid aUid);
+ TBool QueueIsSorted();
+ inline CCustomResolverCache* ResolverCache();
+
+private:
+ /** need a CActive to wait for other async events */
+ CHaltTimer* iHaltTimer;
+
+ CEComServer* iEComServer;
+ };
+
+//==============================================
+// class TEComServer_StateAccessor
+//==============================================
+void TEComServer_StateAccessor::InterceptCallbacks(CEComServer& aEComServer,
+ TCallBackWithArg aCb)
+ {
+ aEComServer.iRegistrar->InstallSwiEventCallBack(aCb);
+ aEComServer.iRegistrar->InstallBurEventCallBack(aCb);
+ aEComServer.iRegistryData->SetImplUpgradeCallBack(aCb);
+ }
+
+CCustomResolverCache*
+TEComServer_StateAccessor::GetResolverCache(CEComServer& aEComServer)
+ {
+ return aEComServer.iResolverCache;
+ }
+
+//==============================================
+// class CCustomResolverCacheTest
+//==============================================
+
+/** CCustomResolverCacheTest constructor */
+CCustomResolverCacheTest::CCustomResolverCacheTest()
+ {
+ }
+
+/** CCustomResolverCacheTest destructor. */
+CCustomResolverCacheTest::~CCustomResolverCacheTest()
+ {
+ delete iEComServer;
+ delete iHaltTimer;
+ }
+
+/** static factory method to instantiate CCustomResolverCacheTest object.
+*/
+CCustomResolverCacheTest* CCustomResolverCacheTest::NewL()
+ {
+ CCustomResolverCacheTest* self = new(ELeave) CCustomResolverCacheTest;
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+/**
+Standardized 2nd phase of two phase construction.
+*/
+void CCustomResolverCacheTest::ConstructL()
+ {
+ iHaltTimer = new(ELeave) CHaltTimer(CActive::EPriorityIdle);
+ iHaltTimer->ConstructL();
+
+ iEComServer = CEComServer::NewLC();
+ CleanupStack::Pop(iEComServer);
+
+ TCallBackWithArg interceptorCB(&InterceptCacheMgrCallback, this);
+ TEComServer_StateAccessor::InterceptCallbacks(*iEComServer, interceptorCB);
+
+ TCallBackWithArg cacheTimerCb(&CacheTimeoutCallback, this);
+ ResolverCache()->iTimerExpireCB = cacheTimerCb;
+ }
+
+/** util to fetch CEComServer::iResolverCache */
+inline CCustomResolverCache* CCustomResolverCacheTest::ResolverCache()
+ {
+ return TEComServer_StateAccessor::GetResolverCache(*iEComServer);
+ }
+
+/** the test harness install this callback with ECOM server objects
+to intercept async events. This callback will relay the original
+call to CEComServer, then raise a flag to indicate what
+event has occurred.
+@param aObj pointer to the CCustomResolverCacheTest object
+@param aEvent ID of event triggering the callback
+@param aData pointer to some data associated with the event.
+@return Always KErrNone. It is ignored.
+*/
+TInt CCustomResolverCacheTest::InterceptCacheMgrCallback(TAny* aObj,
+ TInt aEvent,
+ TAny* aData)
+ {
+ CCustomResolverCacheTest* self = static_cast<CCustomResolverCacheTest*>(aObj);
+ // Pass the event along to let CEComServer does its thing.
+ CEComServer::NotifyEvents(self->iEComServer, aEvent, aData);
+
+ if (self->iHaltTimer->IsActive())
+ {
+ TAsyncEventId event = CallbackDataToEventId(aEvent, aData);
+ AsyncEvents.Set(event);
+
+ self->iHaltTimer->Cancel();
+ CActiveScheduler::Stop();
+ }
+ else
+ {
+ // BUR and SWI unit test cases just call the notifier
+ // directly. So CHaltTimer is not running.
+ test.Printf(_L("CacheTest: caught async event %d when timer not running\n"), aEvent);
+ }
+ return KErrNone;
+ }
+
+/** A callback installed in cache mgr. Whenever the cache timer expires
+this callback is invoked by CCustomResolverCache
+@param aObj pointer to CCustomResolverCacheTest
+@return Always KErrNone. It is ignored.
+*/
+TInt CCustomResolverCacheTest::CacheTimeoutCallback(TAny* aObj, TInt, TAny*)
+ {
+ AsyncEvents.Set(EAsyncEvent_CacheTimer);
+
+ CCustomResolverCacheTest* self = static_cast<CCustomResolverCacheTest*>(aObj);
+ self->iHaltTimer->Cancel();
+ CActiveScheduler::Stop();
+ return KErrNone;
+ }
+
+/** Wrapper function to run normal mode (non-OOM) test
+*/
+void CCustomResolverCacheTest::DoBasicTestL(ClassFuncPtrL aTestFunc)
+ {
+ __UHEAP_MARK;
+ TInt startProcessHandleCount;
+ TInt startThreadHandleCount;
+ RThread().HandleCount(startProcessHandleCount, startThreadHandleCount);
+
+ CCustomResolverCacheTest* p = CCustomResolverCacheTest::NewL();
+ (p->*aTestFunc)();
+ delete p;
+
+ // check that no handles have leaked
+ TInt endProcessHandleCount;
+ TInt endThreadHandleCount;
+ RThread().HandleCount(endProcessHandleCount, endThreadHandleCount);
+
+ test(startProcessHandleCount == endProcessHandleCount);
+ test(startThreadHandleCount == endThreadHandleCount);
+ __UHEAP_MARKEND;
+ }
+
+/**
+@SYMTestCaseID SYSLIB-ECOM-UT-4020
+@SYMTestCaseDesc Verify no memory leak in CCustomResolverCache.
+@SYMTestPriority Critical
+@SYMTestActions Run UT-4015, UT-4016 and UT-4017 under OOM.
+@SYMTestExpectedResults No memory leak, no handle leak.
+@SYMCR CR1182
+*/
+void CCustomResolverCacheTest::DoOOMTestL(ClassFuncPtrL aTestFunc)
+ {
+ test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-UT-4020 "));
+ __UHEAP_MARK;
+ TInt startProcessHandleCount;
+ TInt startThreadHandleCount;
+ RThread().HandleCount(startProcessHandleCount, startThreadHandleCount);
+ TInt err(KErrNone);
+ TInt oomStep = 0;
+
+ do {
+ // Instantiation of CCustomResolverCacheTest involves building
+ // the registry. It will take couple hours under OOM. Hence do it
+ // outside __UHEAP_SETFAIL.
+ CCustomResolverCacheTest* p = CCustomResolverCacheTest::NewL();
+
+ __UHEAP_SETFAIL(RHeap::EDeterministic, ++oomStep);
+ TRAP(err, (p->*aTestFunc)());
+ __UHEAP_SETFAIL(RHeap::ENone, 0);
+
+ delete p;
+ } while (err == KErrNoMemory);
+
+ test(err == KErrNone);
+ test.Printf(_L("OOM succeeded at heap failure rate %d\n"), oomStep);
+
+ // check that no handles have leaked
+ TInt endProcessHandleCount;
+ TInt endThreadHandleCount;
+ RThread().HandleCount(endProcessHandleCount, endThreadHandleCount);
+
+ test(startProcessHandleCount == endProcessHandleCount);
+ test(startThreadHandleCount == endThreadHandleCount);
+ __UHEAP_MARKEND;
+ }
+
+/** helper, ecom3 code
+Issue a list request to add resolver to cache and check if
+the registry has the expected version of the resolver.
+@param aResolverUid the custom resolver to create
+@param aVersion the expected version of the custom resolver. Check is skipped
+ if aVersion is zero.
+*/
+TBool CCustomResolverCacheTest::UseResolverCheckVersionL(TUid aResolverUid,
+ TInt aVersion)
+ {
+ TEComResolverParams resolverparams;
+ _LIT8(KDummyData,"dummy");
+ resolverparams.SetDataType(KDummyData);
+
+ TClientRequest clientReq;
+ RArray<TUid> extendedInterfaces;
+ RImplInfoArray* infoArray = iEComServer->ListImplementationsL(
+ KCustomResolverInterfaceUid, resolverparams, aResolverUid,
+ extendedInterfaces, clientReq);
+
+ TBool ret = (aVersion == 0);
+
+ // infoArray not pushed because there are no leave in this search.
+ for (TInt i = 0; !ret && i < infoArray->Count(); i++)
+ {
+ const CImplementationInformation* impl = (*infoArray)[i];
+ if (impl->ImplementationUid() == aResolverUid && impl->Version() == aVersion)
+ {
+ ret = ETrue;
+ }
+ }
+
+ infoArray->Reset();
+ delete infoArray;
+
+ return ret;
+ }
+
+/** utility to let other CActive s to run. */
+void CCustomResolverCacheTest::YieldToOtherCActive(TInt aMicroSeconds)
+ {
+ iHaltTimer->StartTimer(aMicroSeconds);
+ CActiveScheduler::Start();
+ }
+
+/** Call YieldToOtherCActive as many times as needed
+until aNumSeconds is reached. */
+void CCustomResolverCacheTest::WaitAsyncL(TInt aNumSeconds)
+ {
+ TTime start, now;
+ start.UniversalTime();
+ TTimeIntervalSeconds elapsed;
+
+ for (elapsed = 0; elapsed.Int() < aNumSeconds; )
+ {
+ AsyncEvents.ClearAll();
+ TInt seconds = (aNumSeconds - elapsed.Int());
+ YieldToOtherCActive(KOneSecond * seconds);
+ now.UniversalTime();
+ User::LeaveIfError(now.SecondsFrom(start, elapsed));
+ }
+ }
+
+/**
+This method is used in the situation that cache timer is already
+started when we load the given resolver. Then when cache timer
+expires, the resolver is not ripe to be evicted. Have to wait a
+second time.
+@param aResolverUid the Resolver to wait for evict.
+@return ETrue means the resolver is evicted correctly.
+ EFalse means error, i.e. test fail.
+*/
+TBool CCustomResolverCacheTest::WaitForEvict(TUid aResolverUid)
+ {
+ TBool ret = EFalse;
+ // No point of waiting for 20s for cache timeout.
+ TInt waitMicroSec = KCustomResolverCacheTimeout + KOneSecond;
+ for (TInt i = 0; (i < 2) && !ret; i++)
+ {
+ AsyncEvents.ClearAll();
+ YieldToOtherCActive(waitMicroSec);
+ // Check which async event has stopped the activescheduler
+ test( AsyncEvents.IsSet(EAsyncEvent_CacheTimer) );
+ ret = ! HasResolverUid(aResolverUid);
+ }
+ return ret;
+ }
+
+//==========================================================
+// utilities to access internal data of CCustomResolverCache.
+// This is possible because CCustomResolverCacheTest is a friend.
+//===========================================================
+
+TInt CCustomResolverCacheTest::CacheSize()
+ {
+ return ResolverCache()->iResolvers.Count();
+ }
+
+TBool CCustomResolverCacheTest::HasResolverUid(TUid aUid)
+ {
+ for (TInt i = 0; i < ResolverCache()->iResolvers.Count(); i++)
+ {
+ if (ResolverCache()->iResolvers[i].iResolverUid == aUid)
+ {
+ return ETrue;
+ }
+ }
+ return EFalse;
+ }
+
+TBool CCustomResolverCacheTest::QueueIsSorted()
+ {
+ CCustomResolverCache* theResolverCache = ResolverCache();
+ for (TInt i = 1; i < theResolverCache->iResolvers.Count(); i++)
+ {
+ if (theResolverCache->iResolvers[i-1].iResolverUid.iUid >=
+ theResolverCache->iResolvers[i].iResolverUid.iUid)
+ {
+ test.Printf(_L("Sort error: i-1 %d, 0x%8X, 0x%8X\n"), i-1,
+ theResolverCache->iResolvers[i-1].iResolverUid.iUid,
+ theResolverCache->iResolvers[i].iResolverUid.iUid );
+ return EFalse;
+ }
+ }
+ return ETrue;
+ }
+
+/**
+@SYMTestCaseID SYSLIB-ECOM-CT-4012
+@SYMTestCaseDesc If a cached resolver is superseded by a new version, it
+ is evicted from cache.
+@SYMTestPriority High
+@SYMTestActions 1. Use a custom resolver to get it in cache.
+ 2. copy the upgrade version of the resolver to C: and wait for
+ its discovery.
+@SYMTestExpectedResults 1. a/. The resolver is the base version.
+ b/. It is added in the cache.
+ 2. a/. Cache mgr receives upgrade notification (from CRegistryData).
+ b/. The resolver entry disappears from cache and the cache timer is
+ still running.
+@SYMCR CR1182
+*/
+void CCustomResolverCacheTest::TestUpgradingCachedResolverL()
+ {
+ test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-CT-4012 "));
+ // get the customer resolver in cache. It should be version 1.
+ test (UseResolverCheckVersionL(KMyResolverUid, 1));
+ // Check that KMyResolverUid is added to cache.
+ test(HasResolverUid(KMyResolverUid));
+
+ // Need an extra item in cache to get Bullseye to check off
+ // a conditional. It is not an active ingredient of this test.
+ UseResolverCheckVersionL(KDummyResolverUid1, 0);
+
+ // Copy the upgrade to C: drive
+ EComTestUtils::FileManCopyFileL(KRscUpgradeInZ, KRscUpgradeInC);
+ EComTestUtils::FileManCopyFileL(KDllUpgradeInZ, KDllUpgradeInC);
+
+ // Let CDiscoverer discover the resource file.
+ AsyncEvents.ClearAll();
+ YieldToOtherCActive(KIndefiniteWait); // 20 s
+
+ // Check which async event has stopped the activescheduler
+ test( AsyncEvents.IsSet(EAsyncEvent_ImplUpgrade) );
+
+ // And the cache entry should be gone.
+ test(! HasResolverUid(KMyResolverUid));
+
+ // cleanup. NB: we never loaded the DLL in C: drive so
+ // no need to worry about lazy dll unloading.
+ EComTestUtils::FileManDeleteFileL(KRscUpgradeInC);
+ EComTestUtils::FileManDeleteFileL(KDllUpgradeInC);
+ }
+
+/**
+@SYMTestCaseID SYSLIB-ECOM-CT-4013
+@SYMTestCaseDesc Verify a cached DLL cannot be deleted until it
+ is removed from cache. This test serves as a sanity check that
+ ECOM does need these notifications to trigger unloading DLL
+ on SWI and BUR events.
+@SYMTestPriority Medium
+@SYMTestActions 1. Use a RW drive resolver to get it in cache.
+ 2. Try to delete the DLL within default cache timeout period.
+ 3. Try again after it is evicted from cache.
+@SYMTestExpectedResults 1. The resolver is added in cache.
+ 2. Get KErrAccessDenied error.
+ 3. The delete is either KErrNone or KErrNotFound because in step 2
+ even though the return code is -21, the file may be actually gone.
+@SYMCR CR1182
+*/
+void CCustomResolverCacheTest::TestDeletingCachedResolverL()
+ {
+ test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-CT-4013 "));
+ // NB: lazy Dll unloading interferes with this test.
+ // Best to run this test at the end.
+ WaitForLazyUnloadingL();
+
+ // There is only 1 version of 200126CD. No need to check version.
+ // So ignore the return code.
+ UseResolverCheckVersionL(KDummyResolverUid1, 0);
+
+ // Check that it is added to cache.
+ test( HasResolverUid(KDummyResolverUid1) );
+
+ TInt err(KErrNone);
+ TRAP(err, EComTestUtils::FileManDeleteFileL(KDummyDllInC));
+
+#ifndef __WINSCW__
+ // On hw you can delete the DLL while it is loaded.
+ if (err == KErrNone)
+ {
+ test.Printf(_L("Delete test: RFs allows deletion of loaded DLL on hw. Test not run.\n"));
+ EComTestUtils::FileManCopyFileL(KDummyDllInZ, KDummyDllInC);
+ return;
+ }
+#endif
+
+ test(err == KErrAccessDenied);
+
+ // Wait for its eviction after cache timeout.
+ AsyncEvents.ClearAll();
+ YieldToOtherCActive(KIndefiniteWait); // 20 s
+
+ // Check which async event has stopped the activescheduler
+ test( AsyncEvents.IsSet(EAsyncEvent_CacheTimer) );
+ // Check the resolver is evicted
+ test( !HasResolverUid(KDummyResolverUid1) );
+
+ TRAP(err, EComTestUtils::FileManDeleteFileL(KDummyDllInC));
+ test(err == KErrNone || err == KErrNotFound);
+
+ // restore the file
+ EComTestUtils::FileManCopyFileL(KDummyDllInZ, KDummyDllInC);
+ }
+
+/**
+@SYMTestCaseID SYSLIB-ECOM-UT-4015
+@SYMTestCaseDesc Verify cache queue does not grow beyond the max
+ queue size. Verify when a resolver is added to a full cache,
+ the one to evict is the least recently used.
+
+ There are 3 versions of this test. In Pattern1, the LRU entry
+ has UID value which is the smallest of the 5 resolvers.
+ In pattern 2, UID of the LRU is greatest. In pattern 3, UID of the
+ LRU is the second smallest.
+@SYMTestPriority High
+@SYMTestActions 1. Use 4 different resolvers to fill up the cache.
+ 2. Use a fifth one to bump off the least recently used entry.
+ Run these two steps with the LRU entry in different positions in the
+ queue, i.e. it is first, second, and last in the queue.
+@SYMTestExpectedResults 1. The cache has 4 entries and is sorted in UID order.
+ 2. The oldest entry is gone from cache. The last one used is in cache.
+@SYMCR CR1182
+*/
+void CCustomResolverCacheTest::TestCacheQueueFullPattern1L()
+ {
+ test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-UT-4015 "));
+ RArray<TUid> resolverlist(1);
+ CleanupClosePushL(resolverlist);
+
+ // NB: the following insertion order caused the problem found in
+ // INC115472. Hence there will be a check in DoQueueFullTestL
+ // that the cache queue is sorted correctly.
+ //
+ // Condition for inc115472 is first insert an UID of 0xA???????
+ // in an empty queue. Next insert an UID 0x2???????. The overflow
+ // error causes them to be placed in the wrong order.
+ resolverlist.AppendL(KDummyResolverUid2);
+ resolverlist.AppendL(KDummyResolverUid1);
+ resolverlist.AppendL(KExampleResolverUid);
+ resolverlist.AppendL(KMyResolverUid);
+ resolverlist.AppendL(KDummyResolverUid3);
+ DoQueueFullTestL(resolverlist);
+ CleanupStack::PopAndDestroy(&resolverlist);
+ }
+
+// In pattern 2 the oldest entry in cache has the largest UID value.
+void CCustomResolverCacheTest::TestCacheQueueFullPattern2L()
+ {
+ test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-UT-4015 "));
+ RArray<TUid> resolverlist(1);
+ CleanupClosePushL(resolverlist);
+ resolverlist.AppendL(KDummyResolverUid1);
+ resolverlist.AppendL(KDummyResolverUid2);
+ resolverlist.AppendL(KDummyResolverUid3);
+ resolverlist.AppendL(KExampleResolverUid);
+ resolverlist.AppendL(KMyResolverUid);
+ DoQueueFullTestL(resolverlist);
+ CleanupStack::PopAndDestroy(&resolverlist);
+ }
+
+// In pattern 3 the UID of the oldest entry has the second smallest value.
+void CCustomResolverCacheTest::TestCacheQueueFullPattern3L()
+ {
+ test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-UT-4015 "));
+ RArray<TUid> resolverlist(1);
+ CleanupClosePushL(resolverlist);
+ resolverlist.AppendL(KDummyResolverUid3);
+ resolverlist.AppendL(KDummyResolverUid1);
+ resolverlist.AppendL(KDummyResolverUid2);
+ resolverlist.AppendL(KExampleResolverUid);
+ resolverlist.AppendL(KMyResolverUid);
+ DoQueueFullTestL(resolverlist);
+ CleanupStack::PopAndDestroy(&resolverlist);
+ }
+
+void CCustomResolverCacheTest::DoQueueFullTestL(const RArray<TUid>& aResolverList)
+ {
+ // ensure cache is empty.
+ test(CacheSize() == 0);
+
+ TInt maxQueueSize = ResolverCache()->iMaxCacheSize;
+ test(aResolverList.Count() > maxQueueSize);
+
+ // Put 4 resolvers in the cache. Pause in between so that the time tick
+ // of each entry is different. CacheMissPerfTestL in t_resolverperf exercises
+ // the code path that time ticks are the same.
+ const TInt KInBetweenDelay = 100000;
+ TInt i;
+ for (i = 0; i < maxQueueSize; i++)
+ {
+ UseResolverCheckVersionL(aResolverList[i], 0);
+ User::AfterHighRes(KInBetweenDelay);
+ }
+
+ // Check cache is full.
+ test(CacheSize() == maxQueueSize);
+ // Check cache is sorted properly
+ test( QueueIsSorted() );
+
+ // Add one more to cache.
+ UseResolverCheckVersionL(aResolverList[maxQueueSize], 0);
+
+ // Check that cache size is still full - not exceeding limit.
+ test(CacheSize() == maxQueueSize);
+
+ // Want to check LRU is gone and the last resolver is now in cache.
+ test(! HasResolverUid(aResolverList[0]));
+ test( QueueIsSorted() );
+ // Because of the above 3 checks, this is really redundant.
+ test(HasResolverUid(aResolverList[maxQueueSize]));
+
+ // Because the timestamps of the cache entries are staggered
+ // 100 ms apart, the mgr can only kick out 1 item at each timer expiry.
+ // So let the cache mgr exercise this code path.
+ TInt n = 0;
+ while (CacheSize() > 0)
+ {
+ AsyncEvents.ClearAll();
+ YieldToOtherCActive(KIndefiniteWait); // 20 s
+ // Check which async event has stopped the activescheduler
+ test( AsyncEvents.IsSet(EAsyncEvent_CacheTimer) );
+ n++;
+ }
+
+ // n should be five. aResolverList[0] is bumped due to queue full.
+ // So the first timer expire will not find any expired entry.
+ test.Printf(_L("Gone through %d loops to clear out cache.\n"), n);
+
+ test(n > maxQueueSize);
+ }
+
+/**
+@SYMTestCaseID SYSLIB-ECOM-UT-4016
+@SYMTestCaseDesc Verify resolver is unloaded after the specified timeout.
+@SYMTestPriority Medium
+@SYMTestActions 1. Use a resolver to get it in cache.
+ 2. Measure how long the entry stays in cache before it is evicted.
+@SYMTestExpectedResults The time should be >= default timeout but
+ <= (timeout + 0.5s).
+@SYMCR CR1182
+*/
+void CCustomResolverCacheTest::TestCacheTimerAccuracyL()
+ {
+ test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-UT-4016 "));
+ TTime start;
+ start.UniversalTime();
+
+ UseResolverCheckVersionL(KMyResolverUid, 0);
+ test( HasResolverUid(KMyResolverUid) );
+
+ // Wait for cache timeout
+ AsyncEvents.ClearAll();
+ YieldToOtherCActive(KIndefiniteWait); // 20 s
+ // Check which async event has stopped the activescheduler
+ test( AsyncEvents.IsSet(EAsyncEvent_CacheTimer) );
+
+ TInt microseconds = CalcElapsedMicroseconds(start);
+ test.Printf(_L("Resolver is cached for %d microseconds\n"), microseconds);
+
+ TInt tickperiod;
+ User::LeaveIfError(HAL::Get(HALData::ESystemTickPeriod, tickperiod));
+ TInt lowerLimit = KCustomResolverCacheTimeout - tickperiod;
+ test(microseconds > lowerLimit);
+
+ // The upper bound is tricky because there is no gaurantee on
+ // CTimer accuracy.
+ test(microseconds < (KCustomResolverCacheTimeout + KHalfSecond));
+ }
+
+/**
+@SYMTestCaseID SYSLIB-ECOM-UT-4017
+@SYMTestCaseDesc Verify after a cache hit the time to live of the entry
+ is extended.
+@SYMTestPriority High
+@SYMTestActions 1. Record start time.
+ 2. Use a resolver to put it in cache.
+ 3. After 1 s use it again.
+ 4 Wait for its eviction.
+ 5. Check how long the entry stays in cache.
+@SYMTestExpectedResults The time should be >= 5 seconds.
+@SYMCR CR1182
+*/
+void CCustomResolverCacheTest::TestTimestampUpdateOnCacheHitL()
+ {
+ test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-UT-4017 "));
+ // Check that the resolver is not in cache.
+ test(! HasResolverUid(KMyResolverUid) );
+
+ TTime start;
+ start.UniversalTime();
+
+ UseResolverCheckVersionL(KMyResolverUid, 0);
+ test( HasResolverUid(KMyResolverUid) );
+
+ // Delay one second and use it again.
+ User::AfterHighRes(KOneSecond);
+ UseResolverCheckVersionL(KMyResolverUid, 0);
+
+ // Wait for its eviction
+ while ( HasResolverUid(KMyResolverUid) )
+ {
+ AsyncEvents.ClearAll();
+ YieldToOtherCActive(KIndefiniteWait); // 20 s
+ // Check which async event has stopped the activescheduler
+ test( AsyncEvents.IsSet(EAsyncEvent_CacheTimer) );
+ }
+
+ TInt microseconds = CalcElapsedMicroseconds(start);
+ test.Printf(_L("With cache hit, resolver is cached for %d microseconds\n"), microseconds);
+
+ TInt tickperiod;
+ User::LeaveIfError(HAL::Get(HALData::ESystemTickPeriod, tickperiod));
+ TInt lowerLimit = KCustomResolverCacheTimeout + KOneSecond - tickperiod;
+ test(microseconds > lowerLimit);
+ }
+
+/**
+@SYMTestCaseID SYSLIB-ECOM-UT-4018
+@SYMTestCaseDesc Verify at SWI start RW resolvers are evicted from cache.
+ Verify during SWI ROM resolvers are cached but RW resolvers are not.
+@SYMTestPriority High
+@SYMTestActions 1. Add a RW resolver to cache.
+ 2. Send a SWI start signal.
+ 3. Use a RW resolver.
+ 4 Use a ROM resolver.
+@SYMTestExpectedResults 1. The RW resolver is in cache.
+ 2. The cache entry is evicted.
+ 3. The RW resolver is not cached.
+ 4. The ROM resolver is cached.
+@SYMCR CR1182
+*/
+void CCustomResolverCacheTest::TestSWIDisableRwResolverCachingL()
+ {
+ test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-UT-4018 "));
+ // The TPropertyManager protocol to setup to use a system category P&S.
+ TInt r = PropertyManager::DeleteProperty(KUidSystemCategory,
+ KSAUidSoftwareInstallKeyValue);
+ test(r == KErrNone);
+ r = PropertyManager::DefineProperty(KUidSystemCategory,
+ KSAUidSoftwareInstallKeyValue, RProperty::EInt);
+ test(r == KErrNone);
+
+ // Use a resolver in C: drive.
+ UseResolverCheckVersionL(KDummyResolverUid1, 0);
+ // Check that it is added to cache.
+ test( HasResolverUid(KDummyResolverUid1) );
+
+ // Need a ROM entry in cache to get Bullseye to check off
+ // a conditional. It is not an active ingredient of this test.
+ UseResolverCheckVersionL(KMyResolverUid, 0);
+
+ // SWI start
+ r = PropertyManager::SetProperty(KUidSystemCategory,
+ KSAUidSoftwareInstallKeyValue,ESASwisInstall);
+ test(r == KErrNone);
+
+ // Let CSwiChangeNotifier receive the notification
+ AsyncEvents.ClearAll();
+ YieldToOtherCActive(KIndefiniteWait); // 20 s
+ // Check we receive the correct event
+ test( AsyncEvents.IsSet(EAsyncEvent_SwiStart) );
+
+ // Check the RW resolver is evicted
+ test(! HasResolverUid(KDummyResolverUid1) );
+
+ // during SWI RW resolver will not be cached.
+ UseResolverCheckVersionL(KDummyResolverUid1, 0);
+ test(! HasResolverUid(KDummyResolverUid1) );
+
+ // But ROM resolvers are still cached.
+ UseResolverCheckVersionL(KDummyResolverUid2, 0);
+ test( HasResolverUid(KDummyResolverUid2) );
+
+ // And the ROM resolvers are evicted after 4 s as usual.
+ // Note that we have KMyResolverUid and KDummyResolverUid2 in cache
+ TBool b = WaitForEvict(KDummyResolverUid2);
+ if (! b)
+ { // got KMyResolverUid only, need a second wait.
+ b = WaitForEvict(KDummyResolverUid2);
+ }
+ test(b);
+
+ // Just for completeness. Do not really need this
+ // for Bullseye Coverage.
+ r = PropertyManager::SetProperty(KUidSystemCategory,
+ KSAUidSoftwareInstallKeyValue,ESASwisNone);
+ test(r == KErrNone);
+ // Let CSwiChangeNotifier receive the notification
+ AsyncEvents.ClearAll();
+ YieldToOtherCActive(KIndefiniteWait); // 20 s
+ // Check we receive the correct event
+ test( AsyncEvents.IsSet(EAsyncEvent_SwiEnd) );
+ }
+
+/**
+@SYMTestCaseID SYSLIB-ECOM-UT-4019
+@SYMTestCaseDesc Verify at BUR start RW resolvers are evicted from cache.
+ Verify during BUR ROM resolvers are cached but RW resolvers are not.
+@SYMTestPriority High
+@SYMTestActions 1. Add a RW resolver to cache.
+ 2. Send a BUR start signal.
+ 3. Use a RW resolver.
+ 4 Use a ROM resolver.
+@SYMTestExpectedResults 1. The RW resolver is in cache.
+ 2. The cache entry is evicted.
+ 3. The RW resolver is not cached.
+ 4. The ROM resolver is cached.
+@SYMCR CR1182
+*/
+void CCustomResolverCacheTest::TestBurDisableRwResolverCachingL()
+ {
+ test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-UT-4019 "));
+ // setup backup session wrapper
+ CBaBackupSessionWrapper* ba = CBaBackupSessionWrapper::NewL();
+ CleanupStack::PushL(ba);
+ TBackupOperationAttributes attribs;
+ attribs.iFileFlag=MBackupObserver::EReleaseLockNoAccess;
+ attribs.iOperation=MBackupOperationObserver::EStart;
+
+ // The backup notifier of ECOM is not registered with
+ // BA server at construction time. It delays 15 s.
+ // So we have to wait this long.
+ WaitAsyncL(16);
+
+ // Use a resolver in C: drive.
+ UseResolverCheckVersionL(KDummyResolverUid1, 0);
+ // Check that it is added to cache.
+ test( HasResolverUid(KDummyResolverUid1) );
+
+ // Need a ROM entry in cache to get Bullseye to check off
+ // a conditional. It is not an active ingredient of this test.
+ UseResolverCheckVersionL(KMyResolverUid, 0);
+
+ // backup start
+ ba->NotifyBackupOperationL(attribs);
+ // Let backup notifier receive the backup start
+ AsyncEvents.ClearAll();
+ YieldToOtherCActive(KIndefiniteWait); // 20 s
+ // Check we receive the backup start notification
+ test( AsyncEvents.IsSet(EAsyncEvent_BurStart) );
+
+ // Check the RW resolver is evicted
+ test(! HasResolverUid(KDummyResolverUid1) );
+
+ // during BUR RW resolver will not be cached.
+ UseResolverCheckVersionL(KDummyResolverUid1, 0);
+ test(! HasResolverUid(KDummyResolverUid1) );
+
+ // But ROM resolvers are still cached.
+ UseResolverCheckVersionL(KDummyResolverUid2, 0);
+ test( HasResolverUid(KDummyResolverUid2) );
+
+ // And the ROM resolvers are evicted after 4 s as usual.
+ // Note that we have KMyResolverUid and KDummyResolverUid2 in cache
+ TBool b = WaitForEvict(KDummyResolverUid2);
+ if (! b)
+ { // got KMyResolverUid only, need a second wait.
+ b = WaitForEvict(KDummyResolverUid2);
+ }
+ test(b);
+
+ // Do this for Bullseye Coverage of production code.
+ // NB: attribs.iFileFlag stays the same
+ attribs.iOperation=MBackupOperationObserver::EEnd;
+ ba->NotifyBackupOperationL(attribs);
+ // Let backup notifier receive it
+ AsyncEvents.ClearAll();
+ YieldToOtherCActive(KIndefiniteWait); // 20 s
+ // Check we receive the backup notification
+ test( AsyncEvents.IsSet(EAsyncEvent_BurEnd) );
+
+ CleanupStack::PopAndDestroy(ba);
+
+ // to earn another Bullseye check mark.
+ CEComServer::NotifyEvents(iEComServer, ECallBackId_None, NULL);
+ }
+
+/**
+@SYMTestCaseID SYSLIB-ECOM-UT-4021
+@SYMTestCaseDesc Verify the cache timer and data to keep track of
+ cache entry time to live are immune to device clock change.
+@SYMTestPriority High
+@SYMTestActions 1. Put two resolvers in cache at 20 ticks apart.
+ 2. Spring clock forward by 5 s (1 + default cache timeout).
+ 3. Measure how long the first resolver is cached.
+ 4. Measure how long the second resolver is cached.
+ Repeat steps 1 to 4 in setting clock backward.
+@SYMTestExpectedResults Both resolvers are cached for ~ 4 s
+ (default cache timeout value).
+@SYMCR CR1182
+*/
+void CCustomResolverCacheTest::TestClockChangeHasNoEffectOnCacheTimeoutL()
+ {
+ test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-UT-4021 "));
+ TInt tp;
+ User::LeaveIfError(HAL::Get(HALData::ESystemTickPeriod, tp));
+ TInt delayInBetween = tp * 20;
+ test.Printf(_L("ESystemTickPeriod: %d; delayInBetween: %d;\n"), tp, delayInBetween);
+
+
+ TTime beforeDelay;
+ beforeDelay.UniversalTime();
+
+ UseResolverCheckVersionL(KDummyResolverUid1, 0);
+ test( HasResolverUid(KDummyResolverUid1) );
+
+ User::AfterHighRes(delayInBetween);
+ TInt elapsedBeforeTimeChange = CalcElapsedMicroseconds(beforeDelay);
+
+ UseResolverCheckVersionL(KDummyResolverUid2, 0);
+ test( HasResolverUid(KDummyResolverUid2) );
+
+ TTimeIntervalMicroSeconds AmountOfChange(
+ MAKE_TINT64(0, KCustomResolverCacheTimeout+KOneSecond) );
+
+ // Now set device clock forward
+ TTime t;
+ t.UniversalTime();
+ t += AmountOfChange;
+ User::LeaveIfError( User::SetUTCTime(t) );
+
+ t.UniversalTime(); // need this, apparently SetUTCTime does rounding
+
+ // Wait for cache timeout
+ AsyncEvents.ClearAll();
+ YieldToOtherCActive(KIndefiniteWait); // 20 s
+ // Check which async event has stopped the activescheduler
+ test( AsyncEvents.IsSet(EAsyncEvent_CacheTimer) );
+
+ TInt microseconds = CalcElapsedMicroseconds(t);
+ // compensate for the 20 ticks delay
+ microseconds += elapsedBeforeTimeChange;
+ test.Printf(_L("Clock forward: 1st resolver is cached for %d microseconds\n"), microseconds);
+ test(! HasResolverUid(KDummyResolverUid1) );
+ // Check duration is between 4 to 4.5 s.
+ TInt lowerLimit = KCustomResolverCacheTimeout - (tp*3);
+ TInt upperLimit = (KCustomResolverCacheTimeout + KHalfSecond);
+ test.Printf(_L("lowerLimit: %d; upperLimit: %d\n"), lowerLimit, upperLimit);
+ test(microseconds > lowerLimit);
+
+ // upper limit is tricky because there is no guarantee on CTimer
+ // accuracy.
+ test(microseconds <= upperLimit);
+
+ // Wait for eviction of the second resolver
+ AsyncEvents.ClearAll();
+ YieldToOtherCActive(KIndefiniteWait); // 20 s
+ // Check which async event has stopped the activescheduler
+ test( AsyncEvents.IsSet(EAsyncEvent_CacheTimer) );
+
+ microseconds = CalcElapsedMicroseconds(t);
+ test.Printf(_L("Clock forward: 2nd resolver is cached for %d microseconds\n"), microseconds);
+ test(! HasResolverUid(KDummyResolverUid2) );
+ // Check duration is between 4 to 4.5 s.
+ test(microseconds > lowerLimit);
+ test(microseconds <= upperLimit);
+
+ //
+ // Repeat for setting clock backward.
+ //
+ beforeDelay.UniversalTime();
+
+ UseResolverCheckVersionL(KDummyResolverUid1, 0);
+ test( HasResolverUid(KDummyResolverUid1) );
+
+ User::AfterHighRes(delayInBetween);
+ elapsedBeforeTimeChange = CalcElapsedMicroseconds(beforeDelay);
+
+ UseResolverCheckVersionL(KDummyResolverUid2, 0);
+ test( HasResolverUid(KDummyResolverUid2) );
+
+ // Now set device clock backward
+ t.UniversalTime();
+ t -= AmountOfChange;
+ User::LeaveIfError( User::SetUTCTime(t) );
+ t.UniversalTime();
+
+ // Wait for cache timeout
+ AsyncEvents.ClearAll();
+ YieldToOtherCActive(KIndefiniteWait); // 20 s
+ // Check which async event has stopped the activescheduler
+ test( AsyncEvents.IsSet(EAsyncEvent_CacheTimer) );
+
+ microseconds = CalcElapsedMicroseconds(t);
+ // compensate for the 20 ticks delay
+ microseconds += elapsedBeforeTimeChange;
+ test.Printf(_L("Clock backward: 1st resolver is cached for %d microseconds\n"), microseconds);
+ test(! HasResolverUid(KDummyResolverUid1) );
+ // Check duration is between 4 to 4.5 s.
+ test(microseconds > lowerLimit);
+ test(microseconds <= (KCustomResolverCacheTimeout + KHalfSecond));
+
+ // Wait for eviction of the second resolver
+ AsyncEvents.ClearAll();
+ YieldToOtherCActive(KIndefiniteWait); // 20 s
+ // Check which async event has stopped the activescheduler
+ test( AsyncEvents.IsSet(EAsyncEvent_CacheTimer) );
+
+ microseconds = CalcElapsedMicroseconds(t);
+ test.Printf(_L("Clock backward: 2nd resolver is cached for %d microseconds\n"), microseconds);
+ test(! HasResolverUid(KDummyResolverUid2) );
+ // Check duration is between 4 to 4.5 s.
+ test(microseconds > lowerLimit);
+ test(microseconds <= (KCustomResolverCacheTimeout + KHalfSecond));
+ }
+
+/**
+@SYMTestCaseID SYSLIB-ECOM-UT-4022
+@SYMTestCaseDesc Verify caching runs normally if queue size is zero.
+@SYMTestPriority Medium
+@SYMTestActions 1. Set max. cache size to 0.
+ 2. Use a custom resolver.
+@SYMTestExpectedResults No leave on the list request and cache is empty.
+@SYMCR CR1182
+*/
+void CCustomResolverCacheTest::TestCacheSizeZeroL()
+ {
+ test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-UT-4022 "));
+ ResolverCache()->iMaxCacheSize = 0;
+ UseResolverCheckVersionL(KMyResolverUid, 0);
+ test(! HasResolverUid(KMyResolverUid) );
+ }
+
+/**
+@SYMTestCaseID SYSLIB-ECOM-UT-4023
+@SYMTestCaseDesc Verify caching runs normally if cache timeout is zero.
+@SYMTestPriority Medium
+@SYMTestActions 1. Set cache time-to-live to zero.
+ 2. Use a custom resolver.
+@SYMTestExpectedResults No leave on the list request and cache is empty.
+@SYMCR CR1182
+*/
+void CCustomResolverCacheTest::TestCacheTimeoutZeroL()
+ {
+ test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-UT-4023 "));
+ TInt systemTickPeriod = ResolverCache()->iSystemTickPeriod;
+ // mimic CCustomResolverCache calculate the time-to-live value.
+ const TInt KZeroTimeout = 0;
+ ResolverCache()->iEntryTimeToLive = (KZeroTimeout +
+ systemTickPeriod - 1) / systemTickPeriod;
+
+ // run the test
+ UseResolverCheckVersionL(KMyResolverUid, 0);
+ test(! HasResolverUid(KMyResolverUid) );
+ }
+
+/**
+@SYMTestCaseID SYSLIB-ECOM-UT-4024
+@SYMTestCaseDesc CCustomResolverCache uses system tick to track entry
+ time-to-live. The counter wraps around every 777 days. This test
+ checks when wrap around occurs cached entry is purged correctly.
+@SYMTestPriority Medium
+@SYMTestActions 1. Use a resolver to get it in cache.
+ 2. Set its time-of-use to 0xFFFFFFFF.
+ 3. Wait for cache timer expire.
+@SYMTestExpectedResults The entry is evicted on first timer expiry and
+ the entry stays in cache for ~ 4s.
+@SYMCR CR1182
+*/
+void CCustomResolverCacheTest::TestCounterWrapAroundL()
+ {
+ test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-UT-4024 "));
+ TTime start;
+ start.UniversalTime();
+
+ UseResolverCheckVersionL(KMyResolverUid, 0);
+ RResolverCacheEntry& entry = ResolverCache()->iResolvers[0];
+ test( entry.iResolverUid == KMyResolverUid );
+
+ // Set time-of-use to edge of wrap around
+ entry.iLastUse.iTicks = KMaxTUint;
+
+ // Wait for cache timeout
+ AsyncEvents.ClearAll();
+ YieldToOtherCActive(KIndefiniteWait); // 20 s
+ // Check which async event has stopped the activescheduler
+ test( AsyncEvents.IsSet(EAsyncEvent_CacheTimer) );
+
+ TInt microseconds = CalcElapsedMicroseconds(start);
+ test.Printf(_L("Wrap around: resolver is cached for %d microseconds\n"), microseconds);
+
+ TInt tickperiod;
+ User::LeaveIfError(HAL::Get(HALData::ESystemTickPeriod, tickperiod));
+ TInt lowerLimit = KCustomResolverCacheTimeout - tickperiod;
+ test(microseconds > lowerLimit);
+ // Upper limit must have a wide margin because there is no gaurantee
+ // on CTimer accuracy.
+ test(microseconds < (KCustomResolverCacheTimeout + KHalfSecond));
+ }
+
+/**
+@SYMTestCaseID SYSLIB-ECOM-UT-4025
+@SYMTestCaseDesc Verify if cannot find the NewL method in the proxy
+ instantiation table, ECOM returns KEComErrNoResolver
+@SYMTestPriority Medium
+@SYMTestActions Use a resolver whose proxy table has the wrong Impl. Uid.
+@SYMTestExpectedResults Get KEComErrNoResolver error
+@SYMCR CR1182
+*/
+void CCustomResolverCacheTest::TestResolverWithBadProxyTable()
+ {
+ test.Next(_L(" @SYMTestCaseID:SYSLIB-ECOM-UT-4025 "));
+ const TUid KBadResolverUid = {0x10009DDF};
+ TRAPD(err, UseResolverCheckVersionL(KBadResolverUid, 0) );
+ test(err == KEComErrNoResolver);
+ }
+
+/** wrapper to run all the Basic and OOM tests */
+void CCustomResolverCacheTest::RunAllTestsL()
+ {
+ CopyPluginsL();
+
+ test.Next(_L("Basic TestCounterWrapAroundL"));
+ DoBasicTestL(TestCounterWrapAroundL);
+
+ test.Next(_L("Basic TestUpgradingCachedResolverL"));
+ DoBasicTestL(TestUpgradingCachedResolverL);
+
+ test.Next(_L("Basic TestCacheQueueFullPattern1L"));
+ DoBasicTestL(TestCacheQueueFullPattern1L);
+
+ test.Next(_L("Basic TestCacheQueueFullPattern2L"));
+ DoBasicTestL(TestCacheQueueFullPattern2L);
+
+ test.Next(_L("Basic TestCacheQueueFullPattern3L"));
+ DoBasicTestL(TestCacheQueueFullPattern3L);
+
+ test.Next(_L("Basic TestCacheTimerAccuracyL"));
+ DoBasicTestL(TestCacheTimerAccuracyL);
+
+ test.Next(_L("Basic TestTimestampUpdateOnCacheHitL"));
+ DoBasicTestL(TestTimestampUpdateOnCacheHitL);
+
+ test.Next(_L("Basic TestSWIDisableRwResolverCachingL"));
+ DoBasicTestL(TestSWIDisableRwResolverCachingL);
+
+ test.Next(_L("Basic TestBurDisableRwResolverCachingL"));
+ DoBasicTestL(TestBurDisableRwResolverCachingL);
+
+ test.Next(_L("Basic TestClockChangeHasNoEffectOnCacheTimeoutL"));
+ DoBasicTestL(TestClockChangeHasNoEffectOnCacheTimeoutL);
+
+ test.Next(_L("Basic TestCacheSizeZeroL"));
+ DoBasicTestL(TestCacheSizeZeroL);
+
+ test.Next(_L("Basic TestCacheTimeoutZeroL"));
+ DoBasicTestL(TestCacheTimeoutZeroL);
+
+ test.Next(_L("Basic TestResolverWithBadProxyTable"));
+ DoBasicTestL(TestResolverWithBadProxyTable);
+
+ // Only run OOM on tests which do not involve rescan dir.
+ test.Next(_L("OOM TestCacheQueueFullPattern3L"));
+ DoOOMTestL(TestCacheQueueFullPattern3L);
+
+ test.Next(_L("OOM TestCacheTimerAccuracyL"));
+ DoOOMTestL(TestCacheTimerAccuracyL);
+
+ test.Next(_L("OOM TestTimestampUpdateOnCacheHitL"));
+ DoOOMTestL(TestTimestampUpdateOnCacheHitL);
+
+ // Do all tests affected by Lazy DLL unload last.
+ test.Next(_L("Basic TestDeletingCachedResolverL"));
+ DoBasicTestL(TestDeletingCachedResolverL);
+ }
+
+static TInt KillEComServer()
+ {
+ //Need to ensure that the EComServer process is killed before even starting this test by using
+ //the EComTestUtils library
+ _LIT(KEComServerProcessName,"ecomserver");
+ TRAPD(err, EComTestUtils::KillProcessL(KEComServerProcessName));
+ return err;
+ }
+
+GLDEF_C TInt E32Main()
+ {
+ __UHEAP_MARK;
+
+ beginningOfTest.UniversalTime();
+
+ test.Printf(_L("\n"));
+ test.Title();
+ test.Start( _L("Custom Resolver Cache") );
+
+
+ TheTrapCleanup = CTrapCleanup::New();
+ test(TheTrapCleanup != NULL);
+
+ // Connect the file server instance
+ test(KErrNone == TheFs.Connect());
+
+ TheActiveScheduler = new CDerivedActiveScheduler;
+ test(TheActiveScheduler != NULL);
+ CActiveScheduler::Install(TheActiveScheduler);
+
+ TInt err = ::KillEComServer();
+ test(err == KErrNotFound || err == KErrNone);
+
+ // Call the main tests
+ TRAP(err, CCustomResolverCacheTest::RunAllTestsL());
+ if (err != KErrNone) test.Printf(_L("RunAllTestsL() error, %d\n"), err);
+ test(err == KErrNone);
+
+ // remove the RAMOnly files
+ TRAP_IGNORE( WaitForLazyUnloadingL() );
+ DeleteTestPlugin();
+ User::After(KOneSecond * 3);
+
+ delete TheActiveScheduler;
+ delete TheTrapCleanup;
+
+ TheFs.Close();
+
+ test.End();
+ test.Close();
+
+ __UHEAP_MARKEND;
+ return (KErrNone);
+ }