|
1 // Copyright (c) 2007-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 @test |
|
19 */ |
|
20 |
|
21 #include <test/tefunit.h> // for ASSERT macros |
|
22 #ifndef __INIPARSER_H__ |
|
23 #include <cinidata.h> |
|
24 #endif // __INIPARSER_H__ |
|
25 #include <apgtask.h> |
|
26 #include <e32math.h> |
|
27 #include <e32msgqueue.h> |
|
28 |
|
29 #include "egltestcommonstep.h" |
|
30 #include "egltestcommonsession.h" |
|
31 #include "egltestcommonutils.h" |
|
32 #include "egltestcommonprocess.h" |
|
33 |
|
34 static const TUint KDefaultHeapSize = 0x100000; |
|
35 CEglTestStep::TThreadStatus::TThreadStatus() |
|
36 { |
|
37 for(TInt i=0; i<ESize; i++) |
|
38 { |
|
39 iStatus[i] = 0; |
|
40 } |
|
41 } |
|
42 |
|
43 EXPORT_C CEglTestStep::CEglTestStep() : |
|
44 iWaitForCompletionOnPostamble(EFalse), |
|
45 iSourceFormat(KDefaultSourceFormat), |
|
46 iSurfaceFormat(KDefaultSurfaceFormat) |
|
47 { |
|
48 } |
|
49 |
|
50 EXPORT_C CEglTestStep::~CEglTestStep() |
|
51 { |
|
52 for (TInt i=0; i<KMaxProcessNumber; i++) |
|
53 { |
|
54 iProcessStatus[i].iProcess.Close(); |
|
55 } |
|
56 TInt countThread = iThreadStatus.Count(); |
|
57 for (TInt i=0; i<countThread; i++) |
|
58 { |
|
59 iThreadStatus[i].iThread.Close(); |
|
60 } |
|
61 iThreadStatus.Close(); |
|
62 |
|
63 iSemaphore[0].Close(); |
|
64 iSemaphore[1].Close(); |
|
65 |
|
66 CleanAll(); |
|
67 CloseWsSession(); |
|
68 } |
|
69 |
|
70 EXPORT_C TVerdict CEglTestStep::doTestStepPreambleL() |
|
71 { |
|
72 User::LeaveIfError(Logger().ShareAuto()); |
|
73 //When EGL Logging is enabled this causes a file server session to be allocated |
|
74 //Which needs to be done before any handle checks otherwise the test will fail |
|
75 ASSERT_EGL_TRUE(eglReleaseThread()); |
|
76 __UHEAP_MARK; |
|
77 HandleMark(); |
|
78 return TestStepResult(); |
|
79 } |
|
80 |
|
81 EXPORT_C TVerdict CEglTestStep::doTestStepPostambleL() |
|
82 { |
|
83 if(iWaitForCompletionOnPostamble && (iThreadStatus.Count() > 0)) |
|
84 { |
|
85 INFO_PRINTF1(_L("Main thread waits for other threads to be terminated!!")); |
|
86 Test_MultiThread_WaitL(ETrue, TThreadStatus::ELogin); |
|
87 } |
|
88 |
|
89 if (iDisplay != EGL_NO_DISPLAY) |
|
90 { |
|
91 // Output a warning because this should be done by the test |
|
92 WARN_PRINTF1(_L("Terminating Display during doTestStepPostambleL")); |
|
93 ASSERT_EGL_TRUE(eglTerminate(iDisplay)); |
|
94 iDisplay = EGL_NO_DISPLAY; |
|
95 } |
|
96 |
|
97 ASSERT_EGL_TRUE(eglReleaseThread()); |
|
98 |
|
99 HandleMarkEnd(); |
|
100 __UHEAP_MARKEND; |
|
101 return TestStepResult(); |
|
102 } |
|
103 |
|
104 EXPORT_C void CEglTestStep::CleanAll() |
|
105 { |
|
106 delete iEglSess; |
|
107 iEglSess = NULL; |
|
108 |
|
109 if (iDisplay != EGL_NO_DISPLAY) |
|
110 { |
|
111 ASSERT_EGL_TRUE(eglTerminate(iDisplay)); |
|
112 iDisplay = EGL_NO_DISPLAY; |
|
113 } |
|
114 ASSERT_EGL_TRUE(eglReleaseThread()); |
|
115 } |
|
116 |
|
117 /***************************************************************************** |
|
118 ** Utility methods |
|
119 *****************************************************************************/ |
|
120 |
|
121 void CEglTestStep::HandleMark() |
|
122 { |
|
123 RThread().HandleCount(iProcHandleMark, iThreadHandleMark); |
|
124 INFO_PRINTF3(_L("MARK: (%d) process-owned handle(s) / (%d) thread-owned handle(s)"), iProcHandleMark, iThreadHandleMark); |
|
125 } |
|
126 |
|
127 void CEglTestStep::HandleMarkEnd() |
|
128 { |
|
129 RThread().HandleCount(iProcHandleMarkEnd, iThreadHandleMarkEnd); |
|
130 INFO_PRINTF3(_L("MARK-END: (%d) process-owned handle(s) / (%d) thread-owned handle(s)"), iProcHandleMarkEnd, iThreadHandleMarkEnd); |
|
131 #ifdef __WINS__ |
|
132 WARN_PRINTF1(_L("Process-owned handle test is ignored on WINS build due to Pls() behaviour.")); |
|
133 #endif |
|
134 // When using Pls() on WINS build, it inteferes with handle count assert here due to Pls() behaviour which initialises PLS object |
|
135 // on first call of Pls() rather than during DLL loading, which cause extra count into iProcHandleMark. |
|
136 // ARMV5 build does not suffer this problem as proper WSD support is used. |
|
137 #ifndef __WINS__ |
|
138 ASSERT_EQUALS(iProcHandleMarkEnd, iProcHandleMark); |
|
139 #endif |
|
140 ASSERT_EQUALS(iThreadHandleMarkEnd, iThreadHandleMark); |
|
141 } |
|
142 |
|
143 /** Initialises the window server session and window group objects. */ |
|
144 EXPORT_C void CEglTestStep::OpenWsSessionL(TInt aGroupId) |
|
145 { |
|
146 User::LeaveIfError(iWsSession.Connect()); |
|
147 iWindowGroup = RWindowGroup(iWsSession); |
|
148 User::LeaveIfError(iWindowGroup.Construct(aGroupId)); |
|
149 } |
|
150 |
|
151 /** Uninitialises the window group object and the window server session. */ |
|
152 EXPORT_C void CEglTestStep::CloseWsSession() |
|
153 { |
|
154 iWindowGroup.Close(); |
|
155 iWsSession.Close(); |
|
156 } |
|
157 |
|
158 /** |
|
159 Uses the Eikon Environment to construct a window and put it on top. |
|
160 @param aWindow A non-constructed window object |
|
161 @param aRect The intial position and size of the window |
|
162 @leave Standard system errors |
|
163 */ |
|
164 EXPORT_C void CEglTestStep::ConstructWindowL(RWindow& aWindow, const TRect& aRect) |
|
165 { |
|
166 INFO_PRINTF1(_L("CEglTestStep::CreateWindowL()")); |
|
167 |
|
168 const TUint32 ENullWsHandle = 0xFFFFFFFF; // Events delivered to this handle are thrown away |
|
169 aWindow = RWindow(iWsSession); |
|
170 CleanupClosePushL(aWindow); |
|
171 User::LeaveIfError(aWindow.Construct(iWindowGroup, ENullWsHandle)); |
|
172 aWindow.SetExtent(aRect.iTl, aRect.Size()); |
|
173 aWindow.Activate(); |
|
174 CleanupStack::Pop(&aWindow); |
|
175 } |
|
176 |
|
177 /** |
|
178 Prints both the Source pixel format and the target pixel format |
|
179 */ |
|
180 EXPORT_C void CEglTestStep::PrintUsedPixelConfiguration() |
|
181 { |
|
182 INFO_PRINTF1(_L("******UsedPixelConfiguration******")); |
|
183 INFO_PRINTF1(_L("Source Pixel Format")); |
|
184 PrintPixelFormat(iSourceFormat); |
|
185 |
|
186 INFO_PRINTF1(_L("Target Format")); |
|
187 PrintVGImageFormat(iSurfaceFormat); |
|
188 INFO_PRINTF1(_L("**********************************")); |
|
189 } |
|
190 |
|
191 EXPORT_C void CEglTestStep::PrintPixelFormat(TUidPixelFormat aFormat) |
|
192 { |
|
193 switch(aFormat) |
|
194 { |
|
195 case EUidPixelFormatA_8: |
|
196 INFO_PRINTF1(_L("EUidPixelFormatA_8")); |
|
197 break; |
|
198 case EUidPixelFormatRGB_565: |
|
199 INFO_PRINTF1(_L("EUidPixelFormatRGB_565")); |
|
200 break; |
|
201 case EUidPixelFormatXRGB_8888: |
|
202 INFO_PRINTF1(_L("EUidPixelFormatXRGB_8888")); |
|
203 break; |
|
204 case EUidPixelFormatARGB_8888: |
|
205 INFO_PRINTF1(_L("EUidPixelFormatARGB_8888")); |
|
206 break; |
|
207 case EUidPixelFormatARGB_8888_PRE: |
|
208 INFO_PRINTF1(_L("EUidPixelFormatARGB_8888_PRE")); |
|
209 break; |
|
210 default: |
|
211 ERR_PRINTF2(_L("Unsupported pixel format (%d)"), aFormat); |
|
212 ASSERT_TRUE(EFalse); |
|
213 } |
|
214 } |
|
215 |
|
216 EXPORT_C void CEglTestStep::PrintVGImageFormat(VGImageFormat aAttr) |
|
217 { |
|
218 switch(aAttr) |
|
219 { |
|
220 case VG_sRGB_565: |
|
221 INFO_PRINTF1(_L("VG_sRGB_565")); |
|
222 break; |
|
223 case VG_sXRGB_8888: |
|
224 INFO_PRINTF1(_L("VG_sXRGB_8888")); |
|
225 break; |
|
226 case VG_sARGB_8888: |
|
227 INFO_PRINTF1(_L("VG_sARGB_8888")); |
|
228 break; |
|
229 case VG_sARGB_8888_PRE: |
|
230 INFO_PRINTF1(_L("VG_sARGB_8888_PRE")); |
|
231 break; |
|
232 default: |
|
233 ERR_PRINTF2(_L("Unsupported VGImage format (%d)"), aAttr); |
|
234 ASSERT_TRUE(EFalse); |
|
235 } |
|
236 } |
|
237 |
|
238 |
|
239 /***************************************************************************** |
|
240 ** Multiprocess test utils |
|
241 *****************************************************************************/ |
|
242 |
|
243 /** |
|
244 Launches the specified number of processes, where each process will perform the actions specified in |
|
245 the doProcessFunctionL of the calling test. As no images TSgDrawableId has been passed, an |
|
246 an array of one (NULL) TSgDrawableId will be created. |
|
247 @param aProcessCount Number of processes |
|
248 @param aTestName Name of the calling test case (so that it can call it's doProcessFunctionL method |
|
249 @leave Standard system errors |
|
250 */ |
|
251 EXPORT_C void CEglTestStep::Test_MultiProcessL(const TDesC& aTestDllName, TInt aProcessCount, const TDesC& aTestStepName) |
|
252 { |
|
253 TSgDrawableId sgId; |
|
254 Mem::FillZ(&sgId, sizeof(TSgDrawableId)); |
|
255 Test_MultiProcessL(aTestDllName, aProcessCount, aTestStepName, sgId); |
|
256 } |
|
257 |
|
258 /** |
|
259 Launches the specified number of processes, where each process will perform the actions specified in |
|
260 the doProcessFunctionL of the calling test. |
|
261 @param aProcessCount Number of processes |
|
262 @param aTestName Name of the calling test case (so that it can call it's doProcessFunctionL method |
|
263 @param aSgId Images TSgDrawableId which will be used to create an array of one TSgDrawableId |
|
264 @leave Standard system errors |
|
265 */ |
|
266 EXPORT_C void CEglTestStep::Test_MultiProcessL(const TDesC& aTestDllName, TInt aProcessCount, const TDesC& aTestStepName, const TSgDrawableId& aSgId) |
|
267 { |
|
268 // we assume we pass the same Id to all the processes (array of one) |
|
269 RArray<TSgDrawableId> sgIdList; |
|
270 ASSERT_EQUALS(sgIdList.Insert(aSgId,0), KErrNone); |
|
271 Test_MultiProcessL(aTestDllName, aProcessCount, aTestStepName, sgIdList); |
|
272 sgIdList.Close(); |
|
273 } |
|
274 |
|
275 /** |
|
276 Launches the specified number of processes, where each process will perform the actions specified in |
|
277 the doProcessFunctionL of the calling test. The association of images and processes is done via the |
|
278 predefined ImageIndexFromProcessId() method. |
|
279 @param aProcessCount Number of processes |
|
280 @param aTestName Name of the calling test case (so that it can call it's doProcessFunctionL method |
|
281 @param aSgIdList Array containing the list of images' TSgDrawableId |
|
282 @leave Standard system errors |
|
283 */ |
|
284 EXPORT_C void CEglTestStep::Test_MultiProcessL(const TDesC& aTestDllName, TInt aProcessCount, const TDesC& aTestStepName, const RArray<TSgDrawableId>& aSgIdList) |
|
285 { |
|
286 TInt imageCount = aSgIdList.Count(); |
|
287 if(aProcessCount <= 0 || imageCount <=0 || aProcessCount > KMaxProcessNumber || imageCount > aProcessCount) |
|
288 { |
|
289 ERR_PRINTF1(_L("Invalid process request!")); |
|
290 User::Leave(KErrArgument); |
|
291 } |
|
292 |
|
293 // create MsgQueue (only used in some test to pass data between 2 processes) |
|
294 RMsgQueue<TSgDrawableId> messageQueueSgId; |
|
295 TInt ret = messageQueueSgId.CreateGlobal(KNullDesC, 1, EOwnerProcess); |
|
296 ASSERT_EQUALS(ret, KErrNone); |
|
297 |
|
298 RMsgQueue<TProcessId> messageQueueProcId; |
|
299 ret = messageQueueProcId.CreateGlobal(KNullDesC, 1, EOwnerProcess); |
|
300 ASSERT_EQUALS(ret, KErrNone); |
|
301 |
|
302 // Create semphores that can be shared (only used in some test to synch between 2 process) |
|
303 ret = iSemaphore[0].CreateGlobal(KNullDesC(), 0, EOwnerProcess); |
|
304 ASSERT_EQUALS(ret, KErrNone); |
|
305 ret = iSemaphore[1].CreateGlobal(KNullDesC(), 0, EOwnerProcess); |
|
306 ASSERT_EQUALS(ret, KErrNone); |
|
307 |
|
308 for (TInt i=0; i<aProcessCount; i++) |
|
309 { |
|
310 TProcessInfo info; |
|
311 info.iIdx=i; |
|
312 info.iSgId= aSgIdList[ImageIndexFromProcessId(i, imageCount)]; |
|
313 |
|
314 ret = iProcessStatus[i].iProcess.Create(KEglTestServerWrapperProcess, KNullDesC); |
|
315 User::LeaveIfError(ret); |
|
316 |
|
317 // Specify the test for the process |
|
318 ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotTestDllName, aTestDllName); |
|
319 User::LeaveIfError(ret); |
|
320 ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotTestStepName, aTestStepName); |
|
321 User::LeaveIfError(ret); |
|
322 |
|
323 // Specify the non-handle params passed to the process |
|
324 TPckg<TProcessInfo> pckgInfo(info); |
|
325 ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotParams, pckgInfo); |
|
326 User::LeaveIfError(ret); |
|
327 |
|
328 // Pass in the semaphores |
|
329 ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotSemaphore0, iSemaphore[0]); |
|
330 User::LeaveIfError(ret); |
|
331 ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotSemaphore1, iSemaphore[1]); |
|
332 User::LeaveIfError(ret); |
|
333 ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotMsgQueueSgId, messageQueueSgId); |
|
334 User::LeaveIfError(ret); |
|
335 ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotMsgQueueProcId, messageQueueProcId); |
|
336 User::LeaveIfError(ret); |
|
337 ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotSourceFormat, static_cast<TInt>(iSourceFormat)); |
|
338 User::LeaveIfError(ret); |
|
339 ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotSurfaceFormat, static_cast<TInt>(iSurfaceFormat)); |
|
340 User::LeaveIfError(ret); |
|
341 |
|
342 iProcessStatus[i].iProcess.Logon(iProcessStatus[i].iStatus); |
|
343 iProcessStatus[i].iProcess.Resume(); |
|
344 } |
|
345 |
|
346 // wait for all processes to complete (not worried about the order) |
|
347 // This is needed, as the only way to determine whether the process step has failed is to check |
|
348 // the return value (using TEST(EFalse) has no effect on the spawned process) |
|
349 for (TInt i=0; i<aProcessCount; i++) |
|
350 { |
|
351 User::WaitForRequest(iProcessStatus[i].iStatus); |
|
352 CheckProcessStatusL(i, iProcessStatus[i].iStatus, iProcessStatus[i].iProcess); |
|
353 RDebug::Print(_L(">>>>>(%d)>> status :%d"), i, iProcessStatus[i].iStatus.Int()); |
|
354 iProcessStatus[i].iProcess.Close(); |
|
355 } |
|
356 |
|
357 // close MsgQueue and semaphores (as used in some test with 2 spawned processes) |
|
358 messageQueueSgId.Close(); |
|
359 messageQueueProcId.Close(); |
|
360 iSemaphore[1].Close(); |
|
361 iSemaphore[0].Close(); |
|
362 } |
|
363 |
|
364 /** |
|
365 Check the status of a process running as part of the current teststep. |
|
366 @param aIndex Index of the process |
|
367 @param aStatus The request status of the process in question. |
|
368 @param aProcess The process object itself. |
|
369 @leave Standard system errors |
|
370 */ |
|
371 void CEglTestStep::CheckProcessStatusL(TInt aIndex, const TRequestStatus& aStatus, const RProcess& aProcess) |
|
372 { |
|
373 TInt status = aStatus.Int(); |
|
374 if (status == KErrNone) |
|
375 { |
|
376 return; |
|
377 } |
|
378 if (status == KRequestPending) |
|
379 { |
|
380 // If the process is still running, that's an error, as we waited for the status |
|
381 ERR_PRINTF2(_L("Error in process %d - status should not be KRequestPending"), aIndex); |
|
382 User::Leave(KErrTEFUnitFail); |
|
383 } |
|
384 // Something went wrong |
|
385 switch (aProcess.ExitType()) |
|
386 { |
|
387 case EExitPanic: // The thread or process has been panicked. |
|
388 { |
|
389 TPtrC ptrExitCategory = aProcess.ExitCategory(); |
|
390 ERR_PRINTF4(_L("Panic in process %d - category:[%S] reason: %d"), aIndex, &ptrExitCategory, aProcess.ExitReason()); |
|
391 // Propagate the panic |
|
392 User::Panic(aProcess.ExitCategory(), aProcess.ExitReason()); |
|
393 } |
|
394 // follow through |
|
395 case EExitKill: // The thread or process has ended as a result of a kill, i.e. Kill() has been called on the RThread or RProcess handle. Or a thread was ended as a result of calling User::Exit(). |
|
396 case EExitTerminate: // The thread or process has ended as a result of a terminate, i.e. Terminate() has been called on the RThread or RProcess handle. |
|
397 case EExitPending: // The thread or process is alive. |
|
398 default: |
|
399 // Propagate the error |
|
400 ERR_PRINTF3(_L("Error in process %d - code %d"), aIndex, aStatus.Int()); |
|
401 User::Leave(aStatus.Int()); |
|
402 } |
|
403 ASSERT(0); |
|
404 } |
|
405 |
|
406 |
|
407 /***************************************************************************** |
|
408 ** Multithread test utils |
|
409 *****************************************************************************/ |
|
410 |
|
411 /** |
|
412 Launches the specified number of threads, where each thread will perform the actions specified in |
|
413 the doThreadFunctionL of the calling test. |
|
414 @param aThreadCount Number of threads |
|
415 @param aWaitForCompletion To wait until the launched thread has completed |
|
416 @leave Standard system errors |
|
417 */ |
|
418 EXPORT_C void CEglTestStep::Test_MultiThreadL(TInt aThreadCount, TBool aWaitForCompletion) |
|
419 { |
|
420 if(aThreadCount <= 0 || aThreadCount > KMaxThreadNumber) |
|
421 { |
|
422 ERR_PRINTF1(_L("Invalid thread request!")); |
|
423 User::Leave(KErrArgument); |
|
424 } |
|
425 |
|
426 iWaitForCompletionOnPostamble = !aWaitForCompletion; |
|
427 |
|
428 //we just care for these 2 semaphores |
|
429 ASSERT_EQUALS(iSemaphore[0].CreateLocal(0, EOwnerProcess), KErrNone); |
|
430 ASSERT_EQUALS(iSemaphore[1].CreateLocal(0, EOwnerProcess), KErrNone); |
|
431 |
|
432 _LIT(KThread, "CEglTestStep_Thread"); |
|
433 _LIT(KUnderScore, "_"); |
|
434 |
|
435 TInt ret = KErrNone; |
|
436 ASSERT_EQUALS(iThreadStatus.Count(),0); |
|
437 // Reserve space to avoid reallocation of iThreadStatus.iStatus |
|
438 iThreadStatus.ReserveL(aThreadCount); |
|
439 for (TInt i=0; i<aThreadCount; i++) |
|
440 { |
|
441 iThreadInfos[i].iSelf=this; |
|
442 iThreadInfos[i].iIdx=i; |
|
443 |
|
444 TTime tm; |
|
445 TBuf<32> bufTime; |
|
446 tm.UniversalTime(); |
|
447 tm.FormatL(bufTime, _L("_%H%T%S%C_")); |
|
448 |
|
449 // guaranteed unique thread name (useful if several threads are created with aWaitForCompletion = false) |
|
450 TName threadName(KThread); |
|
451 threadName.Append(KUnderScore); |
|
452 threadName.AppendNum(i, EDecimal); |
|
453 threadName.Append(KUnderScore); |
|
454 threadName.Append(bufTime); |
|
455 threadName.AppendNum(Math::Random(), EHex); |
|
456 |
|
457 iThreadStatus.AppendL(TThreadStatus()); |
|
458 ret = iThreadStatus[i].iThread.Create(threadName, ThreadFunction, KDefaultStackSize, KMinHeapSize, KDefaultHeapSize, &iThreadInfos[i], EOwnerProcess); |
|
459 User::LeaveIfError(ret); |
|
460 |
|
461 if(!aWaitForCompletion) |
|
462 { |
|
463 // We want to wait for the notification that the extra thread is about to be launched |
|
464 // Improves timing issues within a hardware WDP environment |
|
465 iThreadStatus[i].iThread.Rendezvous(iThreadStatus[i].iStatus[TThreadStatus::ERendezvous]); |
|
466 } |
|
467 iThreadStatus[i].iThread.Logon(iThreadStatus[i].iStatus[TThreadStatus::ELogin]); |
|
468 iThreadStatus[i].iThread.Resume(); |
|
469 } |
|
470 Test_MultiThread_WaitL(aWaitForCompletion, aWaitForCompletion ? TThreadStatus::ELogin : TThreadStatus::ERendezvous); |
|
471 } |
|
472 |
|
473 EXPORT_C void CEglTestStep::Test_MultiThread_WaitL(TBool aCloseThreads, TThreadStatus::TStatusId aStatusId) |
|
474 { |
|
475 // Close handles and wait for all threads to complete (not worried about the order). Note that some |
|
476 // tests do not require to wait for completion. Nevertheless, care should be taken to ensure that the |
|
477 // spawned thread is capable of modifying the main TEF process TestStepResult. |
|
478 |
|
479 TInt countThread = iThreadStatus.Count(); |
|
480 for (TInt i=0; i<countThread; i++) |
|
481 { |
|
482 User::WaitForRequest(iThreadStatus[i].iStatus[aStatusId]); |
|
483 CheckThreadStatusL(i, iThreadStatus[i].iStatus[aStatusId], iThreadStatus[i].iThread); |
|
484 INFO_PRINTF3(_L(">>>>>(%d)>> status :%d"), i, iThreadStatus[i].iStatus[aStatusId].Int()); |
|
485 |
|
486 if(aCloseThreads) |
|
487 { |
|
488 iThreadStatus[i].iThread.Close(); |
|
489 } |
|
490 } |
|
491 if(aCloseThreads) |
|
492 { |
|
493 iThreadStatus.Reset(); |
|
494 |
|
495 iSemaphore[0].Close(); |
|
496 iSemaphore[1].Close(); |
|
497 } |
|
498 } |
|
499 |
|
500 /** |
|
501 Check the status of a thread running as part of the current teststep. |
|
502 @param aIndex Index of the thread |
|
503 @param aStatus The request status of the thread in question. |
|
504 @param aThread The thread object itself. |
|
505 @leave Standard system errors |
|
506 */ |
|
507 void CEglTestStep::CheckThreadStatusL(TInt aIndex, const TRequestStatus& aStatus, const RThread& aThread) |
|
508 { |
|
509 TInt status = aStatus.Int(); |
|
510 if (status == KErrNone) |
|
511 { |
|
512 // All went well |
|
513 return; |
|
514 } |
|
515 if (status == KRequestPending) |
|
516 { |
|
517 // If the thread is still running, that's an error, as we waited for the status |
|
518 ERR_PRINTF2(_L("Error in thread %d - status should not be KRequestPending"), aIndex); |
|
519 User::Leave(KErrTEFUnitFail); |
|
520 } |
|
521 // Something went wrong |
|
522 switch (aThread.ExitType()) |
|
523 { |
|
524 case EExitPanic: // The thread or process has been panicked. |
|
525 { |
|
526 TPtrC ptrExitCategory = aThread.ExitCategory(); |
|
527 ERR_PRINTF4(_L("Panic in thread %d - category:[%S] reason: %d"), aIndex, &ptrExitCategory, aThread.ExitReason()); |
|
528 User::Panic(aThread.ExitCategory(), aThread.ExitReason()); |
|
529 } |
|
530 // follow through |
|
531 case EExitKill: // The thread or process has ended as a result of a kill, i.e. Kill() has been called on the RThread or RProcess handle. Or a thread was ended as a result of calling User::Exit(). |
|
532 case EExitTerminate: // The thread or process has ended as a result of a terminate, i.e. Terminate() has been called on the RThread or RProcess handle. |
|
533 case EExitPending: // The thread or process is alive. |
|
534 default: |
|
535 // Propagate the error |
|
536 ERR_PRINTF3(_L("Error in thread %d - code %d"), aIndex, status); |
|
537 User::Leave(aStatus.Int()); |
|
538 } |
|
539 // We should not get here! |
|
540 ASSERT(0); |
|
541 } |
|
542 |
|
543 TInt CEglTestStep::ThreadFunction(TAny* aInfo) |
|
544 // static |
|
545 { |
|
546 __UHEAP_MARK; |
|
547 CTrapCleanup* cleanup = CTrapCleanup::New(); |
|
548 if(cleanup == NULL) |
|
549 { |
|
550 return KErrNoMemory; |
|
551 } |
|
552 |
|
553 CEglTestStep::TThreadInfo* info = reinterpret_cast<CEglTestStep::TThreadInfo*>(aInfo); |
|
554 TRAPD(err, info->iSelf->ThreadFunctionL(*info)); |
|
555 |
|
556 delete cleanup; |
|
557 __UHEAP_MARKEND; |
|
558 return err; |
|
559 } |
|
560 |
|
561 void CEglTestStep::ThreadFunctionL(TThreadInfo& aInfo) |
|
562 { |
|
563 // Mark the handle count for this thread |
|
564 TInt processHandleMark=0; |
|
565 TInt threadHandleMark=0; |
|
566 RThread().HandleCount(processHandleMark, threadHandleMark); |
|
567 INFO_PRINTF4(_L("MARK: THREAD %d: (%d) process-owned handle(s) / (%d) thread-owned handle(s)"), aInfo.iIdx, processHandleMark, threadHandleMark); |
|
568 |
|
569 // Notify the main thread that we are about to launch the extra thread |
|
570 RThread::Rendezvous(KErrNone); |
|
571 |
|
572 // Run the real thread funciton |
|
573 aInfo.iSelf->doThreadFunctionL(aInfo.iIdx); |
|
574 |
|
575 // Release EGL thread state |
|
576 INFO_PRINTF2(_L("thread %d: Calling eglReleaseThread()"), aInfo.iIdx); |
|
577 ASSERT_EGL_TRUE(eglReleaseThread()); |
|
578 |
|
579 // Check the handle count for this thread has not changed |
|
580 TInt processHandleMarkEnd=0; |
|
581 TInt threadHandleMarkEnd=0; |
|
582 RThread().HandleCount(processHandleMarkEnd, threadHandleMarkEnd); |
|
583 INFO_PRINTF4(_L("MARK-END: THREAD %d: (%d) process-owned handle(s) / (%d) thread-owned handle(s)"), aInfo.iIdx, processHandleMarkEnd, threadHandleMarkEnd); |
|
584 |
|
585 //Not testing equality of process-owned handles as these should only be tested from the main thread. |
|
586 //Process handlecount is dependent on all threads, therefore process handle imbalances could be the responsibility of other threads. |
|
587 ASSERT_EQUALS(threadHandleMark, threadHandleMarkEnd); |
|
588 } |
|
589 |
|
590 /** |
|
591 Tests should override this method for multithreaded testing |
|
592 */ |
|
593 EXPORT_C void CEglTestStep::doThreadFunctionL(TInt aIdx) |
|
594 { |
|
595 // Not supported for this test step |
|
596 ERR_PRINTF2(_L("thread %d: Calling CEglTestStep::doThreadFunctionL() - should be overriden"), aIdx); |
|
597 User::Leave(KErrNotSupported); |
|
598 } |
|
599 |
|
600 EXPORT_C void CEglTestStep::doThreadFunctionL(TInt aIdx,const TSgDrawableId& aSgId) |
|
601 { |
|
602 // Not supported for this test step |
|
603 ERR_PRINTF3(_L("thread %d: Calling CEglTestStep::doThreadFunctionL() - should be overriden, TSgDrawableId %lu."), aIdx, aSgId.iId); |
|
604 User::Leave(KErrNotSupported); |
|
605 } |
|
606 |
|
607 /** |
|
608 Tests should override this method for multiprocess testing |
|
609 */ |
|
610 EXPORT_C void CEglTestStep::doProcessFunctionL(TInt aIdx) |
|
611 { |
|
612 // Not supported for this test step |
|
613 ERR_PRINTF2(_L("Process %d: Calling CEglTestStep::doProcessFunctionL() - should be overriden"), aIdx); |
|
614 User::Leave(KErrNotSupported); |
|
615 } |
|
616 |
|
617 EXPORT_C void CEglTestStep::doProcessFunctionL(TInt aIdx,const TSgDrawableId& aSgId) |
|
618 { |
|
619 // Not supported for this test step |
|
620 ERR_PRINTF3(_L("Process %d: Calling CEglTestStep::doProcessFunctionL() - should be overriden, TSgDrawableId %lu."), aIdx, aSgId.iId); |
|
621 User::Leave(KErrNotSupported); |
|
622 } |
|
623 |
|
624 |
|
625 /** |
|
626 Rendezvous: Ensures that both threads get to this point before continuing |
|
627 @param aIdx The thread index value that was passed into |
|
628 the override of CEglTestStep::doThreadFunctionL() |
|
629 */ |
|
630 EXPORT_C void CEglTestStep::Rendezvous(TInt aIdx) |
|
631 { |
|
632 if(aIdx >= 2) |
|
633 { |
|
634 // Currently Rendezvous is only supported between threads with index 0 and index 1 |
|
635 INFO_PRINTF2(_L("CEglTestStep::Rendezvous() - aIdx (%d) is too big!!"), aIdx); |
|
636 ASSERT(0); |
|
637 } |
|
638 INFO_PRINTF2(_L("thread %d: ...At Rendezvous..."), aIdx); |
|
639 iSemaphore[aIdx].Signal(); |
|
640 iSemaphore[1-aIdx].Wait(); |
|
641 } |
|
642 |
|
643 |
|
644 /***************************************************************************** |
|
645 ** Egl Helpers |
|
646 *****************************************************************************/ |
|
647 |
|
648 /** |
|
649 Temporarily initializes the EGL thread and display in order to check for the |
|
650 supplied extension string. |
|
651 The display is then released and terminated. |
|
652 Use this method to pre-check for the existence of an extension string prior |
|
653 to starting a test. |
|
654 There are 2 ways to ask for an extension, via the ID (the default way to do it) |
|
655 or passing a string containing the full name of the extension (used in some tests only) |
|
656 @param aExtensions The extension ID to look for |
|
657 @param aExtensionName The extension name to look for |
|
658 @return Whether the extension string can be found |
|
659 */ |
|
660 EXPORT_C TBool CEglTestStep::CheckForExtensionL(TInt aExtensions, const TDesC& aExtensionName) |
|
661 { |
|
662 ASSERT_TRUE(iDisplay == EGL_NO_DISPLAY); |
|
663 GetDisplayL(); |
|
664 CTestEglSession* eglSess = CTestEglSession::NewLC(Logger(), iDisplay, -1); |
|
665 eglSess->InitializeL(); |
|
666 |
|
667 TBool bFoundExtensions = eglSess->CheckNeededExtensionL(aExtensions, aExtensionName); |
|
668 |
|
669 // Cleanup EGL Completely |
|
670 CleanupStack::PopAndDestroy(eglSess); |
|
671 eglSess = NULL; |
|
672 TerminateDisplayL(); |
|
673 ASSERT_EGL_TRUE(eglReleaseThread()); |
|
674 |
|
675 // return whether the extension string was found |
|
676 return bFoundExtensions; |
|
677 } |
|
678 |
|
679 /** |
|
680 Uses eglGetDisplay() to initialise iDisplay, and to check the result of the call |
|
681 */ |
|
682 EXPORT_C void CEglTestStep::GetDisplayL() |
|
683 { |
|
684 INFO_PRINTF1(_L("Calling eglGetDisplay...")); |
|
685 |
|
686 iDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); |
|
687 ASSERT_EGL_TRUE(iDisplay != EGL_NO_DISPLAY); |
|
688 } |
|
689 |
|
690 /** |
|
691 If the iDisplay has been initialised then this method uses eglTerminate() |
|
692 to terminate iDisplay, and to check the result of the call. |
|
693 This method also resets the value of iDisplay to EGL_NO_DISPLAY to indicate |
|
694 that the display is no longer initialised. |
|
695 */ |
|
696 EXPORT_C void CEglTestStep::TerminateDisplayL() |
|
697 { |
|
698 if (iDisplay != EGL_NO_DISPLAY) |
|
699 { |
|
700 INFO_PRINTF1(_L("Calling eglTerminate...")); |
|
701 ASSERT_EGL_TRUE(eglTerminate(iDisplay)); |
|
702 iDisplay = EGL_NO_DISPLAY; |
|
703 } |
|
704 } |
|
705 |
|
706 /** |
|
707 Cut and paste from CTestStep::SetLogger() - which is not exported |
|
708 As the name suggests, this is for use by the egl test process wrapper |
|
709 */ |
|
710 void CEglTestStep::SetLoggerForProcessWrapperL() |
|
711 { |
|
712 // Create a cinidata object for parsing the testexecute.ini |
|
713 CTestExecuteIniData* parseTestExecuteIni = NULL; |
|
714 TBuf<KMaxTestExecuteNameLength> resultFilePath; |
|
715 TBuf<KMaxTestExecuteNameLength> xmlFilePath; |
|
716 TInt logMode; |
|
717 TInt logLevel; |
|
718 |
|
719 TRAPD(err,parseTestExecuteIni = CTestExecuteIniData::NewL()); |
|
720 if (err == KErrNone) |
|
721 { |
|
722 CleanupStack::PushL(parseTestExecuteIni); |
|
723 parseTestExecuteIni->ExtractValuesFromIni(); |
|
724 parseTestExecuteIni->GetKeyValueFromIni(KTEFHtmlKey, resultFilePath); |
|
725 parseTestExecuteIni->GetKeyValueFromIni(KTEFXmlKey, xmlFilePath); |
|
726 parseTestExecuteIni->GetKeyValueFromIni(KTEFLogMode, logMode); |
|
727 parseTestExecuteIni->GetKeyValueFromIni(KTEFLogSeverityKey, logLevel); |
|
728 parseTestExecuteIni->GetKeyValueFromIni(KTEFEnableIniAccessLog, IniAccessLog()); |
|
729 } |
|
730 else |
|
731 { |
|
732 resultFilePath.Copy(KTestExecuteLogPath); |
|
733 xmlFilePath.Copy(KTestExecuteLogPath); |
|
734 logMode = TLoggerOptions(ELogHTMLOnly); |
|
735 logLevel = RFileFlogger::TLogSeverity(ESevrAll); |
|
736 IniAccessLog() = ETrue; |
|
737 } |
|
738 Logger().SetLoggerOptions(logMode); |
|
739 |
|
740 // Initialise a handle to the file logger |
|
741 User::LeaveIfError(Logger().Connect()); |
|
742 RFs fS; |
|
743 User::LeaveIfError(fS.Connect()); |
|
744 CleanupClosePushL(fS); |
|
745 RFile file; |
|
746 TBuf<KMaxTestExecuteNameLength> xmlLogFile(xmlFilePath); |
|
747 TBuf<KMaxTestExecuteNameLength> logFile; |
|
748 TBuf<KMaxTestExecuteNameLength> logFileNameFile(resultFilePath); |
|
749 logFileNameFile.Append(KTestExecuteScheduleTestLogCompatibilityNameFile); |
|
750 if(file.Open(fS,logFileNameFile,EFileRead | EFileShareAny) != KErrNone) |
|
751 { |
|
752 // For the old flogger we have to create an individual file |
|
753 logFile.Copy(TestStepName()); |
|
754 _LIT(KTxtExtension,".txt"); |
|
755 logFile.Append(KTxtExtension); |
|
756 logMode = TLoggerOptions(0); |
|
757 Logger().SetLoggerOptions(logMode); |
|
758 } |
|
759 else |
|
760 { |
|
761 CleanupClosePushL(file); |
|
762 TBuf8<KMaxTestExecuteNameLength> logFile8; |
|
763 TInt fileSize; |
|
764 User::LeaveIfError(file.Size(fileSize)); |
|
765 User::LeaveIfError(file.Read(logFile8,fileSize)); |
|
766 logFile.Copy(logFile8); |
|
767 xmlLogFile.Append(logFile); |
|
768 _LIT(KXmlExtension,".xml"); |
|
769 xmlLogFile.Append(KXmlExtension); |
|
770 _LIT(KHtmExtension,".htm"); |
|
771 logFile.Append(KHtmExtension); |
|
772 CleanupStack::Pop(&file); |
|
773 file.Close(); |
|
774 } |
|
775 TBuf<KMaxTestExecuteLogFilePath> logFilePath(resultFilePath); |
|
776 logFilePath.Append(logFile); |
|
777 CleanupStack::Pop(&fS); |
|
778 fS.Close(); |
|
779 |
|
780 if (logMode == 0 || logMode == 2) |
|
781 { |
|
782 User::LeaveIfError(Logger().HtmlLogger().CreateLog(logFilePath,RTestExecuteLogServ::ELogModeAppend)); |
|
783 Logger().HtmlLogger().SetLogLevel(TLogSeverity(logLevel)); |
|
784 } |
|
785 if (logMode == 1 || logMode == 2) |
|
786 { |
|
787 User::LeaveIfError(Logger().XmlLogger().CreateLog(xmlLogFile,RFileFlogger::ELogModeAppend)); |
|
788 Logger().XmlLogger().SetLogLevel(RFileFlogger::TLogSeverity(logLevel)); |
|
789 } |
|
790 if (parseTestExecuteIni != NULL) |
|
791 { |
|
792 CleanupStack::PopAndDestroy(parseTestExecuteIni); |
|
793 } |
|
794 } |
|
795 |
|
796 EXPORT_C void CEglTestStep::PartialInitialiseL(const TDesC& aStepName) |
|
797 { |
|
798 SetTestStepName(aStepName); |
|
799 SetLoggerForProcessWrapperL(); |
|
800 // Assume pass |
|
801 SetTestStepResult(EPass); |
|
802 } |
|
803 |
|
804 EXPORT_C void CEglTestStep::CreateEglSessionL(TInt aIdx) |
|
805 { |
|
806 delete iEglSess; //just in case it was called twice |
|
807 iEglSess = CTestEglSession::NewL(Logger(), iDisplay, aIdx); |
|
808 } |
|
809 |