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.
sl@0
     1
// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
//
sl@0
    15
sl@0
    16
/**
sl@0
    17
 @file
sl@0
    18
 @internalComponent
sl@0
    19
*/
sl@0
    20
sl@0
    21
#include <e32property.h>
sl@0
    22
#include <connect/sbdefs.h>
sl@0
    23
#include <centralrepository.h>
sl@0
    24
#include <baflpan.h>
sl@0
    25
#include <bassnd.h>
sl@0
    26
#include "ssndteststep.h"
sl@0
    27
#include "BaSsndStore.h"
sl@0
    28
#include "BASSNDUID.h"
sl@0
    29
sl@0
    30
const TBaSystemSoundUid KLockoutTestSoundCategory = {288};
sl@0
    31
sl@0
    32
/** CResetDbStep constructor */
sl@0
    33
CResetDbStep::CResetDbStep()
sl@0
    34
	{
sl@0
    35
	SetTestStepName(KResetDb);
sl@0
    36
	}
sl@0
    37
sl@0
    38
/** Implementation of the pure virtual base class function.
sl@0
    39
This teststep does not really test anything. It serves as
sl@0
    40
a helper of other steps to clear the sound table at the 
sl@0
    41
beginning of a test.
sl@0
    42
*/
sl@0
    43
TVerdict CResetDbStep::doTestStepL()
sl@0
    44
	{
sl@0
    45
	CRepository* repository = CRepository::NewLC(KSystemSoundRepositoryUID);
sl@0
    46
	TESTL(repository != NULL);
sl@0
    47
	TEST(repository->Reset() == KErrNone);
sl@0
    48
sl@0
    49
	CleanupStack::PopAndDestroy(repository);
sl@0
    50
	return TestStepResult();
sl@0
    51
	}
sl@0
    52
sl@0
    53
//
sl@0
    54
// GetSound/SetSound
sl@0
    55
//
sl@0
    56
_LIT(KUnknownParm, "Err reading INI section %S, unknown value %S");
sl@0
    57
sl@0
    58
_LIT(KSoundCat, "Category");
sl@0
    59
_LIT(KEFile, "EFile");
sl@0
    60
_LIT(KESequence, "ESequence");
sl@0
    61
_LIT(KETone, "ETone");
sl@0
    62
sl@0
    63
_LIT(KSoundFileName, "Filename");
sl@0
    64
_LIT(KFixedSequence, "SequenceNum");
sl@0
    65
_LIT(KToneFrequency, "Frequency");
sl@0
    66
_LIT(KToneDuration, "Duration");
sl@0
    67
sl@0
    68
_LIT(KMajorUid, "MajorUid");
sl@0
    69
_LIT(KMinorUid, "MinorUid");
sl@0
    70
sl@0
    71
/** Read data from the TEF ini file to construct iSound. */
sl@0
    72
void CSsndBaseStep::ConstructSoundL()
sl@0
    73
	{
sl@0
    74
	TPtrC cat;
sl@0
    75
	TPtrC ssndFile;
sl@0
    76
	TInt toneFreq;
sl@0
    77
	TTimeIntervalMicroSeconds32 duration;
sl@0
    78
	TInt intdata;
sl@0
    79
sl@0
    80
	TESTL( GetStringFromConfig(ConfigSection(), KSoundCat, cat) );
sl@0
    81
	if (cat == KEFile())
sl@0
    82
		{
sl@0
    83
		TESTL( GetStringFromConfig(ConfigSection(), KSoundFileName, ssndFile) );
sl@0
    84
		TBaSystemSoundName filebuf(ssndFile);
sl@0
    85
		iSound.SetFileName(filebuf);
sl@0
    86
		}
sl@0
    87
	else if (cat == KESequence())
sl@0
    88
		{
sl@0
    89
		TESTL( GetIntFromConfig(ConfigSection(), KFixedSequence, intdata) );
sl@0
    90
		iSound.SetFixedSequenceNumber(intdata);
sl@0
    91
		}
sl@0
    92
	else if (cat == KETone())
sl@0
    93
		{
sl@0
    94
		TESTL( GetIntFromConfig(ConfigSection(), KToneFrequency, toneFreq) );
sl@0
    95
		TESTL( GetIntFromConfig(ConfigSection(), KToneDuration, intdata) );
sl@0
    96
		duration = intdata;
sl@0
    97
		TBaSystemSoundInfo::TTone tone(toneFreq, duration);
sl@0
    98
		iSound.SetTone(tone);
sl@0
    99
		}
sl@0
   100
	else
sl@0
   101
		{
sl@0
   102
		ERR_PRINTF3(KUnknownParm, &KSoundCat, &cat);
sl@0
   103
		TESTL(EFalse);
sl@0
   104
		}
sl@0
   105
sl@0
   106
	TESTL( GetIntFromConfig(ConfigSection(), KMajorUid, intdata) );
sl@0
   107
	iSound.iType.iMajor.iUid = intdata;
sl@0
   108
	TESTL( GetIntFromConfig(ConfigSection(), KMinorUid, intdata) );
sl@0
   109
	iSound.iType.iMinor.iUid = intdata;
sl@0
   110
	}
sl@0
   111
sl@0
   112
/** CGetSoundStep constructor */
sl@0
   113
CGetSoundStep::CGetSoundStep()
sl@0
   114
	{
sl@0
   115
	SetTestStepName(KGetSound);
sl@0
   116
	}
sl@0
   117
sl@0
   118
/** Implement the pure virtual base class function.
sl@0
   119
Read sound from repository and compare it against
sl@0
   120
the data specified in TEF ini file.
sl@0
   121
*/
sl@0
   122
TVerdict CGetSoundStep::doTestStepL()
sl@0
   123
	{
sl@0
   124
	ConstructSoundL();
sl@0
   125
	RFs dummy;
sl@0
   126
sl@0
   127
	TInt ret = BaSystemSound::GetSound(dummy, iSound.iType, iReadFromRep);
sl@0
   128
	if (ret != KErrNone)
sl@0
   129
		{
sl@0
   130
		// Do it this way for B&R test.
sl@0
   131
		SetTestStepError(ret);
sl@0
   132
		return EFail;
sl@0
   133
		}
sl@0
   134
sl@0
   135
	TBaSystemSoundInfo::TSoundCategory cat = iReadFromRep.SoundCategory();
sl@0
   136
	if (cat == TBaSystemSoundInfo::ETone)
sl@0
   137
		{
sl@0
   138
		TEST(iSound.Tone().iFrequency == iReadFromRep.Tone().iFrequency);
sl@0
   139
		TEST(iSound.Tone().iDuration == iReadFromRep.Tone().iDuration);
sl@0
   140
		}
sl@0
   141
	else if (cat == TBaSystemSoundInfo::ESequence)
sl@0
   142
		{
sl@0
   143
		TEST(iSound.FixedSequenceNumber() == iReadFromRep.FixedSequenceNumber());
sl@0
   144
		}
sl@0
   145
	else if (cat == TBaSystemSoundInfo::EFile)
sl@0
   146
		{
sl@0
   147
		TEST(iSound.FileName() == iReadFromRep.FileName());
sl@0
   148
		}
sl@0
   149
	return TestStepResult();
sl@0
   150
	}
sl@0
   151
sl@0
   152
/** CSetSoundStep constructor */
sl@0
   153
CSetSoundStep::CSetSoundStep()
sl@0
   154
	{
sl@0
   155
	SetTestStepName(KSetSound);
sl@0
   156
	}
sl@0
   157
sl@0
   158
/** Implementation of pure virtual base class method.
sl@0
   159
Call SetSoundL and return pass if KErrNone, fail otherwise.
sl@0
   160
*/
sl@0
   161
TVerdict CSetSoundStep::doTestStepL()
sl@0
   162
	{
sl@0
   163
	ConstructSoundL();
sl@0
   164
	RFs dummy;
sl@0
   165
	TRAPD(ret, BaSystemSound::SetSoundL(dummy, iSound));
sl@0
   166
	if (ret != KErrNone)
sl@0
   167
		{
sl@0
   168
		// SetTestStepError pass the error code back to TEF.
sl@0
   169
		// If the script is expecting this particular error code,
sl@0
   170
		// TEF will flip the EFail into EPass.
sl@0
   171
		SetTestStepError(ret);
sl@0
   172
		return EFail;
sl@0
   173
		}
sl@0
   174
	return EPass;
sl@0
   175
	}
sl@0
   176
sl@0
   177
/** CSystemSoundFileTestStep constructor */
sl@0
   178
CSystemSoundFileTestStep::CSystemSoundFileTestStep()
sl@0
   179
	{
sl@0
   180
	SetTestStepName(KSystemSoundFileTest);
sl@0
   181
	}
sl@0
   182
sl@0
   183
/** Implementation of pure virtual base class method.
sl@0
   184
Call the SystemSoundFile API and check the returned
sl@0
   185
filename is the old sound table file.
sl@0
   186
NB: the SystemSoundFile API has been deprecated.
sl@0
   187
*/
sl@0
   188
TVerdict CSystemSoundFileTestStep::doTestStepL()
sl@0
   189
	{
sl@0
   190
	_LIT(KExpectedName, ":\\system\\data\\syssnd.dat");
sl@0
   191
	TFileName fn = BaSystemSound::SystemSoundFile();
sl@0
   192
	TInt pos = fn.FindF(KExpectedName);
sl@0
   193
	TEST(pos != KErrNotFound);
sl@0
   194
	return TestStepResult();
sl@0
   195
	}
sl@0
   196
sl@0
   197
/** CGapTestStep constructor */
sl@0
   198
CGapTestStep::CGapTestStep()
sl@0
   199
	{
sl@0
   200
	SetTestStepName(KGapTest);
sl@0
   201
	}
sl@0
   202
sl@0
   203
/** Implementation of pure virtual base class method.
sl@0
   204
Create a setting at key 7 leaving a gap at key 3. 
sl@0
   205
Then call SetSoundL. The call should fail with KErrCorrupt.
sl@0
   206
*/
sl@0
   207
TVerdict CGapTestStep::doTestStepL()
sl@0
   208
	{
sl@0
   209
	const TInt32 KKeyWithGap = 7;
sl@0
   210
	const TInt KSomeInteger = 1;
sl@0
   211
	CRepository* rep = CRepository::NewLC(KSystemSoundRepositoryUID);
sl@0
   212
	TESTL(rep->Create(KKeyWithGap, KSomeInteger) == KErrNone);
sl@0
   213
	
sl@0
   214
	TUid minorUid = {KSomeInteger};
sl@0
   215
	TBaSystemSoundType soundId(KLockoutTestSoundCategory, minorUid);
sl@0
   216
	TBaSystemSoundInfo sound(soundId, KSomeInteger);
sl@0
   217
sl@0
   218
	RFs dummy;
sl@0
   219
	TRAPD(ret, BaSystemSound::SetSoundL(dummy, sound));
sl@0
   220
	TEST(ret == KErrCorrupt);
sl@0
   221
sl@0
   222
	CleanupStack::PopAndDestroy(rep);	
sl@0
   223
	return TestStepResult();
sl@0
   224
	}
sl@0
   225
sl@0
   226
/** CSoundFileNoPathTestStep constructor */
sl@0
   227
CSoundFileNoPathTestStep::CSoundFileNoPathTestStep()
sl@0
   228
	{
sl@0
   229
	SetTestStepName(KSoundFileNoPathTest);
sl@0
   230
	}
sl@0
   231
sl@0
   232
/** Implementation of pure virtual base class method.
sl@0
   233
Call SetSoundL with a wav filename which does not contain path.
sl@0
   234
BaSystemSound should panic.
sl@0
   235
*/
sl@0
   236
TVerdict CSoundFileNoPathTestStep::doTestStepL()
sl@0
   237
	{
sl@0
   238
// BaSystemSound only trigger EBafPanicSystemSoundNoPath on udeb.
sl@0
   239
// So on urel do it ourself.
sl@0
   240
#ifndef _DEBUG
sl@0
   241
	Panic(EBafPanicSystemSoundNoPath);
sl@0
   242
#else
sl@0
   243
	const TBaSystemSoundUid KMajorUid = {0x888};
sl@0
   244
	TBaSystemSoundType soundId(KMajorUid);
sl@0
   245
sl@0
   246
	// side bar to fill a code coverage gap in TTone::IsNull 
sl@0
   247
	TTimeIntervalMicroSeconds32 duration = 10;
sl@0
   248
	TBaSystemSoundInfo::TTone tone(0, duration);
sl@0
   249
	TBaSystemSoundInfo sound(soundId, tone);
sl@0
   250
	TBaSystemSoundInfo::TSoundCategory cat = sound.SoundCategory();
sl@0
   251
	TEST(cat == TBaSystemSoundInfo::ETone);
sl@0
   252
	
sl@0
   253
	// now back to the panic test
sl@0
   254
	_LIT(KSoundFileName, "rr.wav");
sl@0
   255
	TBaSystemSoundName filename(KSoundFileName);
sl@0
   256
	sound.SetFileName(filename);
sl@0
   257
sl@0
   258
	RFs dummy;
sl@0
   259
	// Following line should panic
sl@0
   260
	BaSystemSound::SetSoundL(dummy, sound);
sl@0
   261
#endif
sl@0
   262
	return TestStepResult();
sl@0
   263
	}
sl@0
   264
sl@0
   265
/** CCorruptSoundStep constructor */
sl@0
   266
CCorruptSoundStep::CCorruptSoundStep()
sl@0
   267
	{
sl@0
   268
	SetTestStepName(KCorruptSound);
sl@0
   269
	}
sl@0
   270
sl@0
   271
/** Implementation of pure virtual base class method.
sl@0
   272
Corrupt the soundtype, sound cat. and path length fields
sl@0
   273
in the sound data and verify GetSound returns KErrCorrupt.
sl@0
   274
*/
sl@0
   275
TVerdict CCorruptSoundStep::doTestStepL()
sl@0
   276
	{
sl@0
   277
	ConstructSoundL();
sl@0
   278
	RFs dummy;
sl@0
   279
	TInt ret(KErrNone);
sl@0
   280
	BaSystemSound::SetSoundL(dummy, iSound);
sl@0
   281
	
sl@0
   282
	// make a connection to CentRep to directly manipulate the
sl@0
   283
	// setting.
sl@0
   284
	CRepository* rep = CRepository::NewLC(KSystemSoundRepositoryUID);
sl@0
   285
	HBufC8* orighbuf8 = HBufC8::NewLC(sizeof(TBaSystemSoundInfo));
sl@0
   286
	TPtr8 origbuf8 = orighbuf8->Des();
sl@0
   287
sl@0
   288
	const TUint32 KKeyOfFirstSound = 3;
sl@0
   289
	ret = rep->Get(KKeyOfFirstSound, origbuf8);
sl@0
   290
	TESTL(ret == KErrNone);
sl@0
   291
sl@0
   292
	// need a running copy of the sound data
sl@0
   293
	HBufC8* temphbuf8 = orighbuf8->AllocLC();
sl@0
   294
	TPtr8 tempbuf8 = temphbuf8->Des();
sl@0
   295
sl@0
   296
	//Test corrupting the major sound Id
sl@0
   297
	tempbuf8[0] = 1;
sl@0
   298
	tempbuf8[1] = 2;
sl@0
   299
	tempbuf8[2] = 3;
sl@0
   300
	tempbuf8[3] = 4;
sl@0
   301
	TESTL(rep->Set(KKeyOfFirstSound, tempbuf8) == KErrNone);
sl@0
   302
	ret = BaSystemSound::GetSound(dummy, iSound.iType, iReadFromRep);
sl@0
   303
	TEST(ret == KErrCorrupt);
sl@0
   304
sl@0
   305
	//Test corrupting the sound cat. field
sl@0
   306
	//First restore original data.
sl@0
   307
	tempbuf8.Copy(origbuf8);
sl@0
   308
	const TInt KSoundCatLocation = 16;
sl@0
   309
	tempbuf8[KSoundCatLocation] = 255;
sl@0
   310
	tempbuf8[KSoundCatLocation+1] = 127;
sl@0
   311
	TESTL(rep->Set(KKeyOfFirstSound, tempbuf8) == KErrNone);
sl@0
   312
	ret = BaSystemSound::GetSound(dummy, iSound.iType, iReadFromRep);
sl@0
   313
	TEST(ret == KErrCorrupt);
sl@0
   314
sl@0
   315
	//Test corrupting the path length field
sl@0
   316
	//First restore original data.
sl@0
   317
	tempbuf8.Copy(origbuf8);
sl@0
   318
	const TInt KPathLengthLocation = 20;
sl@0
   319
	tempbuf8[KPathLengthLocation] = 255;
sl@0
   320
	tempbuf8[KPathLengthLocation+1] = 127;
sl@0
   321
	TESTL(rep->Set(KKeyOfFirstSound, tempbuf8) == KErrNone);
sl@0
   322
	ret = BaSystemSound::GetSound(dummy, iSound.iType, iReadFromRep);
sl@0
   323
	TEST(ret == KErrCorrupt);
sl@0
   324
	
sl@0
   325
	//Corruption of other fields are not detectable.
sl@0
   326
sl@0
   327
	//If we restore the original data in CentRep, GetSound should pass.
sl@0
   328
	tempbuf8.Copy(origbuf8);
sl@0
   329
	TESTL(rep->Set(KKeyOfFirstSound, tempbuf8) == KErrNone);
sl@0
   330
	ret = BaSystemSound::GetSound(dummy, iSound.iType, iReadFromRep);
sl@0
   331
	TEST(ret == KErrNone);
sl@0
   332
sl@0
   333
	CleanupStack::PopAndDestroy(temphbuf8);	
sl@0
   334
	CleanupStack::PopAndDestroy(orighbuf8);	
sl@0
   335
	CleanupStack::PopAndDestroy(rep);	
sl@0
   336
	return TestStepResult();
sl@0
   337
	}
sl@0
   338
sl@0
   339
/** Derive from CBaSsndStore to force collision between
sl@0
   340
concurrent set sound threads.
sl@0
   341
*/
sl@0
   342
class CCollisionSsndStore : public CBaSsndStore
sl@0
   343
	{
sl@0
   344
public:
sl@0
   345
	static CCollisionSsndStore* NewLC(TTimeIntervalMicroSeconds32 aDelay);
sl@0
   346
	virtual void KeyOfSoundTypeL(TBaSystemSoundType& aSoundType, TUint32& aKey) const;
sl@0
   347
	virtual void SetSoundInTransactionL(TBaSystemSoundType& aSoundType,
sl@0
   348
										const TDesC8& aDes8) const;
sl@0
   349
	inline TUint32 NumCollisions() const {return iNumCollisions;}
sl@0
   350
	inline TUint32 Key() const {return iKey;}
sl@0
   351
sl@0
   352
private:
sl@0
   353
	inline CCollisionSsndStore(const TTimeIntervalMicroSeconds32 aDelay)
sl@0
   354
		: iDelay(aDelay), iNumCollisions(0), iKey(NCentralRepositoryConstants::KUnspecifiedKey) {}
sl@0
   355
	inline void ConstructL() {CBaSsndStore::ConstructL();}
sl@0
   356
	TInt RecordKeyPosition(TBaSystemSoundType& aSoundType) const;
sl@0
   357
sl@0
   358
private:
sl@0
   359
	/** indicate how long to pause in the middle of the transaction.
sl@0
   360
	 The pause causes concurrent transactions to fail. */
sl@0
   361
	TTimeIntervalMicroSeconds32 iDelay;
sl@0
   362
sl@0
   363
	/** Record how many times transaction commit failed. Mutable because
sl@0
   364
	 SetSoundInTransactionL in production code is a const method. */
sl@0
   365
	mutable TUint32 iNumCollisions;
sl@0
   366
sl@0
   367
	/** Record the CentRep key used to store the sound. Mutable because
sl@0
   368
	 KeyOfSoundTypeL in production code is a const method. */
sl@0
   369
	mutable TUint32 iKey;
sl@0
   370
	};
sl@0
   371
sl@0
   372
/** static factory method to instantiate CCollisionSsndStore */
sl@0
   373
CCollisionSsndStore* CCollisionSsndStore::NewLC(
sl@0
   374
	const TTimeIntervalMicroSeconds32 aDelay)
sl@0
   375
	{
sl@0
   376
	CCollisionSsndStore* self = new (ELeave) CCollisionSsndStore(aDelay);
sl@0
   377
	CleanupStack::PushL(self);
sl@0
   378
	self->ConstructL();
sl@0
   379
	return self;
sl@0
   380
	}
sl@0
   381
sl@0
   382
/** After using base class method to get the key, add a delay
sl@0
   383
to cause concurrent threads to collide.
sl@0
   384
*/
sl@0
   385
void CCollisionSsndStore::KeyOfSoundTypeL(TBaSystemSoundType& aSoundType,
sl@0
   386
										  TUint32& aKey) const
sl@0
   387
	{
sl@0
   388
	CBaSsndStore::KeyOfSoundTypeL(aSoundType, aKey);
sl@0
   389
	User::AfterHighRes(iDelay);
sl@0
   390
	}
sl@0
   391
sl@0
   392
/** After using base class method to do SetSound in transaction,
sl@0
   393
check the return code. Record commitFail condition. If succes,
sl@0
   394
record the key position where the SoundType is stored.
sl@0
   395
*/
sl@0
   396
void CCollisionSsndStore::SetSoundInTransactionL(
sl@0
   397
		TBaSystemSoundType& aSoundType,
sl@0
   398
		const TDesC8& aDes8) const
sl@0
   399
	{
sl@0
   400
	// call base class method to do the real work
sl@0
   401
	TRAPD(ret, CBaSsndStore::SetSoundInTransactionL(aSoundType, aDes8));
sl@0
   402
sl@0
   403
	// record any collision
sl@0
   404
	if (KErrLocked == ret || KErrAbort == ret)
sl@0
   405
		{
sl@0
   406
		iNumCollisions++;
sl@0
   407
		}
sl@0
   408
	else if (KErrNone == ret)
sl@0
   409
		{
sl@0
   410
		ret = RecordKeyPosition(aSoundType);
sl@0
   411
		}
sl@0
   412
	else if (KErrNoMemory != ret)
sl@0
   413
		{
sl@0
   414
		RDebug::Print(_L("tef_ssnd test: unexpected error %d"), ret);
sl@0
   415
		}
sl@0
   416
sl@0
   417
	User::LeaveIfError(ret);
sl@0
   418
	}
sl@0
   419
sl@0
   420
/** Provide similar function of CBaSsndStore::FindKeyL.
sl@0
   421
FindKeyL ignores duplicate SoundType in repository. It just
sl@0
   422
returns the first key in the array. Test harness cares because
sl@0
   423
it should fail the test if duplicate entries are detected.
sl@0
   424
*/
sl@0
   425
TInt CCollisionSsndStore::RecordKeyPosition(TBaSystemSoundType& aSoundType) const
sl@0
   426
	{
sl@0
   427
	const TUint32 KSoundTypePartialKey = 0x2;
sl@0
   428
	const TUint32 KSsndKeyMask = 0x3;
sl@0
   429
	TPckg<TBaSystemSoundType> target(aSoundType);
sl@0
   430
	RArray<TUint32> foundIds;
sl@0
   431
sl@0
   432
	TInt ret(KErrNone);
sl@0
   433
	TRAPD(err, ret = iRepository->FindEqL(KSoundTypePartialKey,
sl@0
   434
		KSsndKeyMask, target, foundIds));
sl@0
   435
	if (err != KErrNone)
sl@0
   436
		{
sl@0
   437
		ret = err; // KErrNoMemory
sl@0
   438
		}
sl@0
   439
sl@0
   440
	if (ret == KErrNone)
sl@0
   441
		{
sl@0
   442
		iKey = foundIds[0];
sl@0
   443
		if (foundIds.Count() > 1)
sl@0
   444
			{
sl@0
   445
			ret = KErrWrite;
sl@0
   446
			}
sl@0
   447
sl@0
   448
		foundIds.Reset();
sl@0
   449
		}
sl@0
   450
sl@0
   451
	return ret;
sl@0
   452
	}
sl@0
   453
sl@0
   454
//
sl@0
   455
// Concurrent SetSoundL teststep
sl@0
   456
//
sl@0
   457
sl@0
   458
_LIT(KNumWorkers, "NumWorkers");
sl@0
   459
_LIT(KWorkerId, "WorkerId");
sl@0
   460
_LIT(KSameSound, "SameSsndId");
sl@0
   461
sl@0
   462
const TTimeIntervalMicroSeconds32 KCollisionDelay = 500000;
sl@0
   463
const TInt KMaxNumWorkers = 3;
sl@0
   464
TWorkerData ConcurrentResults[KMaxNumWorkers];
sl@0
   465
sl@0
   466
/** CConcurrentStep constructor */
sl@0
   467
CConcurrentStep::CConcurrentStep()
sl@0
   468
	{
sl@0
   469
	SetTestStepName(KConcurrentSetSound);
sl@0
   470
	}
sl@0
   471
sl@0
   472
/** This postamble insures that if a worker thread leaves in
sl@0
   473
doTestStepL, the iDone flag is still set.
sl@0
   474
*/
sl@0
   475
TVerdict CConcurrentStep::doTestStepPostambleL()
sl@0
   476
	{
sl@0
   477
	if (iWorkerId && iWorkerId <= KMaxNumWorkers)
sl@0
   478
		{
sl@0
   479
		ConcurrentResults[iWorkerId - 1].iDone = ETrue;
sl@0
   480
		}
sl@0
   481
sl@0
   482
	// To silent Leave scan.
sl@0
   483
	CTestStep::doTestStepPostambleL();
sl@0
   484
sl@0
   485
	return TestStepResult();
sl@0
   486
	}
sl@0
   487
sl@0
   488
/** Implementation of pure virtual base class method.
sl@0
   489
Read from config file to determine if the current thread is 
sl@0
   490
master or worker. Workers invoke CCollisionSsndStore::SetSoundL.
sl@0
   491
Master summarises the test results.
sl@0
   492
*/
sl@0
   493
TVerdict CConcurrentStep::doTestStepL()
sl@0
   494
	{
sl@0
   495
	const TDesC& section = ConfigSection();
sl@0
   496
	if (!GetIntFromConfig(section, KWorkerId, iWorkerId))
sl@0
   497
		{
sl@0
   498
		TInt numWorkers;
sl@0
   499
		// This is the master thread. It does not call the
sl@0
   500
		// SetSoundL API. It just sets up the concurrent data,
sl@0
   501
		// wait for the test to complete, and tally up results.
sl@0
   502
		TESTL( GetIntFromConfig(section, KNumWorkers, numWorkers) );
sl@0
   503
		TBool sameSsnd = section.FindF(KSameSound) >= 0;
sl@0
   504
		DoMasterTaskL(numWorkers, sameSsnd);
sl@0
   505
		return TestStepResult();
sl@0
   506
		}
sl@0
   507
sl@0
   508
	// Getting here means this is a worker thread.
sl@0
   509
	TESTL(iWorkerId <= KMaxNumWorkers);
sl@0
   510
sl@0
   511
	// pause a bit to ensure master and other workers are
sl@0
   512
	// all started.
sl@0
   513
	User::AfterHighRes(200000);
sl@0
   514
sl@0
   515
	ConstructSoundL();
sl@0
   516
	CCollisionSsndStore* ssndCollisionSet = 
sl@0
   517
		CCollisionSsndStore::NewLC(KCollisionDelay);
sl@0
   518
	ssndCollisionSet->SetSoundL(iSound);
sl@0
   519
sl@0
   520
	TWorkerData& mySlot = ConcurrentResults[iWorkerId - 1];
sl@0
   521
	mySlot.iTranFailCount = ssndCollisionSet->NumCollisions();
sl@0
   522
	mySlot.iKey = ssndCollisionSet->Key();
sl@0
   523
	mySlot.iDone = ETrue;
sl@0
   524
sl@0
   525
	CleanupStack::PopAndDestroy(ssndCollisionSet);	
sl@0
   526
	return TestStepResult();
sl@0
   527
	}
sl@0
   528
sl@0
   529
/** Set up global data and then wait for the concurrent
sl@0
   530
worker threads. When workers all done, verify that 
sl@0
   531
1. collisions did occur and
sl@0
   532
2. collisions did not cause errors in generating the hash keys.
sl@0
   533
*/
sl@0
   534
void CConcurrentStep::DoMasterTaskL(TInt aNumWorkers,
sl@0
   535
								   TBool aSsndIdAreSame)
sl@0
   536
	{
sl@0
   537
	if (aNumWorkers > KMaxNumWorkers)
sl@0
   538
		{
sl@0
   539
		// If there is valid reason to test more than 3 concurrent
sl@0
   540
		// threads, CBaSsndStore::SetSoundL needs to bump up the
sl@0
   541
		// retry count. 3 retries in production code can handle many
sl@0
   542
		// concurrent threads. But in testing collision is guranteed
sl@0
   543
		// to happen. The retry count needs to be same as number of
sl@0
   544
		// workers.
sl@0
   545
		_LIT(KTooMany, "Not allow to have more than %d concurrent workers.");
sl@0
   546
		ERR_PRINTF2(KTooMany, KMaxNumWorkers);
sl@0
   547
		TESTL(EFalse);
sl@0
   548
		}
sl@0
   549
sl@0
   550
	TWorkerData nullData;
sl@0
   551
	TInt i;
sl@0
   552
	for (i = 0; i < aNumWorkers; i++)
sl@0
   553
		{
sl@0
   554
		ConcurrentResults[i] = nullData;
sl@0
   555
		}
sl@0
   556
sl@0
   557
	// Probably should convert KCollisionDelay.Int() to seconds
sl@0
   558
	// and multiply by num of workers. But 12 seconds for max of 3
sl@0
   559
	// workers should be plenty.
sl@0
   560
	TInt j;
sl@0
   561
	TInt doneCount = 0;
sl@0
   562
	TTimeIntervalMicroSeconds32 halfSec(500000);
sl@0
   563
	const TInt KNumLoops = 24;
sl@0
   564
	for (i = 0; i < KNumLoops && doneCount < aNumWorkers; i++)
sl@0
   565
		{
sl@0
   566
		User::AfterHighRes(halfSec);
sl@0
   567
sl@0
   568
		// count number of dones.
sl@0
   569
		for (j = 0, doneCount = 0; j < aNumWorkers; j++)
sl@0
   570
			{
sl@0
   571
			if (ConcurrentResults[j].iDone)
sl@0
   572
				{
sl@0
   573
				doneCount++;
sl@0
   574
				}
sl@0
   575
			}
sl@0
   576
		}
sl@0
   577
sl@0
   578
	TEST(doneCount == aNumWorkers);
sl@0
   579
sl@0
   580
	// If there are 3 workers, expect 2+1 = 3 collisions.
sl@0
   581
	// But to keep things simple, just use (aNumWorkers - 1)
sl@0
   582
	TInt minCollisions = aNumWorkers - 1;
sl@0
   583
	TInt numCommitFails = 0;
sl@0
   584
	for (j = 0; j < aNumWorkers; j++)
sl@0
   585
		{
sl@0
   586
		numCommitFails += ConcurrentResults[j].iTranFailCount;
sl@0
   587
		}
sl@0
   588
sl@0
   589
	TEST(numCommitFails >= minCollisions);
sl@0
   590
sl@0
   591
	// Next check the sounds are correctly created in CentRep.
sl@0
   592
	for (i = 0; i < (aNumWorkers - 1); i++)
sl@0
   593
		{
sl@0
   594
		TUint32 key = ConcurrentResults[i].iKey;
sl@0
   595
sl@0
   596
		if (aSsndIdAreSame)
sl@0
   597
			{
sl@0
   598
			TEST(key == ConcurrentResults[i+1].iKey);
sl@0
   599
			}
sl@0
   600
		else
sl@0
   601
			{
sl@0
   602
			for (j = i+1; j < aNumWorkers; j++)
sl@0
   603
				{
sl@0
   604
				TEST(key != ConcurrentResults[j].iKey);
sl@0
   605
				}
sl@0
   606
			}
sl@0
   607
		}
sl@0
   608
sl@0
   609
	}
sl@0
   610
sl@0
   611
/** CLockoutTestStep constructor */
sl@0
   612
CLockoutTestStep::CLockoutTestStep()
sl@0
   613
	{
sl@0
   614
	SetTestStepName(KLockoutTest);
sl@0
   615
	}
sl@0
   616
sl@0
   617
/** Implementation of pure virtual base class method.
sl@0
   618
Backup or Restore operation is running in parallel.
sl@0
   619
This test waits for the P&S KUidBackupRestoreKey become
sl@0
   620
active and then call SetSoundL and CBaSystemSoundArray::RestoreL.
sl@0
   621
Expects KErrServerBusy/KErrAbort/KErrLocked to be returned.
sl@0
   622
*/
sl@0
   623
TVerdict CLockoutTestStep::doTestStepL()
sl@0
   624
	{
sl@0
   625
using namespace conn;
sl@0
   626
sl@0
   627
	const TBool KLogOnError = ETrue;
sl@0
   628
sl@0
   629
	RProperty burKey;
sl@0
   630
	TInt ret = burKey.Attach(KUidSystemCategory, KUidBackupRestoreKey);
sl@0
   631
	TEST1L(ret == KErrNone, KLogOnError);
sl@0
   632
sl@0
   633
	TRequestStatus s;
sl@0
   634
	burKey.Subscribe(s);
sl@0
   635
	User::WaitForRequest(s);
sl@0
   636
	TEST1L(s.Int() == KErrNone, KLogOnError);
sl@0
   637
sl@0
   638
	TInt burKeyVal = 0;
sl@0
   639
	ret = burKey.Get(burKeyVal);
sl@0
   640
	TEST1L(ret == KErrNone, KLogOnError);
sl@0
   641
sl@0
   642
	burKeyVal &= KBURPartTypeMask;
sl@0
   643
	const TInt KBurInProgress = EBURBackupFull |
sl@0
   644
								EBURBackupPartial |
sl@0
   645
								EBURRestoreFull |
sl@0
   646
								EBURRestorePartial;
sl@0
   647
	TEST1L(burKeyVal & KBurInProgress, KLogOnError);
sl@0
   648
sl@0
   649
	burKey.Close();
sl@0
   650
sl@0
   651
	TRAP(ret, addSoundInstanceL(1));
sl@0
   652
	TEST1(ret == KErrServerBusy || ret == KErrAbort, KLogOnError);
sl@0
   653
sl@0
   654
	TRAP(ret, readSoundsBackL());
sl@0
   655
	if (burKeyVal & EBURRestoreFull || burKeyVal & EBURRestorePartial)
sl@0
   656
		{
sl@0
   657
	    TEST1(ret == KErrServerBusy, KLogOnError);
sl@0
   658
		}
sl@0
   659
	else
sl@0
   660
		{
sl@0
   661
	    TEST1(ret == KErrNone, KLogOnError);
sl@0
   662
		}
sl@0
   663
sl@0
   664
	return TestStepResult();
sl@0
   665
	}
sl@0
   666
sl@0
   667
/** Construct a sound and store it in repository.
sl@0
   668
@param aSequence used as both minor UID and sound sequence.
sl@0
   669
@leave any of the system-wide errors.
sl@0
   670
*/
sl@0
   671
void CLockoutTestStep::addSoundInstanceL(TInt32 aSequence)
sl@0
   672
	{
sl@0
   673
	TUid minorUid = {aSequence};
sl@0
   674
	TBaSystemSoundType soundId(KLockoutTestSoundCategory, minorUid);
sl@0
   675
	TBaSystemSoundInfo sound(soundId, aSequence);
sl@0
   676
sl@0
   677
	RFs dummy;
sl@0
   678
	BaSystemSound::SetSoundL(dummy, sound);
sl@0
   679
	}
sl@0
   680
sl@0
   681
/** use CBaSystemSoundArray::RestoreL to read back all
sl@0
   682
the sounds in KLockoutTestSoundCategory.
sl@0
   683
@leave any of the system-wide errors.
sl@0
   684
*/
sl@0
   685
void CLockoutTestStep::readSoundsBackL()
sl@0
   686
	{
sl@0
   687
	CBaSystemSoundArray* reader = CBaSystemSoundArray::NewLC();
sl@0
   688
sl@0
   689
	RFs dummy;
sl@0
   690
	reader->RestoreL(dummy, KLockoutTestSoundCategory);
sl@0
   691
	CleanupStack::PopAndDestroy(reader);
sl@0
   692
	}
sl@0
   693