| OLD | NEW |
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import os | 5 import os |
| 6 import re | 6 import re |
| 7 | 7 |
| 8 from google.appengine.ext import testbed | 8 from google.appengine.ext import testbed |
| 9 | 9 |
| 10 import webapp2 | 10 import webapp2 |
| 11 import webtest | 11 import webtest |
| 12 | 12 |
| 13 from common.waterfall import failure_type |
| 13 from handlers import build_failure | 14 from handlers import build_failure |
| 14 from handlers import handlers_util | 15 from handlers import handlers_util |
| 15 from handlers import result_status | 16 from handlers import result_status |
| 16 from model import analysis_approach_type | 17 from model import analysis_approach_type |
| 17 from model import analysis_status | 18 from model import analysis_status |
| 18 from model import suspected_cl_status | 19 from model import suspected_cl_status |
| 19 from model.base_build_model import BaseBuildModel | 20 from model.base_build_model import BaseBuildModel |
| 21 from model.cl_confidence import CLConfidence |
| 20 from model.wf_analysis import WfAnalysis | 22 from model.wf_analysis import WfAnalysis |
| 21 from model.wf_suspected_cl import WfSuspectedCL | 23 from model.wf_suspected_cl import WfSuspectedCL |
| 22 from model.wf_try_job import WfTryJob | 24 from model.wf_try_job import WfTryJob |
| 23 from waterfall import buildbot | 25 from waterfall import buildbot |
| 24 from waterfall.test import wf_testcase | 26 from waterfall.test import wf_testcase |
| 25 | 27 |
| 26 # Root directory appengine/findit. | 28 # Root directory appengine/findit. |
| 27 ROOT_DIR = os.path.join(os.path.dirname(__file__), | 29 ROOT_DIR = os.path.join(os.path.dirname(__file__), |
| 28 os.path.pardir, os.path.pardir) | 30 os.path.pardir, os.path.pardir) |
| 29 | 31 |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 102 'revision': 'rev2', | 104 'revision': 'rev2', |
| 103 'commit_position': '2', | 105 'commit_position': '2', |
| 104 'review_url': 'url_2' | 106 'review_url': 'url_2' |
| 105 } | 107 } |
| 106 } | 108 } |
| 107 ] | 109 ] |
| 108 } | 110 } |
| 109 } | 111 } |
| 110 } | 112 } |
| 111 | 113 |
| 114 SAMPLE_HEURISTIC = { |
| 115 '5': { |
| 116 'confidence': 0.9478 |
| 117 } |
| 118 } |
| 119 |
| 120 SAMPLE_TRY_JOB = { |
| 121 'confidence': 0.85 |
| 122 } |
| 123 |
| 124 SAMPLE_HEURISTIC_TRY_JOB = { |
| 125 'confidence': 0.9778 |
| 126 } |
| 127 |
| 112 | 128 |
| 113 class BuildFailureTest(wf_testcase.WaterfallTestCase): | 129 class BuildFailureTest(wf_testcase.WaterfallTestCase): |
| 114 app_module = webapp2.WSGIApplication([ | 130 app_module = webapp2.WSGIApplication([ |
| 115 ('/build-failure', build_failure.BuildFailure), | 131 ('/build-failure', build_failure.BuildFailure), |
| 116 ], debug=True) | 132 ], debug=True) |
| 117 | 133 |
| 118 def setUp(self): | 134 def setUp(self): |
| 119 super(BuildFailureTest, self).setUp() | 135 super(BuildFailureTest, self).setUp() |
| 120 | 136 |
| 121 # Setup clean task queues. | 137 # Setup clean task queues. |
| 122 self.testbed.init_taskqueue_stub(root_path=ROOT_DIR) | 138 self.testbed.init_taskqueue_stub(root_path=ROOT_DIR) |
| 123 self.taskqueue_stub = self.testbed.get_stub(testbed.TASKQUEUE_SERVICE_NAME) | 139 self.taskqueue_stub = self.testbed.get_stub(testbed.TASKQUEUE_SERVICE_NAME) |
| 124 for queue in self.taskqueue_stub.GetQueues(): | 140 for queue in self.taskqueue_stub.GetQueues(): |
| 125 self.taskqueue_stub.FlushQueue(queue['name']) | 141 self.taskqueue_stub.FlushQueue(queue['name']) |
| 126 | 142 |
| 127 def MockedGetAllTryJobResults(master_name, builder_name, build_number, _): | 143 def MockedGetAllTryJobResults(master_name, builder_name, build_number, _): |
| 128 build_key = BaseBuildModel.CreateBuildId( | 144 build_key = BaseBuildModel.CreateBuildId( |
| 129 master_name, builder_name, build_number) | 145 master_name, builder_name, build_number) |
| 130 return SAMPLE_TRY_JOB_INFO.get(build_key, None) | 146 return SAMPLE_TRY_JOB_INFO.get(build_key, None) |
| 131 self.mock(handlers_util, 'GetAllTryJobResults', MockedGetAllTryJobResults) | 147 self.mock(handlers_util, 'GetAllTryJobResults', MockedGetAllTryJobResults) |
| 132 | 148 |
| 149 self.cl_confidences = CLConfidence() |
| 150 self.cl_confidences.compile_heuristic = SAMPLE_HEURISTIC |
| 151 self.cl_confidences.test_heuristic = SAMPLE_HEURISTIC |
| 152 self.cl_confidences.compile_try_job = SAMPLE_TRY_JOB |
| 153 self.cl_confidences.test_try_job = SAMPLE_TRY_JOB |
| 154 self.cl_confidences.compile_heuristic_try_job = SAMPLE_HEURISTIC_TRY_JOB |
| 155 self.cl_confidences.test_heuristic_try_job = SAMPLE_HEURISTIC_TRY_JOB |
| 156 self.cl_confidences.put() |
| 157 def MockGetMostRecentConfidence(): |
| 158 return self.cl_confidences |
| 159 self.mock( |
| 160 build_failure, '_GetMostRecentConfidence', MockGetMostRecentConfidence) |
| 161 |
| 133 def testGetTriageHistoryWhenUserIsNotAdmin(self): | 162 def testGetTriageHistoryWhenUserIsNotAdmin(self): |
| 134 analysis = WfAnalysis.Create('m', 'b', 1) | 163 analysis = WfAnalysis.Create('m', 'b', 1) |
| 135 analysis.status = analysis_status.COMPLETED | 164 analysis.status = analysis_status.COMPLETED |
| 136 analysis.triage_history = [ | 165 analysis.triage_history = [ |
| 137 { | 166 { |
| 138 'triage_timestamp': 1438380761, | 167 'triage_timestamp': 1438380761, |
| 139 'user_name': 'test', | 168 'user_name': 'test', |
| 140 'result_status': 'dummy status', | 169 'result_status': 'dummy status', |
| 141 'version': 'dummy version', | 170 'version': 'dummy version', |
| 142 } | 171 } |
| (...skipping 652 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 795 'revision': 'rev', | 824 'revision': 'rev', |
| 796 } | 825 } |
| 797 } | 826 } |
| 798 } | 827 } |
| 799 ] | 828 ] |
| 800 try_job.put() | 829 try_job.put() |
| 801 | 830 |
| 802 suspected_cl = WfSuspectedCL.Create('chromium', 'rev', 122) | 831 suspected_cl = WfSuspectedCL.Create('chromium', 'rev', 122) |
| 803 suspected_cl.builds = { | 832 suspected_cl.builds = { |
| 804 'm/b/123': { | 833 'm/b/123': { |
| 805 'failure_type': 'compile', | 834 'failure_type': failure_type.COMPILE, |
| 806 'failures': None, | 835 'failures': None, |
| 807 'status': suspected_cl_status.CORRECT, | 836 'status': suspected_cl_status.CORRECT, |
| 808 'approach': analysis_approach_type.HEURISTIC, | 837 'approaches': [analysis_approach_type.HEURISTIC, |
| 809 'top_score': 5, | 838 analysis_approach_type.TRY_JOB], |
| 810 'Confidence': 97.9 | 839 'top_score': 5 |
| 811 } | 840 } |
| 812 } | 841 } |
| 813 suspected_cl.put() | 842 suspected_cl.put() |
| 814 | 843 |
| 815 expected_try_job_result = { | 844 expected_try_job_result = { |
| 816 'status': 'completed', | 845 'status': 'completed', |
| 817 'url': 'build/url', | 846 'url': 'build/url', |
| 818 'completed': True, | 847 'completed': True, |
| 819 'culprit': { | 848 'culprit': { |
| 820 'revision': 'rev', | 849 'revision': 'rev', |
| 821 }, | 850 }, |
| 822 'failed': False, | 851 'failed': False, |
| 823 } | 852 } |
| 824 | 853 |
| 825 expected_suspected_cls = [ | 854 expected_suspected_cls = [ |
| 826 { | 855 { |
| 827 'repo_name': 'chromium', | 856 'repo_name': 'chromium', |
| 828 'revision': 'rev', | 857 'revision': 'rev', |
| 829 'commit_position': 122, | 858 'commit_position': 122, |
| 830 'url': None, | 859 'url': None, |
| 831 'status': suspected_cl_status.CORRECT | 860 'status': suspected_cl_status.CORRECT, |
| 861 'confidence': build_failure._PercentFormat( |
| 862 self.cl_confidences.compile_heuristic_try_job['confidence']) |
| 832 } | 863 } |
| 833 ] | 864 ] |
| 834 | 865 |
| 835 build_url = buildbot.CreateBuildUrl('m', 'b', 123) | 866 build_url = buildbot.CreateBuildUrl('m', 'b', 123) |
| 836 response = self.test_app.get('/build-failure', | 867 response = self.test_app.get('/build-failure', |
| 837 params={'url': build_url, 'format': 'json'}) | 868 params={'url': build_url, 'format': 'json'}) |
| 838 | 869 |
| 839 self.assertEquals(200, response.status_int) | 870 self.assertEquals(200, response.status_int) |
| 840 self.assertEqual(expected_try_job_result, response.json_body['try_job']) | 871 self.assertEqual(expected_try_job_result, response.json_body['try_job']) |
| 841 self.assertEqual( | 872 self.assertEqual( |
| 842 expected_suspected_cls, response.json_body['suspected_cls']) | 873 expected_suspected_cls, response.json_body['suspected_cls']) |
| 843 | 874 |
| 844 def testGetAllSuspectedCLsAndCheckStatus(self): | 875 def testGetAllSuspectedCLsAndCheckStatus(self): |
| 845 master_name = 'm' | 876 master_name = 'm' |
| 846 builder_name = 'b' | 877 builder_name = 'b' |
| 847 build_number = 123 | 878 build_number = 123 |
| 848 analysis = WfAnalysis.Create(master_name, builder_name, build_number) | 879 analysis = WfAnalysis.Create(master_name, builder_name, build_number) |
| 849 analysis.suspected_cls = [ | 880 analysis.suspected_cls = [ |
| 850 { | 881 { |
| 851 'repo_name': 'chromium', | 882 'repo_name': 'chromium', |
| 852 'revision': 'rev', | 883 'revision': 'rev', |
| 853 'commit_position': 122, | 884 'commit_position': 122, |
| 854 'url': None | 885 'url': None |
| 855 } | 886 } |
| 856 ] | 887 ] |
| 857 analysis.put() | 888 analysis.put() |
| 858 suspected_cl = WfSuspectedCL.Create('chromium', 'rev', 122) | 889 suspected_cl = WfSuspectedCL.Create('chromium', 'rev', 122) |
| 859 suspected_cl.builds = { | 890 suspected_cl.builds = { |
| 860 'm/b/122': { | 891 'm/b/122': { |
| 861 'failure_type': 'compile', | 892 'failure_type': failure_type.COMPILE, |
| 862 'failures': None, | 893 'failures': None, |
| 863 'status': suspected_cl_status.CORRECT, | 894 'status': suspected_cl_status.CORRECT, |
| 864 'approach': analysis_approach_type.HEURISTIC, | 895 'approaches': [analysis_approach_type.TRY_JOB], |
| 865 'top_score': 5, | 896 'top_score': 5 |
| 866 'Confidence': 97.9 | |
| 867 } | 897 } |
| 868 } | 898 } |
| 869 suspected_cl.put() | 899 suspected_cl.put() |
| 870 | 900 |
| 871 expected_suspected_cls = [ | 901 expected_suspected_cls = [ |
| 872 { | 902 { |
| 873 'repo_name': 'chromium', | 903 'repo_name': 'chromium', |
| 874 'revision': 'rev', | 904 'revision': 'rev', |
| 875 'commit_position': 122, | 905 'commit_position': 122, |
| 876 'url': None, | 906 'url': None, |
| 877 'status': None | 907 'status': None, |
| 908 'confidence': None |
| 878 } | 909 } |
| 879 ] | 910 ] |
| 880 | 911 |
| 881 suspected_cls = build_failure._GetAllSuspectedCLsAndCheckStatus( | 912 suspected_cls = build_failure._GetAllSuspectedCLsAndCheckStatus( |
| 882 master_name, builder_name, build_number, analysis) | 913 master_name, builder_name, build_number, analysis) |
| 883 self.assertEqual( | 914 self.assertEqual( |
| 884 expected_suspected_cls, suspected_cls) | 915 expected_suspected_cls, suspected_cls) |
| 885 | 916 |
| 917 def testGetConfidenceTestHeuristic(self): |
| 918 build = { |
| 919 'failure_type': failure_type.TEST, |
| 920 'failures': None, |
| 921 'status': suspected_cl_status.CORRECT, |
| 922 'approaches': [analysis_approach_type.HEURISTIC], |
| 923 'top_score': 5 |
| 924 } |
| 925 |
| 926 self.assertEqual( |
| 927 build_failure._PercentFormat( |
| 928 self.cl_confidences.test_heuristic['5']['confidence']), |
| 929 build_failure._GetConfidence( |
| 930 self.cl_confidences, build)) |
| 931 |
| 932 def testGetConfidenceCompileHeuristic(self): |
| 933 build = { |
| 934 'failure_type': failure_type.COMPILE, |
| 935 'failures': None, |
| 936 'status': suspected_cl_status.CORRECT, |
| 937 'approaches': [analysis_approach_type.HEURISTIC], |
| 938 'top_score': 5 |
| 939 } |
| 940 |
| 941 self.assertEqual( |
| 942 build_failure._PercentFormat( |
| 943 self.cl_confidences.compile_heuristic['5']['confidence']), |
| 944 build_failure._GetConfidence( |
| 945 self.cl_confidences, build)) |
| 946 |
| 947 def testGetConfidenceTestTryJob(self): |
| 948 build = { |
| 949 'failure_type': failure_type.TEST, |
| 950 'failures': None, |
| 951 'status': suspected_cl_status.CORRECT, |
| 952 'approaches': [analysis_approach_type.TRY_JOB], |
| 953 'top_score': 5 |
| 954 } |
| 955 |
| 956 self.assertEqual( |
| 957 build_failure._PercentFormat( |
| 958 self.cl_confidences.test_try_job['confidence']), |
| 959 build_failure._GetConfidence( |
| 960 self.cl_confidences, build)) |
| 961 |
| 962 def testGetConfidenceCompileTryJob(self): |
| 963 build = { |
| 964 'failure_type': failure_type.COMPILE, |
| 965 'failures': None, |
| 966 'status': suspected_cl_status.CORRECT, |
| 967 'approaches': [analysis_approach_type.TRY_JOB], |
| 968 'top_score': 5 |
| 969 } |
| 970 |
| 971 self.assertEqual( |
| 972 build_failure._PercentFormat( |
| 973 self.cl_confidences.test_try_job['confidence']), |
| 974 build_failure._GetConfidence( |
| 975 self.cl_confidences, build)) |
| 976 |
| 977 def testGetConfidenceTestHeuristicTryJob(self): |
| 978 build = { |
| 979 'failure_type': failure_type.TEST, |
| 980 'failures': None, |
| 981 'status': suspected_cl_status.CORRECT, |
| 982 'approaches': [analysis_approach_type.HEURISTIC, |
| 983 analysis_approach_type.TRY_JOB], |
| 984 'top_score': 5 |
| 985 } |
| 986 |
| 987 self.assertEqual( |
| 988 build_failure._PercentFormat( |
| 989 self.cl_confidences.test_heuristic_try_job['confidence']), |
| 990 build_failure._GetConfidence( |
| 991 self.cl_confidences, build)) |
| 992 |
| 993 def testGetConfidenceNone(self): |
| 994 self.assertIsNone(build_failure._GetConfidence(None, None)) |
| 995 |
| 996 def testGetConfidenceUnexpected(self): |
| 997 build = { |
| 998 'failure_type': failure_type.COMPILE, |
| 999 'failures': None, |
| 1000 'status': suspected_cl_status.CORRECT, |
| 1001 'approaches': [], |
| 1002 'top_score': 5 |
| 1003 } |
| 1004 |
| 1005 self.assertIsNone(build_failure._GetConfidence(self.cl_confidences, build)) |
| 1006 |
| 1007 def testPercentFormatNone(self): |
| 1008 self.assertIsNone(build_failure._PercentFormat(None)) |
| OLD | NEW |