OLD | NEW |
---|---|
1 # Copyright 2016 The Chromium Authors. All rights reserved. | 1 # Copyright 2016 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 collections | 5 import collections |
6 import logging | 6 import logging |
7 import numbers | 7 import numbers |
8 import os | |
8 | 9 |
9 from google.appengine.api import taskqueue | 10 from google.appengine.api import taskqueue |
10 from google.appengine.ext import ndb | 11 from google.appengine.ext import ndb |
11 | 12 |
13 from dashboard.common import utils | |
12 from dashboard.pinpoint import mann_whitney_u | 14 from dashboard.pinpoint import mann_whitney_u |
13 from dashboard.pinpoint.models import attempt as attempt_module | 15 from dashboard.pinpoint.models import attempt as attempt_module |
14 from dashboard.pinpoint.models import change as change_module | 16 from dashboard.pinpoint.models import change as change_module |
15 from dashboard.pinpoint.models import quest as quest_module | 17 from dashboard.pinpoint.models import quest as quest_module |
18 from dashboard.services import issue_tracker_service | |
16 | 19 |
17 | 20 |
18 # We want this to be fast to minimize overhead while waiting for tasks to | 21 # We want this to be fast to minimize overhead while waiting for tasks to |
19 # finish, but don't want to consume too many resources. | 22 # finish, but don't want to consume too many resources. |
20 _TASK_INTERVAL = 10 | 23 _TASK_INTERVAL = 10 |
21 | 24 |
22 | 25 |
23 _DEFAULT_MAX_ATTEMPTS = 2 | 26 _DEFAULT_MAX_ATTEMPTS = 2 |
24 _SIGNIFICANCE_LEVEL = 0.5 | 27 _SIGNIFICANCE_LEVEL = 0.5 |
25 | 28 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
57 # Request parameters. | 60 # Request parameters. |
58 configuration = ndb.StringProperty(required=True) | 61 configuration = ndb.StringProperty(required=True) |
59 test_suite = ndb.StringProperty() | 62 test_suite = ndb.StringProperty() |
60 test = ndb.StringProperty() | 63 test = ndb.StringProperty() |
61 metric = ndb.StringProperty() | 64 metric = ndb.StringProperty() |
62 | 65 |
63 # If True, the service should pick additional Changes to run (bisect). | 66 # If True, the service should pick additional Changes to run (bisect). |
64 # If False, only run the Changes explicitly added by the user. | 67 # If False, only run the Changes explicitly added by the user. |
65 auto_explore = ndb.BooleanProperty(required=True) | 68 auto_explore = ndb.BooleanProperty(required=True) |
66 | 69 |
70 # TODO: The bug id is only used for posting bug comments when a job starts and | |
71 # completes. This probably should not be the responsibility of Pinpoint. | |
72 bug_id = ndb.IntegerProperty() | |
perezju
2017/06/29 09:03:30
Note that, probably, we would still want to mainta
| |
73 | |
67 state = ndb.PickleProperty(required=True) | 74 state = ndb.PickleProperty(required=True) |
68 | 75 |
69 @classmethod | 76 @classmethod |
70 def New(cls, configuration, test_suite, test, metric, auto_explore): | 77 def New(cls, configuration, test_suite, test, metric, auto_explore, bug_id): |
71 # Get list of quests. | 78 # Get list of quests. |
72 quests = [quest_module.FindIsolate(configuration)] | 79 quests = [quest_module.FindIsolate(configuration)] |
73 if test_suite: | 80 if test_suite: |
74 quests.append(quest_module.RunTest(configuration, test_suite, test)) | 81 quests.append(quest_module.RunTest(configuration, test_suite, test)) |
75 if metric: | 82 if metric: |
76 quests.append(quest_module.ReadValue(metric, test)) | 83 quests.append(quest_module.ReadValue(metric, test)) |
77 | 84 |
78 # Create job. | 85 # Create job. |
79 return cls( | 86 return cls( |
80 configuration=configuration, | 87 configuration=configuration, |
81 test_suite=test_suite, | 88 test_suite=test_suite, |
82 test=test, | 89 test=test, |
83 metric=metric, | 90 metric=metric, |
84 auto_explore=auto_explore, | 91 auto_explore=auto_explore, |
92 bug_id=bug_id, | |
85 state=_JobState(quests, _DEFAULT_MAX_ATTEMPTS)) | 93 state=_JobState(quests, _DEFAULT_MAX_ATTEMPTS)) |
86 | 94 |
87 @property | 95 @property |
88 def job_id(self): | 96 def job_id(self): |
89 return self.key.urlsafe() | 97 return self.key.urlsafe() |
90 | 98 |
91 @property | 99 @property |
92 def status(self): | 100 def status(self): |
93 if self.task: | 101 if self.task: |
94 return 'Running' | 102 return 'Running' |
95 | 103 |
96 if self.exception: | 104 if self.exception: |
97 return 'Failed' | 105 return 'Failed' |
98 | 106 |
99 return 'Completed' | 107 return 'Completed' |
100 | 108 |
109 @property | |
110 def url(self): | |
111 return 'https://%s/job/%s' % (os.environ['HTTP_HOST'], self.job_id) | |
112 | |
101 def AddChange(self, change): | 113 def AddChange(self, change): |
102 self.state.AddChange(change) | 114 self.state.AddChange(change) |
103 | 115 |
104 def Start(self): | 116 def Start(self): |
117 self.Schedule() | |
118 | |
119 comment = 'Pinpoint job started.\n' + self.url | |
120 issue_tracker = issue_tracker_service.IssueTrackerService( | |
121 utils.ServiceAccountHttp()) | |
122 issue_tracker.AddBugComment(self.bug_id, comment, send_email=False) | |
123 | |
124 def Complete(self): | |
125 comment = 'Pinpoint job complete!\n' + self.url | |
126 issue_tracker = issue_tracker_service.IssueTrackerService( | |
127 utils.ServiceAccountHttp()) | |
128 issue_tracker.AddBugComment(self.bug_id, comment, send_email=False) | |
129 | |
130 def Schedule(self): | |
105 task = taskqueue.add(queue_name='job-queue', url='/api/run/' + self.job_id, | 131 task = taskqueue.add(queue_name='job-queue', url='/api/run/' + self.job_id, |
106 countdown=_TASK_INTERVAL) | 132 countdown=_TASK_INTERVAL) |
107 self.task = task.name | 133 self.task = task.name |
108 | 134 |
109 def Run(self): | 135 def Run(self): |
110 self.exception = None # In case the Job succeeds on retry. | 136 self.exception = None # In case the Job succeeds on retry. |
111 self.task = None # In case an exception is thrown. | 137 self.task = None # In case an exception is thrown. |
112 | 138 |
113 try: | 139 try: |
114 if self.auto_explore: | 140 if self.auto_explore: |
115 self.state.Explore() | 141 self.state.Explore() |
116 work_left = self.state.ScheduleWork() | 142 work_left = self.state.ScheduleWork() |
117 | 143 |
118 # Schedule moar task. | 144 # Schedule moar task. |
119 if work_left: | 145 if work_left: |
120 self.Start() | 146 self.Schedule() |
147 else: | |
148 self.Complete() | |
121 except BaseException as e: | 149 except BaseException as e: |
122 self.exception = str(e) | 150 self.exception = str(e) |
123 raise | 151 raise |
124 | 152 |
125 def AsDict(self): | 153 def AsDict(self): |
126 return { | 154 return { |
127 'job_id': self.job_id, | 155 'job_id': self.job_id, |
128 | 156 |
129 'configuration': self.configuration, | 157 'configuration': self.configuration, |
130 'test_suite': self.test_suite, | 158 'test_suite': self.test_suite, |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
316 # We want the results_values to provide both a message that can be shown to | 344 # We want the results_values to provide both a message that can be shown to |
317 # the user for why something failed, and also something comparable that can | 345 # the user for why something failed, and also something comparable that can |
318 # be used for bisect. Therefore, they contain the thrown Exceptions. This | 346 # be used for bisect. Therefore, they contain the thrown Exceptions. This |
319 # function then converts them into comparable numbers for bisect. | 347 # function then converts them into comparable numbers for bisect. |
320 if isinstance(obj, numbers.Number): | 348 if isinstance(obj, numbers.Number): |
321 return obj | 349 return obj |
322 elif isinstance(obj, Exception): | 350 elif isinstance(obj, Exception): |
323 return hash(obj.__class__) | 351 return hash(obj.__class__) |
324 else: | 352 else: |
325 return hash(obj) | 353 return hash(obj) |
OLD | NEW |