Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
michael@0 | 1 | import re |
michael@0 | 2 | from progressbar import NullProgressBar, ProgressBar |
michael@0 | 3 | import pipes |
michael@0 | 4 | |
michael@0 | 5 | # subprocess.list2cmdline does not properly escape for sh-like shells |
michael@0 | 6 | def escape_cmdline(args): |
michael@0 | 7 | return ' '.join([ pipes.quote(a) for a in args ]) |
michael@0 | 8 | |
michael@0 | 9 | class TestOutput: |
michael@0 | 10 | """Output from a test run.""" |
michael@0 | 11 | def __init__(self, test, cmd, out, err, rc, dt, timed_out): |
michael@0 | 12 | self.test = test # Test |
michael@0 | 13 | self.cmd = cmd # str: command line of test |
michael@0 | 14 | self.out = out # str: stdout |
michael@0 | 15 | self.err = err # str: stderr |
michael@0 | 16 | self.rc = rc # int: return code |
michael@0 | 17 | self.dt = dt # float: run time |
michael@0 | 18 | self.timed_out = timed_out # bool: did the test time out |
michael@0 | 19 | |
michael@0 | 20 | def describe_failure(self): |
michael@0 | 21 | if self.timed_out: |
michael@0 | 22 | return "Timeout" |
michael@0 | 23 | lines = self.err.splitlines() |
michael@0 | 24 | for line in lines: |
michael@0 | 25 | # Skip the asm.js compilation success message. |
michael@0 | 26 | if "Successfully compiled asm.js code" not in line: |
michael@0 | 27 | return line |
michael@0 | 28 | return "Unknown" |
michael@0 | 29 | |
michael@0 | 30 | class NullTestOutput: |
michael@0 | 31 | """Variant of TestOutput that indicates a test was not run.""" |
michael@0 | 32 | def __init__(self, test): |
michael@0 | 33 | self.test = test |
michael@0 | 34 | self.cmd = '' |
michael@0 | 35 | self.out = '' |
michael@0 | 36 | self.err = '' |
michael@0 | 37 | self.rc = 0 |
michael@0 | 38 | self.dt = 0.0 |
michael@0 | 39 | self.timed_out = False |
michael@0 | 40 | |
michael@0 | 41 | class TestResult: |
michael@0 | 42 | PASS = 'PASS' |
michael@0 | 43 | FAIL = 'FAIL' |
michael@0 | 44 | CRASH = 'CRASH' |
michael@0 | 45 | |
michael@0 | 46 | """Classified result from a test run.""" |
michael@0 | 47 | def __init__(self, test, result, results): |
michael@0 | 48 | self.test = test |
michael@0 | 49 | self.result = result |
michael@0 | 50 | self.results = results |
michael@0 | 51 | |
michael@0 | 52 | @classmethod |
michael@0 | 53 | def from_output(cls, output): |
michael@0 | 54 | test = output.test |
michael@0 | 55 | result = None # str: overall result, see class-level variables |
michael@0 | 56 | results = [] # (str,str) list: subtest results (pass/fail, message) |
michael@0 | 57 | |
michael@0 | 58 | out, rc = output.out, output.rc |
michael@0 | 59 | |
michael@0 | 60 | failures = 0 |
michael@0 | 61 | passes = 0 |
michael@0 | 62 | |
michael@0 | 63 | expected_rcs = [] |
michael@0 | 64 | if test.path.endswith('-n.js'): |
michael@0 | 65 | expected_rcs.append(3) |
michael@0 | 66 | |
michael@0 | 67 | for line in out.split('\n'): |
michael@0 | 68 | if line.startswith(' FAILED!'): |
michael@0 | 69 | failures += 1 |
michael@0 | 70 | msg = line[len(' FAILED! '):] |
michael@0 | 71 | results.append((cls.FAIL, msg)) |
michael@0 | 72 | elif line.startswith(' PASSED!'): |
michael@0 | 73 | passes += 1 |
michael@0 | 74 | msg = line[len(' PASSED! '):] |
michael@0 | 75 | results.append((cls.PASS, msg)) |
michael@0 | 76 | else: |
michael@0 | 77 | m = re.match('--- NOTE: IN THIS TESTCASE, WE EXPECT EXIT CODE ((?:-|\\d)+) ---', line) |
michael@0 | 78 | if m: |
michael@0 | 79 | expected_rcs.append(int(m.group(1))) |
michael@0 | 80 | |
michael@0 | 81 | if rc and not rc in expected_rcs: |
michael@0 | 82 | if rc == 3: |
michael@0 | 83 | result = cls.FAIL |
michael@0 | 84 | else: |
michael@0 | 85 | result = cls.CRASH |
michael@0 | 86 | else: |
michael@0 | 87 | if (rc or passes > 0) and failures == 0: |
michael@0 | 88 | result = cls.PASS |
michael@0 | 89 | else: |
michael@0 | 90 | result = cls.FAIL |
michael@0 | 91 | |
michael@0 | 92 | return cls(test, result, results) |
michael@0 | 93 | |
michael@0 | 94 | class ResultsSink: |
michael@0 | 95 | def __init__(self, options, testcount): |
michael@0 | 96 | self.options = options |
michael@0 | 97 | self.fp = options.output_fp |
michael@0 | 98 | |
michael@0 | 99 | self.groups = {} |
michael@0 | 100 | self.counts = {'PASS': 0, 'FAIL': 0, 'TIMEOUT': 0, 'SKIP': 0} |
michael@0 | 101 | self.n = 0 |
michael@0 | 102 | |
michael@0 | 103 | if options.hide_progress: |
michael@0 | 104 | self.pb = NullProgressBar() |
michael@0 | 105 | else: |
michael@0 | 106 | fmt = [ |
michael@0 | 107 | {'value': 'PASS', 'color': 'green'}, |
michael@0 | 108 | {'value': 'FAIL', 'color': 'red'}, |
michael@0 | 109 | {'value': 'TIMEOUT', 'color': 'blue'}, |
michael@0 | 110 | {'value': 'SKIP', 'color': 'brightgray'}, |
michael@0 | 111 | ] |
michael@0 | 112 | self.pb = ProgressBar(testcount, fmt) |
michael@0 | 113 | |
michael@0 | 114 | def push(self, output): |
michael@0 | 115 | if output.timed_out: |
michael@0 | 116 | self.counts['TIMEOUT'] += 1 |
michael@0 | 117 | if isinstance(output, NullTestOutput): |
michael@0 | 118 | if self.options.tinderbox: |
michael@0 | 119 | self.print_tinderbox_result('TEST-KNOWN-FAIL', output.test.path, time=output.dt, skip=True) |
michael@0 | 120 | self.counts['SKIP'] += 1 |
michael@0 | 121 | self.n += 1 |
michael@0 | 122 | else: |
michael@0 | 123 | result = TestResult.from_output(output) |
michael@0 | 124 | tup = (result.result, result.test.expect, result.test.random) |
michael@0 | 125 | dev_label = self.LABELS[tup][1] |
michael@0 | 126 | if output.timed_out: |
michael@0 | 127 | dev_label = 'TIMEOUTS' |
michael@0 | 128 | self.groups.setdefault(dev_label, []).append(result.test.path) |
michael@0 | 129 | |
michael@0 | 130 | show = self.options.show |
michael@0 | 131 | if self.options.failed_only and dev_label not in ('REGRESSIONS', 'TIMEOUTS'): |
michael@0 | 132 | show = False |
michael@0 | 133 | if show: |
michael@0 | 134 | self.pb.beginline() |
michael@0 | 135 | |
michael@0 | 136 | if show: |
michael@0 | 137 | if self.options.show_output: |
michael@0 | 138 | print >> self.fp, '## %s: rc = %d, run time = %f' % (output.test.path, output.rc, output.dt) |
michael@0 | 139 | |
michael@0 | 140 | if self.options.show_cmd: |
michael@0 | 141 | print >> self.fp, escape_cmdline(output.cmd) |
michael@0 | 142 | |
michael@0 | 143 | if self.options.show_output: |
michael@0 | 144 | self.fp.write(output.out) |
michael@0 | 145 | self.fp.write(output.err) |
michael@0 | 146 | |
michael@0 | 147 | self.n += 1 |
michael@0 | 148 | |
michael@0 | 149 | if result.result == TestResult.PASS and not result.test.random: |
michael@0 | 150 | self.counts['PASS'] += 1 |
michael@0 | 151 | elif result.test.expect and not result.test.random: |
michael@0 | 152 | self.counts['FAIL'] += 1 |
michael@0 | 153 | else: |
michael@0 | 154 | self.counts['SKIP'] += 1 |
michael@0 | 155 | |
michael@0 | 156 | if self.options.tinderbox: |
michael@0 | 157 | if len(result.results) > 1: |
michael@0 | 158 | for sub_ok, msg in result.results: |
michael@0 | 159 | label = self.LABELS[(sub_ok, result.test.expect, result.test.random)][0] |
michael@0 | 160 | if label == 'TEST-UNEXPECTED-PASS': |
michael@0 | 161 | label = 'TEST-PASS (EXPECTED RANDOM)' |
michael@0 | 162 | self.print_tinderbox_result(label, result.test.path, time=output.dt, message=msg) |
michael@0 | 163 | self.print_tinderbox_result(self.LABELS[ |
michael@0 | 164 | (result.result, result.test.expect, result.test.random)][0], |
michael@0 | 165 | result.test.path, time=output.dt) |
michael@0 | 166 | return |
michael@0 | 167 | |
michael@0 | 168 | if dev_label: |
michael@0 | 169 | def singular(label): |
michael@0 | 170 | return "FIXED" if label == "FIXES" else label[:-1] |
michael@0 | 171 | self.pb.message("%s - %s" % (singular(dev_label), output.test.path)) |
michael@0 | 172 | |
michael@0 | 173 | self.pb.update(self.n, self.counts) |
michael@0 | 174 | |
michael@0 | 175 | def finish(self, completed): |
michael@0 | 176 | self.pb.finish(completed) |
michael@0 | 177 | if not self.options.tinderbox: |
michael@0 | 178 | self.list(completed) |
michael@0 | 179 | |
michael@0 | 180 | # Conceptually, this maps (test result x test expection) to text labels. |
michael@0 | 181 | # key is (result, expect, random) |
michael@0 | 182 | # value is (tinderbox label, dev test category) |
michael@0 | 183 | LABELS = { |
michael@0 | 184 | (TestResult.CRASH, False, False): ('TEST-UNEXPECTED-FAIL', 'REGRESSIONS'), |
michael@0 | 185 | (TestResult.CRASH, False, True): ('TEST-UNEXPECTED-FAIL', 'REGRESSIONS'), |
michael@0 | 186 | (TestResult.CRASH, True, False): ('TEST-UNEXPECTED-FAIL', 'REGRESSIONS'), |
michael@0 | 187 | (TestResult.CRASH, True, True): ('TEST-UNEXPECTED-FAIL', 'REGRESSIONS'), |
michael@0 | 188 | |
michael@0 | 189 | (TestResult.FAIL, False, False): ('TEST-KNOWN-FAIL', ''), |
michael@0 | 190 | (TestResult.FAIL, False, True): ('TEST-KNOWN-FAIL (EXPECTED RANDOM)', ''), |
michael@0 | 191 | (TestResult.FAIL, True, False): ('TEST-UNEXPECTED-FAIL', 'REGRESSIONS'), |
michael@0 | 192 | (TestResult.FAIL, True, True): ('TEST-KNOWN-FAIL (EXPECTED RANDOM)', ''), |
michael@0 | 193 | |
michael@0 | 194 | (TestResult.PASS, False, False): ('TEST-UNEXPECTED-PASS', 'FIXES'), |
michael@0 | 195 | (TestResult.PASS, False, True): ('TEST-PASS (EXPECTED RANDOM)', ''), |
michael@0 | 196 | (TestResult.PASS, True, False): ('TEST-PASS', ''), |
michael@0 | 197 | (TestResult.PASS, True, True): ('TEST-PASS (EXPECTED RANDOM)', ''), |
michael@0 | 198 | } |
michael@0 | 199 | |
michael@0 | 200 | def list(self, completed): |
michael@0 | 201 | for label, paths in sorted(self.groups.items()): |
michael@0 | 202 | if label == '': continue |
michael@0 | 203 | |
michael@0 | 204 | print label |
michael@0 | 205 | for path in paths: |
michael@0 | 206 | print ' %s'%path |
michael@0 | 207 | |
michael@0 | 208 | if self.options.failure_file: |
michael@0 | 209 | failure_file = open(self.options.failure_file, 'w') |
michael@0 | 210 | if not self.all_passed(): |
michael@0 | 211 | if 'REGRESSIONS' in self.groups: |
michael@0 | 212 | for path in self.groups['REGRESSIONS']: |
michael@0 | 213 | print >> failure_file, path |
michael@0 | 214 | if 'TIMEOUTS' in self.groups: |
michael@0 | 215 | for path in self.groups['TIMEOUTS']: |
michael@0 | 216 | print >> failure_file, path |
michael@0 | 217 | failure_file.close() |
michael@0 | 218 | |
michael@0 | 219 | suffix = '' if completed else ' (partial run -- interrupted by user)' |
michael@0 | 220 | if self.all_passed(): |
michael@0 | 221 | print 'PASS' + suffix |
michael@0 | 222 | else: |
michael@0 | 223 | print 'FAIL' + suffix |
michael@0 | 224 | |
michael@0 | 225 | def all_passed(self): |
michael@0 | 226 | return 'REGRESSIONS' not in self.groups and 'TIMEOUTS' not in self.groups |
michael@0 | 227 | |
michael@0 | 228 | def print_tinderbox_result(self, label, path, message=None, skip=False, time=None): |
michael@0 | 229 | result = label |
michael@0 | 230 | result += " | " + path |
michael@0 | 231 | result += " |" + self.options.shell_args |
michael@0 | 232 | if message: |
michael@0 | 233 | result += " | " + message |
michael@0 | 234 | if skip: |
michael@0 | 235 | result += ' | (SKIP)' |
michael@0 | 236 | if time > self.options.timeout: |
michael@0 | 237 | result += ' | (TIMEOUT)' |
michael@0 | 238 | print result |
michael@0 | 239 |