|
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 @internalComponent - Internal Symbian test code */ |
|
19 |
|
20 |
|
21 #include <e32base.h> |
|
22 #include <e32debug.h> |
|
23 #include <e32msgqueue.h> |
|
24 #include <ecom/ecom.h> |
|
25 #include <test/testexecuteserverbase.h> |
|
26 #include <e32math.h> |
|
27 #include "localtestbase.h" |
|
28 #include "egltest_commscommon.h" |
|
29 #include "egltest_endpoint_util.h" |
|
30 |
|
31 |
|
32 _LIT(KEglEndpointTestServerName,"eglendpointtestserver"); |
|
33 |
|
34 |
|
35 CLocalTestStepBase::CLocalTestStepBase(enum TTestUid aUid) : |
|
36 iTestId(aUid), |
|
37 iIsInTestStep(EFalse) |
|
38 { |
|
39 } |
|
40 |
|
41 void CLocalTestStepBase::DoPreambleL() |
|
42 { |
|
43 //null implmentation for base class |
|
44 } |
|
45 |
|
46 void CLocalTestStepBase::DoPostambleL() |
|
47 { |
|
48 //null implmentation for base class |
|
49 } |
|
50 |
|
51 //function used for creating the queues. |
|
52 TVerdict CLocalTestStepBase::doTestStepPreambleL() |
|
53 { |
|
54 //Open the queues. |
|
55 User::LeaveIfError(iResultOutQueue.OpenGlobal(KResultQueueName)); |
|
56 User::LeaveIfError(iParamsInQueue.OpenGlobal(KParamsQueueName)); |
|
57 SetTestStepResult(EPass); |
|
58 iHasCurrentTestIds = EFalse; |
|
59 iResultLog = CTestIdResultLogger::NewL(Logger()); |
|
60 DoPreambleL(); |
|
61 return EPass; |
|
62 } |
|
63 |
|
64 TVerdict CLocalTestStepBase::doTestStepPostambleL() |
|
65 { |
|
66 //Log the result of the current tests. |
|
67 if(iHasCurrentTestIds) |
|
68 { |
|
69 iResultLog->LogResult(iTestIdVerdict); |
|
70 } |
|
71 |
|
72 DoPostambleL(); |
|
73 delete iResultLog; |
|
74 iResultLog = NULL; |
|
75 iResultOutQueue.Close(); |
|
76 iParamsInQueue.Close(); |
|
77 return EPass; |
|
78 } |
|
79 |
|
80 CLocalTestStepBase::~CLocalTestStepBase() |
|
81 { |
|
82 //closing an already closed handle is harmless |
|
83 iResultOutQueue.Close(); |
|
84 iParamsInQueue.Close(); |
|
85 } |
|
86 |
|
87 TVerdict CLocalTestStepBase::StartRemoteTestStep(const TRemoteTestParams& aMessageIn) |
|
88 { |
|
89 //Starting the remote test step is implemented as a special case |
|
90 //of running a test case, with TestCase = KStartTestStepCaseNumber. |
|
91 iIsInTestStep = ETrue; |
|
92 TVerdict retVal = RunRemoteTestCase(KStartTestStepCaseNumber, aMessageIn); |
|
93 if(retVal != EPass) |
|
94 { |
|
95 iIsInTestStep = EFalse; |
|
96 } |
|
97 return retVal; |
|
98 } |
|
99 |
|
100 TVerdict CLocalTestStepBase::EndRemoteTestStep(const TRemoteTestParams& aMessageIn) |
|
101 { |
|
102 //Ending the remote test step is implemented as a special case |
|
103 //of running a test case, with TestCase = KEndTestStepCaseNumber. |
|
104 TVerdict retVal = RunRemoteTestCase(KEndTestStepCaseNumber, aMessageIn); |
|
105 iIsInTestStep = EFalse; |
|
106 return retVal; |
|
107 } |
|
108 |
|
109 TVerdict CLocalTestStepBase::RunRemoteTestCase(TInt aTestCase, const TRemoteTestParams& aMessageIn) |
|
110 { |
|
111 //Don't attempt to run any test cases if we are not in a test step. |
|
112 if(!iIsInTestStep) |
|
113 { |
|
114 SetTestStepResult(EFail); |
|
115 return TestStepResult(); |
|
116 } |
|
117 |
|
118 //send the message |
|
119 TRemoteTestParamsPacket message(iTestId, aTestCase, aMessageIn); |
|
120 iParamsInQueue.SendBlocking(message); |
|
121 |
|
122 TRemoteTestResult result; |
|
123 do |
|
124 { |
|
125 //relying on TEF timeout if there are problems such as the render stage not loaded. |
|
126 iResultOutQueue.ReceiveBlocking(result); |
|
127 |
|
128 //if uid and test case doesn't match something has gone badly wrong |
|
129 if (result.iUid != iTestId || result.iTestCase != aTestCase) |
|
130 { |
|
131 //test is out of Sync |
|
132 User::Panic(_L("Test out of sync with render stage"), KErrGeneral); |
|
133 } |
|
134 |
|
135 //log the message if there is one |
|
136 if (!result.iFinished) |
|
137 { |
|
138 //Convert the filename to a C string. The remote test env guarantees |
|
139 //that there is a free space at the end of the descriptor to add NULL. |
|
140 const TText8* file = result.iFile.PtrZ(); |
|
141 |
|
142 //Convert the message to unicode and log the message. |
|
143 TBuf<KRSLogMessageLength> message; |
|
144 message.Copy(result.iMessage); |
|
145 Logger().LogExtra(file, result.iLine, result.iSeverity, _L("%S"), &message); |
|
146 } |
|
147 }while (!result.iFinished); |
|
148 |
|
149 //Translate the RemoteTestStep verdict to a TVerdict. |
|
150 TVerdict retVal = EPass; |
|
151 switch (result.iVerdict) |
|
152 { |
|
153 case ERtvPass: |
|
154 retVal = EPass; |
|
155 break; |
|
156 |
|
157 case ERtvFail: |
|
158 retVal = EFail; |
|
159 break; |
|
160 |
|
161 case ERtvInconclusive: |
|
162 retVal = EInconclusive; |
|
163 break; |
|
164 |
|
165 case ERtvAbort: |
|
166 retVal = EAbort; |
|
167 break; |
|
168 |
|
169 case ERtvPanic: |
|
170 //The remote test paniced, so we panic too. |
|
171 //This means the output log relects what actually happened. |
|
172 User::Panic(_L("Remote Test Step Paniced!"), KErrGeneral); |
|
173 break; |
|
174 |
|
175 case ERtvTimeout: |
|
176 //The remote test timedout, so we sleep so that tef times us out too. |
|
177 //This means the output log relects what actually happened. |
|
178 User::After(KMaxTInt); |
|
179 break; |
|
180 |
|
181 case ERtvUnknownTestUid: |
|
182 retVal = EIgnore; |
|
183 break; |
|
184 |
|
185 default: |
|
186 User::Panic(_L("Invalid verdict returned from the remote test step!"), KErrGeneral); |
|
187 break; |
|
188 } |
|
189 |
|
190 if(retVal != EPass) |
|
191 { |
|
192 SetTestStepResult(retVal); |
|
193 } |
|
194 |
|
195 return retVal; |
|
196 } |
|
197 |
|
198 |
|
199 void CLocalTestStepBase::RegisterTestIdsL(const TDesC& aTestString) |
|
200 { |
|
201 iResultLog->RegisterTestIdsL(aTestString); |
|
202 } |
|
203 |
|
204 |
|
205 void CLocalTestStepBase::SetCurrentTestIds(const TDesC& aTestString) |
|
206 { |
|
207 if(iHasCurrentTestIds) |
|
208 { |
|
209 iResultLog->LogResult(iTestIdVerdict); |
|
210 } |
|
211 |
|
212 iResultLog->SetCurrentTestIds(aTestString); |
|
213 iHasCurrentTestIds = ETrue; |
|
214 iTestIdVerdict = EPass; |
|
215 } |
|
216 |
|
217 |
|
218 void CLocalTestStepBase::SetTestStepResult(TVerdict aVerdict) |
|
219 { |
|
220 iTestIdVerdict = aVerdict; |
|
221 CTestStep::SetTestStepResult(aVerdict); |
|
222 } |
|
223 |
|
224 |
|
225 //Used by the result logger to delimit the csv test id strings. |
|
226 class TCommaDelimiter |
|
227 { |
|
228 private: |
|
229 mutable TPtrC iRemaining; |
|
230 |
|
231 public: |
|
232 TCommaDelimiter(const TDesC& aString) |
|
233 { |
|
234 //Set our remaining string to the whole string, or NULL if empty. |
|
235 if(aString.Length() == 0) |
|
236 { |
|
237 iRemaining.Set(NULL, 0); |
|
238 } |
|
239 else |
|
240 { |
|
241 iRemaining.Set(aString); |
|
242 } |
|
243 } |
|
244 |
|
245 |
|
246 TInt GetNext(TPtrC& aSegment) const |
|
247 { |
|
248 //Trim off any leading commas. |
|
249 while(iRemaining.Length() >= 2 && iRemaining[0] == ',') |
|
250 { |
|
251 iRemaining.Set(&iRemaining[1], iRemaining.Length() - 1); |
|
252 } |
|
253 |
|
254 //If remaining string is empty or has one remaining comma, return. |
|
255 if(iRemaining.Length() == 0 || iRemaining[0] == ',') |
|
256 { |
|
257 iRemaining.Set(NULL, 0); |
|
258 return KErrNotFound; |
|
259 } |
|
260 |
|
261 //Find the first comma. |
|
262 TInt pos = iRemaining.Locate(','); |
|
263 |
|
264 //If comma not found, return all remaining string. |
|
265 if(pos == KErrNotFound) |
|
266 { |
|
267 aSegment.Set(iRemaining); |
|
268 iRemaining.Set(NULL, 0); |
|
269 return KErrNone; |
|
270 } |
|
271 |
|
272 //Comma found. There must be non-comma chars between 0 |
|
273 //and pos since we trimmed leading commas previously. |
|
274 aSegment.Set(&iRemaining[0], pos); |
|
275 iRemaining.Set(&iRemaining[pos], iRemaining.Length() - pos); |
|
276 return KErrNone; |
|
277 } |
|
278 |
|
279 |
|
280 TInt GetNextTrimmed(TPtrC& aSegment) const |
|
281 { |
|
282 //Keep calling GetNext() until we get a segment that has |
|
283 //chars other than spaces or there are no more segments. |
|
284 while(1) |
|
285 { |
|
286 TPtrC segment; |
|
287 TInt err = GetNext(segment); |
|
288 if(err != KErrNone) |
|
289 { |
|
290 return err; |
|
291 } |
|
292 |
|
293 TInt front; |
|
294 TInt back; |
|
295 for(front = 0; front < segment.Length() && segment[front] == ' '; front++) {} |
|
296 for(back = segment.Length() - 1; back >= 0 && segment[back] == ' '; back--) {} |
|
297 |
|
298 TInt length = (back + 1) - front; |
|
299 if(length > 0 && segment[front] != ' ' && segment[back] != ' ') |
|
300 { |
|
301 aSegment.Set(&segment[front], length); |
|
302 return KErrNone; |
|
303 } |
|
304 } |
|
305 } |
|
306 }; |
|
307 |
|
308 |
|
309 CTestIdResultLogger* CTestIdResultLogger::NewL(CTestExecuteLogger& aLogger) |
|
310 { |
|
311 CTestIdResultLogger* self = new (ELeave) CTestIdResultLogger(aLogger); |
|
312 CleanupStack::PushL(self); |
|
313 self->ConstructL(); |
|
314 CleanupStack::Pop(self); |
|
315 return self; |
|
316 } |
|
317 |
|
318 |
|
319 CTestIdResultLogger::CTestIdResultLogger(CTestExecuteLogger& aLogger) : |
|
320 iOriginalThread(RThread().Id()), |
|
321 iLogger(aLogger) |
|
322 { |
|
323 } |
|
324 |
|
325 |
|
326 void CTestIdResultLogger::ConstructL() |
|
327 { |
|
328 //Create panic monitor thread. Note that we share the heap with this |
|
329 //thread so that the arrays remain in scope if this thread panics. |
|
330 //Note also no need for explicit locking of arrays since the panic |
|
331 //monitor will only access them if a panic occurs here. |
|
332 static const TInt KStackSize = 0x2000; // 8KB |
|
333 TUint32 random = Math::Random(); |
|
334 TName threadName; |
|
335 _LIT(KThreadNameFormat, "%S-%u"); |
|
336 _LIT(KEnvName, "EpTestIdLogger"); |
|
337 threadName.Format(KThreadNameFormat, &KEnvName, random); |
|
338 User::LeaveIfError(iPanicMonitor.Create(threadName, PanicMonitorMain, KStackSize, &User::Heap(), this, EOwnerThread)); |
|
339 |
|
340 //Rendezvous with panic thread. |
|
341 TRequestStatus rendStat; |
|
342 iPanicMonitor.Rendezvous(rendStat); |
|
343 iPanicMonitor.Resume(); |
|
344 User::WaitForRequest(rendStat); |
|
345 } |
|
346 |
|
347 |
|
348 CTestIdResultLogger::~CTestIdResultLogger() |
|
349 { |
|
350 TRequestStatus logonStat; |
|
351 iPanicMonitor.Logon(logonStat); |
|
352 iPanicMonitor.RequestComplete(iCloseMonitor, KErrNone); |
|
353 User::WaitForRequest(logonStat); |
|
354 iPanicMonitor.Close(); |
|
355 iRegisteredTestIds.Close(); |
|
356 iCurrentTestIds.Close(); |
|
357 } |
|
358 |
|
359 |
|
360 void CTestIdResultLogger::RegisterTestIdsL(const TDesC& aTestString) |
|
361 { |
|
362 //Set up delimitter. |
|
363 TCommaDelimiter delimit(aTestString); |
|
364 |
|
365 //Get every test id from the string and add it to the registered test ids array. |
|
366 TPtrC testIdPtr; |
|
367 while(delimit.GetNextTrimmed(testIdPtr) == KErrNone) |
|
368 { |
|
369 TTestId testId(testIdPtr); |
|
370 iRegisteredTestIds.AppendL(testId); |
|
371 } |
|
372 |
|
373 //Reserve enough space in the current test ids array so that SCurrentTestIds() can not fail. |
|
374 iCurrentTestIds.ReserveL(iRegisteredTestIds.Count()); |
|
375 } |
|
376 |
|
377 |
|
378 void CTestIdResultLogger::SetCurrentTestIds(const TDesC& aTestString) |
|
379 { |
|
380 ASSERT(iCurrentTestIds.Count() == 0); |
|
381 |
|
382 //Set up delimitter. |
|
383 TCommaDelimiter delimit(aTestString); |
|
384 |
|
385 //Get every test id from the string and add it to the registered test ids array. |
|
386 TPtrC testIdPtr; |
|
387 while(delimit.GetNextTrimmed(testIdPtr) == KErrNone) |
|
388 { |
|
389 TTestId testId(testIdPtr); |
|
390 |
|
391 //This cannot fail under legitimate circumstances, since enough |
|
392 //space is reserved in this array when registering TestIds. |
|
393 TInt err = iCurrentTestIds.Append(testId); |
|
394 ASSERT(err == KErrNone); |
|
395 } |
|
396 |
|
397 //Make sure these tests were registered and remove from the registered array. |
|
398 for(TInt i=0; i < iCurrentTestIds.Count(); i++) |
|
399 { |
|
400 TInt idx = iRegisteredTestIds.Find(iCurrentTestIds[i]); |
|
401 ASSERT(idx != KErrNotFound); |
|
402 iRegisteredTestIds.Remove(idx); |
|
403 } |
|
404 } |
|
405 |
|
406 |
|
407 void CTestIdResultLogger::LogResult(TVerdict aVerdict) |
|
408 { |
|
409 const TInt KMaxVerdictLength = 20; |
|
410 TBuf<KMaxVerdictLength> verdict; |
|
411 switch(aVerdict) |
|
412 { |
|
413 case EPass: verdict.Append(_L("PASS")); break; |
|
414 case EFail: verdict.Append(_L("FAIL")); break; |
|
415 case EInconclusive: verdict.Append(_L("INCONCLUSIVE")); break; |
|
416 case ETestSuiteError: verdict.Append(_L("TEST SUTE ERROR")); break; |
|
417 case EAbort: verdict.Append(_L("ABORT")); break; |
|
418 case EIgnore: verdict.Append(_L("IGNORE")); break; |
|
419 } |
|
420 |
|
421 while(iCurrentTestIds.Count()) |
|
422 { |
|
423 LogResult(iLogger, iCurrentTestIds[0], verdict); |
|
424 iCurrentTestIds.Remove(0); |
|
425 } |
|
426 } |
|
427 |
|
428 |
|
429 void CTestIdResultLogger::LogResult(CTestExecuteLogger& aLogger, const TTestId& aTestId, const TDesC& aVerdict) |
|
430 { |
|
431 aLogger.LogExtra(((TText8*)"EGL ENDPOINT TEST RESULT >>>"), 0, ESevrInfo, _L("GRAPHICS-EGL-%S: %S"), &aTestId, &aVerdict); |
|
432 } |
|
433 |
|
434 |
|
435 TInt CTestIdResultLogger::PanicMonitorMain(TAny* aSelf) |
|
436 { |
|
437 CTestIdResultLogger* self = static_cast<CTestIdResultLogger*>(aSelf); |
|
438 |
|
439 //Create cleanup stack. |
|
440 CTrapCleanup* cleanup = CTrapCleanup::New(); |
|
441 ASSERT(cleanup); |
|
442 |
|
443 //Create active scheduler. |
|
444 CActiveScheduler* scheduler = new CActiveScheduler(); |
|
445 ASSERT(scheduler); |
|
446 CActiveScheduler::Install(scheduler); |
|
447 |
|
448 TRAPD(err, self->PanicMonitorMainL()); |
|
449 __ASSERT_ALWAYS(err == KErrNone, User::Invariant()); |
|
450 |
|
451 delete scheduler; |
|
452 delete cleanup; |
|
453 return KErrNone; |
|
454 } |
|
455 |
|
456 |
|
457 void CTestIdResultLogger::PanicMonitorMainL() |
|
458 { |
|
459 //Setup logging. |
|
460 CTestExecuteLogger logger; |
|
461 TEndpointUtil::SetLoggerForProcessWrapperL(logger); |
|
462 |
|
463 //Tell parent how to close us. |
|
464 TRequestStatus closeStatus = KRequestPending; |
|
465 iCloseMonitor = &closeStatus; |
|
466 |
|
467 //Open parent thread and logon. |
|
468 RThread origThread; |
|
469 User::LeaveIfError(origThread.Open(iOriginalThread, EOwnerThread)); |
|
470 TRequestStatus origStatus; |
|
471 origThread.Logon(origStatus); |
|
472 |
|
473 //Rendevous with our parent then wait for thread to exit or close command. |
|
474 RThread().Rendezvous(KErrNone); |
|
475 User::WaitForRequest(closeStatus, origStatus); |
|
476 |
|
477 if (closeStatus != KRequestPending) |
|
478 { |
|
479 //Parent is shutting us down. Just cancel our outstanding request and exit. |
|
480 origThread.LogonCancel(origStatus); |
|
481 User::WaitForRequest(origStatus); |
|
482 } |
|
483 else if (origStatus != KRequestPending) |
|
484 { |
|
485 //We can only get here if parent panicked. |
|
486 //Log that all current tests were panicked and all registered tests were not run. |
|
487 _LIT(KPanicked, "PANIC"); |
|
488 _LIT(KNotRun, "NOT RUN DUE TO PREVIOUS PANIC"); |
|
489 while(iCurrentTestIds.Count()) |
|
490 { |
|
491 LogResult(logger, iCurrentTestIds[0], KPanicked); |
|
492 iCurrentTestIds.Remove(0); |
|
493 } |
|
494 while(iRegisteredTestIds.Count()) |
|
495 { |
|
496 LogResult(logger, iRegisteredTestIds[0], KNotRun); |
|
497 iRegisteredTestIds.Remove(0); |
|
498 } |
|
499 } |
|
500 |
|
501 origThread.Close(); |
|
502 } |
|
503 |
|
504 |
|
505 CEglEndpointTestServer* CEglEndpointTestServer::NewL() |
|
506 { |
|
507 CEglEndpointTestServer* server = new(ELeave) CEglEndpointTestServer(); |
|
508 CleanupStack::PushL(server); |
|
509 // CServer base class call |
|
510 TParsePtrC serverName(RProcess().FileName()); |
|
511 server->StartL(serverName.Name()); |
|
512 CleanupStack::Pop(server); |
|
513 return server; |
|
514 } |
|
515 |
|
516 static void MainL() |
|
517 { |
|
518 CActiveScheduler* sched=NULL; |
|
519 sched=new(ELeave) CActiveScheduler; |
|
520 CActiveScheduler::Install(sched); |
|
521 |
|
522 CEglEndpointTestServer* server = NULL; |
|
523 // Create the CTestServer derived server |
|
524 TRAPD(err, server = CEglEndpointTestServer::NewL()); |
|
525 if(!err) |
|
526 { |
|
527 // Sync with the client and enter the active scheduler |
|
528 RProcess::Rendezvous(KErrNone); |
|
529 sched->Start(); |
|
530 } |
|
531 delete server; |
|
532 delete sched; |
|
533 } |
|
534 |
|
535 /** |
|
536 @return Standard Epoc error code on process exit |
|
537 Process entry point. Called by client using RProcess API |
|
538 */ |
|
539 TInt E32Main() |
|
540 { |
|
541 __UHEAP_MARK; |
|
542 CTrapCleanup* cleanup = CTrapCleanup::New(); |
|
543 if(!cleanup) |
|
544 { |
|
545 return KErrNoMemory; |
|
546 } |
|
547 TRAPD(err,MainL()); |
|
548 |
|
549 if (err) |
|
550 { |
|
551 RDebug::Print(_L("CEglEndpointTestServer::MainL - Error: %d"), err); |
|
552 User::Panic(KEglEndpointTestServerName, err); |
|
553 } |
|
554 |
|
555 delete cleanup; |
|
556 REComSession::FinalClose(); |
|
557 __UHEAP_MARKEND; |
|
558 return KErrNone; |
|
559 } |