450
452
return ["arch", "-arch", "i386"] + cmd
451
453
# otherwise just execute the command normally
456
class ShutdownLeakLogger(object):
458
Parses the mochitest run log when running a debug build, assigns all leaked
459
DOM windows (that are still around after test suite shutdown, despite running
460
the GC) to the tests that created them and prints leak statistics.
464
def __init__(self, logger):
467
self.leakedWindows = {}
468
self.leakedDocShells = set()
469
self.currentTest = None
470
self.seenShutdown = False
473
if line[2:11] == "DOMWINDOW":
474
self._logWindow(line)
475
elif line[2:10] == "DOCSHELL":
476
self._logDocShell(line)
477
elif line.startswith("TEST-START"):
478
fileName = line.split(" ")[-1].strip().replace("chrome://mochitests/content/browser/", "")
479
self.currentTest = {"fileName": fileName, "windows": set(), "docShells": set()}
480
elif line.startswith("INFO TEST-END"):
481
# don't track a test if no windows or docShells leaked
482
if self.currentTest["windows"] or self.currentTest["docShells"]:
483
self.tests.append(self.currentTest)
484
self.currentTest = None
485
elif line.startswith("INFO TEST-START | Shutdown"):
486
self.seenShutdown = True
489
leakingTests = self._parseLeakingTests()
492
totalWindows = sum(len(test["leakedWindows"]) for test in leakingTests)
493
totalDocShells = sum(len(test["leakedDocShells"]) for test in leakingTests)
494
msgType = "INFO" if totalWindows + totalDocShells <= self.MAX_LEAK_COUNT else "UNEXPECTED-FAIL"
495
self.logger.info("TEST-%s | ShutdownLeaks | leaked %d DOMWindow(s) and %d DocShell(s) until shutdown", msgType, totalWindows, totalDocShells)
497
for test in leakingTests:
498
self.logger.info("\n[%s]", test["fileName"])
500
for url, count in self._zipLeakedWindows(test["leakedWindows"]):
501
self.logger.info(" %d window(s) [url = %s]", count, url)
503
if test["leakedDocShells"]:
504
self.logger.info(" %d docShell(s)", len(test["leakedDocShells"]))
506
def _logWindow(self, line):
507
created = line[:2] == "++"
508
id = self._parseValue(line, "serial")
511
windows = self.currentTest["windows"]
516
elif self.seenShutdown and not created:
517
self.leakedWindows[id] = self._parseValue(line, "url")
519
def _logDocShell(self, line):
520
created = line[:2] == "++"
521
id = self._parseValue(line, "id")
524
docShells = self.currentTest["docShells"]
528
docShells.discard(id)
529
elif self.seenShutdown and not created:
530
self.leakedDocShells.add(id)
532
def _parseValue(self, line, name):
533
return re.search("\[%s = (.+?)\]" % name, line).group(1)
535
def _parseLeakingTests(self):
538
for test in self.tests:
539
test["leakedWindows"] = [self.leakedWindows[id] for id in test["windows"] if id in self.leakedWindows]
540
test["leakedDocShells"] = [id for id in test["docShells"] if id in self.leakedDocShells]
541
test["leakCount"] = len(test["leakedWindows"]) + len(test["leakedDocShells"])
543
if test["leakCount"]:
544
leakingTests.append(test)
546
return sorted(leakingTests, key=itemgetter("leakCount"), reverse=True)
548
def _zipLeakedWindows(self, leakedWindows):
552
for url in leakedWindows:
553
if not url in counted:
554
counts.append((url, leakedWindows.count(url)))
557
return sorted(counts, key=itemgetter(1), reverse=True)