Exemple #1
0
    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, '')
Exemple #2
0
 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
Exemple #4
0
 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)
Exemple #5
0
 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
Exemple #6
0
 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)
Exemple #7
0
 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)
Exemple #8
0
    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
Exemple #9
0
 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_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])
Exemple #11
0
 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])
Exemple #12
0
    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])
Exemple #13
0
    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)
Exemple #15
0
 def _assert_ticket_has_sprint(self, ticket_id, sprint_name):
     ticket = AgiloTicket(self.env, ticket_id)
     self.assert_equals(sprint_name, ticket[Key.SPRINT])
Exemple #16
0
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, '')
Exemple #17
0
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, '')
Exemple #18
0
 def _ticket_without_cache(self, ticket_id):
     ticket = AgiloTicket(self.env, ticket_id)
     return ticket
Exemple #19
0
 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)