def test_does_not_explode_if_child_has_no_sprint_field(self): self.teh.allow_link_from_to(Type.USER_STORY, Type.REQUIREMENT) # recreate object because the allowed links are cached inside self.story = AgiloTicket(self.env, self.story.id) requirement = self.teh.create_ticket(t_type=Type.REQUIREMENT) self.assert_true(self.story.link_to(requirement)) mover = TicketHierarchyMover(self.env, self.story, self.old_sprint, self.new_sprint) mover.execute() self._assert_ticket_has_sprint(requirement.id, '')
def add_field_for_type(self, field_name, ticket_type): assert not AgiloTicket( self.env, t_type=ticket_type).is_writeable_field(field_name) config = AgiloConfig(self.env) current_fields = config.get_list(ticket_type, section=AgiloConfig.AGILO_TYPES) config.change_option(ticket_type, ', '.join(current_fields + [field_name]), section=AgiloConfig.AGILO_TYPES) config.save() assert AgiloTicket(self.env, t_type=ticket_type).is_writeable_field(field_name)
def _create_ticket(self, sprint=None, remaining_time=None, ticket_type=Type.TASK, component=None): ticket = AgiloTicket(self.env, t_type=ticket_type) if sprint is None: sprint = self.sprint if sprint != '': # REFACT: create a new method to remove None vs. '' semantics ticket[Key.SPRINT] = self._sprint_name(sprint) if remaining_time is not None: ticket[Key.REMAINING_TIME] = remaining_time if component is not None: ticket[Key.COMPONENT] = component ticket.insert() return ticket
def edit_ticket(self, ticket_id, **kwargs): if 'time_of_last_change' not in kwargs: ticket = AgiloTicket(self.env, ticket_id) kwargs['time_of_last_change'] = to_timestamp(ticket.time_changed) if 'ts' not in kwargs: ticket = AgiloTicket(self.env, ticket_id) kwargs['ts'] = str(ticket.time_changed) from agilo.ticket import AgiloTicketSystem if AgiloTicketSystem.is_trac_1_0(): from trac.util.datefmt import to_utimestamp if 'view_time' not in kwargs: ticket = AgiloTicket(self.env, ticket_id) kwargs['view_time'] = str(to_utimestamp(ticket.time_changed)) if 'submit' not in kwargs: kwargs['submit'] = True return self.server.json.tickets[ticket_id].post(**kwargs)
def _remove_invalid_attributes_for_tasks(self, attributes): # For the filtered burndown we need the component attribute which is not # enabled for the usual case - therefore we'll just ignore that one. for field_name in attributes.keys(): if not AgiloTicket( self.env, t_type=Type.TASK).is_writeable_field(field_name): attributes.pop(field_name) return attributes
def setUp(self): self.super() self.task = AgiloTicket(self.env, t_type=Type.TASK) # this task is not stored in the db on purpose - so I can check # that no workflow does any permanent damage! del self.task._old[Key.TYPE] req = self.teh.mock_request('foo') self.manipulator = TicketStatusManipulator(self.env, req, self.task) self.assert_equals({}, self.task._old)
def setUp(self): self.super() self.task = AgiloTicket(self.env, t_type=Type.TASK) # this task is not stored in the db on purpose - so I can check # that no workflow does any permanent damage! del self.task._old[Key.TYPE] self._set_status_to(Status.NEW) req = self.teh.mock_request('foo') self.finder = TransitionFinder(self.env, req, self.task) self.assert_equals({}, self.task._old)
def ticket_changed(self, ticket, comment, author, old_values): ticket = AgiloTicket.as_agilo_ticket(ticket) generator = ChartGenerator(self.env) # AT: this will only work if the task has been explicitly planned for # the sprint, otherwise it won't update. The sprint change is good for # task containers. # if ticket[Key.SPRINT]: if ticket[Key.SPRINT] or ticket.is_writeable_field(Key.REMAINING_TIME): sprint = self._get_sprint_name(ticket) generator.invalidate_cache(sprint_name=sprint) if old_values.get(Key.SPRINT) and old_values[Key.SPRINT] != ticket[Key.SPRINT]: generator.invalidate_cache(sprint_name=old_values[Key.SPRINT])
def ticket_changed(self, ticket, comment, author, old_values): ticket = AgiloTicket.as_agilo_ticket(ticket) generator = ChartGenerator(self.env) # AT: this will only work if the task has been explicitly planned for # the sprint, otherwise it won't update. The sprint change is good for # task containers. #if ticket[Key.SPRINT]: if ticket[Key.SPRINT] or ticket.is_writeable_field(Key.REMAINING_TIME): sprint = self._get_sprint_name(ticket) generator.invalidate_cache(sprint_name=sprint) if old_values.get( Key.SPRINT) and old_values[Key.SPRINT] != ticket[Key.SPRINT]: generator.invalidate_cache(sprint_name=old_values[Key.SPRINT])
def test_creates_skip_aggregation_markers_when_adding_story_to_sprint( self): story = self._create_ticket_without_history( sprint='', ticket_type=Type.USER_STORY) task = self._create_ticket_without_history(sprint='', ticket_type=Type.TASK) self.assert_true(story.link_to(task)) self._change_ticket_and_save(story, Key.SPRINT, self.sprint.name) changes = self._changes_for_sprint(self.sprint) self.assert_minimum_length(2, changes) self.assert_true(changes[0].has_marker( BurndownDataConstants.SKIP_AGGREGATION)) self.assert_true(changes[1].has_marker( BurndownDataConstants.SKIP_AGGREGATION)) task = AgiloTicket(self.env, task.id) self.assert_equals(self.sprint.name, task[Key.SPRINT])
def runTest(self): self.super() self.windmill.click(name=u'update') self.windmill.waits.forPageLoad(timeout=u'20000') self.windmill.check(name=u'selected_ticket') self.windmill.check( xpath=u"//thead//input[contains(@type,'checkbox')]") self.windmill.click(link=u'Batch Modify') comment = "comment everything" self.windmill.type(id=u'batchmod_value_comment', text=comment) self.windmill.click(id=u'batchmod_submit') self.windmill.waits.forPageLoad(timeout=u'20000') js = "$('table.listing.tickets .id:contains(\"#\")').text()" tickets_ids = self.windmill_tester.output_for_js(js).split('#')[1:] for ticket_id in tickets_ids: comment_tuple = AgiloTicket(self.env, ticket_id).get_comment_history(1)[0] self.assert_equals(comment_tuple[len(comment_tuple) - 1], comment)
def ticket_deleted(self, ticket): ticket = AgiloTicket.as_agilo_ticket(ticket) if ticket[Key.SPRINT] or ticket.is_writeable_field(Key.REMAINING_TIME): sprint = self._get_sprint_name(ticket) generator = ChartGenerator(self.env) generator.invalidate_cache(sprint_name=sprint)
def _assert_ticket_has_sprint(self, ticket_id, sprint_name): ticket = AgiloTicket(self.env, ticket_id) self.assert_equals(sprint_name, ticket[Key.SPRINT])
class TestMoveTicketHierarchyOnSprintChange(AgiloTestCase): def setUp(self): self.super() self.old_sprint = 'Old Sprint' self.new_sprint = 'New Sprint' self.teh.create_sprint(self.old_sprint) self.teh.create_sprint(self.new_sprint) self._create_story_and_task() def _create_story_and_task(self): self.story = self.teh.create_story(sprint=self.old_sprint) self.task = self.teh.create_task(sprint=self.old_sprint) self.assert_true(self.story.link_to(self.task)) def _assert_ticket_has_sprint(self, ticket_id, sprint_name): ticket = AgiloTicket(self.env, ticket_id) self.assert_equals(sprint_name, ticket[Key.SPRINT]) def _assert_ticket_has_new_sprint(self, ticket_id): self._assert_ticket_has_sprint(ticket_id, self.new_sprint) def _assert_ticket_has_old_sprint(self, ticket_id): self._assert_ticket_has_sprint(ticket_id, self.old_sprint) def _assert_move_task_of_story(self): mover = TicketHierarchyMover(self.env, self.story, self.old_sprint, self.new_sprint) self._assert_ticket_has_old_sprint(self.task.id) mover.execute() self._assert_ticket_has_new_sprint(self.task.id) def test_can_move_task_of_a_story(self): self._assert_move_task_of_story() def test_can_pull_in_task_of_a_story(self): self.old_sprint = '' self._create_story_and_task() self._assert_move_task_of_story() def test_can_pull_out_task_of_a_story(self): self.new_sprint = '' self._assert_move_task_of_story() def test_can_have_identical_source_and_destination(self): self.new_sprint = self.old_sprint self._assert_move_task_of_story() def test_does_not_move_closed_task(self): self.task[Key.STATUS] = Status.CLOSED self.task.save_changes(None, None) mover = TicketHierarchyMover(self.env, self.story, self.old_sprint, self.new_sprint) mover.execute() self._assert_ticket_has_old_sprint(self.task.id) def test_does_not_move_task_with_different_sprint(self): self.teh.create_sprint('Third Sprint') self.task[Key.SPRINT] = 'Third Sprint' self.task.save_changes(None, None) mover = TicketHierarchyMover(self.env, self.story, self.old_sprint, self.new_sprint) mover.execute() self._assert_ticket_has_sprint(self.task.id, 'Third Sprint') def test_can_move_indirect_task(self): bug = self.teh.create_ticket(t_type=Type.BUG, props=dict(sprint=self.old_sprint)) self.assert_true(bug.link_to(self.story)) mover = TicketHierarchyMover(self.env, bug, self.old_sprint, self.new_sprint) mover.execute() self._assert_ticket_has_new_sprint(self.task.id) def test_will_store_default_author_on_changelog(self): self._assert_move_task_of_story() self.assert_equals("agilo", self.teh.last_changelog_author(self.task)) def test_will_store_custom_author_on_changelog(self): mover = TicketHierarchyMover(self.env, self.story, self.old_sprint, self.new_sprint, changelog_author="fnord") mover.execute() self.assert_equals("fnord", self.teh.last_changelog_author(self.task)) def test_does_not_explode_if_child_has_no_sprint_field(self): self.teh.allow_link_from_to(Type.USER_STORY, Type.REQUIREMENT) # recreate object because the allowed links are cached inside self.story = AgiloTicket(self.env, self.story.id) requirement = self.teh.create_ticket(t_type=Type.REQUIREMENT) self.assert_true(self.story.link_to(requirement)) mover = TicketHierarchyMover(self.env, self.story, self.old_sprint, self.new_sprint) mover.execute() self._assert_ticket_has_sprint(requirement.id, '')
def _ticket_without_cache(self, ticket_id): ticket = AgiloTicket(self.env, ticket_id) return ticket