author | Jon Chatten |
Mon, 13 Sep 2010 14:04:04 +0100 | |
changeset 641 | 8dd670a9f34f |
parent 625 | a1925fb7753a |
child 674 | 37ee82a83d43 |
permissions | -rw-r--r-- |
591 | 1 |
# |
2 |
# Copyright (c) 2009-2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 |
# All rights reserved. |
|
4 |
# This component and the accompanying materials are made available |
|
5 |
# under the terms of the License "Eclipse Public License v1.0" |
|
6 |
# which accompanies this distribution, and is available |
|
7 |
# at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 |
# |
|
9 |
# Initial Contributors: |
|
10 |
# Nokia Corporation - initial contribution. |
|
11 |
# |
|
12 |
# Contributors: |
|
13 |
# |
|
14 |
# Description: |
|
15 |
# |
|
16 |
||
17 |
# run the smoke tests |
|
18 |
||
19 |
import os |
|
20 |
import re |
|
21 |
import stat |
|
22 |
import sys |
|
23 |
import subprocess |
|
24 |
import traceback |
|
25 |
from shutil import rmtree |
|
26 |
||
27 |
sys.path.append(os.environ["SBS_HOME"]+"/python") |
|
28 |
from raptor_meta import BldInfFile |
|
29 |
||
30 |
logDir = "$(EPOCROOT)/epoc32/build/smoketestlogs" |
|
31 |
||
32 |
debug_mode_active = False |
|
33 |
||
34 |
# Environment ################################################################# |
|
35 |
||
36 |
# On MYS there is USERNAME but not USER |
|
37 |
if 'USER' not in os.environ: |
|
38 |
os.environ['USER'] = os.environ['USERNAME'] |
|
39 |
||
40 |
def activate_debug(): |
|
41 |
""" |
|
42 |
Activate debug-mode remotely |
|
43 |
""" |
|
44 |
global debug_mode_active |
|
45 |
debug_mode_active = True |
|
46 |
||
47 |
# Determine the OS version in the epocroot we're testing |
|
48 |
# since some tests expect different outcomes for 9.4 and 9.5 |
|
49 |
def getsymbianversion(): |
|
50 |
epocroot = os.environ['EPOCROOT'] |
|
51 |
b = open (epocroot+"/epoc32/data/buildinfo.txt","r") |
|
52 |
binfo = " ".join(b.readlines()) |
|
53 |
vmatch = (re.compile("v(9\.[0-9])")).search(binfo) |
|
54 |
if vmatch: |
|
55 |
osversion = vmatch.group(1) |
|
56 |
else: |
|
57 |
osversion = '9.4' |
|
58 |
return osversion |
|
59 |
||
60 |
envRegex = re.compile("\$\((.+?)\)") |
|
61 |
fixEnvironment = ['EPOCROOT', 'SBS_HOME', 'SBS_CYGWIN', 'SBS_MINGW', 'SBS_PYTHON'] |
|
62 |
||
63 |
def ReplaceEnvs(item): |
|
64 |
||
65 |
envs = envRegex.findall(item) |
|
66 |
||
67 |
for e in set(envs): |
|
68 |
try: |
|
69 |
val = os.environ[e] |
|
70 |
if e in fixEnvironment: |
|
71 |
# Raptor "fixes up" EPOCROOT etc. so we must do the same: |
|
72 |
# add the drive letter (make absolute) |
|
73 |
val = os.path.abspath(val) |
|
74 |
# use forward slashes |
|
75 |
val = val.replace("\\", "/") |
|
76 |
# remove trailing slashes |
|
77 |
val = val.rstrip("/") |
|
78 |
item = item.replace("$(" + e + ")", val) |
|
79 |
except KeyError: |
|
80 |
print e, "is not set in the environment" |
|
81 |
raise ValueError |
|
82 |
||
83 |
return item |
|
84 |
||
85 |
# Utility functions ########################################################### |
|
86 |
||
87 |
||
88 |
||
89 |
def where(input_file): |
|
90 |
"""Search for 'input_file' in the system path""" |
|
91 |
locations = [] |
|
92 |
if sys.platform.startswith("win"): |
|
93 |
if not input_file.lower().endswith(".exe"): |
|
94 |
input_file += ".exe" |
|
95 |
for current_file in [loop_number + "\\" + input_file for loop_number in |
|
96 |
os.environ["PATH"].split(";")]: |
|
97 |
try: |
|
98 |
stat = os.stat(current_file) |
|
99 |
locations.append(current_file) |
|
100 |
except OSError, error: |
|
101 |
pass |
|
102 |
else: |
|
103 |
whichproc = subprocess.Popen(args=["which", input_file], |
|
104 |
stdout=subprocess.PIPE, |
|
105 |
stderr=subprocess.STDOUT, |
|
106 |
shell=False, |
|
107 |
universal_newlines=True) |
|
108 |
output = whichproc.stdout.readlines() |
|
109 |
whichproc.wait() |
|
110 |
||
111 |
if len(output) > 0: |
|
112 |
locations.append(output[0:(len(output) - 1)]) |
|
113 |
||
114 |
if len(locations) == 0: |
|
115 |
print "Error: " + input_file + " not defined in PATH environment variable" |
|
116 |
else: |
|
117 |
return locations[0] |
|
118 |
||
119 |
def clean_epocroot(): |
|
120 |
""" |
|
121 |
This method walks through epocroot and cleans every file and folder that is |
|
122 |
not present in the manifest file |
|
123 |
""" |
|
124 |
epocroot = os.path.abspath(os.environ['EPOCROOT']).replace('\\','/') |
|
125 |
print "Cleaning Epocroot: %s" % epocroot |
|
126 |
all_files = {} # dictionary to hold all files |
|
127 |
folders = [] # holds all unique folders in manifest |
|
128 |
host_platform = os.environ["HOSTPLATFORM_DIR"] |
|
129 |
try: |
|
130 |
mani = "$(EPOCROOT)/manifest" |
|
131 |
manifest = open(ReplaceEnvs(mani), "r") |
|
132 |
le = len(epocroot) |
|
133 |
for line in manifest: |
|
134 |
line = line.replace("$(HOSTPLATFORM_DIR)", host_platform) |
|
135 |
line = line.replace("./", epocroot+"/").rstrip("\n") |
|
136 |
all_files[line] = True |
|
137 |
# This bit makes a record of unique folders into a list |
|
138 |
pos = line.rfind("/", le) |
|
139 |
while pos > le: # Look through the parent folders |
|
140 |
f = line[:pos] |
|
141 |
if f not in folders: |
|
142 |
folders.append(f) |
|
143 |
pos = line.rfind("/", le, pos) |
|
144 |
||
145 |
||
146 |
# This algorithm walks through epocroot and handles files and folders |
|
147 |
walkpath = "$(EPOCROOT)" |
|
148 |
for (root, dirs, files) in os.walk(ReplaceEnvs(walkpath), topdown = |
|
149 |
False): |
|
150 |
if root.find(".hg") != -1: |
|
151 |
continue |
|
152 |
||
153 |
# This loop handles all files |
|
154 |
for name in files: |
|
155 |
name = os.path.join(root, name).replace("\\", "/") |
|
156 |
||
157 |
if name not in all_files: |
|
158 |
try: |
|
159 |
os.remove(name) |
|
160 |
except: |
|
161 |
# chmod to rw and try again |
|
162 |
try: |
|
163 |
os.chmod(name, stat.S_IRWXU) |
|
164 |
os.remove(name) |
|
165 |
except: |
|
166 |
print "\nEPOCROOT-CLEAN ERROR:" |
|
167 |
print (sys.exc_type.__name__ + ":"), \ |
|
168 |
sys.exc_value |
|
169 |
if sys.exc_type.__name__ != "WindowsError": |
|
170 |
print traceback.print_tb(sys.exc_traceback) |
|
171 |
||
172 |
# This loop handles folders |
|
173 |
for name in dirs: |
|
174 |
if name.find(".hg") != -1: |
|
175 |
continue |
|
176 |
||
177 |
name = os.path.join(root, name).replace("\\", "/") |
|
178 |
if name not in all_files and name not in folders: |
|
179 |
# Remove the folder fully with no errors if full |
|
180 |
try: |
|
181 |
rmtree(ReplaceEnvs(name)) |
|
182 |
except: |
|
183 |
print "\nEPOCROOT-CLEAN ERROR:" |
|
184 |
print (sys.exc_type.__name__ + ":"), \ |
|
185 |
sys.exc_value |
|
186 |
if sys.exc_type.__name__ != "WindowsError": |
|
187 |
print traceback.print_tb(sys.exc_traceback) |
|
188 |
except IOError,e: |
|
189 |
print e |
|
190 |
||
191 |
print "Epocroot Cleaned" |
|
192 |
||
193 |
def fix_id(input_id): |
|
194 |
return input_id.zfill(4) |
|
195 |
||
196 |
||
197 |
def grep(file, string): |
|
198 |
return |
|
199 |
||
200 |
||
201 |
# Test classes ################################################################ |
|
202 |
||
203 |
class SmokeTest(object): |
|
204 |
"""Base class for Smoke Test objects. |
|
205 |
||
206 |
Each test is defined (minimally) by, |
|
207 |
1) an ID number as a string |
|
208 |
2) a name |
|
209 |
3) a raptor command-line |
|
210 |
4) some parameters to check the command results against |
|
211 |
||
212 |
The run() method will, |
|
213 |
1) delete all the listed target files |
|
214 |
2) execute the raptor command |
|
215 |
3) check that the test results match the test parameters |
|
216 |
4) count the warnings and errors reported |
|
217 |
""" |
|
218 |
||
219 |
PASS = "pass" |
|
220 |
FAIL = "fail" |
|
221 |
SKIP = "skip" |
|
222 |
||
223 |
def __init__(self): |
|
224 |
||
225 |
self.id = "0" |
|
226 |
self.name = "smoketest" |
|
227 |
self.description = "" |
|
228 |
self.command = "sbs --do_what_i_want" |
|
229 |
self.targets = [] |
|
230 |
self.missing = 0 |
|
231 |
self.warnings = 0 |
|
232 |
self.errors = 0 |
|
233 |
self.exceptions = 0 |
|
234 |
self.returncode = 0 |
|
235 |
||
236 |
self.onWindows = sys.platform.startswith("win") |
|
237 |
||
238 |
# These variables are for tests that treat the text as a list of lines. In |
|
239 |
# particular, "." will not match end-of-line. This means that, for example, |
|
240 |
# "abc.*def" will only match if "abc" and "def" appear on the same line. |
|
241 |
self.mustmatch = [] |
|
242 |
self.mustnotmatch = [] |
|
243 |
self.mustmatch_singleline = [] |
|
244 |
self.mustnotmatch_singleline = [] |
|
245 |
||
246 |
# These variables are for tests that treat the text as a single string of |
|
247 |
# characters. The pattern "." will match anything, including end-of-line. |
|
248 |
self.mustmatch_multiline = [] |
|
249 |
self.mustnotmatch_multiline = [] |
|
250 |
||
251 |
self.countmatch = [] |
|
252 |
||
253 |
self.outputok = True |
|
254 |
self.usebash = False |
|
255 |
self.failsbecause = None |
|
256 |
self.result = SmokeTest.SKIP |
|
257 |
self.environ = {} # Allow tests to set the environment in which commands run. |
|
258 |
self.sbs_build_dir = "$(EPOCROOT)/epoc32/build" |
|
259 |
||
260 |
def run(self, platform = "all"): |
|
261 |
previousResult = self.result |
|
262 |
self.id = fix_id(self.id) |
|
263 |
try: |
|
264 |
if self.runnable(platform): |
|
265 |
||
266 |
if not self.pretest(): |
|
267 |
self.result = SmokeTest.FAIL |
|
268 |
||
269 |
elif not self.test(): |
|
270 |
self.result = SmokeTest.FAIL |
|
271 |
||
272 |
elif not self.posttest(): |
|
273 |
self.result = SmokeTest.FAIL |
|
274 |
||
275 |
else: |
|
276 |
self.result = SmokeTest.PASS |
|
277 |
else: |
|
278 |
self.skip(platform) |
|
279 |
except Exception, e: |
|
280 |
print e |
|
281 |
self.result = SmokeTest.FAIL |
|
282 |
||
283 |
# print the result of this run() |
|
284 |
self.print_result(internal = True) |
|
285 |
||
286 |
# if a previous run() failed then the overall result is a FAIL |
|
287 |
if previousResult == SmokeTest.FAIL: |
|
288 |
self.result = SmokeTest.FAIL |
|
289 |
||
290 |
def print_result(self, value = "", internal = False): |
|
291 |
# the test passed :-) |
|
292 |
||
293 |
result = self.result |
|
294 |
||
295 |
string = "" |
|
296 |
if not internal: |
|
297 |
string += "\n" + self.name + ": " |
|
298 |
||
299 |
if value: |
|
300 |
print string + value |
|
301 |
else: |
|
302 |
if result == SmokeTest.PASS: |
|
303 |
string += "PASSED" |
|
304 |
elif result == SmokeTest.FAIL: |
|
305 |
string += "FAILED" |
|
306 |
||
307 |
print string |
|
308 |
||
309 |
def runnable(self, platform): |
|
310 |
# can this test run on this platform? |
|
311 |
if platform == "all": |
|
312 |
return True |
|
313 |
||
314 |
isWin = self.onWindows |
|
315 |
wantWin = platform.startswith("win") |
|
316 |
||
317 |
return (isWin == wantWin) |
|
318 |
||
319 |
def skip(self, platform): |
|
320 |
print "\nSKIPPING:", self.name, "for", platform |
|
321 |
||
322 |
def logfileOption(self): |
|
323 |
return "-f " + self.logfile(); |
|
324 |
||
325 |
def logfile(self): |
|
641 | 326 |
return logDir + "/" + self.name.replace(" ","_") + ".log" |
591 | 327 |
|
328 |
def makefileOption(self): |
|
329 |
return "-m " + self.makefile(); |
|
330 |
||
331 |
def makefile(self): |
|
332 |
return logDir + "/" + self.name + ".mk" |
|
333 |
||
334 |
def removeFiles(self, files): |
|
335 |
for t in files: |
|
336 |
tgt = os.path.normpath(ReplaceEnvs(t)) |
|
337 |
||
338 |
if os.path.exists(tgt): |
|
339 |
try: |
|
340 |
os.chmod(tgt, stat.S_IRWXU) |
|
341 |
if os.path.isdir(tgt): |
|
342 |
rmtree(tgt) |
|
343 |
else: |
|
344 |
os.remove(tgt) |
|
345 |
except OSError: |
|
346 |
print "Could not remove", tgt, "before the test" |
|
347 |
return False |
|
348 |
return True |
|
349 |
||
350 |
||
351 |
def clean(self): |
|
352 |
# remove all the target files |
|
353 |
||
354 |
# flatten any lists first (only 1 level of flattenening expected) |
|
355 |
# these indicate alternative files - one of them will exist after a build |
|
356 |
removables = [] |
|
357 |
for i in self.targets: |
|
358 |
if type(i) is not list: |
|
359 |
removables.append(i) |
|
360 |
else: |
|
361 |
removables.extend(i) |
|
362 |
||
363 |
return self.removeFiles(removables) |
|
364 |
||
365 |
def pretest(self): |
|
366 |
# what to do before the test runs |
|
367 |
||
368 |
print "\nID:", self.id |
|
369 |
print "TEST:", self.name |
|
641 | 370 |
print "LOGFILE:", self.logfile() |
591 | 371 |
|
372 |
return self.clean() |
|
373 |
||
374 |
def test(self): |
|
375 |
# run the actual test |
|
376 |
||
377 |
# put the makefile and log in $EPOCROOT/build/smoketestlogs |
|
378 |
if self.usebash: |
|
379 |
command = ReplaceEnvs(self.command) |
|
380 |
else: |
|
381 |
command = ReplaceEnvs(self.command + |
|
382 |
" " + self.makefileOption() + |
|
383 |
" " + self.logfileOption()) |
|
384 |
||
385 |
print "COMMAND:", command |
|
386 |
||
387 |
||
388 |
# Any environment settings specific to this test |
|
389 |
shellenv = os.environ.copy() |
|
390 |
for ev in self.environ: |
|
391 |
shellenv[ev] = self.environ[ev] |
|
392 |
||
393 |
if self.usebash: |
|
394 |
shellpath = shellenv['PATH'] |
|
395 |
||
396 |
if 'SBS_SHELL' in os.environ: |
|
397 |
BASH = os.environ['SBS_SHELL'] |
|
398 |
else: |
|
399 |
if self.onWindows: |
|
400 |
if 'SBS_CYGWIN' in shellenv: |
|
401 |
BASH = ReplaceEnvs("$(SBS_CYGWIN)/bin/bash.exe") |
|
402 |
else: |
|
403 |
BASH = ReplaceEnvs("$(SBS_HOME)/win32/cygwin/bin/bash.exe") |
|
404 |
else: |
|
405 |
BASH = ReplaceEnvs("$(SBS_HOME)/$(HOSTPLATFORM_DIR)/bin/bash") |
|
406 |
||
407 |
if self.onWindows: |
|
408 |
if 'SBS_CYGWIN' in shellenv: |
|
409 |
shellpath = ReplaceEnvs("$(SBS_CYGWIN)/bin") + ";" + shellpath |
|
410 |
else: |
|
411 |
shellpath = ReplaceEnvs("$(SBS_HOME)/win32/cygwin/bin") + ";" + shellpath |
|
412 |
||
413 |
shellenv['SBSMAKEFILE']=ReplaceEnvs(self.makefile()) |
|
414 |
shellenv['SBSLOGFILE']=ReplaceEnvs(self.logfile()) |
|
415 |
shellenv['PATH']=shellpath |
|
416 |
shellenv['PYTHON_HOME'] = "" |
|
417 |
shellenv['CYGWIN']="nontsec nosmbntsec" |
|
418 |
||
419 |
p = subprocess.Popen(args=[BASH, '-c', command], |
|
420 |
stdout=subprocess.PIPE, |
|
421 |
stderr=subprocess.PIPE, |
|
422 |
env=shellenv, |
|
423 |
shell=False, |
|
424 |
universal_newlines=True) |
|
425 |
||
426 |
(std_out, std_err) = p.communicate() |
|
427 |
||
428 |
self.output = std_out + std_err |
|
429 |
else: |
|
430 |
p = subprocess.Popen(command, |
|
431 |
stdout=subprocess.PIPE, |
|
432 |
stderr=subprocess.PIPE, |
|
433 |
env=shellenv, |
|
434 |
shell=True, |
|
435 |
universal_newlines=True) |
|
436 |
||
437 |
(std_out, std_err) = p.communicate() |
|
438 |
||
439 |
self.output = std_out + std_err |
|
440 |
||
441 |
if debug_mode_active: |
|
442 |
print self.output |
|
443 |
||
444 |
if p.returncode != self.returncode: |
|
445 |
print "RETURN: got", p.returncode, "expected", self.returncode |
|
446 |
return False |
|
447 |
||
448 |
return True |
|
449 |
||
450 |
def posttest(self): |
|
451 |
# what to do after the test has run |
|
452 |
||
625
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
453 |
# count the targets that got built, recording those that are found |
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
454 |
# to be missing |
591 | 455 |
found = 0 |
456 |
missing = [] |
|
457 |
for t in self.targets: |
|
625
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
458 |
# Either we're looking at a single target file here, or a list of related target files where |
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
459 |
# at least one needs to match. We therefore use a list for the check that includes one or |
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
460 |
# more items |
591 | 461 |
if type(t) is not list: |
625
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
462 |
unresolved_targets=[t] |
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
463 |
else: |
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
464 |
unresolved_targets=t |
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
465 |
|
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
466 |
resolved_targets = [] |
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
467 |
for target in unresolved_targets: |
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
468 |
resolved_targets.append(os.path.normpath(ReplaceEnvs(target))) |
591 | 469 |
|
470 |
found_flag = False |
|
625
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
471 |
for target in resolved_targets: |
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
472 |
if os.path.exists(target): |
591 | 473 |
found_flag = True |
474 |
break |
|
475 |
if found_flag: |
|
476 |
found += 1 |
|
477 |
else: |
|
625
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
478 |
missing.append(resolved_targets) |
591 | 479 |
|
480 |
# count the errors and warnings |
|
481 |
warn = 0 |
|
482 |
error = 0 |
|
483 |
exception = 0 |
|
484 |
lines = self.output.split("\n") |
|
485 |
||
486 |
for line in lines: |
|
487 |
if line.find("sbs: warning:") != -1 or line.find("<warning") != -1: |
|
488 |
warn += 1 |
|
489 |
elif line.find("sbs: error:") != -1 or line.find("<error") != -1: |
|
490 |
error += 1 |
|
491 |
elif line.startswith("Traceback"): |
|
492 |
exception += 1 |
|
493 |
||
494 |
# Check the output for required, forbidden and counted regexp matches |
|
495 |
self.outputok = True |
|
496 |
||
497 |
for expr in self.mustmatch_singleline + self.mustmatch: |
|
498 |
if not re.search(expr, self.output, re.MULTILINE): |
|
499 |
self.outputok = False |
|
500 |
print "OUTPUTMISMATCH: output did not match: %s" % expr |
|
501 |
||
502 |
for expr in self.mustnotmatch_singleline + self.mustnotmatch: |
|
503 |
if re.search(expr, self.output, re.MULTILINE): |
|
504 |
self.outputok = False |
|
505 |
print "OUTPUTMISMATCH: output should not have matched: %s" % expr |
|
506 |
||
507 |
for expr in self.mustmatch_multiline: |
|
508 |
if not re.search(expr, self.output, re.DOTALL): |
|
509 |
self.outputok = False |
|
510 |
print "OUTPUTMISMATCH: output did not match: %s" % expr |
|
511 |
||
512 |
for expr in self.mustnotmatch_multiline: |
|
513 |
if re.search(expr, self.output, re.DOTALL): |
|
514 |
self.outputok = False |
|
515 |
print "OUTPUTMISMATCH: output should not have matched: %s" % expr |
|
516 |
||
517 |
for (expr,num) in self.countmatch: |
|
518 |
expr_re = re.compile(expr) |
|
519 |
matchnum = len(expr_re.findall(self.output)) |
|
520 |
if matchnum != num: |
|
521 |
print "OUTPUTMISMATCH: %d matches occurred when %d were expected: %s" % (matchnum, num, expr) |
|
522 |
self.outputok = False |
|
523 |
||
524 |
# Ignore errors/warnings if they are set to (-1) |
|
525 |
if self.errors == (-1): |
|
526 |
self.errors = error |
|
527 |
if self.warnings == (-1): |
|
528 |
self.warnings= warn |
|
529 |
||
530 |
# all as expected? |
|
531 |
if self.missing == len(missing) \ |
|
532 |
and self.warnings == warn \ |
|
533 |
and self.errors == error \ |
|
534 |
and self.exceptions == exception \ |
|
535 |
and self.outputok: |
|
536 |
return True |
|
537 |
||
538 |
# something was wrong :-( |
|
539 |
||
540 |
if len(missing) != self.missing: |
|
541 |
print "MISSING: %d, expected %s" % (len(missing), self.missing) |
|
625
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
542 |
|
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
543 |
# Missing entries are lists containing either a single missing file, or multiple alternative |
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
544 |
# files that were all found to be missing when checked |
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
545 |
for entry in missing: |
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
546 |
for index,file in enumerate(entry): |
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
547 |
if index != len(entry)-1: |
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
548 |
suffix = " or" |
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
549 |
else: |
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
550 |
suffix = "" |
a1925fb7753a
sbs version 2.15.0
Richard Taylor <richard.i.taylor@nokia.com>
parents:
591
diff
changeset
|
551 |
print "\t%s" % (file) + suffix |
591 | 552 |
|
553 |
if warn != self.warnings: |
|
554 |
print "WARNINGS: %d, expected %d" % (warn, self.warnings) |
|
555 |
||
556 |
if error != self.errors: |
|
557 |
print "ERRORS: %d, expected %d" % ( error, self.errors) |
|
558 |
||
559 |
if exception != self.exceptions: |
|
560 |
print "EXCEPTIONS: %d, expected %d" % (exception, self.exceptions) |
|
561 |
||
562 |
return False |
|
563 |
||
564 |
def addbuildtargets(self, bldinfsourcepath, targetsuffixes): |
|
565 |
"""Add targets that are under epoc32/build whose path |
|
566 |
can change based on an md5 hash of the path to the bld.inf. |
|
567 |
""" |
|
568 |
||
569 |
fragment = BldInfFile.outputPathFragment(bldinfsourcepath) |
|
570 |
||
571 |
for t in targetsuffixes: |
|
572 |
if type(t) is not list: |
|
573 |
newt=self.sbs_build_dir+'/'+fragment+"/"+t |
|
574 |
self.targets.append(newt) |
|
575 |
else: |
|
576 |
self.targets.append([self.sbs_build_dir+'/'+fragment+"/"+x for x in t]) |
|
577 |
return |
|
578 |
||
579 |
# derived class for tests that invoke some process, which have no log file and no makefile |
|
580 |
# e.g. unit tests |
|
581 |
||
582 |
class GenericSmokeTest(SmokeTest): |
|
583 |
||
584 |
def __init__(self): |
|
585 |
SmokeTest.__init__(self) |
|
586 |
||
587 |
def logfileOption(self): |
|
588 |
return "" |
|
589 |
||
590 |
def makefileOption(self): |
|
591 |
return "" |
|
592 |
||
593 |
def posttest(self): |
|
594 |
# dump the standard output to a log file |
|
595 |
dir = ReplaceEnvs(logDir) |
|
596 |
logfile = os.path.join(dir, self.name + ".log") |
|
597 |
try: |
|
598 |
if not os.path.exists(dir): |
|
599 |
os.makedirs(dir) |
|
600 |
file = open(logfile, "w") |
|
601 |
file.write(self.output) |
|
602 |
file.close() |
|
603 |
except: |
|
604 |
print "Could not save stdout in", logfile |
|
605 |
return False |
|
606 |
||
607 |
# do the base class things too |
|
608 |
return SmokeTest.posttest(self) |
|
609 |
||
610 |
# derived class for --check, --what and .whatlog tests - these all write to stdout, but may |
|
611 |
# not actually build anything |
|
612 |
||
613 |
class CheckWhatSmokeTest(SmokeTest): |
|
614 |
||
615 |
def __init__(self): |
|
616 |
SmokeTest.__init__(self) |
|
617 |
||
618 |
# regular expression match object to restrict comparisons to specific lines |
|
619 |
self.regexlinefilter = None |
|
620 |
||
621 |
# paths in --what output are tailored to the host OS, hence slashes are converted appropriately |
|
622 |
# .whatlog output is used verbatim from the build/TEM/EM output |
|
623 |
self.hostossensitive = True |
|
624 |
||
625 |
# Indicate whether output is expected to appear only once. If so, set it to True |
|
626 |
self.output_expected_only_once = False |
|
627 |
||
628 |
def posttest(self): |
|
629 |
outlines = self.output.splitlines() |
|
630 |
if self.output_expected_only_once: |
|
631 |
outlines_left = list(outlines) |
|
632 |
||
633 |
ok = True |
|
634 |
seen = [] |
|
635 |
||
636 |
# check for lines that we expected to see, optionally filtered |
|
637 |
for line in self.stdout: |
|
638 |
if self.regexlinefilter and not self.regexlinefilter.match(line): |
|
639 |
continue |
|
640 |
line = ReplaceEnvs(line) |
|
641 |
if self.hostossensitive and self.onWindows: |
|
642 |
line = line.replace("/", "\\") |
|
643 |
||
644 |
if line in outlines: |
|
645 |
seen.append(line) |
|
646 |
if self.output_expected_only_once: |
|
647 |
outlines_left.remove(line) |
|
648 |
else: |
|
649 |
print "OUTPUT NOT FOUND:", line |
|
650 |
ok = False |
|
651 |
||
652 |
# and check for extra lines that we didn't expect, optionally filtered |
|
653 |
for line in outlines: |
|
654 |
if self.regexlinefilter and not self.regexlinefilter.match(line): |
|
655 |
continue |
|
656 |
if not line in seen: |
|
657 |
print "UNEXPECTED OUTPUT:", line |
|
658 |
ok = False |
|
659 |
||
660 |
# and check for lines that we expected to see only once |
|
661 |
if self.output_expected_only_once: |
|
662 |
for line in outlines_left: |
|
663 |
print "OUTPUT MORE THAN ONCE:", line |
|
664 |
ok = False |
|
665 |
||
666 |
||
667 |
# do the base class things too |
|
668 |
return (SmokeTest.posttest(self) and ok) |
|
669 |
||
670 |
# derived class for tests that also need to make sure that certain files |
|
671 |
# are NOT created - sort of anti-targets. |
|
672 |
||
673 |
class AntiTargetSmokeTest(SmokeTest): |
|
674 |
||
675 |
def __init__(self): |
|
676 |
SmokeTest.__init__(self) |
|
677 |
self.antitargets = [] |
|
678 |
||
679 |
def pretest(self): |
|
680 |
""" Prepare for the test """ |
|
681 |
# parent pretest first |
|
682 |
ok = SmokeTest.pretest(self) |
|
683 |
||
684 |
# remove all the anti-target files |
|
685 |
return (self.removeFiles(self.antitargets) and ok) |
|
686 |
||
687 |
def posttest(self): |
|
688 |
""" look for antitargets """ |
|
689 |
ok = True |
|
690 |
for t in self.antitargets: |
|
691 |
tgt = os.path.normpath(ReplaceEnvs(t)) |
|
692 |
if os.path.exists(tgt): |
|
693 |
print "UNWANTED", tgt |
|
694 |
ok = False |
|
695 |
||
696 |
# do the base class things too |
|
697 |
return (SmokeTest.posttest(self) and ok) |
|
698 |
||
699 |
def addbuildantitargets(self, bldinfsourcepath, targetsuffixes): |
|
700 |
"""Add targets that are under epoc32/build whose path |
|
701 |
can change based on an md5 hash of the path to the bld.inf. |
|
702 |
""" |
|
703 |
||
704 |
fragment = BldInfFile.outputPathFragment(bldinfsourcepath) |
|
705 |
||
706 |
for t in targetsuffixes: |
|
707 |
if type(t) is not list: |
|
708 |
newt="$(EPOCROOT)/epoc32/build/"+fragment+"/"+t |
|
709 |
self.antitargets.append(newt) |
|
710 |
else: |
|
711 |
self.antitargets.append(["$(EPOCROOT)/epoc32/build/"+fragment+"/"+x for x in t]) |
|
712 |
return |
|
713 |
||
714 |
||
715 |
# the end |