def get(self, queue_name): queue_name = queue_name.lower() if not Queue.queue_with_name(queue_name): self.error(404) return timestamp = self._get_timestamp() view_range = self._get_view_range() time_unit, time_unit_name = charts.get_time_unit(view_range) all_queue_names = map(Queue.name, Queue.all()) template_values = { "all_queue_names": all_queue_names, "patch_data": self._get_patch_data(queue_name, timestamp, view_range), "queue_data": self._get_queue_data(queue_name, timestamp, view_range), "queue_name": queue_name, "seconds_ago_min": 0, "seconds_ago_max": view_range, "time_unit_name": time_unit_name, "time_unit": time_unit, "timestamp": timestamp, "view_range": view_range, "view_range_choices": charts.view_range_choices, } self.response.out.write(template.render("templates/queuecharts.html", template_values))
def _queue_from_request(self): queue_name = self.request.get("queue_name") queue = Queue.queue_with_name(queue_name) if not queue: self.response.out.write("\"%s\" is not in queues %s" % (queue_name, Queue.all())) return None return queue
def get(self, queue_name): queue_name = queue_name.lower() if not Queue.queue_with_name(queue_name): self.error(404) return timestamp = self._get_timestamp() view_range = self._get_view_range() time_unit, time_unit_name = charts.get_time_unit(view_range) all_queue_names = map(Queue.name, Queue.all()) template_values = { "all_queue_names": all_queue_names, "patch_data": self._get_patch_data(queue_name, timestamp, view_range), "queue_data": self._get_queue_data(queue_name, timestamp, view_range), "queue_name": queue_name, "seconds_ago_min": 0, "seconds_ago_max": view_range, "time_unit_name": time_unit_name, "time_unit": time_unit, "timestamp": timestamp, "view_range": view_range, "view_range_choices": charts.view_range_choices, } self.response.out.write( template.render("templates/queuecharts.html", template_values))
def _work_items_from_request(self): queue_name = self.request.get("queue_name") queue = Queue.queue_with_name(queue_name) if not queue: self.response.out.write("\"%s\" is not in queues %s" % (queue_name, Queue.all())) return None items_string = self.request.get("work_items") work_items = queue.work_items() work_items.item_ids = self._parse_work_items_string(items_string) work_items.date = datetime.now() return work_items
def post(self): queue_name = self.request.get("queue_name") # FIXME: This queue lookup should be shared between handlers. queue = Queue.queue_with_name(queue_name) if not queue: self.error(404) return attachment_id = self._int_from_request("attachment_id") attachment = Attachment(attachment_id) last_status = attachment.status_for_queue(queue) # Ideally we should use a transaction for the calls to # WorkItems and ActiveWorkItems. # Only remove it from the queue if the last message is not a retry request. # Allow removing it from the queue even if there is no last_status for easier testing. if not last_status or not last_status.is_retry_request(): queue.work_items().remove_work_item(attachment_id) RecordPatchEvent.stopped(attachment_id, queue_name) else: RecordPatchEvent.retrying(attachment_id, queue_name) # Always release the lock on the item. queue.active_work_items().expire_item(attachment_id)
def get(self, queue_name, bot_id=None): queue_name = queue_name.lower() queue = Queue.queue_with_name(queue_name) if not queue: self.error(404) return statuses = self._fetch_statuses(queue, bot_id) template_values = { "page_title": self._page_title(queue, bot_id), "work_item_rows": self._rows_for_work_items(queue), "status_groups": self._build_status_groups(statuses), "bot_id": bot_id, "last_pass": self._fetch_last_message_matching(queue, bot_id, "Pass"), "last_boot": self._fetch_last_message_matching(queue, bot_id, "Starting Queue"), "trailing_month_pass_count": self._fetch_trailing_days_pass_count_string(queue, bot_id, 30), "trailing_week_pass_count": self._fetch_trailing_days_pass_count_string(queue, bot_id, 7), } self.response.out.write( template.render("templates/queuestatus.html", template_values))
class Dashboard(webapp.RequestHandler): # We may want to sort these? _ordered_queues = Queue.all() _header_names = [queue.short_name() for queue in _ordered_queues] def _build_bubble(self, attachment, queue): queue_status = attachment.status_for_queue(queue) bubble = { "status_class": attachment.state_from_queue_status(queue_status) if queue_status else "none", "status_date": queue_status.date if queue_status else None, } return bubble def _build_row(self, attachment): row = { "bug_id": attachment.bug_id(), "attachment_id": attachment.id, "bubbles": [self._build_bubble(attachment, queue) for queue in self._ordered_queues], } return row def get(self): template_values = { "headers": self._header_names, "rows": [self._build_row(attachment) for attachment in Attachment.recent(limit=25)], } self.response.out.write(template.render("templates/dashboard.html", template_values))
def get(self, queue_name): queue_name = queue_name.lower() queue = Queue.queue_with_name(queue_name) if not queue: self.error(404) return status_groups = [] last_patch_id = None synthetic_patch_id_counter = 0 statuses = queuestatus.QueueStatus.all().filter("queue_name =", queue.name()).order("-date").fetch(15) for status in statuses: patch_id = status.active_patch_id if not patch_id or last_patch_id != patch_id: status_group = [] status_groups.append(status_group) else: status_group = status_groups[-1] status_group.append(status) last_patch_id = patch_id template_values = { "display_queue_name": queue.display_name(), "work_item_rows": self._rows_for_work_items(queue), "status_groups": status_groups, } self.response.out.write(template.render("templates/queuestatus.html", template_values))
class StatusBubble(webapp.RequestHandler): _queues_to_display = [queue for queue in Queue.all() if queue.is_ews()] def _build_bubble(self, queue, attachment): queue_status = attachment.status_for_queue(queue) bubble = { "name": queue.short_name().lower(), "attachment_id": attachment.id, "queue_position": attachment.position_in_queue(queue), "state": attachment.state_from_queue_status(queue_status) if queue_status else "none", "status": queue_status, } return bubble def get(self, attachment_id): attachment = Attachment(int(attachment_id)) bubbles = [ self._build_bubble(queue, attachment) for queue in self._queues_to_display ] template_values = { "bubbles": bubbles, } self.response.out.write( template.render("templates/statusbubble.html", template_values))
def test_queue_property(self): test_object = ObjectWithQueueName() mac_ews = Queue("mac-ews") test_object.queue = mac_ews self.assertEquals(test_object.queue.name(), "mac-ews") self.assertEquals(test_object.queue_name, "mac-ews") test_object.queue = None self.assertEquals(test_object.queue_name, None)
def test_build_bubble(self): bubble = StatusBubble() queue = Queue("mac-ews") attachment = MockAttachment() bubble_dict = bubble._build_bubble(queue, attachment) # FIXME: assertDictEqual (in Python 2.7) would be better to use here. self.assertEqual(bubble_dict["name"], "mac") self.assertEqual(bubble_dict["attachment_id"], 1) self.assertEqual(bubble_dict["queue_position"], 1) self.assertEqual(bubble_dict["state"], "none") self.assertEqual(bubble_dict["status"], None)
def get(self, queue_name): queue = Queue.queue_with_name(queue_name) if not queue: self.error(404) return # FIXME: Patch assignment should probably move into Queue. patch_id = db.run_in_transaction(self._assign_patch, queue.active_work_items().key(), queue.work_items().item_ids) if not patch_id: self.error(404) return self.response.out.write(patch_id)
def _build_bubbles_for_attachment(self, attachment): show_submit_to_ews = True bubbles = [] for queue in Queue.all(): if not self._have_status_for(attachment, queue): continue bubbles.append(self._build_bubble(queue, attachment)) # If even one ews has status, we don't show the submit-to-ews button. if queue.is_ews(): show_submit_to_ews = False return (bubbles, show_submit_to_ews)
def get(self, queue_name): queue = Queue.queue_with_name(queue_name) if not queue: self.error(404) return # FIXME: Patch assignment should probably move into Queue. patch_id = db.run_in_transaction(self._assign_patch, queue.active_work_items().key(), queue.work_items().item_ids) if not patch_id: self.error(404) return RecordPatchEvent.started(patch_id, queue_name) self.response.out.write(patch_id)
def get(self, queue_name): self.response.headers["Access-Control-Allow-Origin"] = "*" queue_name = queue_name.lower() queue = Queue.queue_with_name(queue_name) if not queue: self.error(404) return self.response.headers['Content-Type'] = 'application/json' status = {"queue_length": len(queue.work_items().item_ids)} self.response.out.write(json.dumps(status))
def get(self, queue_name): queue_name = queue_name.lower() queue = Queue.queue_with_name(queue_name) if not queue: self.error(404) return statuses = queuestatus.QueueStatus.all().filter("queue_name =", queue.name()).order("-date").fetch(15) template_values = { "display_queue_name": queue.display_name(), "work_item_rows": self._rows_for_work_items(queue), "status_groups": self._build_status_groups(statuses), } self.response.out.write(template.render("templates/queuestatus.html", template_values))
def get(self, queue_name): self.response.headers["Access-Control-Allow-Origin"] = "*" queue_name = queue_name.lower() queue = Queue.queue_with_name(queue_name) if not queue: self.error(404) return self.response.headers['Content-Type'] = 'application/json' status = { "queue_length": len(queue.work_items().item_ids) } self.response.out.write(json.dumps(status))
def get(self, queue_name, bot_id=None): queue_name = queue_name.lower() queue = Queue.queue_with_name(queue_name) if not queue: self.error(404) return statuses = self._fetch_statuses(queue, bot_id) template_values = { "page_title": self._page_title(queue, bot_id), "work_item_rows": self._rows_for_work_items(queue), "status_groups": self._build_status_groups(statuses), "bot_id": bot_id, } self.response.out.write(template.render("templates/queuestatus.html", template_values))
def post(self): queue_name = self.request.get("queue_name") # FIXME: This queue lookup should be shared between handlers. queue = Queue.queue_with_name(queue_name) if not queue: self.error(404) return attachment_id = self._int_from_request("attachment_id") queue.active_work_items().expire_item(attachment_id) # ReleaseLock is used when a queue neither succeeded nor failed, so it silently releases the patch. # Let's try other patches before retrying this one, in the interest of fairness, and also because # another patch could be posted to address queue problems. queue.work_items().move_to_end(attachment_id)
def _build_bubbles_for_attachment(self, attachment): show_submit_to_ews = True bubbles = [] for queue in Queue.all(): if not self._should_show_bubble_for(attachment, queue): continue queue_position = attachment.position_in_queue(queue) bubble = self._build_bubble(queue, attachment, queue_position) if bubble: bubbles.append(bubble) # If at least one EWS queue has status, we don't show the submit-to-ews button. if queue.is_ews(): show_submit_to_ews = False return (bubbles, show_submit_to_ews)
def _build_bubbles_for_attachment(self, attachment): show_submit_to_ews = True bubbles = [] for queue in Queue.all(): if not self._have_status_for(attachment, queue): continue queue_position = attachment.position_in_queue(queue) if queue_position and queue_position >= 100: # This queue is so far behind it's not even worth showing. continue bubbles.append(self._build_bubble(queue, attachment, queue_position)) # If even one ews has status, we don't show the submit-to-ews button. if queue.is_ews(): show_submit_to_ews = False return (bubbles, show_submit_to_ews)
def get(self, queue_name): queue_name = queue_name.lower() queue = Queue.queue_with_name(queue_name) if not queue: self.error(404) return self.response.headers['Content-Type'] = 'application/json' status = { "status_page": self.request.host_url + "/queue-status/" + queue_name, "queue": self._rows_for_work_items(queue), "bots": self._bots(queue), } dthandler = lambda obj: obj.isoformat() if isinstance(obj, datetime.datetime) or isinstance(obj, datetime.date) else None self.response.out.write(json.dumps(status, default=dthandler))
def get(self, queue_name, bot_id=None): queue_name = queue_name.lower() queue = Queue.queue_with_name(queue_name) if not queue: self.error(404) return statuses = self._fetch_statuses(queue, bot_id) template_values = { "page_title": self._page_title(queue, bot_id), "work_item_rows": self._rows_for_work_items(queue), "status_groups": self._build_status_groups(statuses), "bot_id": bot_id, } self.response.out.write( template.render("templates/queuestatus.html", template_values))
def _build_bubbles_for_attachment(self, attachment): show_submit_to_ews = True bubbles = [] for queue in Queue.all(): if not self._have_status_for(attachment, queue): continue queue_position = attachment.position_in_queue(queue) if queue_position and queue_position >= 100: # This queue is so far behind it's not even worth showing. continue bubbles.append( self._build_bubble(queue, attachment, queue_position)) # If even one ews has status, we don't show the submit-to-ews button. if queue.is_ews(): show_submit_to_ews = False return (bubbles, show_submit_to_ews)
def _fetch_summary(self): summary = { "attachment_id" : self.id } first_status = QueueStatus.all().filter('active_patch_id =', self.id).get() if not first_status: # We don't have any record of this attachment. return summary summary["bug_id"] = first_status.active_bug_id for queue in Queue.all(): summary[queue.name_with_underscores()] = None status = QueueStatus.all().filter('queue_name =', queue.name()).filter('active_patch_id =', self.id).order('-date').get() if status: # summary() is a horrible API and should be killed. summary[queue.name_with_underscores()] = { "status": status, } return summary
def _build_bubbles_for_attachment(self, attachment): show_submit_to_ews = True bubbles = [] for queue in Queue.all(): if not self._should_show_bubble_for(attachment, queue): continue queue_position = attachment.position_in_queue(queue) bubble = self._build_bubble(queue, attachment, queue_position) if bubble: bubbles.append(bubble) # If at least one EWS queue has status, we don't show the submit-to-ews button. if queue.is_ews(): show_submit_to_ews = False failed_to_apply = any(map(lambda bubble: "failed_to_apply" in bubble, bubbles)) had_resultative_status_other_than_failure_to_apply = any(map(lambda bubble: bubble["had_resultative_status_other_than_failure_to_apply"], bubbles)) return (bubbles, show_submit_to_ews, failed_to_apply and not had_resultative_status_other_than_failure_to_apply)
def get(self, queue_name, bot_id=None): queue_name = queue_name.lower() queue = Queue.queue_with_name(queue_name) if not queue: self.error(404) return statuses = self._fetch_statuses(queue, bot_id) template_values = { "page_title": self._page_title(queue, bot_id), "work_item_rows": self._rows_for_work_items(queue), "status_groups": self._build_status_groups(statuses), "bot_id": bot_id, "last_pass": self._fetch_last_message_matching(queue, bot_id, "Pass"), "last_boot": self._fetch_last_message_matching(queue, bot_id, "Starting Queue"), "trailing_month_pass_count": self._fetch_trailing_days_pass_count_string(queue, bot_id, 30), "trailing_week_pass_count": self._fetch_trailing_days_pass_count_string(queue, bot_id, 7), } self.response.out.write(template.render("templates/queuestatus.html", template_values))
def _fetch_summary(self): summary = { "attachment_id" : self.id } first_status = QueueStatus.all().filter('active_patch_id =', self.id).get() if not first_status: # We don't have any record of this attachment. return summary summary["bug_id"] = first_status.active_bug_id for queue in Queue.all(): summary[queue.name_with_underscores()] = None status = QueueStatus.all().filter('queue_name =', queue.name()).filter('active_patch_id =', self.id).order('-date').get() if status: # summary() is a horrible API and should be killed. summary[queue.name_with_underscores()] = { "state": self.state_from_queue_status(status), "status": status, } return summary
def post(self): queue_name = self.request.get("queue_name") # FIXME: This queue lookup should be shared between handlers. queue = Queue.queue_with_name(queue_name) if not queue: self.error(404) return attachment_id = self._int_from_request("attachment_id") attachment = Attachment(attachment_id) last_status = attachment.status_for_queue(queue) # Ideally we should use a transaction for the calls to # WorkItems and ActiveWorkItems. queue.work_items().remove_work_item(attachment_id) RecordPatchEvent.stopped(attachment_id, queue_name) queue.active_work_items().expire_item(attachment_id)
def post(self): queue_name = self.request.get("queue_name") # FIXME: This queue lookup should be shared between handlers. queue = Queue.queue_with_name(queue_name) if not queue: self.error(404) return attachment_id = self._int_from_request("attachment_id") attachment = Attachment(attachment_id) last_status = attachment.status_for_queue(queue) # Ideally we should use a transaction for the calls to # WorkItems and ActiveWorkItems. queue.work_items().remove_work_item(attachment_id) RecordPatchEvent.stopped(attachment_id, queue_name, last_status.message) queue.active_work_items().expire_item(attachment_id)
def get(self, queue_name): self.response.headers["Access-Control-Allow-Origin"] = "*" queue_name = queue_name.lower() queue = Queue.queue_with_name(queue_name) if not queue: self.error(404) return self.response.headers['Content-Type'] = 'application/json' status = { "status_page": self.request.host_url + "/queue-status/" + queue_name, "queue": self._rows_for_work_items(queue), "bots": self._bots(queue), } dthandler = lambda obj: obj.isoformat() if isinstance( obj, datetime.datetime) or isinstance(obj, datetime.date) else None self.response.out.write(json.dumps(status, default=dthandler))
def test_queue_with_name(self): self.assertEqual(Queue.queue_with_name("bogus"), None) self.assertEqual(Queue.queue_with_name("mac-ews").name(), "mac-ews") self.assertRaises(AssertionError, Queue, ("bogus"))
def test_style_queue_is_ews(self): # For now we treat the style-queue as an EWS since most users would # describe it as such. If is_ews() ever needs to mean "builds the patch" # or similar, then we will need to adjust all callers. self.assertTrue(Queue("style-queue").is_ews()) self.assertTrue("style-queue" in map(Queue.name, Queue.all_ews()))
def _assert_short_name(self, queue_name, short_name): self.assertEqual(Queue(queue_name).short_name(), short_name)
def test_is_ews(self): mac_ews = Queue("mac-ews") self.assertTrue(mac_ews.is_ews())
def _calculate_queue_positions(self): all_work_items = WorkItems.all().fetch(limit=len(Queue.all())) return dict([(items.queue.name(), items.display_position_for_attachment(self.id)) for items in all_work_items if items.queue])
def _assert_name_with_underscores(self, queue_name, short_name): self.assertEqual(Queue(queue_name).name_with_underscores(), short_name)
def _assert_display_name(self, queue_name, short_name): self.assertEqual(Queue(queue_name).display_name(), short_name)
def _queue_getter(self): # Import at runtime to avoid circular imports from model.queues import Queue return Queue.queue_with_name(self.queue_name)
def _add_attachment_to_ews_queues(self, attachment): for queue in Queue.all_ews(): if self._should_add_to_ews_queue(queue, attachment): queue.work_items().add_work_item(attachment.id)
def _add_attachment_to_ews_queues(self, attachment): for queue in Queue.all_ews(): # all_ews() currently includes the style-queue if self._should_add_to_ews_queue(queue, attachment): queue.work_items().add_work_item(attachment.id) RecordPatchEvent.added(attachment.id, queue.name())
def get(self): template_values = {"queues": [QueueBubble(queue) for queue in Queue.all()]} self.response.out.write(template.render("templates/recentstatus.html", template_values))
def get(self): template_values = { "queues": [QueueBubble(queue) for queue in Queue.all()], } self.response.out.write(template.render("templates/recentstatus.html", template_values))