os/ossrv/lowlevellibsandfws/apputils/test/tef/ssnd/src/ssndteststep.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
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".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 /**
    17  @file
    18  @internalComponent
    19 */
    20 
    21 #include <e32property.h>
    22 #include <connect/sbdefs.h>
    23 #include <centralrepository.h>
    24 #include <baflpan.h>
    25 #include <bassnd.h>
    26 #include "ssndteststep.h"
    27 #include "BaSsndStore.h"
    28 #include "BASSNDUID.h"
    29 
    30 const TBaSystemSoundUid KLockoutTestSoundCategory = {288};
    31 
    32 /** CResetDbStep constructor */
    33 CResetDbStep::CResetDbStep()
    34 	{
    35 	SetTestStepName(KResetDb);
    36 	}
    37 
    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 
    41 beginning of a test.
    42 */
    43 TVerdict CResetDbStep::doTestStepL()
    44 	{
    45 	CRepository* repository = CRepository::NewLC(KSystemSoundRepositoryUID);
    46 	TESTL(repository != NULL);
    47 	TEST(repository->Reset() == KErrNone);
    48 
    49 	CleanupStack::PopAndDestroy(repository);
    50 	return TestStepResult();
    51 	}
    52 
    53 //
    54 // GetSound/SetSound
    55 //
    56 _LIT(KUnknownParm, "Err reading INI section %S, unknown value %S");
    57 
    58 _LIT(KSoundCat, "Category");
    59 _LIT(KEFile, "EFile");
    60 _LIT(KESequence, "ESequence");
    61 _LIT(KETone, "ETone");
    62 
    63 _LIT(KSoundFileName, "Filename");
    64 _LIT(KFixedSequence, "SequenceNum");
    65 _LIT(KToneFrequency, "Frequency");
    66 _LIT(KToneDuration, "Duration");
    67 
    68 _LIT(KMajorUid, "MajorUid");
    69 _LIT(KMinorUid, "MinorUid");
    70 
    71 /** Read data from the TEF ini file to construct iSound. */
    72 void CSsndBaseStep::ConstructSoundL()
    73 	{
    74 	TPtrC cat;
    75 	TPtrC ssndFile;
    76 	TInt toneFreq;
    77 	TTimeIntervalMicroSeconds32 duration;
    78 	TInt intdata;
    79 
    80 	TESTL( GetStringFromConfig(ConfigSection(), KSoundCat, cat) );
    81 	if (cat == KEFile())
    82 		{
    83 		TESTL( GetStringFromConfig(ConfigSection(), KSoundFileName, ssndFile) );
    84 		TBaSystemSoundName filebuf(ssndFile);
    85 		iSound.SetFileName(filebuf);
    86 		}
    87 	else if (cat == KESequence())
    88 		{
    89 		TESTL( GetIntFromConfig(ConfigSection(), KFixedSequence, intdata) );
    90 		iSound.SetFixedSequenceNumber(intdata);
    91 		}
    92 	else if (cat == KETone())
    93 		{
    94 		TESTL( GetIntFromConfig(ConfigSection(), KToneFrequency, toneFreq) );
    95 		TESTL( GetIntFromConfig(ConfigSection(), KToneDuration, intdata) );
    96 		duration = intdata;
    97 		TBaSystemSoundInfo::TTone tone(toneFreq, duration);
    98 		iSound.SetTone(tone);
    99 		}
   100 	else
   101 		{
   102 		ERR_PRINTF3(KUnknownParm, &KSoundCat, &cat);
   103 		TESTL(EFalse);
   104 		}
   105 
   106 	TESTL( GetIntFromConfig(ConfigSection(), KMajorUid, intdata) );
   107 	iSound.iType.iMajor.iUid = intdata;
   108 	TESTL( GetIntFromConfig(ConfigSection(), KMinorUid, intdata) );
   109 	iSound.iType.iMinor.iUid = intdata;
   110 	}
   111 
   112 /** CGetSoundStep constructor */
   113 CGetSoundStep::CGetSoundStep()
   114 	{
   115 	SetTestStepName(KGetSound);
   116 	}
   117 
   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.
   121 */
   122 TVerdict CGetSoundStep::doTestStepL()
   123 	{
   124 	ConstructSoundL();
   125 	RFs dummy;
   126 
   127 	TInt ret = BaSystemSound::GetSound(dummy, iSound.iType, iReadFromRep);
   128 	if (ret != KErrNone)
   129 		{
   130 		// Do it this way for B&R test.
   131 		SetTestStepError(ret);
   132 		return EFail;
   133 		}
   134 
   135 	TBaSystemSoundInfo::TSoundCategory cat = iReadFromRep.SoundCategory();
   136 	if (cat == TBaSystemSoundInfo::ETone)
   137 		{
   138 		TEST(iSound.Tone().iFrequency == iReadFromRep.Tone().iFrequency);
   139 		TEST(iSound.Tone().iDuration == iReadFromRep.Tone().iDuration);
   140 		}
   141 	else if (cat == TBaSystemSoundInfo::ESequence)
   142 		{
   143 		TEST(iSound.FixedSequenceNumber() == iReadFromRep.FixedSequenceNumber());
   144 		}
   145 	else if (cat == TBaSystemSoundInfo::EFile)
   146 		{
   147 		TEST(iSound.FileName() == iReadFromRep.FileName());
   148 		}
   149 	return TestStepResult();
   150 	}
   151 
   152 /** CSetSoundStep constructor */
   153 CSetSoundStep::CSetSoundStep()
   154 	{
   155 	SetTestStepName(KSetSound);
   156 	}
   157 
   158 /** Implementation of pure virtual base class method.
   159 Call SetSoundL and return pass if KErrNone, fail otherwise.
   160 */
   161 TVerdict CSetSoundStep::doTestStepL()
   162 	{
   163 	ConstructSoundL();
   164 	RFs dummy;
   165 	TRAPD(ret, BaSystemSound::SetSoundL(dummy, iSound));
   166 	if (ret != KErrNone)
   167 		{
   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);
   172 		return EFail;
   173 		}
   174 	return EPass;
   175 	}
   176 
   177 /** CSystemSoundFileTestStep constructor */
   178 CSystemSoundFileTestStep::CSystemSoundFileTestStep()
   179 	{
   180 	SetTestStepName(KSystemSoundFileTest);
   181 	}
   182 
   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.
   187 */
   188 TVerdict CSystemSoundFileTestStep::doTestStepL()
   189 	{
   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();
   195 	}
   196 
   197 /** CGapTestStep constructor */
   198 CGapTestStep::CGapTestStep()
   199 	{
   200 	SetTestStepName(KGapTest);
   201 	}
   202 
   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.
   206 */
   207 TVerdict CGapTestStep::doTestStepL()
   208 	{
   209 	const TInt32 KKeyWithGap = 7;
   210 	const TInt KSomeInteger = 1;
   211 	CRepository* rep = CRepository::NewLC(KSystemSoundRepositoryUID);
   212 	TESTL(rep->Create(KKeyWithGap, KSomeInteger) == KErrNone);
   213 	
   214 	TUid minorUid = {KSomeInteger};
   215 	TBaSystemSoundType soundId(KLockoutTestSoundCategory, minorUid);
   216 	TBaSystemSoundInfo sound(soundId, KSomeInteger);
   217 
   218 	RFs dummy;
   219 	TRAPD(ret, BaSystemSound::SetSoundL(dummy, sound));
   220 	TEST(ret == KErrCorrupt);
   221 
   222 	CleanupStack::PopAndDestroy(rep);	
   223 	return TestStepResult();
   224 	}
   225 
   226 /** CSoundFileNoPathTestStep constructor */
   227 CSoundFileNoPathTestStep::CSoundFileNoPathTestStep()
   228 	{
   229 	SetTestStepName(KSoundFileNoPathTest);
   230 	}
   231 
   232 /** Implementation of pure virtual base class method.
   233 Call SetSoundL with a wav filename which does not contain path.
   234 BaSystemSound should panic.
   235 */
   236 TVerdict CSoundFileNoPathTestStep::doTestStepL()
   237 	{
   238 // BaSystemSound only trigger EBafPanicSystemSoundNoPath on udeb.
   239 // So on urel do it ourself.
   240 #ifndef _DEBUG
   241 	Panic(EBafPanicSystemSoundNoPath);
   242 #else
   243 	const TBaSystemSoundUid KMajorUid = {0x888};
   244 	TBaSystemSoundType soundId(KMajorUid);
   245 
   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);
   252 	
   253 	// now back to the panic test
   254 	_LIT(KSoundFileName, "rr.wav");
   255 	TBaSystemSoundName filename(KSoundFileName);
   256 	sound.SetFileName(filename);
   257 
   258 	RFs dummy;
   259 	// Following line should panic
   260 	BaSystemSound::SetSoundL(dummy, sound);
   261 #endif
   262 	return TestStepResult();
   263 	}
   264 
   265 /** CCorruptSoundStep constructor */
   266 CCorruptSoundStep::CCorruptSoundStep()
   267 	{
   268 	SetTestStepName(KCorruptSound);
   269 	}
   270 
   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.
   274 */
   275 TVerdict CCorruptSoundStep::doTestStepL()
   276 	{
   277 	ConstructSoundL();
   278 	RFs dummy;
   279 	TInt ret(KErrNone);
   280 	BaSystemSound::SetSoundL(dummy, iSound);
   281 	
   282 	// make a connection to CentRep to directly manipulate the
   283 	// setting.
   284 	CRepository* rep = CRepository::NewLC(KSystemSoundRepositoryUID);
   285 	HBufC8* orighbuf8 = HBufC8::NewLC(sizeof(TBaSystemSoundInfo));
   286 	TPtr8 origbuf8 = orighbuf8->Des();
   287 
   288 	const TUint32 KKeyOfFirstSound = 3;
   289 	ret = rep->Get(KKeyOfFirstSound, origbuf8);
   290 	TESTL(ret == KErrNone);
   291 
   292 	// need a running copy of the sound data
   293 	HBufC8* temphbuf8 = orighbuf8->AllocLC();
   294 	TPtr8 tempbuf8 = temphbuf8->Des();
   295 
   296 	//Test corrupting the major sound Id
   297 	tempbuf8[0] = 1;
   298 	tempbuf8[1] = 2;
   299 	tempbuf8[2] = 3;
   300 	tempbuf8[3] = 4;
   301 	TESTL(rep->Set(KKeyOfFirstSound, tempbuf8) == KErrNone);
   302 	ret = BaSystemSound::GetSound(dummy, iSound.iType, iReadFromRep);
   303 	TEST(ret == KErrCorrupt);
   304 
   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);
   314 
   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);
   324 	
   325 	//Corruption of other fields are not detectable.
   326 
   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);
   332 
   333 	CleanupStack::PopAndDestroy(temphbuf8);	
   334 	CleanupStack::PopAndDestroy(orighbuf8);	
   335 	CleanupStack::PopAndDestroy(rep);	
   336 	return TestStepResult();
   337 	}
   338 
   339 /** Derive from CBaSsndStore to force collision between
   340 concurrent set sound threads.
   341 */
   342 class CCollisionSsndStore : public CBaSsndStore
   343 	{
   344 public:
   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;}
   351 
   352 private:
   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;
   357 
   358 private:
   359 	/** indicate how long to pause in the middle of the transaction.
   360 	 The pause causes concurrent transactions to fail. */
   361 	TTimeIntervalMicroSeconds32 iDelay;
   362 
   363 	/** Record how many times transaction commit failed. Mutable because
   364 	 SetSoundInTransactionL in production code is a const method. */
   365 	mutable TUint32 iNumCollisions;
   366 
   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;
   370 	};
   371 
   372 /** static factory method to instantiate CCollisionSsndStore */
   373 CCollisionSsndStore* CCollisionSsndStore::NewLC(
   374 	const TTimeIntervalMicroSeconds32 aDelay)
   375 	{
   376 	CCollisionSsndStore* self = new (ELeave) CCollisionSsndStore(aDelay);
   377 	CleanupStack::PushL(self);
   378 	self->ConstructL();
   379 	return self;
   380 	}
   381 
   382 /** After using base class method to get the key, add a delay
   383 to cause concurrent threads to collide.
   384 */
   385 void CCollisionSsndStore::KeyOfSoundTypeL(TBaSystemSoundType& aSoundType,
   386 										  TUint32& aKey) const
   387 	{
   388 	CBaSsndStore::KeyOfSoundTypeL(aSoundType, aKey);
   389 	User::AfterHighRes(iDelay);
   390 	}
   391 
   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.
   395 */
   396 void CCollisionSsndStore::SetSoundInTransactionL(
   397 		TBaSystemSoundType& aSoundType,
   398 		const TDesC8& aDes8) const
   399 	{
   400 	// call base class method to do the real work
   401 	TRAPD(ret, CBaSsndStore::SetSoundInTransactionL(aSoundType, aDes8));
   402 
   403 	// record any collision
   404 	if (KErrLocked == ret || KErrAbort == ret)
   405 		{
   406 		iNumCollisions++;
   407 		}
   408 	else if (KErrNone == ret)
   409 		{
   410 		ret = RecordKeyPosition(aSoundType);
   411 		}
   412 	else if (KErrNoMemory != ret)
   413 		{
   414 		RDebug::Print(_L("tef_ssnd test: unexpected error %d"), ret);
   415 		}
   416 
   417 	User::LeaveIfError(ret);
   418 	}
   419 
   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.
   424 */
   425 TInt CCollisionSsndStore::RecordKeyPosition(TBaSystemSoundType& aSoundType) const
   426 	{
   427 	const TUint32 KSoundTypePartialKey = 0x2;
   428 	const TUint32 KSsndKeyMask = 0x3;
   429 	TPckg<TBaSystemSoundType> target(aSoundType);
   430 	RArray<TUint32> foundIds;
   431 
   432 	TInt ret(KErrNone);
   433 	TRAPD(err, ret = iRepository->FindEqL(KSoundTypePartialKey,
   434 		KSsndKeyMask, target, foundIds));
   435 	if (err != KErrNone)
   436 		{
   437 		ret = err; // KErrNoMemory
   438 		}
   439 
   440 	if (ret == KErrNone)
   441 		{
   442 		iKey = foundIds[0];
   443 		if (foundIds.Count() > 1)
   444 			{
   445 			ret = KErrWrite;
   446 			}
   447 
   448 		foundIds.Reset();
   449 		}
   450 
   451 	return ret;
   452 	}
   453 
   454 //
   455 // Concurrent SetSoundL teststep
   456 //
   457 
   458 _LIT(KNumWorkers, "NumWorkers");
   459 _LIT(KWorkerId, "WorkerId");
   460 _LIT(KSameSound, "SameSsndId");
   461 
   462 const TTimeIntervalMicroSeconds32 KCollisionDelay = 500000;
   463 const TInt KMaxNumWorkers = 3;
   464 TWorkerData ConcurrentResults[KMaxNumWorkers];
   465 
   466 /** CConcurrentStep constructor */
   467 CConcurrentStep::CConcurrentStep()
   468 	{
   469 	SetTestStepName(KConcurrentSetSound);
   470 	}
   471 
   472 /** This postamble insures that if a worker thread leaves in
   473 doTestStepL, the iDone flag is still set.
   474 */
   475 TVerdict CConcurrentStep::doTestStepPostambleL()
   476 	{
   477 	if (iWorkerId && iWorkerId <= KMaxNumWorkers)
   478 		{
   479 		ConcurrentResults[iWorkerId - 1].iDone = ETrue;
   480 		}
   481 
   482 	// To silent Leave scan.
   483 	CTestStep::doTestStepPostambleL();
   484 
   485 	return TestStepResult();
   486 	}
   487 
   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.
   492 */
   493 TVerdict CConcurrentStep::doTestStepL()
   494 	{
   495 	const TDesC& section = ConfigSection();
   496 	if (!GetIntFromConfig(section, KWorkerId, iWorkerId))
   497 		{
   498 		TInt numWorkers;
   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();
   506 		}
   507 
   508 	// Getting here means this is a worker thread.
   509 	TESTL(iWorkerId <= KMaxNumWorkers);
   510 
   511 	// pause a bit to ensure master and other workers are
   512 	// all started.
   513 	User::AfterHighRes(200000);
   514 
   515 	ConstructSoundL();
   516 	CCollisionSsndStore* ssndCollisionSet = 
   517 		CCollisionSsndStore::NewLC(KCollisionDelay);
   518 	ssndCollisionSet->SetSoundL(iSound);
   519 
   520 	TWorkerData& mySlot = ConcurrentResults[iWorkerId - 1];
   521 	mySlot.iTranFailCount = ssndCollisionSet->NumCollisions();
   522 	mySlot.iKey = ssndCollisionSet->Key();
   523 	mySlot.iDone = ETrue;
   524 
   525 	CleanupStack::PopAndDestroy(ssndCollisionSet);	
   526 	return TestStepResult();
   527 	}
   528 
   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.
   533 */
   534 void CConcurrentStep::DoMasterTaskL(TInt aNumWorkers,
   535 								   TBool aSsndIdAreSame)
   536 	{
   537 	if (aNumWorkers > KMaxNumWorkers)
   538 		{
   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
   544 		// workers.
   545 		_LIT(KTooMany, "Not allow to have more than %d concurrent workers.");
   546 		ERR_PRINTF2(KTooMany, KMaxNumWorkers);
   547 		TESTL(EFalse);
   548 		}
   549 
   550 	TWorkerData nullData;
   551 	TInt i;
   552 	for (i = 0; i < aNumWorkers; i++)
   553 		{
   554 		ConcurrentResults[i] = nullData;
   555 		}
   556 
   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.
   560 	TInt j;
   561 	TInt doneCount = 0;
   562 	TTimeIntervalMicroSeconds32 halfSec(500000);
   563 	const TInt KNumLoops = 24;
   564 	for (i = 0; i < KNumLoops && doneCount < aNumWorkers; i++)
   565 		{
   566 		User::AfterHighRes(halfSec);
   567 
   568 		// count number of dones.
   569 		for (j = 0, doneCount = 0; j < aNumWorkers; j++)
   570 			{
   571 			if (ConcurrentResults[j].iDone)
   572 				{
   573 				doneCount++;
   574 				}
   575 			}
   576 		}
   577 
   578 	TEST(doneCount == aNumWorkers);
   579 
   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++)
   585 		{
   586 		numCommitFails += ConcurrentResults[j].iTranFailCount;
   587 		}
   588 
   589 	TEST(numCommitFails >= minCollisions);
   590 
   591 	// Next check the sounds are correctly created in CentRep.
   592 	for (i = 0; i < (aNumWorkers - 1); i++)
   593 		{
   594 		TUint32 key = ConcurrentResults[i].iKey;
   595 
   596 		if (aSsndIdAreSame)
   597 			{
   598 			TEST(key == ConcurrentResults[i+1].iKey);
   599 			}
   600 		else
   601 			{
   602 			for (j = i+1; j < aNumWorkers; j++)
   603 				{
   604 				TEST(key != ConcurrentResults[j].iKey);
   605 				}
   606 			}
   607 		}
   608 
   609 	}
   610 
   611 /** CLockoutTestStep constructor */
   612 CLockoutTestStep::CLockoutTestStep()
   613 	{
   614 	SetTestStepName(KLockoutTest);
   615 	}
   616 
   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.
   622 */
   623 TVerdict CLockoutTestStep::doTestStepL()
   624 	{
   625 using namespace conn;
   626 
   627 	const TBool KLogOnError = ETrue;
   628 
   629 	RProperty burKey;
   630 	TInt ret = burKey.Attach(KUidSystemCategory, KUidBackupRestoreKey);
   631 	TEST1L(ret == KErrNone, KLogOnError);
   632 
   633 	TRequestStatus s;
   634 	burKey.Subscribe(s);
   635 	User::WaitForRequest(s);
   636 	TEST1L(s.Int() == KErrNone, KLogOnError);
   637 
   638 	TInt burKeyVal = 0;
   639 	ret = burKey.Get(burKeyVal);
   640 	TEST1L(ret == KErrNone, KLogOnError);
   641 
   642 	burKeyVal &= KBURPartTypeMask;
   643 	const TInt KBurInProgress = EBURBackupFull |
   644 								EBURBackupPartial |
   645 								EBURRestoreFull |
   646 								EBURRestorePartial;
   647 	TEST1L(burKeyVal & KBurInProgress, KLogOnError);
   648 
   649 	burKey.Close();
   650 
   651 	TRAP(ret, addSoundInstanceL(1));
   652 	TEST1(ret == KErrServerBusy || ret == KErrAbort, KLogOnError);
   653 
   654 	TRAP(ret, readSoundsBackL());
   655 	if (burKeyVal & EBURRestoreFull || burKeyVal & EBURRestorePartial)
   656 		{
   657 	    TEST1(ret == KErrServerBusy, KLogOnError);
   658 		}
   659 	else
   660 		{
   661 	    TEST1(ret == KErrNone, KLogOnError);
   662 		}
   663 
   664 	return TestStepResult();
   665 	}
   666 
   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.
   670 */
   671 void CLockoutTestStep::addSoundInstanceL(TInt32 aSequence)
   672 	{
   673 	TUid minorUid = {aSequence};
   674 	TBaSystemSoundType soundId(KLockoutTestSoundCategory, minorUid);
   675 	TBaSystemSoundInfo sound(soundId, aSequence);
   676 
   677 	RFs dummy;
   678 	BaSystemSound::SetSoundL(dummy, sound);
   679 	}
   680 
   681 /** use CBaSystemSoundArray::RestoreL to read back all
   682 the sounds in KLockoutTestSoundCategory.
   683 @leave any of the system-wide errors.
   684 */
   685 void CLockoutTestStep::readSoundsBackL()
   686 	{
   687 	CBaSystemSoundArray* reader = CBaSystemSoundArray::NewLC();
   688 
   689 	RFs dummy;
   690 	reader->RestoreL(dummy, KLockoutTestSoundCategory);
   691 	CleanupStack::PopAndDestroy(reader);
   692 	}
   693