sl@0: // Copyright (c) 2006-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: /** sl@0: @file sl@0: @internalComponent sl@0: */ sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include "ssndteststep.h" sl@0: #include "BaSsndStore.h" sl@0: #include "BASSNDUID.h" sl@0: sl@0: const TBaSystemSoundUid KLockoutTestSoundCategory = {288}; sl@0: sl@0: /** CResetDbStep constructor */ sl@0: CResetDbStep::CResetDbStep() sl@0: { sl@0: SetTestStepName(KResetDb); sl@0: } sl@0: sl@0: /** Implementation of the pure virtual base class function. sl@0: This teststep does not really test anything. It serves as sl@0: a helper of other steps to clear the sound table at the sl@0: beginning of a test. sl@0: */ sl@0: TVerdict CResetDbStep::doTestStepL() sl@0: { sl@0: CRepository* repository = CRepository::NewLC(KSystemSoundRepositoryUID); sl@0: TESTL(repository != NULL); sl@0: TEST(repository->Reset() == KErrNone); sl@0: sl@0: CleanupStack::PopAndDestroy(repository); sl@0: return TestStepResult(); sl@0: } sl@0: sl@0: // sl@0: // GetSound/SetSound sl@0: // sl@0: _LIT(KUnknownParm, "Err reading INI section %S, unknown value %S"); sl@0: sl@0: _LIT(KSoundCat, "Category"); sl@0: _LIT(KEFile, "EFile"); sl@0: _LIT(KESequence, "ESequence"); sl@0: _LIT(KETone, "ETone"); sl@0: sl@0: _LIT(KSoundFileName, "Filename"); sl@0: _LIT(KFixedSequence, "SequenceNum"); sl@0: _LIT(KToneFrequency, "Frequency"); sl@0: _LIT(KToneDuration, "Duration"); sl@0: sl@0: _LIT(KMajorUid, "MajorUid"); sl@0: _LIT(KMinorUid, "MinorUid"); sl@0: sl@0: /** Read data from the TEF ini file to construct iSound. */ sl@0: void CSsndBaseStep::ConstructSoundL() sl@0: { sl@0: TPtrC cat; sl@0: TPtrC ssndFile; sl@0: TInt toneFreq; sl@0: TTimeIntervalMicroSeconds32 duration; sl@0: TInt intdata; sl@0: sl@0: TESTL( GetStringFromConfig(ConfigSection(), KSoundCat, cat) ); sl@0: if (cat == KEFile()) sl@0: { sl@0: TESTL( GetStringFromConfig(ConfigSection(), KSoundFileName, ssndFile) ); sl@0: TBaSystemSoundName filebuf(ssndFile); sl@0: iSound.SetFileName(filebuf); sl@0: } sl@0: else if (cat == KESequence()) sl@0: { sl@0: TESTL( GetIntFromConfig(ConfigSection(), KFixedSequence, intdata) ); sl@0: iSound.SetFixedSequenceNumber(intdata); sl@0: } sl@0: else if (cat == KETone()) sl@0: { sl@0: TESTL( GetIntFromConfig(ConfigSection(), KToneFrequency, toneFreq) ); sl@0: TESTL( GetIntFromConfig(ConfigSection(), KToneDuration, intdata) ); sl@0: duration = intdata; sl@0: TBaSystemSoundInfo::TTone tone(toneFreq, duration); sl@0: iSound.SetTone(tone); sl@0: } sl@0: else sl@0: { sl@0: ERR_PRINTF3(KUnknownParm, &KSoundCat, &cat); sl@0: TESTL(EFalse); sl@0: } sl@0: sl@0: TESTL( GetIntFromConfig(ConfigSection(), KMajorUid, intdata) ); sl@0: iSound.iType.iMajor.iUid = intdata; sl@0: TESTL( GetIntFromConfig(ConfigSection(), KMinorUid, intdata) ); sl@0: iSound.iType.iMinor.iUid = intdata; sl@0: } sl@0: sl@0: /** CGetSoundStep constructor */ sl@0: CGetSoundStep::CGetSoundStep() sl@0: { sl@0: SetTestStepName(KGetSound); sl@0: } sl@0: sl@0: /** Implement the pure virtual base class function. sl@0: Read sound from repository and compare it against sl@0: the data specified in TEF ini file. sl@0: */ sl@0: TVerdict CGetSoundStep::doTestStepL() sl@0: { sl@0: ConstructSoundL(); sl@0: RFs dummy; sl@0: sl@0: TInt ret = BaSystemSound::GetSound(dummy, iSound.iType, iReadFromRep); sl@0: if (ret != KErrNone) sl@0: { sl@0: // Do it this way for B&R test. sl@0: SetTestStepError(ret); sl@0: return EFail; sl@0: } sl@0: sl@0: TBaSystemSoundInfo::TSoundCategory cat = iReadFromRep.SoundCategory(); sl@0: if (cat == TBaSystemSoundInfo::ETone) sl@0: { sl@0: TEST(iSound.Tone().iFrequency == iReadFromRep.Tone().iFrequency); sl@0: TEST(iSound.Tone().iDuration == iReadFromRep.Tone().iDuration); sl@0: } sl@0: else if (cat == TBaSystemSoundInfo::ESequence) sl@0: { sl@0: TEST(iSound.FixedSequenceNumber() == iReadFromRep.FixedSequenceNumber()); sl@0: } sl@0: else if (cat == TBaSystemSoundInfo::EFile) sl@0: { sl@0: TEST(iSound.FileName() == iReadFromRep.FileName()); sl@0: } sl@0: return TestStepResult(); sl@0: } sl@0: sl@0: /** CSetSoundStep constructor */ sl@0: CSetSoundStep::CSetSoundStep() sl@0: { sl@0: SetTestStepName(KSetSound); sl@0: } sl@0: sl@0: /** Implementation of pure virtual base class method. sl@0: Call SetSoundL and return pass if KErrNone, fail otherwise. sl@0: */ sl@0: TVerdict CSetSoundStep::doTestStepL() sl@0: { sl@0: ConstructSoundL(); sl@0: RFs dummy; sl@0: TRAPD(ret, BaSystemSound::SetSoundL(dummy, iSound)); sl@0: if (ret != KErrNone) sl@0: { sl@0: // SetTestStepError pass the error code back to TEF. sl@0: // If the script is expecting this particular error code, sl@0: // TEF will flip the EFail into EPass. sl@0: SetTestStepError(ret); sl@0: return EFail; sl@0: } sl@0: return EPass; sl@0: } sl@0: sl@0: /** CSystemSoundFileTestStep constructor */ sl@0: CSystemSoundFileTestStep::CSystemSoundFileTestStep() sl@0: { sl@0: SetTestStepName(KSystemSoundFileTest); sl@0: } sl@0: sl@0: /** Implementation of pure virtual base class method. sl@0: Call the SystemSoundFile API and check the returned sl@0: filename is the old sound table file. sl@0: NB: the SystemSoundFile API has been deprecated. sl@0: */ sl@0: TVerdict CSystemSoundFileTestStep::doTestStepL() sl@0: { sl@0: _LIT(KExpectedName, ":\\system\\data\\syssnd.dat"); sl@0: TFileName fn = BaSystemSound::SystemSoundFile(); sl@0: TInt pos = fn.FindF(KExpectedName); sl@0: TEST(pos != KErrNotFound); sl@0: return TestStepResult(); sl@0: } sl@0: sl@0: /** CGapTestStep constructor */ sl@0: CGapTestStep::CGapTestStep() sl@0: { sl@0: SetTestStepName(KGapTest); sl@0: } sl@0: sl@0: /** Implementation of pure virtual base class method. sl@0: Create a setting at key 7 leaving a gap at key 3. sl@0: Then call SetSoundL. The call should fail with KErrCorrupt. sl@0: */ sl@0: TVerdict CGapTestStep::doTestStepL() sl@0: { sl@0: const TInt32 KKeyWithGap = 7; sl@0: const TInt KSomeInteger = 1; sl@0: CRepository* rep = CRepository::NewLC(KSystemSoundRepositoryUID); sl@0: TESTL(rep->Create(KKeyWithGap, KSomeInteger) == KErrNone); sl@0: sl@0: TUid minorUid = {KSomeInteger}; sl@0: TBaSystemSoundType soundId(KLockoutTestSoundCategory, minorUid); sl@0: TBaSystemSoundInfo sound(soundId, KSomeInteger); sl@0: sl@0: RFs dummy; sl@0: TRAPD(ret, BaSystemSound::SetSoundL(dummy, sound)); sl@0: TEST(ret == KErrCorrupt); sl@0: sl@0: CleanupStack::PopAndDestroy(rep); sl@0: return TestStepResult(); sl@0: } sl@0: sl@0: /** CSoundFileNoPathTestStep constructor */ sl@0: CSoundFileNoPathTestStep::CSoundFileNoPathTestStep() sl@0: { sl@0: SetTestStepName(KSoundFileNoPathTest); sl@0: } sl@0: sl@0: /** Implementation of pure virtual base class method. sl@0: Call SetSoundL with a wav filename which does not contain path. sl@0: BaSystemSound should panic. sl@0: */ sl@0: TVerdict CSoundFileNoPathTestStep::doTestStepL() sl@0: { sl@0: // BaSystemSound only trigger EBafPanicSystemSoundNoPath on udeb. sl@0: // So on urel do it ourself. sl@0: #ifndef _DEBUG sl@0: Panic(EBafPanicSystemSoundNoPath); sl@0: #else sl@0: const TBaSystemSoundUid KMajorUid = {0x888}; sl@0: TBaSystemSoundType soundId(KMajorUid); sl@0: sl@0: // side bar to fill a code coverage gap in TTone::IsNull sl@0: TTimeIntervalMicroSeconds32 duration = 10; sl@0: TBaSystemSoundInfo::TTone tone(0, duration); sl@0: TBaSystemSoundInfo sound(soundId, tone); sl@0: TBaSystemSoundInfo::TSoundCategory cat = sound.SoundCategory(); sl@0: TEST(cat == TBaSystemSoundInfo::ETone); sl@0: sl@0: // now back to the panic test sl@0: _LIT(KSoundFileName, "rr.wav"); sl@0: TBaSystemSoundName filename(KSoundFileName); sl@0: sound.SetFileName(filename); sl@0: sl@0: RFs dummy; sl@0: // Following line should panic sl@0: BaSystemSound::SetSoundL(dummy, sound); sl@0: #endif sl@0: return TestStepResult(); sl@0: } sl@0: sl@0: /** CCorruptSoundStep constructor */ sl@0: CCorruptSoundStep::CCorruptSoundStep() sl@0: { sl@0: SetTestStepName(KCorruptSound); sl@0: } sl@0: sl@0: /** Implementation of pure virtual base class method. sl@0: Corrupt the soundtype, sound cat. and path length fields sl@0: in the sound data and verify GetSound returns KErrCorrupt. sl@0: */ sl@0: TVerdict CCorruptSoundStep::doTestStepL() sl@0: { sl@0: ConstructSoundL(); sl@0: RFs dummy; sl@0: TInt ret(KErrNone); sl@0: BaSystemSound::SetSoundL(dummy, iSound); sl@0: sl@0: // make a connection to CentRep to directly manipulate the sl@0: // setting. sl@0: CRepository* rep = CRepository::NewLC(KSystemSoundRepositoryUID); sl@0: HBufC8* orighbuf8 = HBufC8::NewLC(sizeof(TBaSystemSoundInfo)); sl@0: TPtr8 origbuf8 = orighbuf8->Des(); sl@0: sl@0: const TUint32 KKeyOfFirstSound = 3; sl@0: ret = rep->Get(KKeyOfFirstSound, origbuf8); sl@0: TESTL(ret == KErrNone); sl@0: sl@0: // need a running copy of the sound data sl@0: HBufC8* temphbuf8 = orighbuf8->AllocLC(); sl@0: TPtr8 tempbuf8 = temphbuf8->Des(); sl@0: sl@0: //Test corrupting the major sound Id sl@0: tempbuf8[0] = 1; sl@0: tempbuf8[1] = 2; sl@0: tempbuf8[2] = 3; sl@0: tempbuf8[3] = 4; sl@0: TESTL(rep->Set(KKeyOfFirstSound, tempbuf8) == KErrNone); sl@0: ret = BaSystemSound::GetSound(dummy, iSound.iType, iReadFromRep); sl@0: TEST(ret == KErrCorrupt); sl@0: sl@0: //Test corrupting the sound cat. field sl@0: //First restore original data. sl@0: tempbuf8.Copy(origbuf8); sl@0: const TInt KSoundCatLocation = 16; sl@0: tempbuf8[KSoundCatLocation] = 255; sl@0: tempbuf8[KSoundCatLocation+1] = 127; sl@0: TESTL(rep->Set(KKeyOfFirstSound, tempbuf8) == KErrNone); sl@0: ret = BaSystemSound::GetSound(dummy, iSound.iType, iReadFromRep); sl@0: TEST(ret == KErrCorrupt); sl@0: sl@0: //Test corrupting the path length field sl@0: //First restore original data. sl@0: tempbuf8.Copy(origbuf8); sl@0: const TInt KPathLengthLocation = 20; sl@0: tempbuf8[KPathLengthLocation] = 255; sl@0: tempbuf8[KPathLengthLocation+1] = 127; sl@0: TESTL(rep->Set(KKeyOfFirstSound, tempbuf8) == KErrNone); sl@0: ret = BaSystemSound::GetSound(dummy, iSound.iType, iReadFromRep); sl@0: TEST(ret == KErrCorrupt); sl@0: sl@0: //Corruption of other fields are not detectable. sl@0: sl@0: //If we restore the original data in CentRep, GetSound should pass. sl@0: tempbuf8.Copy(origbuf8); sl@0: TESTL(rep->Set(KKeyOfFirstSound, tempbuf8) == KErrNone); sl@0: ret = BaSystemSound::GetSound(dummy, iSound.iType, iReadFromRep); sl@0: TEST(ret == KErrNone); sl@0: sl@0: CleanupStack::PopAndDestroy(temphbuf8); sl@0: CleanupStack::PopAndDestroy(orighbuf8); sl@0: CleanupStack::PopAndDestroy(rep); sl@0: return TestStepResult(); sl@0: } sl@0: sl@0: /** Derive from CBaSsndStore to force collision between sl@0: concurrent set sound threads. sl@0: */ sl@0: class CCollisionSsndStore : public CBaSsndStore sl@0: { sl@0: public: sl@0: static CCollisionSsndStore* NewLC(TTimeIntervalMicroSeconds32 aDelay); sl@0: virtual void KeyOfSoundTypeL(TBaSystemSoundType& aSoundType, TUint32& aKey) const; sl@0: virtual void SetSoundInTransactionL(TBaSystemSoundType& aSoundType, sl@0: const TDesC8& aDes8) const; sl@0: inline TUint32 NumCollisions() const {return iNumCollisions;} sl@0: inline TUint32 Key() const {return iKey;} sl@0: sl@0: private: sl@0: inline CCollisionSsndStore(const TTimeIntervalMicroSeconds32 aDelay) sl@0: : iDelay(aDelay), iNumCollisions(0), iKey(NCentralRepositoryConstants::KUnspecifiedKey) {} sl@0: inline void ConstructL() {CBaSsndStore::ConstructL();} sl@0: TInt RecordKeyPosition(TBaSystemSoundType& aSoundType) const; sl@0: sl@0: private: sl@0: /** indicate how long to pause in the middle of the transaction. sl@0: The pause causes concurrent transactions to fail. */ sl@0: TTimeIntervalMicroSeconds32 iDelay; sl@0: sl@0: /** Record how many times transaction commit failed. Mutable because sl@0: SetSoundInTransactionL in production code is a const method. */ sl@0: mutable TUint32 iNumCollisions; sl@0: sl@0: /** Record the CentRep key used to store the sound. Mutable because sl@0: KeyOfSoundTypeL in production code is a const method. */ sl@0: mutable TUint32 iKey; sl@0: }; sl@0: sl@0: /** static factory method to instantiate CCollisionSsndStore */ sl@0: CCollisionSsndStore* CCollisionSsndStore::NewLC( sl@0: const TTimeIntervalMicroSeconds32 aDelay) sl@0: { sl@0: CCollisionSsndStore* self = new (ELeave) CCollisionSsndStore(aDelay); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: return self; sl@0: } sl@0: sl@0: /** After using base class method to get the key, add a delay sl@0: to cause concurrent threads to collide. sl@0: */ sl@0: void CCollisionSsndStore::KeyOfSoundTypeL(TBaSystemSoundType& aSoundType, sl@0: TUint32& aKey) const sl@0: { sl@0: CBaSsndStore::KeyOfSoundTypeL(aSoundType, aKey); sl@0: User::AfterHighRes(iDelay); sl@0: } sl@0: sl@0: /** After using base class method to do SetSound in transaction, sl@0: check the return code. Record commitFail condition. If succes, sl@0: record the key position where the SoundType is stored. sl@0: */ sl@0: void CCollisionSsndStore::SetSoundInTransactionL( sl@0: TBaSystemSoundType& aSoundType, sl@0: const TDesC8& aDes8) const sl@0: { sl@0: // call base class method to do the real work sl@0: TRAPD(ret, CBaSsndStore::SetSoundInTransactionL(aSoundType, aDes8)); sl@0: sl@0: // record any collision sl@0: if (KErrLocked == ret || KErrAbort == ret) sl@0: { sl@0: iNumCollisions++; sl@0: } sl@0: else if (KErrNone == ret) sl@0: { sl@0: ret = RecordKeyPosition(aSoundType); sl@0: } sl@0: else if (KErrNoMemory != ret) sl@0: { sl@0: RDebug::Print(_L("tef_ssnd test: unexpected error %d"), ret); sl@0: } sl@0: sl@0: User::LeaveIfError(ret); sl@0: } sl@0: sl@0: /** Provide similar function of CBaSsndStore::FindKeyL. sl@0: FindKeyL ignores duplicate SoundType in repository. It just sl@0: returns the first key in the array. Test harness cares because sl@0: it should fail the test if duplicate entries are detected. sl@0: */ sl@0: TInt CCollisionSsndStore::RecordKeyPosition(TBaSystemSoundType& aSoundType) const sl@0: { sl@0: const TUint32 KSoundTypePartialKey = 0x2; sl@0: const TUint32 KSsndKeyMask = 0x3; sl@0: TPckg target(aSoundType); sl@0: RArray foundIds; sl@0: sl@0: TInt ret(KErrNone); sl@0: TRAPD(err, ret = iRepository->FindEqL(KSoundTypePartialKey, sl@0: KSsndKeyMask, target, foundIds)); sl@0: if (err != KErrNone) sl@0: { sl@0: ret = err; // KErrNoMemory sl@0: } sl@0: sl@0: if (ret == KErrNone) sl@0: { sl@0: iKey = foundIds[0]; sl@0: if (foundIds.Count() > 1) sl@0: { sl@0: ret = KErrWrite; sl@0: } sl@0: sl@0: foundIds.Reset(); sl@0: } sl@0: sl@0: return ret; sl@0: } sl@0: sl@0: // sl@0: // Concurrent SetSoundL teststep sl@0: // sl@0: sl@0: _LIT(KNumWorkers, "NumWorkers"); sl@0: _LIT(KWorkerId, "WorkerId"); sl@0: _LIT(KSameSound, "SameSsndId"); sl@0: sl@0: const TTimeIntervalMicroSeconds32 KCollisionDelay = 500000; sl@0: const TInt KMaxNumWorkers = 3; sl@0: TWorkerData ConcurrentResults[KMaxNumWorkers]; sl@0: sl@0: /** CConcurrentStep constructor */ sl@0: CConcurrentStep::CConcurrentStep() sl@0: { sl@0: SetTestStepName(KConcurrentSetSound); sl@0: } sl@0: sl@0: /** This postamble insures that if a worker thread leaves in sl@0: doTestStepL, the iDone flag is still set. sl@0: */ sl@0: TVerdict CConcurrentStep::doTestStepPostambleL() sl@0: { sl@0: if (iWorkerId && iWorkerId <= KMaxNumWorkers) sl@0: { sl@0: ConcurrentResults[iWorkerId - 1].iDone = ETrue; sl@0: } sl@0: sl@0: // To silent Leave scan. sl@0: CTestStep::doTestStepPostambleL(); sl@0: sl@0: return TestStepResult(); sl@0: } sl@0: sl@0: /** Implementation of pure virtual base class method. sl@0: Read from config file to determine if the current thread is sl@0: master or worker. Workers invoke CCollisionSsndStore::SetSoundL. sl@0: Master summarises the test results. sl@0: */ sl@0: TVerdict CConcurrentStep::doTestStepL() sl@0: { sl@0: const TDesC& section = ConfigSection(); sl@0: if (!GetIntFromConfig(section, KWorkerId, iWorkerId)) sl@0: { sl@0: TInt numWorkers; sl@0: // This is the master thread. It does not call the sl@0: // SetSoundL API. It just sets up the concurrent data, sl@0: // wait for the test to complete, and tally up results. sl@0: TESTL( GetIntFromConfig(section, KNumWorkers, numWorkers) ); sl@0: TBool sameSsnd = section.FindF(KSameSound) >= 0; sl@0: DoMasterTaskL(numWorkers, sameSsnd); sl@0: return TestStepResult(); sl@0: } sl@0: sl@0: // Getting here means this is a worker thread. sl@0: TESTL(iWorkerId <= KMaxNumWorkers); sl@0: sl@0: // pause a bit to ensure master and other workers are sl@0: // all started. sl@0: User::AfterHighRes(200000); sl@0: sl@0: ConstructSoundL(); sl@0: CCollisionSsndStore* ssndCollisionSet = sl@0: CCollisionSsndStore::NewLC(KCollisionDelay); sl@0: ssndCollisionSet->SetSoundL(iSound); sl@0: sl@0: TWorkerData& mySlot = ConcurrentResults[iWorkerId - 1]; sl@0: mySlot.iTranFailCount = ssndCollisionSet->NumCollisions(); sl@0: mySlot.iKey = ssndCollisionSet->Key(); sl@0: mySlot.iDone = ETrue; sl@0: sl@0: CleanupStack::PopAndDestroy(ssndCollisionSet); sl@0: return TestStepResult(); sl@0: } sl@0: sl@0: /** Set up global data and then wait for the concurrent sl@0: worker threads. When workers all done, verify that sl@0: 1. collisions did occur and sl@0: 2. collisions did not cause errors in generating the hash keys. sl@0: */ sl@0: void CConcurrentStep::DoMasterTaskL(TInt aNumWorkers, sl@0: TBool aSsndIdAreSame) sl@0: { sl@0: if (aNumWorkers > KMaxNumWorkers) sl@0: { sl@0: // If there is valid reason to test more than 3 concurrent sl@0: // threads, CBaSsndStore::SetSoundL needs to bump up the sl@0: // retry count. 3 retries in production code can handle many sl@0: // concurrent threads. But in testing collision is guranteed sl@0: // to happen. The retry count needs to be same as number of sl@0: // workers. sl@0: _LIT(KTooMany, "Not allow to have more than %d concurrent workers."); sl@0: ERR_PRINTF2(KTooMany, KMaxNumWorkers); sl@0: TESTL(EFalse); sl@0: } sl@0: sl@0: TWorkerData nullData; sl@0: TInt i; sl@0: for (i = 0; i < aNumWorkers; i++) sl@0: { sl@0: ConcurrentResults[i] = nullData; sl@0: } sl@0: sl@0: // Probably should convert KCollisionDelay.Int() to seconds sl@0: // and multiply by num of workers. But 12 seconds for max of 3 sl@0: // workers should be plenty. sl@0: TInt j; sl@0: TInt doneCount = 0; sl@0: TTimeIntervalMicroSeconds32 halfSec(500000); sl@0: const TInt KNumLoops = 24; sl@0: for (i = 0; i < KNumLoops && doneCount < aNumWorkers; i++) sl@0: { sl@0: User::AfterHighRes(halfSec); sl@0: sl@0: // count number of dones. sl@0: for (j = 0, doneCount = 0; j < aNumWorkers; j++) sl@0: { sl@0: if (ConcurrentResults[j].iDone) sl@0: { sl@0: doneCount++; sl@0: } sl@0: } sl@0: } sl@0: sl@0: TEST(doneCount == aNumWorkers); sl@0: sl@0: // If there are 3 workers, expect 2+1 = 3 collisions. sl@0: // But to keep things simple, just use (aNumWorkers - 1) sl@0: TInt minCollisions = aNumWorkers - 1; sl@0: TInt numCommitFails = 0; sl@0: for (j = 0; j < aNumWorkers; j++) sl@0: { sl@0: numCommitFails += ConcurrentResults[j].iTranFailCount; sl@0: } sl@0: sl@0: TEST(numCommitFails >= minCollisions); sl@0: sl@0: // Next check the sounds are correctly created in CentRep. sl@0: for (i = 0; i < (aNumWorkers - 1); i++) sl@0: { sl@0: TUint32 key = ConcurrentResults[i].iKey; sl@0: sl@0: if (aSsndIdAreSame) sl@0: { sl@0: TEST(key == ConcurrentResults[i+1].iKey); sl@0: } sl@0: else sl@0: { sl@0: for (j = i+1; j < aNumWorkers; j++) sl@0: { sl@0: TEST(key != ConcurrentResults[j].iKey); sl@0: } sl@0: } sl@0: } sl@0: sl@0: } sl@0: sl@0: /** CLockoutTestStep constructor */ sl@0: CLockoutTestStep::CLockoutTestStep() sl@0: { sl@0: SetTestStepName(KLockoutTest); sl@0: } sl@0: sl@0: /** Implementation of pure virtual base class method. sl@0: Backup or Restore operation is running in parallel. sl@0: This test waits for the P&S KUidBackupRestoreKey become sl@0: active and then call SetSoundL and CBaSystemSoundArray::RestoreL. sl@0: Expects KErrServerBusy/KErrAbort/KErrLocked to be returned. sl@0: */ sl@0: TVerdict CLockoutTestStep::doTestStepL() sl@0: { sl@0: using namespace conn; sl@0: sl@0: const TBool KLogOnError = ETrue; sl@0: sl@0: RProperty burKey; sl@0: TInt ret = burKey.Attach(KUidSystemCategory, KUidBackupRestoreKey); sl@0: TEST1L(ret == KErrNone, KLogOnError); sl@0: sl@0: TRequestStatus s; sl@0: burKey.Subscribe(s); sl@0: User::WaitForRequest(s); sl@0: TEST1L(s.Int() == KErrNone, KLogOnError); sl@0: sl@0: TInt burKeyVal = 0; sl@0: ret = burKey.Get(burKeyVal); sl@0: TEST1L(ret == KErrNone, KLogOnError); sl@0: sl@0: burKeyVal &= KBURPartTypeMask; sl@0: const TInt KBurInProgress = EBURBackupFull | sl@0: EBURBackupPartial | sl@0: EBURRestoreFull | sl@0: EBURRestorePartial; sl@0: TEST1L(burKeyVal & KBurInProgress, KLogOnError); sl@0: sl@0: burKey.Close(); sl@0: sl@0: TRAP(ret, addSoundInstanceL(1)); sl@0: TEST1(ret == KErrServerBusy || ret == KErrAbort, KLogOnError); sl@0: sl@0: TRAP(ret, readSoundsBackL()); sl@0: if (burKeyVal & EBURRestoreFull || burKeyVal & EBURRestorePartial) sl@0: { sl@0: TEST1(ret == KErrServerBusy, KLogOnError); sl@0: } sl@0: else sl@0: { sl@0: TEST1(ret == KErrNone, KLogOnError); sl@0: } sl@0: sl@0: return TestStepResult(); sl@0: } sl@0: sl@0: /** Construct a sound and store it in repository. sl@0: @param aSequence used as both minor UID and sound sequence. sl@0: @leave any of the system-wide errors. sl@0: */ sl@0: void CLockoutTestStep::addSoundInstanceL(TInt32 aSequence) sl@0: { sl@0: TUid minorUid = {aSequence}; sl@0: TBaSystemSoundType soundId(KLockoutTestSoundCategory, minorUid); sl@0: TBaSystemSoundInfo sound(soundId, aSequence); sl@0: sl@0: RFs dummy; sl@0: BaSystemSound::SetSoundL(dummy, sound); sl@0: } sl@0: sl@0: /** use CBaSystemSoundArray::RestoreL to read back all sl@0: the sounds in KLockoutTestSoundCategory. sl@0: @leave any of the system-wide errors. sl@0: */ sl@0: void CLockoutTestStep::readSoundsBackL() sl@0: { sl@0: CBaSystemSoundArray* reader = CBaSystemSoundArray::NewLC(); sl@0: sl@0: RFs dummy; sl@0: reader->RestoreL(dummy, KLockoutTestSoundCategory); sl@0: CleanupStack::PopAndDestroy(reader); sl@0: } sl@0: