k8s.io/test-infra@v0.0.0-20240520184403-27c6b4c223d8/kettle/make_json_test.py (about) 1 #!/usr/bin/env python3 2 3 # Copyright 2017 The Kubernetes Authors. 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 17 import io as StringIO 18 import json 19 import time 20 import unittest 21 22 from parameterized import parameterized 23 24 import make_json 25 import model 26 27 28 class ValidateBuckets(unittest.TestCase): 29 def test_buckets(self): 30 prefixes = set() 31 for name, options in sorted(make_json.BUCKETS.items()): 32 if name == 'gs://kubernetes-jenkins/logs/': 33 continue # only bucket without a prefix 34 prefix = options.get('prefix', '') 35 self.assertNotEqual(prefix, '', 'bucket %s must have a prefix' % name) 36 self.assertNotIn(prefix, prefixes, "bucket %s prefix %r isn't unique" % (name, prefix)) 37 self.assertEqual(prefix[-1], ':', "bucket %s prefix should be %s:" % (name, prefix)) 38 39 40 class BuildObjectTests(unittest.TestCase): 41 @parameterized.expand([ 42 ( 43 "Empty_Build", 44 make_json.Build.__new__(make_json.Build), 45 {}, 46 ), 47 ( 48 "Base_Build", 49 make_json.Build("gs://kubernetes-jenkins/pr-logs/path", []), 50 {"path":"gs://kubernetes-jenkins/pr-logs/path", 51 "test": [], 52 "tests_run": 0, 53 "tests_failed": 0, 54 "job": "pr:pr-logs", 55 }, 56 ), 57 ( 58 "Tests_populate", 59 make_json.Build( 60 "gs://kubernetes-jenkins/pr-logs/path", 61 [{'name': 'Test1', 'failed': True}], 62 ), 63 {"path":"gs://kubernetes-jenkins/pr-logs/path", 64 "test": [{'name': 'Test1', 'failed': True}], 65 "tests_run": 1, 66 "tests_failed": 1, 67 "job": "pr:pr-logs", 68 }, 69 ), 70 ]) 71 def test_as_dict(self, _, build, expected): 72 self.assertEqual(build.as_dict(), expected) 73 74 @parameterized.expand([ 75 ( 76 "No started", 77 {}, 78 {}, 79 ), 80 ( 81 "CI Decorated", 82 { 83 "timestamp":1595284709, 84 "repos":{"kubernetes/kubernetes":"master"}, 85 "repo-version":"5a529aa3a0dd3a050c5302329681e871ef6c162e", 86 "repo-commit":"5a529aa3a0dd3a050c5302329681e871ef6c162e", 87 }, 88 { 89 "started": 1595284709, 90 "repo_commit":"5a529aa3a0dd3a050c5302329681e871ef6c162e", 91 "repos": '{"kubernetes/kubernetes": "master"}', 92 }, 93 ), 94 ( 95 "PR Decorated", 96 { 97 "timestamp":1595277241, 98 "pull":"93264", 99 "repos":{"kubernetes/kubernetes":"master:5feab0"}, 100 "repo-version":"30f64c5b1fc57a3beb1476f9beb29280166954d1", 101 "repo-commit":"30f64c5b1fc57a3beb1476f9beb29280166954d1", 102 }, 103 { 104 "started": 1595277241, 105 "repo_commit":"30f64c5b1fc57a3beb1476f9beb29280166954d1", 106 "repos": '{"kubernetes/kubernetes": "master:5feab0"}', 107 }, 108 ), 109 ( 110 "PR Bootstrap", 111 { 112 "node": "0790211c-cacb-11ea-a4b9-4a19d9b965b2", 113 "pull": "master:5a529", 114 "repo-version": "v1.20.0-alpha.0.261+06ea384605f172", 115 "timestamp": 1595278460, 116 "repos": {"k8s.io/kubernetes": "master:5a529", "k8s.io/release": "master"}, 117 "version": "v1.20.0-alpha.0.261+06ea384605f172" 118 }, 119 { 120 "started": 1595278460, 121 "repo_commit":"v1.20.0-alpha.0.261+06ea384605f172", 122 "repos": '{"k8s.io/kubernetes": "master:5a529", "k8s.io/release": "master"}', 123 "executor": "0790211c-cacb-11ea-a4b9-4a19d9b965b2", 124 }, 125 ), 126 ( 127 "CI Bootstrap", 128 { 129 "timestamp":1595263104, 130 "node":"592473ae-caa7-11ea-b130-525df2b76a8d", 131 "repos":{ 132 "k8s.io/kubernetes":"master", 133 "k8s.io/release":"master" 134 }, 135 "repo-version":"v1.20.0-alpha.0.255+5feab0aa1e592a", 136 }, 137 { 138 "started": 1595263104, 139 "repo_commit":"v1.20.0-alpha.0.255+5feab0aa1e592a", 140 "repos": '{"k8s.io/kubernetes": "master", "k8s.io/release": "master"}', 141 "executor": "592473ae-caa7-11ea-b130-525df2b76a8d", 142 }, 143 ), 144 ]) 145 def test_populate_start(self, _, started, updates): 146 build = make_json.Build("gs://kubernetes-jenkins/pr-logs/path", []) 147 attrs = { 148 "path":"gs://kubernetes-jenkins/pr-logs/path", 149 "test": [], 150 "tests_run": 0, 151 "tests_failed": 0, 152 "job": "pr:pr-logs", 153 } 154 attrs.update(updates) 155 build.populate_start(started) 156 self.assertEqual(build.as_dict(), attrs) 157 158 @parameterized.expand([ 159 ( 160 "No finished", 161 {}, 162 {}, 163 ), 164 ( 165 "CI Decorated", 166 { 167 "timestamp":1595286616, 168 "passed":True, 169 "result":"SUCCESS", 170 "revision":"master", 171 }, 172 { 173 "finished": 1595286616, 174 "result": "SUCCESS", 175 "passed": True, 176 }, 177 ), 178 ( 179 "PR Decorated", 180 { 181 "timestamp":1595279434, 182 "passed":True, 183 "result":"SUCCESS", 184 "revision":"5dd9241d43f256984358354d1fec468f274f9ac4" 185 }, 186 { 187 "finished": 1595279434, 188 "result": "SUCCESS", 189 "passed": True, 190 }, 191 ), 192 ( 193 "PR Bootstrap", 194 { 195 "timestamp": 1595282312, 196 "version": "v1.20.0-alpha.0.261+06ea384605f172", 197 "result": "SUCCESS", 198 "passed": True, 199 "job-version": "v1.20.0-alpha.0.261+06ea384605f172", 200 }, 201 { 202 "finished": 1595282312, 203 "version": "v1.20.0-alpha.0.261+06ea384605f172", 204 "result": "SUCCESS", 205 "passed": True, 206 }, 207 ), 208 ( 209 "CI Bootstrap", 210 { 211 "timestamp": 1595263185, 212 "version": "v1.20.0-alpha.0.255+5feab0aa1e592a", 213 "result": "SUCCESS", 214 "passed": True, 215 "job-version": "v1.20.0-alpha.0.255+5feab0aa1e592a", 216 }, 217 { 218 "finished": 1595263185, 219 "version": "v1.20.0-alpha.0.255+5feab0aa1e592a", 220 "result": "SUCCESS", 221 "passed": True, 222 }, 223 ), 224 ]) 225 def test_populate_finish(self, _, finished, updates): 226 build = make_json.Build("gs://kubernetes-jenkins/pr-logs/path", []) 227 attrs = {"path":"gs://kubernetes-jenkins/pr-logs/path", 228 "test": [], 229 "tests_run": 0, 230 "tests_failed": 0, 231 "job": "pr:pr-logs", 232 } 233 build.populate_finish(finished) 234 attrs.update(updates) 235 self.assertEqual(build.as_dict(), attrs) 236 237 238 class GenerateBuilds(unittest.TestCase): 239 @parameterized.expand([ 240 ( 241 "Basic_pass", 242 "gs://kubernetes-jenkins/pr-logs/path", 243 [{'name': "Test1", 'failed': False}], 244 None, 245 None, 246 None, 247 None, 248 { 249 'job': 'pr:pr-logs', 250 'path': 'gs://kubernetes-jenkins/pr-logs/path', 251 'test': [{'name': 'Test1', 'failed': False}], 252 'tests_run': 1, 253 'tests_failed':0, 254 }, 255 ), 256 ( 257 "Basic_fail", 258 "gs://kubernetes-jenkins/pr-logs/path", 259 [{'name': "Test1", 'failed': True}], 260 None, 261 None, 262 None, 263 None, 264 { 265 'job': 'pr:pr-logs', 266 'path': 'gs://kubernetes-jenkins/pr-logs/path', 267 'test': [{'name': 'Test1', 'failed': True}], 268 'tests_run': 1, 269 'tests_failed':1, 270 }, 271 ), 272 ( 273 "Ci_decorated", 274 "gs://kubernetes-jenkins/pr-logs/path", 275 [{'name': "Test1", 'failed': True}], 276 { 277 "timestamp":1595284709, 278 "repos":{"kubernetes/kubernetes":"master"}, 279 "repo-version":"5a529aa3a0dd3a050c5302329681e871ef6c162e", 280 "repo-commit":"5a529aa3a0dd3a050c5302329681e871ef6c162e", 281 }, 282 { 283 "timestamp":1595286616, 284 "passed":True, 285 "result":"SUCCESS", 286 "revision":"master", 287 }, 288 None, 289 None, 290 { 291 'job': 'pr:pr-logs', 292 'path': 'gs://kubernetes-jenkins/pr-logs/path', 293 'test': [{'name': 'Test1', 'failed': True}], 294 'passed': True, 295 'result': 'SUCCESS', 296 'elapsed': 1907, 297 'tests_run': 1, 298 'tests_failed':1, 299 'started': 1595284709, 300 'finished': 1595286616, 301 'repo_commit': '5a529aa3a0dd3a050c5302329681e871ef6c162e', 302 'repos': '{"kubernetes/kubernetes": "master"}', 303 }, 304 ), 305 ( 306 "Pr_decorated", 307 "gs://kubernetes-jenkins/pr-logs/path", 308 [{'name': "Test1", 'failed': True}], 309 { 310 "timestamp":1595277241, 311 "pull":"93264", 312 "repos":{"kubernetes/kubernetes":"master:5feab0"}, 313 "repo-version":"30f64c5b1fc57a3beb1476f9beb29280166954d1", 314 "repo-commit":"30f64c5b1fc57a3beb1476f9beb29280166954d1", 315 }, 316 { 317 "timestamp":1595279434, 318 "passed":True, 319 "result":"SUCCESS", 320 "revision":"5dd9241d43f256984358354d1fec468f274f9ac4" 321 }, 322 None, 323 None, 324 { 325 'job': 'pr:pr-logs', 326 'path': 'gs://kubernetes-jenkins/pr-logs/path', 327 'test': [{'name': 'Test1', 'failed': True}], 328 'passed': True, 329 'result': 'SUCCESS', 330 'elapsed': 2193, 331 'tests_run': 1, 332 'tests_failed':1, 333 'started': 1595277241, 334 'finished': 1595279434, 335 'repo_commit': '30f64c5b1fc57a3beb1476f9beb29280166954d1', 336 'repos': '{"kubernetes/kubernetes": "master:5feab0"}', 337 }, 338 ), 339 ( 340 "Pr_bootstrap", 341 "gs://kubernetes-jenkins/pr-logs/path", 342 [{'name': "Test1", 'failed': True}], 343 { 344 "node": "0790211c-cacb-11ea-a4b9-4a19d9b965b2", 345 "pull": "master:5a529", 346 "repo-version": "v1.20.0-alpha.0.261+06ea384605f172", 347 "timestamp": 1595278460, 348 "repos": { 349 "k8s.io/kubernetes": "master:5a529", 350 "k8s.io/release": "master" 351 }, 352 "version": "v1.20.0-alpha.0.261+06ea384605f172" 353 }, 354 { 355 "timestamp": 1595282312, 356 "version": "v1.20.0-alpha.0.261+06ea384605f172", 357 "result": "SUCCESS", 358 "passed": True, 359 "job-version": "v1.20.0-alpha.0.261+06ea384605f172", 360 }, 361 { 362 "node_os_image": "cos-81-12871-59-0", 363 "infra-commit": "2a9a0f868", 364 "repo": "k8s.io/kubernetes", 365 "master_os_image": "cos-81-12871-59-0", 366 }, 367 { 368 "k8s.io/kubernetes": "master:5a529", 369 "k8s.io/release": "master" 370 }, 371 { 372 'job': 'pr:pr-logs', 373 'executor': '0790211c-cacb-11ea-a4b9-4a19d9b965b2', 374 'path': 'gs://kubernetes-jenkins/pr-logs/path', 375 'test': [{'name': 'Test1', 'failed': True}], 376 'passed': True, 377 'result': 'SUCCESS', 378 'elapsed': 3852, 379 'tests_run': 1, 380 'tests_failed':1, 381 'started': 1595278460, 382 'finished': 1595282312, 383 'version': 'v1.20.0-alpha.0.261+06ea384605f172', 384 'repo_commit': 'v1.20.0-alpha.0.261+06ea384605f172', 385 'repos': '{"k8s.io/kubernetes": "master:5a529", "k8s.io/release": "master"}', 386 'metadata': { 387 "node_os_image": "cos-81-12871-59-0", 388 "infra-commit": "2a9a0f868", 389 "repo": "k8s.io/kubernetes", 390 "master_os_image": "cos-81-12871-59-0", 391 }, 392 }, 393 ), 394 ( 395 "Ci_bootstrap", 396 "gs://kubernetes-jenkins/pr-logs/path", 397 [{'name': "Test1", 'failed': True}], 398 { 399 "timestamp":1595263104, 400 "node":"592473ae-caa7-11ea-b130-525df2b76a8d", 401 "repos":{ 402 "k8s.io/kubernetes":"master", 403 "k8s.io/release":"master" 404 }, 405 "repo-version":"v1.20.0-alpha.0.255+5feab0aa1e592a", 406 }, 407 { 408 "timestamp": 1595263185, 409 "version": "v1.20.0-alpha.0.255+5feab0aa1e592a", 410 "result": "SUCCESS", 411 "passed": True, 412 "job-version": "v1.20.0-alpha.0.255+5feab0aa1e592a", 413 }, 414 { 415 "repo": "k8s.io/kubernetes", 416 "repos": { 417 "k8s.io/kubernetes": "master", 418 "k8s.io/release": "master" 419 }, 420 "infra-commit": "5f39b744b", 421 "repo-commit": "5feab0aa1e592ab413b461bc3ad08a6b74a427b4" 422 }, 423 { 424 "k8s.io/kubernetes":"master", 425 "k8s.io/release":"master" 426 }, 427 { 428 'job': 'pr:pr-logs', 429 'executor': '592473ae-caa7-11ea-b130-525df2b76a8d', 430 'path': 'gs://kubernetes-jenkins/pr-logs/path', 431 'test': [{'name': 'Test1', 'failed': True}], 432 'passed': True, 433 'result': 'SUCCESS', 434 'elapsed': 81, 435 'tests_run': 1, 436 'tests_failed':1, 437 'started': 1595263104, 438 'finished': 1595263185, 439 'version': 'v1.20.0-alpha.0.255+5feab0aa1e592a', 440 'repo_commit': 'v1.20.0-alpha.0.255+5feab0aa1e592a', 441 'repos': '{"k8s.io/kubernetes": "master", "k8s.io/release": "master"}', 442 'metadata': { 443 "repo": "k8s.io/kubernetes", 444 "repos": { 445 "k8s.io/kubernetes": "master", 446 "k8s.io/release": "master" 447 }, 448 "infra-commit": "5f39b744b", 449 "repo-commit": "5feab0aa1e592ab413b461bc3ad08a6b74a427b4" 450 }, 451 }, 452 ), 453 ( 454 "Started_no_meta_repo", 455 "gs://kubernetes-jenkins/pr-logs/path", 456 [{'name': "Test1", 'failed': False}], 457 { 458 "timestamp":1595263104, 459 "node":"592473ae-caa7-11ea-b130-525df2b76a8d", 460 "repos":{ 461 "k8s.io/kubernetes":"master", 462 "k8s.io/release":"master" 463 }, 464 "repo-version":"v1.20.0-alpha.0.255+5feab0aa1e592a", 465 }, 466 None, 467 None, 468 None, 469 { 470 'job': 'pr:pr-logs', 471 'executor': '592473ae-caa7-11ea-b130-525df2b76a8d', 472 'path': 'gs://kubernetes-jenkins/pr-logs/path', 473 'test': [{'name': 'Test1', 'failed': False}], 474 'tests_run': 1, 475 'tests_failed':0, 476 'repo_commit': 'v1.20.0-alpha.0.255+5feab0aa1e592a', 477 'repos': '{"k8s.io/kubernetes": "master", "k8s.io/release": "master"}', 478 'started': 1595263104, 479 }, 480 ), 481 ]) 482 def test_gen_build(self, _, path, tests, started, finished, metadata, repos, expected): 483 self.maxDiff = None 484 build = make_json.Build.generate(path, tests, started, finished, metadata, repos) 485 build_dict = build.as_dict() 486 self.assertEqual(build_dict, expected) 487 488 489 class MakeJsonTest(unittest.TestCase): 490 def setUp(self): 491 self.db = model.Database(':memory:') 492 493 def test_path_to_job_and_number(self): 494 def expect(path, job, number): 495 build = make_json.Build(path, []) 496 self.assertEqual((build.job, build.number), (job, number)) 497 498 expect('gs://kubernetes-jenkins/logs/some-build/123', 'some-build', 123) 499 expect('gs://kubernetes-jenkins/logs/some-build/123asdf', 'some-build', None) 500 expect('gs://kubernetes-jenkins/pr-logs/123/e2e-node/456', 'pr:e2e-node', 456) 501 502 with self.assertRaises(ValueError): 503 expect('gs://unknown-bucket/foo/123', None, None) 504 expect('gs://unknown-bucket/foo/123/', None, None) 505 506 def test_row_for_build(self): 507 def expect(path, start, finish, results, **kwargs): 508 expected = { 509 'path': path, 510 'test': [], 511 'tests_failed': 0, 512 'tests_run': 0, 513 } 514 if finish: 515 expected['passed'] = kwargs.get('result') == 'SUCCESS' 516 expected.update(kwargs) 517 row = make_json.row_for_build(path, start, finish, results) 518 self.assertEqual(row, expected) 519 520 path = 'gs://kubernetes-jenkins/logs/J/123' 521 expect(path, None, None, [], job='J', number=123) 522 expect(path, None, None, [], job='J', number=123) 523 expect(path, 524 {'timestamp': 10, 'node': 'agent-34'}, 525 {'timestamp': 15, 'result': 'SUCCESS', 'version': 'v1.2.3'}, 526 [], 527 job='J', number=123, 528 started=10, finished=15, elapsed=5, 529 version='v1.2.3', result='SUCCESS', executor='agent-34', 530 ) 531 expect(path, 532 {'timestamp': 10}, 533 {'timestamp': 15, 'passed': True}, 534 [], 535 job='J', number=123, 536 started=10, finished=15, elapsed=5, 537 result='SUCCESS', 538 ) 539 expect(path, None, 540 {'timestamp': 15, 'result': 'FAILURE', 541 'metadata': {'repo': 'ignored', 'pull': 'asdf'}}, [], 542 result='FAILURE', job='J', number=123, finished=15, 543 metadata=[{'key': 'pull', 'value': 'asdf'}, {'key': 'repo', 'value': 'ignored'}]) 544 expect(path, None, None, [''' 545 <testsuite> 546 <properties><property name="test" value="don't crash!"></property></properties> 547 <testcase name="t1" time="1.0"><failure>stacktrace</failure></testcase> 548 <testcase name="t2" time="2.0"></testcase> 549 <testcase name="t2#1" time="2.0"></testcase> 550 </testsuite>'''], 551 job='J', number=123, 552 tests_run=2, tests_failed=1, 553 test=[{'name': 't1', 'time': 1.0, 'failed': True, 'failure_text': 'stacktrace'}, 554 {'name': 't2', 'time': 2.0}]) 555 556 def test_main(self): 557 now = time.time() 558 last_month = now - (60 * 60 * 24 * 30) 559 junits = ['<testsuite><testcase name="t1" time="3.0"></testcase></testsuite>'] 560 561 def add_build(path, start, finish, result, junits): 562 path = 'gs://kubernetes-jenkins/logs/%s' % path 563 self.db.insert_build( 564 path, {'timestamp': start}, {'timestamp': finish, 'result': result}) 565 # fake build rowid doesn't matter here 566 self.db.insert_build_junits( 567 hash(path), 568 {'%s/artifacts/junit_%d.xml' % (path, n): junit for n, junit in enumerate(junits)}) 569 self.db.commit() 570 571 def expect(args, needles, negneedles, expected_ret=None): 572 buf = StringIO.StringIO() 573 opts = make_json.parse_args(args) 574 ret = make_json.main(self.db, opts, buf) 575 result = buf.getvalue() 576 577 if expected_ret is not None: 578 self.assertEqual(ret, expected_ret) 579 580 # validate that output is newline-delimited JSON 581 for line in result.split('\n'): 582 if line.strip(): 583 json.loads(line) 584 585 # test for expected patterns / expected missing patterns 586 for needle in needles: 587 self.assertIn(needle, result) 588 for needle in negneedles: 589 # Only match negative needles in the middle of a word, to avoid 590 # failures on timestamps that happen to contain a short number. 591 self.assertNotRegexpMatches(result, r'\b%s\b' % needle) # pylint: disable=deprecated-method 592 593 add_build('some-job/123', last_month, last_month + 10, 'SUCCESS', junits) 594 add_build('some-job/456', now - 10, now, 'FAILURE', junits) 595 596 expect([], ['123', '456', 'SUCCESS', 'FAILURE'], []) # everything 597 expect([], [], ['123', '456', 'SUCCESS', 'FAILURE']) # nothing 598 599 expect(['--days=1'], ['456'], []) # recent 600 expect(['--days', '1'], [], ['456']) # nothing (already emitted) 601 602 add_build('some-job/457', now + 1, now + 11, 'SUCCESS', junits) 603 expect(['--days=1'], ['457'], ['456']) # latest (day) 604 expect([], ['457'], ['456']) # latest (all) 605 606 expect(['--days=1', '--reset-emitted'], ['456', '457'], []) # both (reset) 607 expect([], [], ['123', '456', '457']) # reset only works for given day 608 609 # verify that direct paths work 610 expect(['gs://kubernetes-jenkins/logs/some-job/123'], ['123'], []) 611 expect(['gs://kubernetes-jenkins/logs/some-job/123'], ['123'], []) 612 613 # verify that assert_oldest works 614 expect(['--days=30'], ['123', '456'], []) 615 expect(['--days=30', '--assert-oldest=60'], [], [], 0) 616 expect(['--days=30', '--assert-oldest=25'], [], [], 1) 617 618 619 class ParseJsonTest(unittest.TestCase): 620 @parameterized.expand([ 621 ('Green Path', 622 'kettle/testdata/standard.xml', 623 [{'name': 'TearDown Previous', 'time': 2.065e-05}, 624 {'name': 'Up', 'time': 6.342e-06}, 625 {'name': 'test setup', 'time': 5.298e-06}, 626 {'failed': True, 627 'failure_text': 'error during go run', 628 'name': 'Node Tests', 629 'time': 654.279097299}, 630 {'name': 'DumpClusterLogs', 'time': 5.399023835}, 631 {'name': 'TearDown', 'time': 1.21e-05}, 632 {'name': 'Deferred TearDown', 'time': 2.17e-07}, 633 {'name': 'Timeout', 'time': 3900.0}], 634 ), 635 ('No Suite Name', 636 'kettle/testdata/junit_no_suite_name.xml', 637 [{'failed': True, 638 'failure_text': 'simple_test.go:186: Running tests in file plumbing', 639 'name': '<unspecified> TestSimpleFile', 640 'time': 0.0}, 641 {'name': '<unspecified> TestSimpleFile/plumbing/min/min_program', 'time': 0.0}, 642 {'name': '<unspecified> TestSimpleFile/plumbing/eval_results/error_result', 643 'time': 0.0}], 644 ), 645 ('Failure as Message', 646 'kettle/testdata/failure_message.xml', 647 [{'failed': True, 648 'failure_text': 'simple_test.go:186: Running tests in file plumbing', 649 'name': '<unspecified> TestSimpleFile', 650 'time': 0.0}], 651 ), 652 ('Failure as Text', 653 'kettle/testdata/failure_text.xml', 654 [{'failed': True, 655 'failure_text': 'simple_test.go:186: Running tests in file plumbing', 656 'name': '<unspecified> TestSimpleFile', 657 'time': 0.0}], 658 ), 659 ('Malformed XML', 660 'kettle/testdata/malformed.xml', 661 [], 662 ), 663 ('Malformed Testcase', 664 'kettle/testdata/malformed_no_testcase_name.xml', 665 [{'name': 'TearDown Previous', 'time': 2.065e-05}, 666 {'name': 'Up', 'time': 6.342e-06}, 667 {'name': 'test setup', 'time': 5.298e-06}, 668 {'failed': True, 669 'failure_text': 'error during go run', 670 'name': 'Node Tests', 671 'time': 654.279097299}, 672 {'name': '<unspecified>', 'time': 5.399023835}, 673 {'name': '<unspecified>', 'time': 1.21e-05}, 674 {'name': 'Deferred TearDown', 'time': 2.17e-07}, 675 {'name': 'Timeout', 'time': 3900.0}], 676 ) 677 ]) 678 def test_parse_junit(self, _, path, expected): 679 self.maxDiff = None 680 datasource = open(path) 681 failures = make_json.parse_junit(datasource.read()) 682 self.assertEqual(list(failures), expected) 683 684 if __name__ == '__main__': 685 unittest.main()