|
1 // Copyright (c) 2003-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 <fbs.h> |
|
17 #include "TestFrameworkRecog.h" |
|
18 #include "TestFrameworkMain.h" |
|
19 |
|
20 #ifdef __WINS__ |
|
21 #include <windows.h> // for ExitProcess |
|
22 #endif // __WINS__ |
|
23 |
|
24 GLREF_C void StartupL(); |
|
25 const TInt KThreadStackSize=0x2000; // 8KB |
|
26 const TInt KThreadInitHeapSize=0x1000; // 4KB |
|
27 const TInt KThreadMaxHeapSize=0x1000000; // 16MB |
|
28 const TInt KThreadStartupDelay=30000000; // 30 seconds |
|
29 const TInt KMaxLineLength=256; // max length of config file line |
|
30 _LIT(KLitConfigFileName, "C:\\MM\\AutorunTests.cfg"); |
|
31 |
|
32 // |
|
33 |
|
34 CTestFrameworkRecognizer::CTestFrameworkRecognizer() |
|
35 : CApaDataRecognizerType(KUidTestFrameworkRecognizer, CApaDataRecognizerType::ENormal) |
|
36 { |
|
37 } |
|
38 |
|
39 CTestFrameworkRecognizer::~CTestFrameworkRecognizer() |
|
40 { |
|
41 delete iTestActive; |
|
42 } |
|
43 |
|
44 // |
|
45 // CApaDataRecognizerType stuff... |
|
46 TUint CTestFrameworkRecognizer::PreferredBufSize() |
|
47 { |
|
48 return 0; |
|
49 } |
|
50 |
|
51 TDataType CTestFrameworkRecognizer::SupportedDataTypeL(TInt /*aIndex*/) const |
|
52 { |
|
53 return TDataType(); |
|
54 } |
|
55 |
|
56 void CTestFrameworkRecognizer::DoRecognizeL(const TDesC& /*aName*/, const TDesC8& /*aBuffer*/) |
|
57 { |
|
58 } |
|
59 |
|
60 // |
|
61 // Entry point of recognizer |
|
62 EXPORT_C CApaDataRecognizerType* CreateRecognizer() |
|
63 { |
|
64 CTestFrameworkRecognizer* self = new CTestFrameworkRecognizer(); |
|
65 TRAPD(err, self->DoCreateL()); |
|
66 return self; |
|
67 } |
|
68 |
|
69 void CTestFrameworkRecognizer::DoCreateL() |
|
70 { |
|
71 // Open the config file |
|
72 LoadConfigFileL(KLitConfigFileName); |
|
73 |
|
74 // If the RUN_SCRIPT command is present in the config file, run each test in a separate thread |
|
75 if (iRunScript) |
|
76 { |
|
77 // Create active object waiting on thread death |
|
78 iTestActive = new(ELeave) CTestFrameworkRecogActive(iTestScriptArray); // Takes ownership of iTestScriptArray |
|
79 |
|
80 // Create the first test thread |
|
81 iTestActive->CreateNextTestThread(); |
|
82 } |
|
83 } |
|
84 |
|
85 void CTestFrameworkRecognizer::LoadConfigFileL(const TDesC& aFileName) |
|
86 { |
|
87 RFs fs; |
|
88 User::LeaveIfError(fs.Connect()); |
|
89 CleanupClosePushL(fs); |
|
90 |
|
91 TEntry entry; |
|
92 User::LeaveIfError(fs.Entry(aFileName, entry)); |
|
93 |
|
94 RFile file; |
|
95 User::LeaveIfError(file.Open(fs, aFileName, EFileRead)); |
|
96 CleanupClosePushL(file); |
|
97 |
|
98 TInt size; |
|
99 User::LeaveIfError(file.Size(size)); |
|
100 TUint8* fileData = (TUint8*)User::AllocLC(size); |
|
101 TPtr8 ptr(fileData, 0, size); |
|
102 User::LeaveIfError(file.Read(ptr)); |
|
103 |
|
104 iTestScriptArray = new(ELeave) CTestScriptArray(4); |
|
105 |
|
106 // Process the config file |
|
107 TLex8 lex(ptr); |
|
108 while (!lex.Eos()) |
|
109 { |
|
110 // skip any spaces |
|
111 while (lex.Peek() == ' ') |
|
112 lex.Inc(); |
|
113 // mark the start of the line |
|
114 lex.Mark(); |
|
115 // move to the next |
|
116 while (!lex.Eos() && lex.Peek() != '\n') |
|
117 lex.Inc(); |
|
118 // step over \n |
|
119 if (lex.Peek() == '\n' ) |
|
120 lex.Inc(); |
|
121 |
|
122 // Process line |
|
123 TPtrC8 linePtr = lex.MarkedToken(); |
|
124 ProcessLineL(linePtr); |
|
125 } |
|
126 CleanupStack::PopAndDestroy(fileData); |
|
127 CleanupStack::PopAndDestroy(2); // file, fs |
|
128 } |
|
129 |
|
130 void CTestFrameworkRecognizer::ProcessLineL(const TDesC8& aLine) |
|
131 { |
|
132 ASSERT(aLine.Length() <= KMaxLineLength); |
|
133 TBuf<KMaxLineLength> buf; |
|
134 buf.Copy(aLine); |
|
135 if (buf.Find(_L("//"))==0) |
|
136 { |
|
137 // ignore comments |
|
138 } |
|
139 else |
|
140 { |
|
141 // Get the script path and startup delay |
|
142 TLex lex(buf); |
|
143 if (!iRunScript) |
|
144 { |
|
145 if (lex.NextToken().Compare(_L("RUN_SCRIPT")) == 0) |
|
146 iRunScript = ETrue; |
|
147 } |
|
148 else |
|
149 { |
|
150 // Parse the parameters |
|
151 TTestScriptInfo info; |
|
152 info.iScriptPath = lex.NextToken(); |
|
153 info.iThreadStartupDelay = 0; |
|
154 |
|
155 TPtrC token(lex.NextToken()); |
|
156 while (token.Length()) |
|
157 { |
|
158 if (token[0] == '-') |
|
159 { |
|
160 info.iParams.Append(token); |
|
161 info.iParams.Append(' '); |
|
162 } |
|
163 else |
|
164 { |
|
165 // Assume this to be the startup delay |
|
166 TLex tokenLex(token); |
|
167 User::LeaveIfError(tokenLex.Val(info.iThreadStartupDelay)); |
|
168 if (info.iThreadStartupDelay < 0) |
|
169 info.iThreadStartupDelay = 0; |
|
170 } |
|
171 token.Set(lex.NextToken()); |
|
172 } |
|
173 |
|
174 // Add the script info |
|
175 if (info.iScriptPath.Length()) |
|
176 iTestScriptArray->AppendL(info); |
|
177 } |
|
178 } |
|
179 } |
|
180 |
|
181 // |
|
182 // CTestFrameworkRecogActive |
|
183 CTestFrameworkRecogActive::CTestFrameworkRecogActive(CTestScriptArray* aTestScriptArray) |
|
184 : CActive(EPriorityStandard), iTestScriptArray(aTestScriptArray) |
|
185 { |
|
186 CActiveScheduler::Add(this); |
|
187 iCurrentScript = -1; |
|
188 } |
|
189 |
|
190 CTestFrameworkRecogActive::~CTestFrameworkRecogActive() |
|
191 { |
|
192 delete iTestScriptArray; |
|
193 } |
|
194 |
|
195 TInt CTestFrameworkRecogActive::CreateNextTestThread() |
|
196 { |
|
197 // Create the next test in a separate thread |
|
198 iCurrentScript++; |
|
199 RThread thread; |
|
200 TBuf<16> threadName; |
|
201 threadName.Format(_L("TFR_THREAD_%d"), iCurrentScript); |
|
202 |
|
203 TInt err = thread.Create(threadName, &StartTestThreadFn, KThreadStackSize, |
|
204 &User::Heap(), this); |
|
205 |
|
206 if (err == KErrNone) |
|
207 { |
|
208 thread.Logon(iStatus); |
|
209 thread.Resume(); |
|
210 SetActive(); |
|
211 } |
|
212 return err; |
|
213 } |
|
214 |
|
215 void CTestFrameworkRecogActive::DoCancel() |
|
216 { |
|
217 } |
|
218 |
|
219 void CTestFrameworkRecogActive::RunL() |
|
220 { |
|
221 // This will run when the thread created in CreateNextTestThreadL dies |
|
222 // |
|
223 TInt err = KErrNone; |
|
224 if (iCurrentScript < (iTestScriptArray->Count() - 1)) |
|
225 { |
|
226 err = CreateNextTestThread(); |
|
227 } |
|
228 else |
|
229 { |
|
230 // Tests finished |
|
231 delete iTestScriptArray; |
|
232 iTestScriptArray = NULL; |
|
233 #ifdef __WINS__ |
|
234 // Cause the emulator to exit |
|
235 ExitProcess(0); |
|
236 #endif // __WINS__ |
|
237 } |
|
238 } |
|
239 |
|
240 TInt CTestFrameworkRecogActive::StartTestThreadFn(TAny* aPtr) |
|
241 { |
|
242 CTestFrameworkRecogActive* self = static_cast<CTestFrameworkRecogActive*>(aPtr); |
|
243 TRAPD(err, self->DoStartTestThreadL()); |
|
244 return err; |
|
245 } |
|
246 |
|
247 void CTestFrameworkRecogActive::DoStartTestThreadL() |
|
248 { |
|
249 // Create the thread and wait until it's finished |
|
250 RThread thread; |
|
251 TBuf<16> threadName; |
|
252 threadName.Format(_L("TESTFRMRECOG_%d"), iCurrentScript); |
|
253 |
|
254 TInt err = thread.Create(threadName, &ThreadFunc, KThreadStackSize, |
|
255 &User::Heap(), this); |
|
256 |
|
257 if (err == KErrNone) |
|
258 { |
|
259 RSemaphore sem; |
|
260 err = sem.CreateGlobal(KRecogSemaphoreName, 0); |
|
261 if (err == KErrAlreadyExists) |
|
262 err = sem.OpenGlobal(KRecogSemaphoreName); |
|
263 if (err == KErrNone) |
|
264 { |
|
265 // Start the thread and wait for it to signal us that it's finished |
|
266 thread.Resume(); |
|
267 sem.Wait(); |
|
268 } |
|
269 } |
|
270 User::LeaveIfError(err); |
|
271 } |
|
272 |
|
273 |
|
274 TInt CTestFrameworkRecogActive::ThreadFunc(TAny* aPtr) |
|
275 { |
|
276 CTrapCleanup* cleanup = CTrapCleanup::New(); // get clean-up stack |
|
277 CTestFrameworkRecogActive* self = static_cast<CTestFrameworkRecogActive*>(aPtr); |
|
278 TRAPD(err, self->DoThreadFuncL()); |
|
279 delete cleanup; // destroy clean-up stack |
|
280 return err; |
|
281 } |
|
282 |
|
283 void CTestFrameworkRecogActive::DoThreadFuncL() |
|
284 { |
|
285 // Run the test script, using filename held in iScriptPath |
|
286 CActiveScheduler* scheduler=new(ELeave) CActiveScheduler; |
|
287 CleanupStack::PushL(scheduler); |
|
288 CActiveScheduler::Install(scheduler); |
|
289 |
|
290 // Hurricane emulator only - start all services which we require to run tests. |
|
291 // Future enhancement :- add these startups to TestUtils |
|
292 #if defined(__WINS__) |
|
293 #ifndef EXCLUDE_FOR_UNITTEST |
|
294 FbsStartup(); |
|
295 #endif // EXCLUDE_FOR_UNITTEST |
|
296 #endif |
|
297 |
|
298 // Get the current script |
|
299 const TTestScriptInfo& script = iTestScriptArray->At(iCurrentScript); |
|
300 |
|
301 // Delay for several seconds to allow vital bits of the emulator to start up (window server bits) |
|
302 User::After(script.iThreadStartupDelay); |
|
303 |
|
304 // Format the parameter to be passed to the test framework |
|
305 TFileName args; |
|
306 if (script.iParams.Length()) |
|
307 { |
|
308 // Add the params |
|
309 args.Append(script.iParams); |
|
310 args.Append(' '); |
|
311 } |
|
312 args.Append(script.iScriptPath); |
|
313 |
|
314 // Run the script |
|
315 CTestFrameworkMain* tester = CTestFrameworkMain::NewLC(); |
|
316 tester->StartTestingL(args); |
|
317 |
|
318 CleanupStack::PopAndDestroy(2, scheduler); // tester, scheduler |
|
319 } |
|
320 |
|
321 |