Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(27)

Side by Side Diff: webkit/tools/layout_tests/run_webkit_tests.py

Issue 213031: Insert summary results to the JSON. These are the same results spit to stdout... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 11 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « webkit/tools/layout_tests/layout_package/json_results_generator.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Run layout tests using the test_shell. 6 """Run layout tests using the test_shell.
7 7
8 This is a port of the existing webkit test script run-webkit-tests. 8 This is a port of the existing webkit test script run-webkit-tests.
9 9
10 The TestRunner class runs a series of tests (TestType interface) against a set 10 The TestRunner class runs a series of tests (TestType interface) against a set
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
61 self.timeout = timeout 61 self.timeout = timeout
62 expected_hash_file = path_utils.ExpectedFilename(filename, '.checksum') 62 expected_hash_file = path_utils.ExpectedFilename(filename, '.checksum')
63 try: 63 try:
64 self.image_hash = open(expected_hash_file, "r").read() 64 self.image_hash = open(expected_hash_file, "r").read()
65 except IOError, e: 65 except IOError, e:
66 if errno.ENOENT != e.errno: 66 if errno.ENOENT != e.errno:
67 raise 67 raise
68 self.image_hash = None 68 self.image_hash = None
69 69
70 70
71 class ResultSummaryEntry:
72 def __init__(self, all, failed, failure_counts, skipped):
73 """Resolves result counts.
74
75 Args:
76 all: list of all tests in this category
77 failed: list of failing tests in this category
78 skipped: list of skipped tests
79 failure_counts: dictionary of (TestFailure -> frequency)
80 """
81 self.skip_count = len(skipped)
82 self.total_count = len(all | skipped)
83 self.pass_count = self.total_count - self.skip_count - len(failed)
84 self.failure_counts = failure_counts;
85
86
87 class ResultSummary:
88 """Container for all result summaries for this test run.
89
90 Args:
91 deferred: ResultSummary object for deferred tests.
92 non_wontfix: ResultSummary object for non_wontfix tests.
93 all: ResultSummary object for all tests, including skipped tests.
94 fixable_count: Count of all fixable and skipped tests. This is essentially
95 a deduped sum of all the non_wontfix failure counts.
96 """
97 def __init__(self, deferred, non_wontfix, all, fixable_count):
98 self.deferred = deferred
99 self.non_wontfix = non_wontfix
100 self.all = all
101 self.fixable_count = fixable_count
102
103
71 class TestRunner: 104 class TestRunner:
72 """A class for managing running a series of tests on a series of test 105 """A class for managing running a series of tests on a series of test
73 files.""" 106 files."""
74 107
75 # When collecting test cases, we include any file with these extensions. 108 # When collecting test cases, we include any file with these extensions.
76 _supported_file_extensions = set(['.html', '.shtml', '.xml', '.xhtml', '.pl', 109 _supported_file_extensions = set(['.html', '.shtml', '.xml', '.xhtml', '.pl',
77 '.php', '.svg']) 110 '.php', '.svg'])
78 # When collecting test cases, skip these directories 111 # When collecting test cases, skip these directories
79 _skipped_directories = set(['.svn', '_svn', 'resources', 'script-tests']) 112 _skipped_directories = set(['.svn', '_svn', 'resources', 'script-tests'])
80 113
(...skipping 480 matching lines...) Expand 10 before | Expand all | Expand 10 after
561 self._PrintTimingStatistics(test_timings, individual_test_timings, failures) 594 self._PrintTimingStatistics(test_timings, individual_test_timings, failures)
562 595
563 print "-" * 78 596 print "-" * 78
564 597
565 # Tests are done running. Compare failures with expected failures. 598 # Tests are done running. Compare failures with expected failures.
566 regressions = self._CompareFailures(failures) 599 regressions = self._CompareFailures(failures)
567 600
568 print "-" * 78 601 print "-" * 78
569 602
570 # Write summaries to stdout. 603 # Write summaries to stdout.
571 self._PrintResults(failures, sys.stdout) 604 result_summary = self._GetResultSummary(failures)
605 self._PrintResultSummary(result_summary, sys.stdout)
572 606
573 if self._options.verbose: 607 if self._options.verbose:
574 self._WriteJSONFiles(failures, individual_test_timings); 608 self._WriteJSONFiles(failures, individual_test_timings, result_summary);
575 609
576 # Write the same data to a log file. 610 # Write the same data to a log file.
577 out_filename = os.path.join(self._options.results_directory, "score.txt") 611 out_filename = os.path.join(self._options.results_directory, "score.txt")
578 output_file = open(out_filename, "w") 612 output_file = open(out_filename, "w")
579 self._PrintResults(failures, output_file) 613 self._PrintResultSummary(result_summary, output_file)
580 output_file.close() 614 output_file.close()
581 615
582 # Write the summary to disk (results.html) and maybe open the test_shell 616 # Write the summary to disk (results.html) and maybe open the test_shell
583 # to this file. 617 # to this file.
584 wrote_results = self._WriteResultsHtmlFile(failures, regressions) 618 wrote_results = self._WriteResultsHtmlFile(failures, regressions)
585 if not self._options.noshow_results and wrote_results: 619 if not self._options.noshow_results and wrote_results:
586 self._ShowResultsHtmlFile() 620 self._ShowResultsHtmlFile()
587 621
588 sys.stdout.flush() 622 sys.stdout.flush()
589 sys.stderr.flush() 623 sys.stderr.flush()
590 return len(regressions) 624 return len(regressions)
591 625
592 def _WriteJSONFiles(self, failures, individual_test_timings): 626 def _WriteJSONFiles(self, failures, individual_test_timings, result_summary):
593 logging.debug("Writing JSON files in %s." % self._options.results_directory) 627 logging.debug("Writing JSON files in %s." % self._options.results_directory)
594 # Write a json file of the test_expectations.txt file for the layout tests 628 # Write a json file of the test_expectations.txt file for the layout tests
595 # dashboard. 629 # dashboard.
596 expectations_file = open(os.path.join(self._options.results_directory, 630 expectations_file = open(os.path.join(self._options.results_directory,
597 "expectations.json"), "w") 631 "expectations.json"), "w")
598 expectations_json = self._expectations.GetExpectationsJsonForAllPlatforms() 632 expectations_json = self._expectations.GetExpectationsJsonForAllPlatforms()
599 expectations_file.write(("ADD_EXPECTATIONS(" + expectations_json + ");")) 633 expectations_file.write(("ADD_EXPECTATIONS(" + expectations_json + ");"))
600 expectations_file.close() 634 expectations_file.close()
601 635
602 results_file_path = os.path.join(self._options.results_directory, 636 results_file_path = os.path.join(self._options.results_directory,
603 "results.json") 637 "results.json")
604 builder_name = self._options.builder_name # "WebKitBuilder" 638 builder_name = self._options.builder_name # "WebKitBuilder"
605 build_number = self._options.build_number # "12346" 639 build_number = self._options.build_number # "12346"
606 json_generator = json_results_generator.JSONResultsGenerator(failures, 640 json_generator = json_results_generator.JSONResultsGenerator(failures,
607 individual_test_timings, builder_name, build_number, 641 individual_test_timings, builder_name, build_number,
608 results_file_path, self._test_files_list) 642 results_file_path, self._test_files_list, result_summary)
609 results_json = json_generator.GetJSON() 643 results_json = json_generator.GetJSON()
610 644
611 results_file = open(results_file_path, "w") 645 results_file = open(results_file_path, "w")
612 results_file.write(results_json) 646 results_file.write(results_json)
613 results_file.close() 647 results_file.close()
614 648
615 logging.debug("Finished writing JSON files.") 649 logging.debug("Finished writing JSON files.")
616 650
617 def _PrintTimingStatistics(self, directory_test_timings, 651 def _PrintTimingStatistics(self, directory_test_timings,
618 individual_test_timings, failures): 652 individual_test_timings, failures):
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
740 mean = sum(timings) / num_tests 774 mean = sum(timings) / num_tests
741 775
742 for time in timings: 776 for time in timings:
743 sum_of_deviations = math.pow(time - mean, 2) 777 sum_of_deviations = math.pow(time - mean, 2)
744 778
745 std_deviation = math.sqrt(sum_of_deviations / num_tests) 779 std_deviation = math.sqrt(sum_of_deviations / num_tests)
746 logging.debug(("Median: %s, Mean: %s, 90th percentile: %s, " 780 logging.debug(("Median: %s, Mean: %s, 90th percentile: %s, "
747 "99th percentile: %s, Standard deviation: %s\n" % ( 781 "99th percentile: %s, Standard deviation: %s\n" % (
748 median, mean, percentile90, percentile99, std_deviation))) 782 median, mean, percentile90, percentile99, std_deviation)))
749 783
750 def _PrintResults(self, failures, output): 784 def _GetResultSummary(self, failures):
751 """Print a short summary to stdout about how many tests passed. 785 """Returns a ResultSummary object with failure counts.
752 786
753 Args: 787 Args:
754 failures is a dictionary mapping the test filename to a list of 788 failures: dictionary mapping the test filename to a list of
755 TestFailure objects if the test failed 789 TestFailure objects if the test failed
756
757 output is the file descriptor to write the results to. For example,
758 sys.stdout.
759 """ 790 """
760
761 failure_counts = {} 791 failure_counts = {}
762 deferred_counts = {} 792 deferred_counts = {}
763 fixable_counts = {} 793 fixable_counts = {}
764 non_ignored_counts = {} 794 non_wontfix_counts = {}
765 fixable_failures = set() 795 fixable_failures = set()
766 deferred_failures = set() 796 deferred_failures = set()
767 non_ignored_failures = set() 797 non_wontfix_failures = set()
768 798
769 # Aggregate failures in a dictionary (TestFailure -> frequency), 799 # Aggregate failures in a dictionary (TestFailure -> frequency),
770 # with known (fixable and ignored) failures separated out. 800 # with known (fixable and wontfix) failures separated out.
771 def AddFailure(dictionary, key): 801 def AddFailure(dictionary, key):
772 if key in dictionary: 802 if key in dictionary:
773 dictionary[key] += 1 803 dictionary[key] += 1
774 else: 804 else:
775 dictionary[key] = 1 805 dictionary[key] = 1
776 806
777 for test, failures in failures.iteritems(): 807 for test, failures in failures.iteritems():
778 for failure in failures: 808 for failure in failures:
779 AddFailure(failure_counts, failure.__class__) 809 AddFailure(failure_counts, failure.__class__)
780 if self._expectations.IsDeferred(test): 810 if self._expectations.IsDeferred(test):
781 AddFailure(deferred_counts, failure.__class__) 811 AddFailure(deferred_counts, failure.__class__)
782 deferred_failures.add(test) 812 deferred_failures.add(test)
783 else: 813 else:
784 if self._expectations.IsFixable(test): 814 if self._expectations.IsFixable(test):
785 AddFailure(fixable_counts, failure.__class__) 815 AddFailure(fixable_counts, failure.__class__)
786 fixable_failures.add(test) 816 fixable_failures.add(test)
787 if not self._expectations.IsIgnored(test): 817 if not self._expectations.IsIgnored(test):
788 AddFailure(non_ignored_counts, failure.__class__) 818 AddFailure(non_wontfix_counts, failure.__class__)
789 non_ignored_failures.add(test) 819 non_wontfix_failures.add(test)
790 820
791 # Print breakdown of tests we need to fix and want to pass. 821 # Print breakdown of tests we need to fix and want to pass.
792 # Include skipped fixable tests in the statistics. 822 # Include skipped fixable tests in the statistics.
793 skipped = (self._expectations.GetSkipped() - 823 skipped = (self._expectations.GetSkipped() -
794 self._expectations.GetDeferredSkipped()) 824 self._expectations.GetDeferredSkipped())
795 825
796 self._PrintResultSummary("=> Tests to be fixed for the current release", 826 deferred_tests = self._expectations.GetDeferred()
797 self._expectations.GetFixable(), 827 non_wontfix_result_summary = ResultSummaryEntry(
798 fixable_failures, 828 (self._test_files - self._expectations.GetWontFix() - deferred_tests),
799 fixable_counts, 829 non_wontfix_failures,
800 skipped, 830 non_wontfix_counts,
801 output) 831 skipped)
802 832
803 self._PrintResultSummary("=> Tests we want to pass for the current release", 833 deferred_result_summary = ResultSummaryEntry(
804 (self._test_files - 834 deferred_tests,
805 self._expectations.GetWontFix() - 835 deferred_failures,
806 self._expectations.GetDeferred()), 836 deferred_counts,
807 non_ignored_failures, 837 self._expectations.GetDeferredSkipped())
808 non_ignored_counts,
809 skipped,
810 output)
811 838
812 self._PrintResultSummary("=> Tests to be fixed for a future release", 839 skipped |= self._expectations.GetWontFixSkipped()
813 self._expectations.GetDeferred(), 840 all_result_summary = ResultSummaryEntry(
814 deferred_failures, 841 self._test_files,
815 deferred_counts, 842 failures,
816 self._expectations.GetDeferredSkipped(), 843 failure_counts,
817 output) 844 skipped)
845
846 total_fixable_count = len(self._expectations.GetFixable() | skipped)
847
848 return ResultSummary(deferred_result_summary, non_wontfix_result_summary,
849 all_result_summary, total_fixable_count)
850
851 def _PrintResultSummary(self, result_summary, output):
852 """Print a short summary to stdout about how many tests passed.
853
854 Args:
855 result_summary: ResultSummary object with failure counts.
856 output: file descriptor to write the results to. For example, sys.stdout.
857 """
858 output.write(
859 "\nTotal expected failures: %s\n" % result_summary.fixable_count)
860
861 self._PrintResultSummaryEntry(
862 "Tests we want to pass for the current release",
863 result_summary.non_wontfix,
864 output)
865
866 self._PrintResultSummaryEntry("Tests to be fixed for a future release",
867 result_summary.deferred,
868 output)
818 869
819 # Print breakdown of all tests including all skipped tests. 870 # Print breakdown of all tests including all skipped tests.
820 skipped |= self._expectations.GetWontFixSkipped() 871 self._PrintResultSummaryEntry("All tests",
821 self._PrintResultSummary("=> All tests", 872 result_summary.all,
822 self._test_files, 873 output)
823 failures,
824 failure_counts,
825 skipped,
826 output)
827 print 874 print
828 875
829 def _PrintResultSummary(self, heading, all, failed, failure_counts, skipped, 876 def _PrintResultSummaryEntry(self, heading, result_summary, output):
830 output):
831 """Print a summary block of results for a particular category of test. 877 """Print a summary block of results for a particular category of test.
832 878
833 Args: 879 Args:
834 heading: text to print before the block, followed by the total count 880 heading: text to print before the block, followed by the total count
835 all: list of all tests in this category 881 result_summary: ResultSummaryEntry object with the result counts
836 failed: list of failing tests in this category
837 failure_counts: dictionary of (TestFailure -> frequency)
838 output: file descriptor to write the results to 882 output: file descriptor to write the results to
839 """ 883 """
840 total = len(all | skipped) 884 output.write("\n=> %s (%d):\n" % (heading, result_summary.total_count))
841 output.write("\n%s (%d):\n" % (heading, total)) 885 self._PrintResultLine(result_summary.pass_count, result_summary.total_count,
842 skip_count = len(skipped) 886 "Passed", output)
843 pass_count = total - skip_count - len(failed) 887 self._PrintResultLine(result_summary.skip_count, result_summary.total_count,
844 self._PrintResultLine(pass_count, total, "Passed", output) 888 "Skipped", output)
845 self._PrintResultLine(skip_count, total, "Skipped", output) 889 sorted_keys = sorted(result_summary.failure_counts.keys(),
846 # Sort the failure counts and print them one by one.
847 sorted_keys = sorted(failure_counts.keys(),
848 key=test_failures.FailureSort.SortOrder) 890 key=test_failures.FailureSort.SortOrder)
849 for failure in sorted_keys: 891 for failure in sorted_keys:
850 self._PrintResultLine(failure_counts[failure], total, failure.Message(), 892 self._PrintResultLine(result_summary.failure_counts[failure],
893 result_summary.total_count,
894 failure.Message(),
851 output) 895 output)
852 896
853 def _PrintResultLine(self, count, total, message, output): 897 def _PrintResultLine(self, count, total, message, output):
854 if count == 0: return 898 if count == 0: return
855 output.write( 899 output.write(
856 ("%(count)d test case%(plural)s (%(percent).1f%%) %(message)s\n" % 900 ("%(count)d test case%(plural)s (%(percent).1f%%) %(message)s\n" %
857 { 'count' : count, 901 { 'count' : count,
858 'plural' : ('s', '')[count == 1], 902 'plural' : ('s', '')[count == 1],
859 'percent' : float(count) * 100 / total, 903 'percent' : float(count) * 100 / total,
860 'message' : message })) 904 'message' : message }))
(...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after
1189 option_parser.add_option("", "--build-number", 1233 option_parser.add_option("", "--build-number",
1190 default="DUMMY_BUILD_NUMBER", 1234 default="DUMMY_BUILD_NUMBER",
1191 help=("The build number of the builder running" 1235 help=("The build number of the builder running"
1192 "this script.")) 1236 "this script."))
1193 option_parser.add_option("", "--find-baselines", action="store_true", 1237 option_parser.add_option("", "--find-baselines", action="store_true",
1194 default=False, 1238 default=False,
1195 help="Prints a table mapping tests to their " 1239 help="Prints a table mapping tests to their "
1196 "expected results") 1240 "expected results")
1197 options, args = option_parser.parse_args() 1241 options, args = option_parser.parse_args()
1198 main(options, args) 1242 main(options, args)
OLDNEW
« no previous file with comments | « webkit/tools/layout_tests/layout_package/json_results_generator.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698