1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/ossrv/lowlevellibsandfws/apputils/test/tef/ssnd/src/ssndteststep.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,693 @@
1.4 +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +/**
1.20 + @file
1.21 + @internalComponent
1.22 +*/
1.23 +
1.24 +#include <e32property.h>
1.25 +#include <connect/sbdefs.h>
1.26 +#include <centralrepository.h>
1.27 +#include <baflpan.h>
1.28 +#include <bassnd.h>
1.29 +#include "ssndteststep.h"
1.30 +#include "BaSsndStore.h"
1.31 +#include "BASSNDUID.h"
1.32 +
1.33 +const TBaSystemSoundUid KLockoutTestSoundCategory = {288};
1.34 +
1.35 +/** CResetDbStep constructor */
1.36 +CResetDbStep::CResetDbStep()
1.37 + {
1.38 + SetTestStepName(KResetDb);
1.39 + }
1.40 +
1.41 +/** Implementation of the pure virtual base class function.
1.42 +This teststep does not really test anything. It serves as
1.43 +a helper of other steps to clear the sound table at the
1.44 +beginning of a test.
1.45 +*/
1.46 +TVerdict CResetDbStep::doTestStepL()
1.47 + {
1.48 + CRepository* repository = CRepository::NewLC(KSystemSoundRepositoryUID);
1.49 + TESTL(repository != NULL);
1.50 + TEST(repository->Reset() == KErrNone);
1.51 +
1.52 + CleanupStack::PopAndDestroy(repository);
1.53 + return TestStepResult();
1.54 + }
1.55 +
1.56 +//
1.57 +// GetSound/SetSound
1.58 +//
1.59 +_LIT(KUnknownParm, "Err reading INI section %S, unknown value %S");
1.60 +
1.61 +_LIT(KSoundCat, "Category");
1.62 +_LIT(KEFile, "EFile");
1.63 +_LIT(KESequence, "ESequence");
1.64 +_LIT(KETone, "ETone");
1.65 +
1.66 +_LIT(KSoundFileName, "Filename");
1.67 +_LIT(KFixedSequence, "SequenceNum");
1.68 +_LIT(KToneFrequency, "Frequency");
1.69 +_LIT(KToneDuration, "Duration");
1.70 +
1.71 +_LIT(KMajorUid, "MajorUid");
1.72 +_LIT(KMinorUid, "MinorUid");
1.73 +
1.74 +/** Read data from the TEF ini file to construct iSound. */
1.75 +void CSsndBaseStep::ConstructSoundL()
1.76 + {
1.77 + TPtrC cat;
1.78 + TPtrC ssndFile;
1.79 + TInt toneFreq;
1.80 + TTimeIntervalMicroSeconds32 duration;
1.81 + TInt intdata;
1.82 +
1.83 + TESTL( GetStringFromConfig(ConfigSection(), KSoundCat, cat) );
1.84 + if (cat == KEFile())
1.85 + {
1.86 + TESTL( GetStringFromConfig(ConfigSection(), KSoundFileName, ssndFile) );
1.87 + TBaSystemSoundName filebuf(ssndFile);
1.88 + iSound.SetFileName(filebuf);
1.89 + }
1.90 + else if (cat == KESequence())
1.91 + {
1.92 + TESTL( GetIntFromConfig(ConfigSection(), KFixedSequence, intdata) );
1.93 + iSound.SetFixedSequenceNumber(intdata);
1.94 + }
1.95 + else if (cat == KETone())
1.96 + {
1.97 + TESTL( GetIntFromConfig(ConfigSection(), KToneFrequency, toneFreq) );
1.98 + TESTL( GetIntFromConfig(ConfigSection(), KToneDuration, intdata) );
1.99 + duration = intdata;
1.100 + TBaSystemSoundInfo::TTone tone(toneFreq, duration);
1.101 + iSound.SetTone(tone);
1.102 + }
1.103 + else
1.104 + {
1.105 + ERR_PRINTF3(KUnknownParm, &KSoundCat, &cat);
1.106 + TESTL(EFalse);
1.107 + }
1.108 +
1.109 + TESTL( GetIntFromConfig(ConfigSection(), KMajorUid, intdata) );
1.110 + iSound.iType.iMajor.iUid = intdata;
1.111 + TESTL( GetIntFromConfig(ConfigSection(), KMinorUid, intdata) );
1.112 + iSound.iType.iMinor.iUid = intdata;
1.113 + }
1.114 +
1.115 +/** CGetSoundStep constructor */
1.116 +CGetSoundStep::CGetSoundStep()
1.117 + {
1.118 + SetTestStepName(KGetSound);
1.119 + }
1.120 +
1.121 +/** Implement the pure virtual base class function.
1.122 +Read sound from repository and compare it against
1.123 +the data specified in TEF ini file.
1.124 +*/
1.125 +TVerdict CGetSoundStep::doTestStepL()
1.126 + {
1.127 + ConstructSoundL();
1.128 + RFs dummy;
1.129 +
1.130 + TInt ret = BaSystemSound::GetSound(dummy, iSound.iType, iReadFromRep);
1.131 + if (ret != KErrNone)
1.132 + {
1.133 + // Do it this way for B&R test.
1.134 + SetTestStepError(ret);
1.135 + return EFail;
1.136 + }
1.137 +
1.138 + TBaSystemSoundInfo::TSoundCategory cat = iReadFromRep.SoundCategory();
1.139 + if (cat == TBaSystemSoundInfo::ETone)
1.140 + {
1.141 + TEST(iSound.Tone().iFrequency == iReadFromRep.Tone().iFrequency);
1.142 + TEST(iSound.Tone().iDuration == iReadFromRep.Tone().iDuration);
1.143 + }
1.144 + else if (cat == TBaSystemSoundInfo::ESequence)
1.145 + {
1.146 + TEST(iSound.FixedSequenceNumber() == iReadFromRep.FixedSequenceNumber());
1.147 + }
1.148 + else if (cat == TBaSystemSoundInfo::EFile)
1.149 + {
1.150 + TEST(iSound.FileName() == iReadFromRep.FileName());
1.151 + }
1.152 + return TestStepResult();
1.153 + }
1.154 +
1.155 +/** CSetSoundStep constructor */
1.156 +CSetSoundStep::CSetSoundStep()
1.157 + {
1.158 + SetTestStepName(KSetSound);
1.159 + }
1.160 +
1.161 +/** Implementation of pure virtual base class method.
1.162 +Call SetSoundL and return pass if KErrNone, fail otherwise.
1.163 +*/
1.164 +TVerdict CSetSoundStep::doTestStepL()
1.165 + {
1.166 + ConstructSoundL();
1.167 + RFs dummy;
1.168 + TRAPD(ret, BaSystemSound::SetSoundL(dummy, iSound));
1.169 + if (ret != KErrNone)
1.170 + {
1.171 + // SetTestStepError pass the error code back to TEF.
1.172 + // If the script is expecting this particular error code,
1.173 + // TEF will flip the EFail into EPass.
1.174 + SetTestStepError(ret);
1.175 + return EFail;
1.176 + }
1.177 + return EPass;
1.178 + }
1.179 +
1.180 +/** CSystemSoundFileTestStep constructor */
1.181 +CSystemSoundFileTestStep::CSystemSoundFileTestStep()
1.182 + {
1.183 + SetTestStepName(KSystemSoundFileTest);
1.184 + }
1.185 +
1.186 +/** Implementation of pure virtual base class method.
1.187 +Call the SystemSoundFile API and check the returned
1.188 +filename is the old sound table file.
1.189 +NB: the SystemSoundFile API has been deprecated.
1.190 +*/
1.191 +TVerdict CSystemSoundFileTestStep::doTestStepL()
1.192 + {
1.193 + _LIT(KExpectedName, ":\\system\\data\\syssnd.dat");
1.194 + TFileName fn = BaSystemSound::SystemSoundFile();
1.195 + TInt pos = fn.FindF(KExpectedName);
1.196 + TEST(pos != KErrNotFound);
1.197 + return TestStepResult();
1.198 + }
1.199 +
1.200 +/** CGapTestStep constructor */
1.201 +CGapTestStep::CGapTestStep()
1.202 + {
1.203 + SetTestStepName(KGapTest);
1.204 + }
1.205 +
1.206 +/** Implementation of pure virtual base class method.
1.207 +Create a setting at key 7 leaving a gap at key 3.
1.208 +Then call SetSoundL. The call should fail with KErrCorrupt.
1.209 +*/
1.210 +TVerdict CGapTestStep::doTestStepL()
1.211 + {
1.212 + const TInt32 KKeyWithGap = 7;
1.213 + const TInt KSomeInteger = 1;
1.214 + CRepository* rep = CRepository::NewLC(KSystemSoundRepositoryUID);
1.215 + TESTL(rep->Create(KKeyWithGap, KSomeInteger) == KErrNone);
1.216 +
1.217 + TUid minorUid = {KSomeInteger};
1.218 + TBaSystemSoundType soundId(KLockoutTestSoundCategory, minorUid);
1.219 + TBaSystemSoundInfo sound(soundId, KSomeInteger);
1.220 +
1.221 + RFs dummy;
1.222 + TRAPD(ret, BaSystemSound::SetSoundL(dummy, sound));
1.223 + TEST(ret == KErrCorrupt);
1.224 +
1.225 + CleanupStack::PopAndDestroy(rep);
1.226 + return TestStepResult();
1.227 + }
1.228 +
1.229 +/** CSoundFileNoPathTestStep constructor */
1.230 +CSoundFileNoPathTestStep::CSoundFileNoPathTestStep()
1.231 + {
1.232 + SetTestStepName(KSoundFileNoPathTest);
1.233 + }
1.234 +
1.235 +/** Implementation of pure virtual base class method.
1.236 +Call SetSoundL with a wav filename which does not contain path.
1.237 +BaSystemSound should panic.
1.238 +*/
1.239 +TVerdict CSoundFileNoPathTestStep::doTestStepL()
1.240 + {
1.241 +// BaSystemSound only trigger EBafPanicSystemSoundNoPath on udeb.
1.242 +// So on urel do it ourself.
1.243 +#ifndef _DEBUG
1.244 + Panic(EBafPanicSystemSoundNoPath);
1.245 +#else
1.246 + const TBaSystemSoundUid KMajorUid = {0x888};
1.247 + TBaSystemSoundType soundId(KMajorUid);
1.248 +
1.249 + // side bar to fill a code coverage gap in TTone::IsNull
1.250 + TTimeIntervalMicroSeconds32 duration = 10;
1.251 + TBaSystemSoundInfo::TTone tone(0, duration);
1.252 + TBaSystemSoundInfo sound(soundId, tone);
1.253 + TBaSystemSoundInfo::TSoundCategory cat = sound.SoundCategory();
1.254 + TEST(cat == TBaSystemSoundInfo::ETone);
1.255 +
1.256 + // now back to the panic test
1.257 + _LIT(KSoundFileName, "rr.wav");
1.258 + TBaSystemSoundName filename(KSoundFileName);
1.259 + sound.SetFileName(filename);
1.260 +
1.261 + RFs dummy;
1.262 + // Following line should panic
1.263 + BaSystemSound::SetSoundL(dummy, sound);
1.264 +#endif
1.265 + return TestStepResult();
1.266 + }
1.267 +
1.268 +/** CCorruptSoundStep constructor */
1.269 +CCorruptSoundStep::CCorruptSoundStep()
1.270 + {
1.271 + SetTestStepName(KCorruptSound);
1.272 + }
1.273 +
1.274 +/** Implementation of pure virtual base class method.
1.275 +Corrupt the soundtype, sound cat. and path length fields
1.276 +in the sound data and verify GetSound returns KErrCorrupt.
1.277 +*/
1.278 +TVerdict CCorruptSoundStep::doTestStepL()
1.279 + {
1.280 + ConstructSoundL();
1.281 + RFs dummy;
1.282 + TInt ret(KErrNone);
1.283 + BaSystemSound::SetSoundL(dummy, iSound);
1.284 +
1.285 + // make a connection to CentRep to directly manipulate the
1.286 + // setting.
1.287 + CRepository* rep = CRepository::NewLC(KSystemSoundRepositoryUID);
1.288 + HBufC8* orighbuf8 = HBufC8::NewLC(sizeof(TBaSystemSoundInfo));
1.289 + TPtr8 origbuf8 = orighbuf8->Des();
1.290 +
1.291 + const TUint32 KKeyOfFirstSound = 3;
1.292 + ret = rep->Get(KKeyOfFirstSound, origbuf8);
1.293 + TESTL(ret == KErrNone);
1.294 +
1.295 + // need a running copy of the sound data
1.296 + HBufC8* temphbuf8 = orighbuf8->AllocLC();
1.297 + TPtr8 tempbuf8 = temphbuf8->Des();
1.298 +
1.299 + //Test corrupting the major sound Id
1.300 + tempbuf8[0] = 1;
1.301 + tempbuf8[1] = 2;
1.302 + tempbuf8[2] = 3;
1.303 + tempbuf8[3] = 4;
1.304 + TESTL(rep->Set(KKeyOfFirstSound, tempbuf8) == KErrNone);
1.305 + ret = BaSystemSound::GetSound(dummy, iSound.iType, iReadFromRep);
1.306 + TEST(ret == KErrCorrupt);
1.307 +
1.308 + //Test corrupting the sound cat. field
1.309 + //First restore original data.
1.310 + tempbuf8.Copy(origbuf8);
1.311 + const TInt KSoundCatLocation = 16;
1.312 + tempbuf8[KSoundCatLocation] = 255;
1.313 + tempbuf8[KSoundCatLocation+1] = 127;
1.314 + TESTL(rep->Set(KKeyOfFirstSound, tempbuf8) == KErrNone);
1.315 + ret = BaSystemSound::GetSound(dummy, iSound.iType, iReadFromRep);
1.316 + TEST(ret == KErrCorrupt);
1.317 +
1.318 + //Test corrupting the path length field
1.319 + //First restore original data.
1.320 + tempbuf8.Copy(origbuf8);
1.321 + const TInt KPathLengthLocation = 20;
1.322 + tempbuf8[KPathLengthLocation] = 255;
1.323 + tempbuf8[KPathLengthLocation+1] = 127;
1.324 + TESTL(rep->Set(KKeyOfFirstSound, tempbuf8) == KErrNone);
1.325 + ret = BaSystemSound::GetSound(dummy, iSound.iType, iReadFromRep);
1.326 + TEST(ret == KErrCorrupt);
1.327 +
1.328 + //Corruption of other fields are not detectable.
1.329 +
1.330 + //If we restore the original data in CentRep, GetSound should pass.
1.331 + tempbuf8.Copy(origbuf8);
1.332 + TESTL(rep->Set(KKeyOfFirstSound, tempbuf8) == KErrNone);
1.333 + ret = BaSystemSound::GetSound(dummy, iSound.iType, iReadFromRep);
1.334 + TEST(ret == KErrNone);
1.335 +
1.336 + CleanupStack::PopAndDestroy(temphbuf8);
1.337 + CleanupStack::PopAndDestroy(orighbuf8);
1.338 + CleanupStack::PopAndDestroy(rep);
1.339 + return TestStepResult();
1.340 + }
1.341 +
1.342 +/** Derive from CBaSsndStore to force collision between
1.343 +concurrent set sound threads.
1.344 +*/
1.345 +class CCollisionSsndStore : public CBaSsndStore
1.346 + {
1.347 +public:
1.348 + static CCollisionSsndStore* NewLC(TTimeIntervalMicroSeconds32 aDelay);
1.349 + virtual void KeyOfSoundTypeL(TBaSystemSoundType& aSoundType, TUint32& aKey) const;
1.350 + virtual void SetSoundInTransactionL(TBaSystemSoundType& aSoundType,
1.351 + const TDesC8& aDes8) const;
1.352 + inline TUint32 NumCollisions() const {return iNumCollisions;}
1.353 + inline TUint32 Key() const {return iKey;}
1.354 +
1.355 +private:
1.356 + inline CCollisionSsndStore(const TTimeIntervalMicroSeconds32 aDelay)
1.357 + : iDelay(aDelay), iNumCollisions(0), iKey(NCentralRepositoryConstants::KUnspecifiedKey) {}
1.358 + inline void ConstructL() {CBaSsndStore::ConstructL();}
1.359 + TInt RecordKeyPosition(TBaSystemSoundType& aSoundType) const;
1.360 +
1.361 +private:
1.362 + /** indicate how long to pause in the middle of the transaction.
1.363 + The pause causes concurrent transactions to fail. */
1.364 + TTimeIntervalMicroSeconds32 iDelay;
1.365 +
1.366 + /** Record how many times transaction commit failed. Mutable because
1.367 + SetSoundInTransactionL in production code is a const method. */
1.368 + mutable TUint32 iNumCollisions;
1.369 +
1.370 + /** Record the CentRep key used to store the sound. Mutable because
1.371 + KeyOfSoundTypeL in production code is a const method. */
1.372 + mutable TUint32 iKey;
1.373 + };
1.374 +
1.375 +/** static factory method to instantiate CCollisionSsndStore */
1.376 +CCollisionSsndStore* CCollisionSsndStore::NewLC(
1.377 + const TTimeIntervalMicroSeconds32 aDelay)
1.378 + {
1.379 + CCollisionSsndStore* self = new (ELeave) CCollisionSsndStore(aDelay);
1.380 + CleanupStack::PushL(self);
1.381 + self->ConstructL();
1.382 + return self;
1.383 + }
1.384 +
1.385 +/** After using base class method to get the key, add a delay
1.386 +to cause concurrent threads to collide.
1.387 +*/
1.388 +void CCollisionSsndStore::KeyOfSoundTypeL(TBaSystemSoundType& aSoundType,
1.389 + TUint32& aKey) const
1.390 + {
1.391 + CBaSsndStore::KeyOfSoundTypeL(aSoundType, aKey);
1.392 + User::AfterHighRes(iDelay);
1.393 + }
1.394 +
1.395 +/** After using base class method to do SetSound in transaction,
1.396 +check the return code. Record commitFail condition. If succes,
1.397 +record the key position where the SoundType is stored.
1.398 +*/
1.399 +void CCollisionSsndStore::SetSoundInTransactionL(
1.400 + TBaSystemSoundType& aSoundType,
1.401 + const TDesC8& aDes8) const
1.402 + {
1.403 + // call base class method to do the real work
1.404 + TRAPD(ret, CBaSsndStore::SetSoundInTransactionL(aSoundType, aDes8));
1.405 +
1.406 + // record any collision
1.407 + if (KErrLocked == ret || KErrAbort == ret)
1.408 + {
1.409 + iNumCollisions++;
1.410 + }
1.411 + else if (KErrNone == ret)
1.412 + {
1.413 + ret = RecordKeyPosition(aSoundType);
1.414 + }
1.415 + else if (KErrNoMemory != ret)
1.416 + {
1.417 + RDebug::Print(_L("tef_ssnd test: unexpected error %d"), ret);
1.418 + }
1.419 +
1.420 + User::LeaveIfError(ret);
1.421 + }
1.422 +
1.423 +/** Provide similar function of CBaSsndStore::FindKeyL.
1.424 +FindKeyL ignores duplicate SoundType in repository. It just
1.425 +returns the first key in the array. Test harness cares because
1.426 +it should fail the test if duplicate entries are detected.
1.427 +*/
1.428 +TInt CCollisionSsndStore::RecordKeyPosition(TBaSystemSoundType& aSoundType) const
1.429 + {
1.430 + const TUint32 KSoundTypePartialKey = 0x2;
1.431 + const TUint32 KSsndKeyMask = 0x3;
1.432 + TPckg<TBaSystemSoundType> target(aSoundType);
1.433 + RArray<TUint32> foundIds;
1.434 +
1.435 + TInt ret(KErrNone);
1.436 + TRAPD(err, ret = iRepository->FindEqL(KSoundTypePartialKey,
1.437 + KSsndKeyMask, target, foundIds));
1.438 + if (err != KErrNone)
1.439 + {
1.440 + ret = err; // KErrNoMemory
1.441 + }
1.442 +
1.443 + if (ret == KErrNone)
1.444 + {
1.445 + iKey = foundIds[0];
1.446 + if (foundIds.Count() > 1)
1.447 + {
1.448 + ret = KErrWrite;
1.449 + }
1.450 +
1.451 + foundIds.Reset();
1.452 + }
1.453 +
1.454 + return ret;
1.455 + }
1.456 +
1.457 +//
1.458 +// Concurrent SetSoundL teststep
1.459 +//
1.460 +
1.461 +_LIT(KNumWorkers, "NumWorkers");
1.462 +_LIT(KWorkerId, "WorkerId");
1.463 +_LIT(KSameSound, "SameSsndId");
1.464 +
1.465 +const TTimeIntervalMicroSeconds32 KCollisionDelay = 500000;
1.466 +const TInt KMaxNumWorkers = 3;
1.467 +TWorkerData ConcurrentResults[KMaxNumWorkers];
1.468 +
1.469 +/** CConcurrentStep constructor */
1.470 +CConcurrentStep::CConcurrentStep()
1.471 + {
1.472 + SetTestStepName(KConcurrentSetSound);
1.473 + }
1.474 +
1.475 +/** This postamble insures that if a worker thread leaves in
1.476 +doTestStepL, the iDone flag is still set.
1.477 +*/
1.478 +TVerdict CConcurrentStep::doTestStepPostambleL()
1.479 + {
1.480 + if (iWorkerId && iWorkerId <= KMaxNumWorkers)
1.481 + {
1.482 + ConcurrentResults[iWorkerId - 1].iDone = ETrue;
1.483 + }
1.484 +
1.485 + // To silent Leave scan.
1.486 + CTestStep::doTestStepPostambleL();
1.487 +
1.488 + return TestStepResult();
1.489 + }
1.490 +
1.491 +/** Implementation of pure virtual base class method.
1.492 +Read from config file to determine if the current thread is
1.493 +master or worker. Workers invoke CCollisionSsndStore::SetSoundL.
1.494 +Master summarises the test results.
1.495 +*/
1.496 +TVerdict CConcurrentStep::doTestStepL()
1.497 + {
1.498 + const TDesC& section = ConfigSection();
1.499 + if (!GetIntFromConfig(section, KWorkerId, iWorkerId))
1.500 + {
1.501 + TInt numWorkers;
1.502 + // This is the master thread. It does not call the
1.503 + // SetSoundL API. It just sets up the concurrent data,
1.504 + // wait for the test to complete, and tally up results.
1.505 + TESTL( GetIntFromConfig(section, KNumWorkers, numWorkers) );
1.506 + TBool sameSsnd = section.FindF(KSameSound) >= 0;
1.507 + DoMasterTaskL(numWorkers, sameSsnd);
1.508 + return TestStepResult();
1.509 + }
1.510 +
1.511 + // Getting here means this is a worker thread.
1.512 + TESTL(iWorkerId <= KMaxNumWorkers);
1.513 +
1.514 + // pause a bit to ensure master and other workers are
1.515 + // all started.
1.516 + User::AfterHighRes(200000);
1.517 +
1.518 + ConstructSoundL();
1.519 + CCollisionSsndStore* ssndCollisionSet =
1.520 + CCollisionSsndStore::NewLC(KCollisionDelay);
1.521 + ssndCollisionSet->SetSoundL(iSound);
1.522 +
1.523 + TWorkerData& mySlot = ConcurrentResults[iWorkerId - 1];
1.524 + mySlot.iTranFailCount = ssndCollisionSet->NumCollisions();
1.525 + mySlot.iKey = ssndCollisionSet->Key();
1.526 + mySlot.iDone = ETrue;
1.527 +
1.528 + CleanupStack::PopAndDestroy(ssndCollisionSet);
1.529 + return TestStepResult();
1.530 + }
1.531 +
1.532 +/** Set up global data and then wait for the concurrent
1.533 +worker threads. When workers all done, verify that
1.534 +1. collisions did occur and
1.535 +2. collisions did not cause errors in generating the hash keys.
1.536 +*/
1.537 +void CConcurrentStep::DoMasterTaskL(TInt aNumWorkers,
1.538 + TBool aSsndIdAreSame)
1.539 + {
1.540 + if (aNumWorkers > KMaxNumWorkers)
1.541 + {
1.542 + // If there is valid reason to test more than 3 concurrent
1.543 + // threads, CBaSsndStore::SetSoundL needs to bump up the
1.544 + // retry count. 3 retries in production code can handle many
1.545 + // concurrent threads. But in testing collision is guranteed
1.546 + // to happen. The retry count needs to be same as number of
1.547 + // workers.
1.548 + _LIT(KTooMany, "Not allow to have more than %d concurrent workers.");
1.549 + ERR_PRINTF2(KTooMany, KMaxNumWorkers);
1.550 + TESTL(EFalse);
1.551 + }
1.552 +
1.553 + TWorkerData nullData;
1.554 + TInt i;
1.555 + for (i = 0; i < aNumWorkers; i++)
1.556 + {
1.557 + ConcurrentResults[i] = nullData;
1.558 + }
1.559 +
1.560 + // Probably should convert KCollisionDelay.Int() to seconds
1.561 + // and multiply by num of workers. But 12 seconds for max of 3
1.562 + // workers should be plenty.
1.563 + TInt j;
1.564 + TInt doneCount = 0;
1.565 + TTimeIntervalMicroSeconds32 halfSec(500000);
1.566 + const TInt KNumLoops = 24;
1.567 + for (i = 0; i < KNumLoops && doneCount < aNumWorkers; i++)
1.568 + {
1.569 + User::AfterHighRes(halfSec);
1.570 +
1.571 + // count number of dones.
1.572 + for (j = 0, doneCount = 0; j < aNumWorkers; j++)
1.573 + {
1.574 + if (ConcurrentResults[j].iDone)
1.575 + {
1.576 + doneCount++;
1.577 + }
1.578 + }
1.579 + }
1.580 +
1.581 + TEST(doneCount == aNumWorkers);
1.582 +
1.583 + // If there are 3 workers, expect 2+1 = 3 collisions.
1.584 + // But to keep things simple, just use (aNumWorkers - 1)
1.585 + TInt minCollisions = aNumWorkers - 1;
1.586 + TInt numCommitFails = 0;
1.587 + for (j = 0; j < aNumWorkers; j++)
1.588 + {
1.589 + numCommitFails += ConcurrentResults[j].iTranFailCount;
1.590 + }
1.591 +
1.592 + TEST(numCommitFails >= minCollisions);
1.593 +
1.594 + // Next check the sounds are correctly created in CentRep.
1.595 + for (i = 0; i < (aNumWorkers - 1); i++)
1.596 + {
1.597 + TUint32 key = ConcurrentResults[i].iKey;
1.598 +
1.599 + if (aSsndIdAreSame)
1.600 + {
1.601 + TEST(key == ConcurrentResults[i+1].iKey);
1.602 + }
1.603 + else
1.604 + {
1.605 + for (j = i+1; j < aNumWorkers; j++)
1.606 + {
1.607 + TEST(key != ConcurrentResults[j].iKey);
1.608 + }
1.609 + }
1.610 + }
1.611 +
1.612 + }
1.613 +
1.614 +/** CLockoutTestStep constructor */
1.615 +CLockoutTestStep::CLockoutTestStep()
1.616 + {
1.617 + SetTestStepName(KLockoutTest);
1.618 + }
1.619 +
1.620 +/** Implementation of pure virtual base class method.
1.621 +Backup or Restore operation is running in parallel.
1.622 +This test waits for the P&S KUidBackupRestoreKey become
1.623 +active and then call SetSoundL and CBaSystemSoundArray::RestoreL.
1.624 +Expects KErrServerBusy/KErrAbort/KErrLocked to be returned.
1.625 +*/
1.626 +TVerdict CLockoutTestStep::doTestStepL()
1.627 + {
1.628 +using namespace conn;
1.629 +
1.630 + const TBool KLogOnError = ETrue;
1.631 +
1.632 + RProperty burKey;
1.633 + TInt ret = burKey.Attach(KUidSystemCategory, KUidBackupRestoreKey);
1.634 + TEST1L(ret == KErrNone, KLogOnError);
1.635 +
1.636 + TRequestStatus s;
1.637 + burKey.Subscribe(s);
1.638 + User::WaitForRequest(s);
1.639 + TEST1L(s.Int() == KErrNone, KLogOnError);
1.640 +
1.641 + TInt burKeyVal = 0;
1.642 + ret = burKey.Get(burKeyVal);
1.643 + TEST1L(ret == KErrNone, KLogOnError);
1.644 +
1.645 + burKeyVal &= KBURPartTypeMask;
1.646 + const TInt KBurInProgress = EBURBackupFull |
1.647 + EBURBackupPartial |
1.648 + EBURRestoreFull |
1.649 + EBURRestorePartial;
1.650 + TEST1L(burKeyVal & KBurInProgress, KLogOnError);
1.651 +
1.652 + burKey.Close();
1.653 +
1.654 + TRAP(ret, addSoundInstanceL(1));
1.655 + TEST1(ret == KErrServerBusy || ret == KErrAbort, KLogOnError);
1.656 +
1.657 + TRAP(ret, readSoundsBackL());
1.658 + if (burKeyVal & EBURRestoreFull || burKeyVal & EBURRestorePartial)
1.659 + {
1.660 + TEST1(ret == KErrServerBusy, KLogOnError);
1.661 + }
1.662 + else
1.663 + {
1.664 + TEST1(ret == KErrNone, KLogOnError);
1.665 + }
1.666 +
1.667 + return TestStepResult();
1.668 + }
1.669 +
1.670 +/** Construct a sound and store it in repository.
1.671 +@param aSequence used as both minor UID and sound sequence.
1.672 +@leave any of the system-wide errors.
1.673 +*/
1.674 +void CLockoutTestStep::addSoundInstanceL(TInt32 aSequence)
1.675 + {
1.676 + TUid minorUid = {aSequence};
1.677 + TBaSystemSoundType soundId(KLockoutTestSoundCategory, minorUid);
1.678 + TBaSystemSoundInfo sound(soundId, aSequence);
1.679 +
1.680 + RFs dummy;
1.681 + BaSystemSound::SetSoundL(dummy, sound);
1.682 + }
1.683 +
1.684 +/** use CBaSystemSoundArray::RestoreL to read back all
1.685 +the sounds in KLockoutTestSoundCategory.
1.686 +@leave any of the system-wide errors.
1.687 +*/
1.688 +void CLockoutTestStep::readSoundsBackL()
1.689 + {
1.690 + CBaSystemSoundArray* reader = CBaSystemSoundArray::NewLC();
1.691 +
1.692 + RFs dummy;
1.693 + reader->RestoreL(dummy, KLockoutTestSoundCategory);
1.694 + CleanupStack::PopAndDestroy(reader);
1.695 + }
1.696 +