|
1 // Copyright (c) 2001-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 #include "HttpTestCore.h" |
|
17 |
|
18 _LIT(KTextFailure,"Test failed with error %d.\n"); |
|
19 _LIT(KTextFailedTest,"TEST %S FAILED\n"); |
|
20 _LIT(KTextPassedTest,"TEST %S PASSED\n"); |
|
21 _LIT(KTextInterruptTest, "TEST %S INTERRUPTED\n"); |
|
22 |
|
23 // Dummy POST body provided in test base should a specific test not want to generate its own |
|
24 _LIT8(KTestPostBody, "a=10\r\n"); |
|
25 |
|
26 // format for output of data/time values |
|
27 _LIT(KDateFormat,"%D%M%Y%/0%1%/1%2%/2%3%/3 %:0%H%:1%T%:2%S.%C%:3"); |
|
28 |
|
29 |
|
30 // Test harness requirements: |
|
31 // Uses an active object state machine to run tests. |
|
32 |
|
33 |
|
34 //##ModelId=3A76DDA701A2 |
|
35 EXPORT_C void CTestScheduler::Error(TInt anError) const |
|
36 { |
|
37 _LIT(KTestPanic,"CTestScheduler RunL leave"); |
|
38 User::Panic(KTestPanic,anError); |
|
39 } |
|
40 |
|
41 // CHttpTestEngine |
|
42 |
|
43 EXPORT_C void CHttpTestEngine::SetCurrentStatusCode(TInt aStatusCode) |
|
44 { |
|
45 iCurrentStatusCode=aStatusCode; |
|
46 } |
|
47 |
|
48 |
|
49 void CHttpTestEngine::DoCancel() |
|
50 { |
|
51 // cancel the current test |
|
52 if (iCurrentTest) |
|
53 iCurrentTest->Cancel(); |
|
54 } |
|
55 |
|
56 void CHttpTestEngine::RunL() |
|
57 { |
|
58 switch (iState) |
|
59 { |
|
60 case EIdle: |
|
61 { |
|
62 TRAPD(err,RunNextTestL()) |
|
63 if (err!=KErrNone) |
|
64 { |
|
65 Console().Printf(KTextFailure, err); |
|
66 } |
|
67 } |
|
68 break; |
|
69 case ERunningTest: |
|
70 case ESingleTestCaseFailed: |
|
71 break; |
|
72 case EShuttingDown: |
|
73 CActiveScheduler::Stop(); |
|
74 break; |
|
75 } |
|
76 } |
|
77 |
|
78 |
|
79 EXPORT_C void CHttpTestEngine::PressAnyKey() |
|
80 { |
|
81 if (iDetectKeyPress) |
|
82 iDetectKeyPress->Cancel(); |
|
83 |
|
84 iUtils->PressAnyKey(); |
|
85 |
|
86 if (iDetectKeyPress) |
|
87 iDetectKeyPress->RequestKey(); |
|
88 |
|
89 } |
|
90 |
|
91 void CHttpTestEngine::TestInteractionDetectedL(TTestInteraction aTestInteraction) |
|
92 { |
|
93 if (aTestInteraction == EStopCurrentTest) |
|
94 { |
|
95 iCurrentTest->Cancel(); |
|
96 TestCompleted(KErrTestInterrupted); |
|
97 } |
|
98 } |
|
99 |
|
100 |
|
101 /** |
|
102 * Static factory function for a new test engine |
|
103 */ |
|
104 EXPORT_C CHttpTestEngine* CHttpTestEngine::NewL(const TDesC& aTestTitle, TBool aSilent) |
|
105 { |
|
106 CHttpTestEngine* self = new(ELeave) CHttpTestEngine(aSilent); |
|
107 CleanupStack::PushL(self); |
|
108 self->ConstructL(aTestTitle); |
|
109 CleanupStack::Pop(self); |
|
110 return self; |
|
111 } |
|
112 |
|
113 CHttpTestEngine::CHttpTestEngine(TBool aSilent) |
|
114 : CActive(CActive::EPriorityUserInput), iSilent(aSilent) |
|
115 { |
|
116 } |
|
117 |
|
118 /** |
|
119 * Constructor for the test engine |
|
120 * Creates a console and sets itself active |
|
121 */ |
|
122 void CHttpTestEngine::ConstructL(const TDesC& aTestTitle) |
|
123 { |
|
124 iUtils = CHTTPTestUtils::NewL(aTestTitle); |
|
125 iUtils->SetSilent(iSilent); |
|
126 iDetectKeyPress = CDetectKeyPress::NewLC(*(iUtils->Test().Console()),*this); |
|
127 CleanupStack::Pop(iDetectKeyPress); |
|
128 CActiveScheduler::Add(this); |
|
129 SetActive(); |
|
130 TRequestStatus* stat = &iStatus; |
|
131 User::RequestComplete(stat,KErrNone); |
|
132 } |
|
133 |
|
134 /** |
|
135 * Destructor for CHttpTestEngine |
|
136 * Cancels any outstanding requests and deletes member variables |
|
137 */ |
|
138 EXPORT_C CHttpTestEngine::~CHttpTestEngine() |
|
139 { |
|
140 Cancel(); |
|
141 iTestSet.Close(); |
|
142 iTestResults.Close(); |
|
143 delete iDetectKeyPress; |
|
144 delete iUtils; |
|
145 } |
|
146 |
|
147 /** |
|
148 * Configure the set of tests to be done in this run of the test engine. |
|
149 */ |
|
150 EXPORT_C void CHttpTestEngine::ConfigureTestSet(RPointerArray<CHttpTestBase> aTestSet) |
|
151 { |
|
152 iTestSet = aTestSet; |
|
153 } |
|
154 |
|
155 /** |
|
156 * This should be called by tests to indicate that they have |
|
157 * completed and whether they were sucessful or not |
|
158 */ |
|
159 EXPORT_C void CHttpTestEngine::TestCompleted(TInt aResult) |
|
160 { |
|
161 // Log test result. Override silence to ensure something gets displayed |
|
162 TBool wasSilent = iUtils->IsSilent(); |
|
163 iUtils->SetSilent(EFalse); |
|
164 // An expected status code of 0 is used if the test doesn't care about a status code to pass |
|
165 if (aResult == 0) |
|
166 { |
|
167 iUtils->LogIt(KTextPassedTest, &(iCurrentTest->TestName())); |
|
168 iTestResults.Append(ETrue); |
|
169 } |
|
170 else if (aResult == KErrTestInterrupted) |
|
171 { |
|
172 iUtils->LogIt(KTextInterruptTest, &(iCurrentTest->TestName())); |
|
173 iTestResults.Append(EFalse); |
|
174 } |
|
175 else |
|
176 { |
|
177 iUtils->LogIt(KTextFailedTest, &(iCurrentTest->TestName())); |
|
178 iTestResults.Append(EFalse); |
|
179 } |
|
180 iUtils->SetSilent(wasSilent); |
|
181 |
|
182 // Inform test utils that this test is over |
|
183 iUtils->EndTest(aResult); |
|
184 |
|
185 // Switch state so the engine can point at the next test, then set the engine active again |
|
186 iState=EIdle; |
|
187 TRequestStatus* stat = &iStatus; |
|
188 User::RequestComplete(stat,KErrNone); |
|
189 SetActive(); |
|
190 } |
|
191 |
|
192 |
|
193 /** |
|
194 * Run the next test |
|
195 * The switch statement lists all tests to be run |
|
196 * |
|
197 */ |
|
198 void CHttpTestEngine::RunNextTestL() |
|
199 { |
|
200 // delete the test previously run |
|
201 |
|
202 delete iCurrentTest; |
|
203 iCurrentTest=NULL; |
|
204 |
|
205 // Advance to the next test |
|
206 |
|
207 iTestIndex++; |
|
208 if (iTestIndex <= iTestSet.Count()) |
|
209 { |
|
210 // still going... |
|
211 iCurrentTest = iTestSet[iTestIndex - 1]; |
|
212 iCurrentTest->SetEngine(this); |
|
213 iUtils->StartTestL(iCurrentTest->TestName()); |
|
214 iState = ERunningTest; |
|
215 iCurrentTest->BeginTest(); |
|
216 } |
|
217 else |
|
218 { |
|
219 // finished testing - set status to shut down and complete our own request |
|
220 SetPriority(EPriorityIdle); |
|
221 iState = EShuttingDown; |
|
222 int a,b; |
|
223 TestSummary(a,b); |
|
224 TRequestStatus* stat = &iStatus; |
|
225 User::RequestComplete(stat,KErrNone); |
|
226 SetActive(); |
|
227 return; |
|
228 } |
|
229 } |
|
230 |
|
231 /** |
|
232 * return a reference to the console used by the test harness |
|
233 */ |
|
234 EXPORT_C CConsoleBase& CHttpTestEngine::Console() const |
|
235 { |
|
236 return *(iUtils->Test().Console()); |
|
237 } |
|
238 |
|
239 /** |
|
240 * return a reference to the test harness utilities |
|
241 */ |
|
242 EXPORT_C CHTTPTestUtils& CHttpTestEngine::Utils() const |
|
243 { |
|
244 return *iUtils; |
|
245 } |
|
246 |
|
247 |
|
248 EXPORT_C void CHttpTestEngine::TestSummary(TInt& aNumPasses, TInt& aNumFailures) const |
|
249 { |
|
250 aNumPasses = 0; |
|
251 aNumFailures = 0; |
|
252 for (TInt ii = 0; ii < iTestResults.Count(); ii++) |
|
253 iTestResults[ii]?(aNumPasses++):(aNumFailures++); |
|
254 } |
|
255 |
|
256 |
|
257 //-----CHttpTestBase------------------------------------------------------------------ |
|
258 |
|
259 EXPORT_C CHttpTestBase::CHttpTestBase() : CActive(CActive::EPriorityStandard) |
|
260 { |
|
261 iExpectedStatusCode= 200; |
|
262 iTestFail=0; |
|
263 } |
|
264 |
|
265 EXPORT_C TInt CHttpTestBase::ExpectedStatusCode() |
|
266 { |
|
267 return iExpectedStatusCode; |
|
268 } |
|
269 |
|
270 EXPORT_C void CHttpTestBase::BeginTest() |
|
271 { |
|
272 CActiveScheduler::Add(this); |
|
273 SetActive(); |
|
274 TRequestStatus* stat = &iStatus; |
|
275 User::RequestComplete(stat,KErrNone); |
|
276 } |
|
277 |
|
278 EXPORT_C void CHttpTestBase::RunL() |
|
279 { |
|
280 // Either do leak tests or regular tests |
|
281 TInt err = KErrNone; |
|
282 if (iLeakTests > 0) |
|
283 { |
|
284 TRAP(err,DoLeakTestsL()); |
|
285 } |
|
286 else |
|
287 { |
|
288 TRAP(err,DoRunL()); |
|
289 } |
|
290 |
|
291 switch(err) |
|
292 { |
|
293 case KErrNone: |
|
294 { |
|
295 iEngine->Utils().LogIt(_L("\nTest case finished")); |
|
296 if (!iEngine->IsSilent()) |
|
297 iEngine->PressAnyKey(); |
|
298 } |
|
299 break; |
|
300 default:// any error |
|
301 { |
|
302 iEngine->Utils().LogIt(_L("Test case failed (caught a Leave) ... skipping to the next test case")); |
|
303 } |
|
304 break; |
|
305 } |
|
306 iEngine->TestCompleted(err); |
|
307 } |
|
308 |
|
309 |
|
310 void CHttpTestBase::DoLeakTestsL() |
|
311 { |
|
312 for (TInt ii = iFirstLeakIteration; ii < iLeakTests; ++ii) |
|
313 { |
|
314 iEngine->Utils().LogIt(_L("Memory Leak Testing on allocation %d\n"), ii); |
|
315 |
|
316 TInt err = KErrNoMemory; |
|
317 |
|
318 __UHEAP_MARK; |
|
319 __UHEAP_FAILNEXT(ii); |
|
320 TRAP(err,DoRunL()); |
|
321 __UHEAP_MARKEND; |
|
322 User::Heap().Check(); |
|
323 __UHEAP_RESET; |
|
324 |
|
325 // Break out if the test passes successfully; allow only memory failure or test failure codes to proceed. |
|
326 if (err == KErrNone) |
|
327 return; |
|
328 else if (err != KErrNoMemory && err != KErrTestFailed) |
|
329 User::Leave(err); |
|
330 } |
|
331 } |
|
332 |
|
333 EXPORT_C TInt CHttpTestBase::RunError(TInt aErr) |
|
334 { |
|
335 iEngine->Utils().LogIt(_L("\nTest failed with error code %d\n"), aErr); |
|
336 return KErrNone; |
|
337 } |
|
338 |
|
339 EXPORT_C void CHttpTestBase::CompleteOwnRequest() |
|
340 { |
|
341 TRequestStatus* stat = &iStatus; |
|
342 User::RequestComplete(stat,KErrNone); |
|
343 if (!IsActive()) |
|
344 SetActive(); |
|
345 } |
|
346 |
|
347 |
|
348 //-----CHttpTestTransBase------------------------------------------------------------------ |
|
349 |
|
350 EXPORT_C CHttpTestTransBase::CHttpTestTransBase() : CHttpTestBase() |
|
351 { |
|
352 } |
|
353 |
|
354 EXPORT_C TBool CHttpTestTransBase::GetNextDataPart(TPtrC8& aDataChunk) |
|
355 { |
|
356 //add a body |
|
357 aDataChunk.Set(KTestPostBody); |
|
358 return ETrue; |
|
359 } |
|
360 |
|
361 EXPORT_C void CHttpTestTransBase::ReleaseData() |
|
362 { |
|
363 } |
|
364 |
|
365 EXPORT_C TInt CHttpTestTransBase::OverallDataSize() |
|
366 { |
|
367 return KTestPostBody().Length(); |
|
368 } |
|
369 |
|
370 EXPORT_C void CHttpTestTransBase::DumpResponseBody(RHTTPTransaction& aTrans) |
|
371 //dump all the body's chunks |
|
372 { |
|
373 MHTTPDataSupplier* body = aTrans.Response().Body(); |
|
374 TPtrC8 dataChunk; |
|
375 TBool isLast = body->GetNextDataPart(dataChunk); |
|
376 iEngine->Utils().DumpData(dataChunk); |
|
377 if (isLast && !iEngine->IsSilent()) |
|
378 iEngine->Utils().LogIt(_L("Got last data chunk.\n")); |
|
379 body->ReleaseData(); |
|
380 } |
|
381 |
|
382 EXPORT_C void CHttpTestTransBase::DumpRespHeaders(RHTTPTransaction& aTrans) |
|
383 //dump the message's headers |
|
384 { |
|
385 //dump the message's headers |
|
386 RHTTPResponse resp = aTrans.Response(); |
|
387 TInt status = resp.StatusCode(); |
|
388 if (!iEngine->IsSilent()) |
|
389 iEngine->Utils().LogIt(_L("Status code = %d\n"), status); |
|
390 |
|
391 RStringPool strP = aTrans.Session().StringPool(); |
|
392 RHTTPHeaders hdr = resp.GetHeaderCollection(); |
|
393 THTTPHdrFieldIter it = hdr.Fields(); |
|
394 |
|
395 TBuf<32> fieldName16; |
|
396 TBuf<128> fieldVal16; |
|
397 |
|
398 while (it.AtEnd() == EFalse) |
|
399 { |
|
400 RStringTokenF fieldNameTk = it(); |
|
401 RStringF fieldName = strP.StringF(fieldNameTk); |
|
402 THTTPHdrVal hVal; |
|
403 if (hdr.GetField(fieldName,0,hVal) == KErrNone) |
|
404 { |
|
405 TPtrC8 fieldNameStr(strP.StringF(fieldName).DesC()); |
|
406 if (fieldNameStr.Length() > 32) |
|
407 fieldNameStr.Set(fieldNameStr.Left(32)); |
|
408 |
|
409 fieldName16.Copy(fieldNameStr); |
|
410 |
|
411 THTTPHdrVal fieldVal; |
|
412 hdr.GetField(fieldName,0,fieldVal); |
|
413 switch (fieldVal.Type()) |
|
414 { |
|
415 case THTTPHdrVal::KTIntVal: |
|
416 { |
|
417 iEngine->Utils().LogIt(_L("%S: %d\n"), &fieldName16, fieldVal.Int()); |
|
418 } break; |
|
419 case THTTPHdrVal::KStrVal: |
|
420 case THTTPHdrVal::KStrFVal: |
|
421 { |
|
422 TPtrC8 fieldValStr(strP.StringF(fieldVal.StrF()).DesC()); |
|
423 if (fieldValStr.Length() > 128) |
|
424 fieldValStr.Set(fieldValStr.Left(128)); |
|
425 |
|
426 fieldVal16.Copy(fieldValStr); |
|
427 iEngine->Utils().LogIt(_L("%S: %S\n"), &fieldName16, &fieldVal16); |
|
428 } break; |
|
429 case THTTPHdrVal::KDateVal: |
|
430 { |
|
431 TDateTime date = fieldVal.DateTime(); |
|
432 TTime t(date); |
|
433 TBuf<128> dateTimeString; |
|
434 TRAPD(err,t.FormatL(dateTimeString,KDateFormat)); |
|
435 if (err == KErrNone) |
|
436 iEngine->Utils().LogIt(_L("%S: %S\n"), &fieldName16, &dateTimeString); |
|
437 } break; |
|
438 default: |
|
439 { |
|
440 iEngine->Utils().LogIt(_L("%S: <unrecognised value type>\n"), &fieldName16); |
|
441 } |
|
442 } |
|
443 } |
|
444 ++it; |
|
445 } |
|
446 } |
|
447 |
|
448 EXPORT_C TInt CHttpTestTransBase::MHFRunError(TInt aError, |
|
449 RHTTPTransaction /*aTransaction*/, |
|
450 const THTTPEvent& /*aEvent*/) |
|
451 { |
|
452 iEngine->Utils().LogIt(_L("\nTest failed with error code %d\n"), aError); |
|
453 return KErrNone; |
|
454 } |
|
455 |
|
456 EXPORT_C void CHttpTestTransBase::MHFRunL(RHTTPTransaction aTransaction, |
|
457 const THTTPEvent& aEvent) |
|
458 { |
|
459 switch (aEvent.iStatus) |
|
460 { |
|
461 case THTTPEvent::EGotResponseHeaders: |
|
462 { |
|
463 // HTTP response headers have been received |
|
464 iEngine->Utils().LogIt(_L("<EGotResponseHeaders>\n")); |
|
465 DumpRespHeaders(aTransaction); |
|
466 iEngine->SetCurrentStatusCode(aTransaction.Response().StatusCode()); |
|
467 } break; |
|
468 case THTTPEvent::EGotResponseBodyData: |
|
469 { |
|
470 // Some (more) body data has been received (in the HTTP response) |
|
471 iEngine->Utils().LogIt(_L("<EGotResponseBodyData received>\n")); |
|
472 // for each chunk of data received we have to empty the buffer before to be able to receive |
|
473 MHTTPDataSupplier* body = aTransaction.Response().Body(); |
|
474 body->ReleaseData(); |
|
475 } break; |
|
476 case THTTPEvent::EResponseComplete: |
|
477 { |
|
478 // The transaction's response is complete |
|
479 iEngine->Utils().LogIt(_L("<EResponseComplete received >\n")); |
|
480 } break; |
|
481 case THTTPEvent::ESucceeded: |
|
482 { |
|
483 iEngine->Utils().LogIt(_L("<ESucceeded received from the VF>\n")); |
|
484 CActiveScheduler::Stop(); |
|
485 } break; |
|
486 case THTTPEvent::EFailed: |
|
487 { |
|
488 iEngine->Utils().LogIt(_L("<EFailed received from the VF>\n")); |
|
489 CActiveScheduler::Stop(); |
|
490 } break; |
|
491 default: |
|
492 { |
|
493 iEngine->Utils().LogIt(_L("<unrecognised event>\n %d"),aEvent.iStatus); |
|
494 iEngine->Utils().LogIt(_L("Test Failed\n")); |
|
495 iEngine->PressAnyKey(); |
|
496 CActiveScheduler::Stop(); |
|
497 } |
|
498 break; |
|
499 } |
|
500 } |
|
501 |
|
502 EXPORT_C void CHttpTestEngine::SetSilent(TBool aSilent) |
|
503 { |
|
504 iUtils->SetSilent(aSilent); |
|
505 } |
|
506 |
|
507 EXPORT_C TInt CHttpTestTransBase::Reset() |
|
508 { |
|
509 return KErrNone; |
|
510 } |