Update contrib.
1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
21 #include <e32property.h>
22 #include <connect/sbdefs.h>
23 #include <centralrepository.h>
26 #include "ssndteststep.h"
27 #include "BaSsndStore.h"
28 #include "BASSNDUID.h"
30 const TBaSystemSoundUid KLockoutTestSoundCategory = {288};
32 /** CResetDbStep constructor */
33 CResetDbStep::CResetDbStep()
35 SetTestStepName(KResetDb);
38 /** Implementation of the pure virtual base class function.
39 This teststep does not really test anything. It serves as
40 a helper of other steps to clear the sound table at the
43 TVerdict CResetDbStep::doTestStepL()
45 CRepository* repository = CRepository::NewLC(KSystemSoundRepositoryUID);
46 TESTL(repository != NULL);
47 TEST(repository->Reset() == KErrNone);
49 CleanupStack::PopAndDestroy(repository);
50 return TestStepResult();
56 _LIT(KUnknownParm, "Err reading INI section %S, unknown value %S");
58 _LIT(KSoundCat, "Category");
59 _LIT(KEFile, "EFile");
60 _LIT(KESequence, "ESequence");
61 _LIT(KETone, "ETone");
63 _LIT(KSoundFileName, "Filename");
64 _LIT(KFixedSequence, "SequenceNum");
65 _LIT(KToneFrequency, "Frequency");
66 _LIT(KToneDuration, "Duration");
68 _LIT(KMajorUid, "MajorUid");
69 _LIT(KMinorUid, "MinorUid");
71 /** Read data from the TEF ini file to construct iSound. */
72 void CSsndBaseStep::ConstructSoundL()
77 TTimeIntervalMicroSeconds32 duration;
80 TESTL( GetStringFromConfig(ConfigSection(), KSoundCat, cat) );
83 TESTL( GetStringFromConfig(ConfigSection(), KSoundFileName, ssndFile) );
84 TBaSystemSoundName filebuf(ssndFile);
85 iSound.SetFileName(filebuf);
87 else if (cat == KESequence())
89 TESTL( GetIntFromConfig(ConfigSection(), KFixedSequence, intdata) );
90 iSound.SetFixedSequenceNumber(intdata);
92 else if (cat == KETone())
94 TESTL( GetIntFromConfig(ConfigSection(), KToneFrequency, toneFreq) );
95 TESTL( GetIntFromConfig(ConfigSection(), KToneDuration, intdata) );
97 TBaSystemSoundInfo::TTone tone(toneFreq, duration);
102 ERR_PRINTF3(KUnknownParm, &KSoundCat, &cat);
106 TESTL( GetIntFromConfig(ConfigSection(), KMajorUid, intdata) );
107 iSound.iType.iMajor.iUid = intdata;
108 TESTL( GetIntFromConfig(ConfigSection(), KMinorUid, intdata) );
109 iSound.iType.iMinor.iUid = intdata;
112 /** CGetSoundStep constructor */
113 CGetSoundStep::CGetSoundStep()
115 SetTestStepName(KGetSound);
118 /** Implement the pure virtual base class function.
119 Read sound from repository and compare it against
120 the data specified in TEF ini file.
122 TVerdict CGetSoundStep::doTestStepL()
127 TInt ret = BaSystemSound::GetSound(dummy, iSound.iType, iReadFromRep);
130 // Do it this way for B&R test.
131 SetTestStepError(ret);
135 TBaSystemSoundInfo::TSoundCategory cat = iReadFromRep.SoundCategory();
136 if (cat == TBaSystemSoundInfo::ETone)
138 TEST(iSound.Tone().iFrequency == iReadFromRep.Tone().iFrequency);
139 TEST(iSound.Tone().iDuration == iReadFromRep.Tone().iDuration);
141 else if (cat == TBaSystemSoundInfo::ESequence)
143 TEST(iSound.FixedSequenceNumber() == iReadFromRep.FixedSequenceNumber());
145 else if (cat == TBaSystemSoundInfo::EFile)
147 TEST(iSound.FileName() == iReadFromRep.FileName());
149 return TestStepResult();
152 /** CSetSoundStep constructor */
153 CSetSoundStep::CSetSoundStep()
155 SetTestStepName(KSetSound);
158 /** Implementation of pure virtual base class method.
159 Call SetSoundL and return pass if KErrNone, fail otherwise.
161 TVerdict CSetSoundStep::doTestStepL()
165 TRAPD(ret, BaSystemSound::SetSoundL(dummy, iSound));
168 // SetTestStepError pass the error code back to TEF.
169 // If the script is expecting this particular error code,
170 // TEF will flip the EFail into EPass.
171 SetTestStepError(ret);
177 /** CSystemSoundFileTestStep constructor */
178 CSystemSoundFileTestStep::CSystemSoundFileTestStep()
180 SetTestStepName(KSystemSoundFileTest);
183 /** Implementation of pure virtual base class method.
184 Call the SystemSoundFile API and check the returned
185 filename is the old sound table file.
186 NB: the SystemSoundFile API has been deprecated.
188 TVerdict CSystemSoundFileTestStep::doTestStepL()
190 _LIT(KExpectedName, ":\\system\\data\\syssnd.dat");
191 TFileName fn = BaSystemSound::SystemSoundFile();
192 TInt pos = fn.FindF(KExpectedName);
193 TEST(pos != KErrNotFound);
194 return TestStepResult();
197 /** CGapTestStep constructor */
198 CGapTestStep::CGapTestStep()
200 SetTestStepName(KGapTest);
203 /** Implementation of pure virtual base class method.
204 Create a setting at key 7 leaving a gap at key 3.
205 Then call SetSoundL. The call should fail with KErrCorrupt.
207 TVerdict CGapTestStep::doTestStepL()
209 const TInt32 KKeyWithGap = 7;
210 const TInt KSomeInteger = 1;
211 CRepository* rep = CRepository::NewLC(KSystemSoundRepositoryUID);
212 TESTL(rep->Create(KKeyWithGap, KSomeInteger) == KErrNone);
214 TUid minorUid = {KSomeInteger};
215 TBaSystemSoundType soundId(KLockoutTestSoundCategory, minorUid);
216 TBaSystemSoundInfo sound(soundId, KSomeInteger);
219 TRAPD(ret, BaSystemSound::SetSoundL(dummy, sound));
220 TEST(ret == KErrCorrupt);
222 CleanupStack::PopAndDestroy(rep);
223 return TestStepResult();
226 /** CSoundFileNoPathTestStep constructor */
227 CSoundFileNoPathTestStep::CSoundFileNoPathTestStep()
229 SetTestStepName(KSoundFileNoPathTest);
232 /** Implementation of pure virtual base class method.
233 Call SetSoundL with a wav filename which does not contain path.
234 BaSystemSound should panic.
236 TVerdict CSoundFileNoPathTestStep::doTestStepL()
238 // BaSystemSound only trigger EBafPanicSystemSoundNoPath on udeb.
239 // So on urel do it ourself.
241 Panic(EBafPanicSystemSoundNoPath);
243 const TBaSystemSoundUid KMajorUid = {0x888};
244 TBaSystemSoundType soundId(KMajorUid);
246 // side bar to fill a code coverage gap in TTone::IsNull
247 TTimeIntervalMicroSeconds32 duration = 10;
248 TBaSystemSoundInfo::TTone tone(0, duration);
249 TBaSystemSoundInfo sound(soundId, tone);
250 TBaSystemSoundInfo::TSoundCategory cat = sound.SoundCategory();
251 TEST(cat == TBaSystemSoundInfo::ETone);
253 // now back to the panic test
254 _LIT(KSoundFileName, "rr.wav");
255 TBaSystemSoundName filename(KSoundFileName);
256 sound.SetFileName(filename);
259 // Following line should panic
260 BaSystemSound::SetSoundL(dummy, sound);
262 return TestStepResult();
265 /** CCorruptSoundStep constructor */
266 CCorruptSoundStep::CCorruptSoundStep()
268 SetTestStepName(KCorruptSound);
271 /** Implementation of pure virtual base class method.
272 Corrupt the soundtype, sound cat. and path length fields
273 in the sound data and verify GetSound returns KErrCorrupt.
275 TVerdict CCorruptSoundStep::doTestStepL()
280 BaSystemSound::SetSoundL(dummy, iSound);
282 // make a connection to CentRep to directly manipulate the
284 CRepository* rep = CRepository::NewLC(KSystemSoundRepositoryUID);
285 HBufC8* orighbuf8 = HBufC8::NewLC(sizeof(TBaSystemSoundInfo));
286 TPtr8 origbuf8 = orighbuf8->Des();
288 const TUint32 KKeyOfFirstSound = 3;
289 ret = rep->Get(KKeyOfFirstSound, origbuf8);
290 TESTL(ret == KErrNone);
292 // need a running copy of the sound data
293 HBufC8* temphbuf8 = orighbuf8->AllocLC();
294 TPtr8 tempbuf8 = temphbuf8->Des();
296 //Test corrupting the major sound Id
301 TESTL(rep->Set(KKeyOfFirstSound, tempbuf8) == KErrNone);
302 ret = BaSystemSound::GetSound(dummy, iSound.iType, iReadFromRep);
303 TEST(ret == KErrCorrupt);
305 //Test corrupting the sound cat. field
306 //First restore original data.
307 tempbuf8.Copy(origbuf8);
308 const TInt KSoundCatLocation = 16;
309 tempbuf8[KSoundCatLocation] = 255;
310 tempbuf8[KSoundCatLocation+1] = 127;
311 TESTL(rep->Set(KKeyOfFirstSound, tempbuf8) == KErrNone);
312 ret = BaSystemSound::GetSound(dummy, iSound.iType, iReadFromRep);
313 TEST(ret == KErrCorrupt);
315 //Test corrupting the path length field
316 //First restore original data.
317 tempbuf8.Copy(origbuf8);
318 const TInt KPathLengthLocation = 20;
319 tempbuf8[KPathLengthLocation] = 255;
320 tempbuf8[KPathLengthLocation+1] = 127;
321 TESTL(rep->Set(KKeyOfFirstSound, tempbuf8) == KErrNone);
322 ret = BaSystemSound::GetSound(dummy, iSound.iType, iReadFromRep);
323 TEST(ret == KErrCorrupt);
325 //Corruption of other fields are not detectable.
327 //If we restore the original data in CentRep, GetSound should pass.
328 tempbuf8.Copy(origbuf8);
329 TESTL(rep->Set(KKeyOfFirstSound, tempbuf8) == KErrNone);
330 ret = BaSystemSound::GetSound(dummy, iSound.iType, iReadFromRep);
331 TEST(ret == KErrNone);
333 CleanupStack::PopAndDestroy(temphbuf8);
334 CleanupStack::PopAndDestroy(orighbuf8);
335 CleanupStack::PopAndDestroy(rep);
336 return TestStepResult();
339 /** Derive from CBaSsndStore to force collision between
340 concurrent set sound threads.
342 class CCollisionSsndStore : public CBaSsndStore
345 static CCollisionSsndStore* NewLC(TTimeIntervalMicroSeconds32 aDelay);
346 virtual void KeyOfSoundTypeL(TBaSystemSoundType& aSoundType, TUint32& aKey) const;
347 virtual void SetSoundInTransactionL(TBaSystemSoundType& aSoundType,
348 const TDesC8& aDes8) const;
349 inline TUint32 NumCollisions() const {return iNumCollisions;}
350 inline TUint32 Key() const {return iKey;}
353 inline CCollisionSsndStore(const TTimeIntervalMicroSeconds32 aDelay)
354 : iDelay(aDelay), iNumCollisions(0), iKey(NCentralRepositoryConstants::KUnspecifiedKey) {}
355 inline void ConstructL() {CBaSsndStore::ConstructL();}
356 TInt RecordKeyPosition(TBaSystemSoundType& aSoundType) const;
359 /** indicate how long to pause in the middle of the transaction.
360 The pause causes concurrent transactions to fail. */
361 TTimeIntervalMicroSeconds32 iDelay;
363 /** Record how many times transaction commit failed. Mutable because
364 SetSoundInTransactionL in production code is a const method. */
365 mutable TUint32 iNumCollisions;
367 /** Record the CentRep key used to store the sound. Mutable because
368 KeyOfSoundTypeL in production code is a const method. */
369 mutable TUint32 iKey;
372 /** static factory method to instantiate CCollisionSsndStore */
373 CCollisionSsndStore* CCollisionSsndStore::NewLC(
374 const TTimeIntervalMicroSeconds32 aDelay)
376 CCollisionSsndStore* self = new (ELeave) CCollisionSsndStore(aDelay);
377 CleanupStack::PushL(self);
382 /** After using base class method to get the key, add a delay
383 to cause concurrent threads to collide.
385 void CCollisionSsndStore::KeyOfSoundTypeL(TBaSystemSoundType& aSoundType,
388 CBaSsndStore::KeyOfSoundTypeL(aSoundType, aKey);
389 User::AfterHighRes(iDelay);
392 /** After using base class method to do SetSound in transaction,
393 check the return code. Record commitFail condition. If succes,
394 record the key position where the SoundType is stored.
396 void CCollisionSsndStore::SetSoundInTransactionL(
397 TBaSystemSoundType& aSoundType,
398 const TDesC8& aDes8) const
400 // call base class method to do the real work
401 TRAPD(ret, CBaSsndStore::SetSoundInTransactionL(aSoundType, aDes8));
403 // record any collision
404 if (KErrLocked == ret || KErrAbort == ret)
408 else if (KErrNone == ret)
410 ret = RecordKeyPosition(aSoundType);
412 else if (KErrNoMemory != ret)
414 RDebug::Print(_L("tef_ssnd test: unexpected error %d"), ret);
417 User::LeaveIfError(ret);
420 /** Provide similar function of CBaSsndStore::FindKeyL.
421 FindKeyL ignores duplicate SoundType in repository. It just
422 returns the first key in the array. Test harness cares because
423 it should fail the test if duplicate entries are detected.
425 TInt CCollisionSsndStore::RecordKeyPosition(TBaSystemSoundType& aSoundType) const
427 const TUint32 KSoundTypePartialKey = 0x2;
428 const TUint32 KSsndKeyMask = 0x3;
429 TPckg<TBaSystemSoundType> target(aSoundType);
430 RArray<TUint32> foundIds;
433 TRAPD(err, ret = iRepository->FindEqL(KSoundTypePartialKey,
434 KSsndKeyMask, target, foundIds));
437 ret = err; // KErrNoMemory
443 if (foundIds.Count() > 1)
455 // Concurrent SetSoundL teststep
458 _LIT(KNumWorkers, "NumWorkers");
459 _LIT(KWorkerId, "WorkerId");
460 _LIT(KSameSound, "SameSsndId");
462 const TTimeIntervalMicroSeconds32 KCollisionDelay = 500000;
463 const TInt KMaxNumWorkers = 3;
464 TWorkerData ConcurrentResults[KMaxNumWorkers];
466 /** CConcurrentStep constructor */
467 CConcurrentStep::CConcurrentStep()
469 SetTestStepName(KConcurrentSetSound);
472 /** This postamble insures that if a worker thread leaves in
473 doTestStepL, the iDone flag is still set.
475 TVerdict CConcurrentStep::doTestStepPostambleL()
477 if (iWorkerId && iWorkerId <= KMaxNumWorkers)
479 ConcurrentResults[iWorkerId - 1].iDone = ETrue;
482 // To silent Leave scan.
483 CTestStep::doTestStepPostambleL();
485 return TestStepResult();
488 /** Implementation of pure virtual base class method.
489 Read from config file to determine if the current thread is
490 master or worker. Workers invoke CCollisionSsndStore::SetSoundL.
491 Master summarises the test results.
493 TVerdict CConcurrentStep::doTestStepL()
495 const TDesC& section = ConfigSection();
496 if (!GetIntFromConfig(section, KWorkerId, iWorkerId))
499 // This is the master thread. It does not call the
500 // SetSoundL API. It just sets up the concurrent data,
501 // wait for the test to complete, and tally up results.
502 TESTL( GetIntFromConfig(section, KNumWorkers, numWorkers) );
503 TBool sameSsnd = section.FindF(KSameSound) >= 0;
504 DoMasterTaskL(numWorkers, sameSsnd);
505 return TestStepResult();
508 // Getting here means this is a worker thread.
509 TESTL(iWorkerId <= KMaxNumWorkers);
511 // pause a bit to ensure master and other workers are
513 User::AfterHighRes(200000);
516 CCollisionSsndStore* ssndCollisionSet =
517 CCollisionSsndStore::NewLC(KCollisionDelay);
518 ssndCollisionSet->SetSoundL(iSound);
520 TWorkerData& mySlot = ConcurrentResults[iWorkerId - 1];
521 mySlot.iTranFailCount = ssndCollisionSet->NumCollisions();
522 mySlot.iKey = ssndCollisionSet->Key();
523 mySlot.iDone = ETrue;
525 CleanupStack::PopAndDestroy(ssndCollisionSet);
526 return TestStepResult();
529 /** Set up global data and then wait for the concurrent
530 worker threads. When workers all done, verify that
531 1. collisions did occur and
532 2. collisions did not cause errors in generating the hash keys.
534 void CConcurrentStep::DoMasterTaskL(TInt aNumWorkers,
535 TBool aSsndIdAreSame)
537 if (aNumWorkers > KMaxNumWorkers)
539 // If there is valid reason to test more than 3 concurrent
540 // threads, CBaSsndStore::SetSoundL needs to bump up the
541 // retry count. 3 retries in production code can handle many
542 // concurrent threads. But in testing collision is guranteed
543 // to happen. The retry count needs to be same as number of
545 _LIT(KTooMany, "Not allow to have more than %d concurrent workers.");
546 ERR_PRINTF2(KTooMany, KMaxNumWorkers);
550 TWorkerData nullData;
552 for (i = 0; i < aNumWorkers; i++)
554 ConcurrentResults[i] = nullData;
557 // Probably should convert KCollisionDelay.Int() to seconds
558 // and multiply by num of workers. But 12 seconds for max of 3
559 // workers should be plenty.
562 TTimeIntervalMicroSeconds32 halfSec(500000);
563 const TInt KNumLoops = 24;
564 for (i = 0; i < KNumLoops && doneCount < aNumWorkers; i++)
566 User::AfterHighRes(halfSec);
568 // count number of dones.
569 for (j = 0, doneCount = 0; j < aNumWorkers; j++)
571 if (ConcurrentResults[j].iDone)
578 TEST(doneCount == aNumWorkers);
580 // If there are 3 workers, expect 2+1 = 3 collisions.
581 // But to keep things simple, just use (aNumWorkers - 1)
582 TInt minCollisions = aNumWorkers - 1;
583 TInt numCommitFails = 0;
584 for (j = 0; j < aNumWorkers; j++)
586 numCommitFails += ConcurrentResults[j].iTranFailCount;
589 TEST(numCommitFails >= minCollisions);
591 // Next check the sounds are correctly created in CentRep.
592 for (i = 0; i < (aNumWorkers - 1); i++)
594 TUint32 key = ConcurrentResults[i].iKey;
598 TEST(key == ConcurrentResults[i+1].iKey);
602 for (j = i+1; j < aNumWorkers; j++)
604 TEST(key != ConcurrentResults[j].iKey);
611 /** CLockoutTestStep constructor */
612 CLockoutTestStep::CLockoutTestStep()
614 SetTestStepName(KLockoutTest);
617 /** Implementation of pure virtual base class method.
618 Backup or Restore operation is running in parallel.
619 This test waits for the P&S KUidBackupRestoreKey become
620 active and then call SetSoundL and CBaSystemSoundArray::RestoreL.
621 Expects KErrServerBusy/KErrAbort/KErrLocked to be returned.
623 TVerdict CLockoutTestStep::doTestStepL()
625 using namespace conn;
627 const TBool KLogOnError = ETrue;
630 TInt ret = burKey.Attach(KUidSystemCategory, KUidBackupRestoreKey);
631 TEST1L(ret == KErrNone, KLogOnError);
635 User::WaitForRequest(s);
636 TEST1L(s.Int() == KErrNone, KLogOnError);
639 ret = burKey.Get(burKeyVal);
640 TEST1L(ret == KErrNone, KLogOnError);
642 burKeyVal &= KBURPartTypeMask;
643 const TInt KBurInProgress = EBURBackupFull |
647 TEST1L(burKeyVal & KBurInProgress, KLogOnError);
651 TRAP(ret, addSoundInstanceL(1));
652 TEST1(ret == KErrServerBusy || ret == KErrAbort, KLogOnError);
654 TRAP(ret, readSoundsBackL());
655 if (burKeyVal & EBURRestoreFull || burKeyVal & EBURRestorePartial)
657 TEST1(ret == KErrServerBusy, KLogOnError);
661 TEST1(ret == KErrNone, KLogOnError);
664 return TestStepResult();
667 /** Construct a sound and store it in repository.
668 @param aSequence used as both minor UID and sound sequence.
669 @leave any of the system-wide errors.
671 void CLockoutTestStep::addSoundInstanceL(TInt32 aSequence)
673 TUid minorUid = {aSequence};
674 TBaSystemSoundType soundId(KLockoutTestSoundCategory, minorUid);
675 TBaSystemSoundInfo sound(soundId, aSequence);
678 BaSystemSound::SetSoundL(dummy, sound);
681 /** use CBaSystemSoundArray::RestoreL to read back all
682 the sounds in KLockoutTestSoundCategory.
683 @leave any of the system-wide errors.
685 void CLockoutTestStep::readSoundsBackL()
687 CBaSystemSoundArray* reader = CBaSystemSoundArray::NewLC();
690 reader->RestoreL(dummy, KLockoutTestSoundCategory);
691 CleanupStack::PopAndDestroy(reader);