def testDeleteBacklogFromManager(self): """Test the deletion of a Backlog using the model manager""" model_manager = BacklogModelManager(self.env) backlog = model_manager.create(name='TestDeleteBacklog') self.assert_not_none(backlog) self.assert_true(backlog.exists) self.assert_equals('global', backlog.scope) # now delete it model_manager.delete(backlog) self.assert_raises(BacklogTypeError, model_manager.get, name='TestDeleteBacklog')
def testGetModelFromManager(self): """Tests the get model from the manager""" backlog = self.teh.create_backlog('TestModelBacklog') self.assert_true(backlog.exists) # Now try to get it with the Model Manager model_manager = BacklogModelManager(self.env) same_backlog = model_manager.get(name='TestModelBacklog') self.assert_equals(backlog.name, same_backlog.name) self.assert_equals(len(backlog), len(same_backlog)) # Now check the object identity self.assert_equals(id(backlog), id(same_backlog))
def setUp(self): self.super() self.r1 = self.teh.create_ticket(Type.REQUIREMENT) self.r2 = self.teh.create_ticket(Type.REQUIREMENT) self.us1 = self.teh.create_ticket(Type.USER_STORY) self.us2 = self.teh.create_ticket(Type.USER_STORY) self.us3 = self.teh.create_ticket(Type.USER_STORY) self.t1 = self.teh.create_ticket(Type.TASK) self.t2 = self.teh.create_ticket(Type.TASK) self.r1.link_to(self.us1) self.r2.link_to(self.us2) self.r2.link_to(self.us3) self.tickets = [ self.r1, self.r2, self.us1, self.us2, self.us3, self.t1, self.t2 ] # The tickets should have no milestone nor story set :-) for t in self.tickets: self.assert_equals('', t[Key.MILESTONE]) # Now create a Backlog item for each and reload it, we need a backlog self.pb = Backlog(self.env, Key.PRODUCT_BACKLOG) self.assert_not_none(self.pb, "Product Backlog not loaded...") self.assert_not_equals(0, len(self.pb.config.ticket_types)) self.assert_equals(Key.PRODUCT_BACKLOG, self.pb.name, "Backlog name not matching... %s" % self.pb.name) self.assert_equals(5, len(self.pb)) self.milestone = self.teh.create_milestone("BacklogMilestone") self.sprint = self.teh.create_sprint("BacklogTestSprint", milestone="BacklogMilestone") self.sb = Backlog(self.env, Key.SPRINT_BACKLOG, scope=self.sprint.name) self.assert_equals(0, len(self.sb)) self.assert_not_none(self.sb, "Sprint Backlog not loaded...") self.assert_not_equals(0, len(self.sb.config.ticket_types)) # a BacklogItemModelManager self.bimm = BacklogModelManager.BacklogItemModelManager(self.env)
class TestReleaseBacklog(AgiloTestCase): """Tests the Release Backlog""" def setUp(self): self.super() self.bmm = BacklogModelManager(self.env) def test_backlog_shows_right_tickets(self): """Tests the Release Backlog shows the Requirements belonging to a specific Milestone""" sprint = self.teh.create_sprint("Release Sprint") release_backlog = BacklogConfiguration(self.env, name="Release Backlog", type=BacklogType.MILESTONE) release_backlog.ticket_types = [Type.REQUIREMENT, Type.USER_STORY] release_backlog.save() req = self.teh.create_ticket(Type.REQUIREMENT, props={Key.MILESTONE: sprint.milestone}) # load the real backlog release_backlog = self.bmm.get(name="Release Backlog", scope=sprint.milestone) self.assert_contains(req, release_backlog) self.assert_length(1, release_backlog) # Now add 2 stories to the requirement, one planned for the sprint one # not, only the one assigned to the sprint should appear in the backlog us1 = self.teh.create_ticket(Type.USER_STORY, props={Key.SPRINT: sprint.name}) us2 = self.teh.create_ticket(Type.USER_STORY) self.assert_true(us1 in release_backlog) self.assert_not_contains(us2, release_backlog) self.assert_length(1 + 1, release_backlog)
def testCreateModelFromManager(self): """Tests the creation of a new model using the Manager""" params = {'name': 'TestCreateBacklog'} model_manager = BacklogModelManager(self.env) backlog = model_manager.create(**params) self.assert_not_none(backlog) self.assert_true(backlog.exists) self.assert_equals('global', backlog.scope) # Now let's add a scope sprint = self.teh.create_sprint('ScopeSprint') params['name'] = 'AnotherBacklog' params['type'] = BacklogType.SPRINT params['scope'] = sprint.name sprint_backlog = model_manager.create(**params) self.assert_not_none(sprint_backlog) self.assert_true(sprint_backlog.exists) self.assert_equals(sprint.name, sprint_backlog.scope) self.assert_equals(BacklogType.SPRINT, sprint_backlog.config.type) # now trying to create a backlog twice should return None self.assert_none(model_manager.create(**params))
def testSelectBacklogFromManager(self): """Tests the select from the manager, with the order_by parameter""" model_manager = BacklogModelManager(self.env) letters = ['A', 'B', 'C'] for letter in letters: backlog = model_manager.create(name='Test%sBacklog' % letter) self.assert_not_none(backlog) self.assert_true(backlog.exists) self.assert_equals('global', backlog.scope) # now select and verify that the default order is by name backlogs = model_manager.select() r_letters = [l for l in reversed(letters)] for backlog in backlogs: if backlog.name.startswith('Test'): letter = r_letters.pop() self.assert_equals('Test%sBacklog' % letter, backlog.name) # now sort descending by name backlogs = model_manager.select(order_by=['-name']) for backlog in backlogs: if backlog.name.startswith('Test'): letter = letters.pop() self.assert_equals('Test%sBacklog' % letter, backlog.name)
def __init__(self): """Create a reference to the Model Manager""" self.manager = BacklogModelManager(self.env)
def _invalidate_backlog_cache(self): BacklogModelManager(self.env).get_cache().invalidate()
def setUp(self): self.super() self.bmm = BacklogModelManager(self.env)
class TestSprintBacklog(AgiloTestCase): """Specific tests for the Sprint Backlog""" def setUp(self): self.super() self.bmm = BacklogModelManager(self.env) def test_tickets_from_other_sprint_not_appearing(self): """ Tests that tasks created for other sprints are not appearing in the sprint backlog, see bug #345 (https://dev.agile42.com/ticket/345) """ s = self.teh.create_sprint("Test") sb = self.teh.create_backlog("Sprint Backlog", num_of_items=100, ticket_types=[Type.USER_STORY, Type.TASK], b_type=BacklogType.SPRINT, scope=s.name) self.assert_length(100, sb) # get a ticket from the backlog and check that it is planned for the sprint self.assert_equals(s.name, sb[10][Key.SPRINT]) # Now add an extra ticket task = self.teh.create_ticket(Type.TASK, props={Key.SPRINT: s.name, Key.REMAINING_TIME: '2'}) self.assert_length(101, sb) self.assert_contains(task, sb) # Now remove the ticket explicitly and check if the sprint field is set # to None self.teh.move_changetime_to_the_past([task]) sb.remove(task) self.assert_not_contains(task, sb) # reload task and backlog, the remove should have saved the task task = self.teh.load_ticket(task) self.assert_not_contains(task, sb) self.assert_equals('', task[Key.SPRINT]) # Now move the ticket to another sprint s2 = self.teh.create_sprint("Another Sprint") task[Key.SPRINT] = s2.name task.save_changes('tester', 'Moved to sprint %s' % s2.name, when=now() + timedelta(seconds=1)) self.assert_equals(s2.name, task[Key.SPRINT]) # Now should not be in the backlog anymore self.assert_not_contains(task, sb) # Now change sprint again, twice task[Key.SPRINT] = s.name task.save_changes('tester', 'Moved to sprint %s' % s.name, when=now() + timedelta(seconds=2)) self.assert_contains(task, sb) # again task[Key.SPRINT] = s2.name task.save_changes('tester', 'Moved to sprint %s' % s2.name, when=now() + timedelta(seconds=3)) self.assert_equals(s2.name, task[Key.SPRINT]) # Now should not be in the backlog anymore self.assert_not_contains(task, sb) def test_referenced_requirements_are_displayed_in_the_sprint_backlog(self): """Test that referenced requirements are shown in the sprint backlog even if they are planned for a milestone.""" milestone = self.teh.create_milestone('1.0') sprint = self.teh.create_sprint("First Sprint") backlog_name = 'My Backlog' my_backlog = BacklogConfiguration(self.env, name=backlog_name, type=BacklogType.SPRINT) my_backlog.ticket_types=[Type.USER_STORY, Type.TASK, Type.REQUIREMENT] my_backlog.save() req = self.teh.create_ticket(Type.REQUIREMENT, {Key.SUMMARY: 'Requirement', Key.MILESTONE: milestone.name}) story = self.teh.create_ticket(Type.USER_STORY, {Key.SUMMARY: 'Story', Key.SPRINT: sprint.name}) req.link_to(story) backlog = self.bmm.get(name=backlog_name, scope=sprint.name) self.assert_length(2, backlog)
def setUp(self): self.super() self.bmm = BacklogModelManager(self.env) # Creates and It's me backlog its_me = self.teh.create_sprint("It's me") self.assert_true(its_me.exists)
class TestSprintBacklog(AgiloTestCase): """Specific tests for the Sprint Backlog""" def setUp(self): self.super() self.bmm = BacklogModelManager(self.env) def test_tickets_from_other_sprint_not_appearing(self): """ Tests that tasks created for other sprints are not appearing in the sprint backlog, see bug #345 (https://dev.agile42.com/ticket/345) """ s = self.teh.create_sprint("Test") sb = self.teh.create_backlog("Sprint Backlog", num_of_items=100, ticket_types=[Type.USER_STORY, Type.TASK], b_type=BacklogType.SPRINT, scope=s.name) self.assert_length(100, sb) # get a ticket from the backlog and check that it is planned for the sprint self.assert_equals(s.name, sb[10][Key.SPRINT]) # Now add an extra ticket task = self.teh.create_ticket(Type.TASK, props={ Key.SPRINT: s.name, Key.REMAINING_TIME: '2' }) self.assert_length(101, sb) self.assert_contains(task, sb) # Now remove the ticket explicitly and check if the sprint field is set # to None self.teh.move_changetime_to_the_past([task]) sb.remove(task) self.assert_not_contains(task, sb) # reload task and backlog, the remove should have saved the task task = self.teh.load_ticket(task) self.assert_not_contains(task, sb) self.assert_equals('', task[Key.SPRINT]) # Now move the ticket to another sprint s2 = self.teh.create_sprint("Another Sprint") task[Key.SPRINT] = s2.name task.save_changes('tester', 'Moved to sprint %s' % s2.name, when=now() + timedelta(seconds=1)) self.assert_equals(s2.name, task[Key.SPRINT]) # Now should not be in the backlog anymore self.assert_not_contains(task, sb) # Now change sprint again, twice task[Key.SPRINT] = s.name task.save_changes('tester', 'Moved to sprint %s' % s.name, when=now() + timedelta(seconds=2)) self.assert_contains(task, sb) # again task[Key.SPRINT] = s2.name task.save_changes('tester', 'Moved to sprint %s' % s2.name, when=now() + timedelta(seconds=3)) self.assert_equals(s2.name, task[Key.SPRINT]) # Now should not be in the backlog anymore self.assert_not_contains(task, sb) def test_referenced_requirements_are_displayed_in_the_sprint_backlog(self): """Test that referenced requirements are shown in the sprint backlog even if they are planned for a milestone.""" milestone = self.teh.create_milestone('1.0') sprint = self.teh.create_sprint("First Sprint") backlog_name = 'My Backlog' my_backlog = BacklogConfiguration(self.env, name=backlog_name, type=BacklogType.SPRINT) my_backlog.ticket_types = [ Type.USER_STORY, Type.TASK, Type.REQUIREMENT ] my_backlog.save() req = self.teh.create_ticket(Type.REQUIREMENT, { Key.SUMMARY: 'Requirement', Key.MILESTONE: milestone.name }) story = self.teh.create_ticket(Type.USER_STORY, { Key.SUMMARY: 'Story', Key.SPRINT: sprint.name }) req.link_to(story) backlog = self.bmm.get(name=backlog_name, scope=sprint.name) self.assert_length(2, backlog)
class TestBacklog(AgiloTestCase): """Tests for the Backlog class""" def setUp(self): self.super() self.bmm = BacklogModelManager(self.env) # Creates and It's me backlog its_me = self.teh.create_sprint("It's me") self.assert_true(its_me.exists) def _create_sprint_backlog(self): """Creates stories and tasks for a Sprint Backlog and returns the Backlog""" sprint = self.teh.create_sprint("Test") s1 = self.teh.create_ticket(Type.USER_STORY, props={ Key.STORY_POINTS: '3', Key.SPRINT: sprint.name }) self.assert_true( s1.link_to( self.teh.create_ticket(Type.TASK, props={ Key.REMAINING_TIME: '4', Key.SPRINT: sprint.name }))) self.assert_true( s1.link_to( self.teh.create_ticket(Type.TASK, props={ Key.REMAINING_TIME: '8', Key.SPRINT: sprint.name }))) self.assert_true( s1.link_to( self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '4'}))) s2 = self.teh.create_ticket(Type.USER_STORY, props={ Key.STORY_POINTS: '5', Key.SPRINT: sprint.name }) self.assert_true( s2.link_to( self.teh.create_ticket(Type.TASK, props={ Key.REMAINING_TIME: '2', Key.SPRINT: sprint.name }))) self.assert_true( s2.link_to( self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '3'}))) sprint_backlog = self.bmm.get(name="Sprint Backlog", scope=sprint.name) self.assert_contains(s1, sprint_backlog) self.assert_contains(s2, sprint_backlog) self.assert_length(5, sprint_backlog) return sprint_backlog def _create_product_backlog(self): """Creates Requirements and Stories for a Product Backlog and returns the Backlog""" def _create_story(props): """Creates a ticket of type story and returns it""" return self.teh.create_ticket(Type.USER_STORY, props=props) r1 = self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '3000'}) self.assert_true( r1.link_to(_create_story({Key.STORY_PRIORITY: 'Linear'}))) self.assert_true( r1.link_to(_create_story({Key.STORY_PRIORITY: 'Exciter'}))) self.assert_true( r1.link_to(_create_story({Key.STORY_PRIORITY: 'Mandatory'}))) r2 = self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '1200'}) self.assert_true( r2.link_to(_create_story({Key.STORY_PRIORITY: 'Mandatory'}))) self.assert_true( r2.link_to(_create_story({Key.STORY_PRIORITY: 'Exciter'}))) r3 = self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '2000'}) self.assert_true( r3.link_to(_create_story({Key.STORY_PRIORITY: 'Mandatory'}))) r4 = self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '800'}) self.assert_true( r4.link_to(_create_story({Key.STORY_PRIORITY: 'Linear'}))) r5 = self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '3000'}) self.assert_true( r5.link_to(_create_story({Key.STORY_PRIORITY: 'Exciter'}))) self.assert_true( r5.link_to(_create_story({Key.STORY_PRIORITY: 'Mandatory'}))) product_backlog = self.bmm.get(name="Product Backlog") self.assert_equals(len(product_backlog), 14) return product_backlog def testBacklogAsDictDecorator(self): """Tests that the Backlog car return itself with the Dict Decorator""" def testBacklogCreation(self): """Tests the creation of a Backlog""" global_backlog = BacklogConfiguration(self.env, name="Global Backlog") global_backlog.ticket_types = [Type.REQUIREMENT] global_backlog.save() # Now reload the same backlog and check that the type and order are kept b1 = self.bmm.get(name="Global Backlog") self.assert_equals(b1.ticket_types, [Type.REQUIREMENT]) def testProductBacklogItems(self): """Tests the creation of a Global Backlog and add some Items to it""" backlog = BacklogConfiguration(self.env, name="Global Backlog") backlog.ticket_types = [Type.REQUIREMENT] backlog.save() # Create some tickets and add them to the Backlog b = self.bmm.get(name="Global Backlog") b.add( self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '3000'})) b.add( self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '1200'})) b.add( self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '2000'})) b.add( self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '800'})) b.add( self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '3000'})) # Now test that the ticket are sorted by the defined Key ref = 3000 self.assert_equals(5, len(b), 'Wrong number of tickets in this (%s) Backlog!' % \ len(b)) # Now load it again, and verify that the order is still ok b1 = self.bmm.get(name="Global Backlog") self.assert_true( len(b1) > 0, 'There is no ticket associated to this Backlog!') def testMoveItemInBacklog(self): """Test the movement of an item into the backlog, change the position""" backlog = BacklogConfiguration(self.env, name="Global Backlog") backlog.ticket_types = [Type.REQUIREMENT] backlog.save() # Create some tickets and add them to the Backlog b = self.bmm.get(name="Global Backlog") b.add( self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '3000'})) b.add( self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '1200'})) b.add( self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '2000'})) b.add( self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '800'})) b.add( self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '3000'})) b1 = self.bmm.get(name="Global Backlog") t2000 = None for b in b1: #print "b: %s" % type(b) if int(b.ticket[Key.BUSINESS_VALUE]) == 2000: t2000 = b break self.assert_not_none(t2000) new_pos = b1.insert(0, t2000) self.assert_equals(new_pos, 0) # Now try to move a normal ticket and not a BacklogItem t2000 = self.teh.load_ticket(t_id=t2000.ticket.id) b1.insert(1, t2000) self.assert_equals(t2000, b1[1].ticket) def testBacklogPositionPersistence(self): """Tests the Backlog position persistence of items, after being saved and reloaded""" backlog = BacklogConfiguration(self.env, name="Global Backlog") backlog.ticket_types = [Type.REQUIREMENT] backlog.save() # Create some tickets and add them to the Backlog b = self.bmm.get(name="Global Backlog") b.add( self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '3000'})) b.add( self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '1200'})) b.add( self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '2000'})) # Now reload the backlog, move the item in pos 2 to 1, save and reload b1 = self.bmm.get(name="Global Backlog") self.assert_equals(3, len(b1)) t1200 = b1[1] b1.insert(0, t1200) # reload the backlgo and verify that the item is in position 0 b2 = self.bmm.get(name='Global Backlog') self.assert_equals(t1200.ticket.id, b2[0].ticket.id) self.assert_equals(0, b2[0].pos) def testBacklogWithItemNotAdded(self): """Tests the Backlog with Items that have not been explicitly added""" backlog = BacklogConfiguration(self.env, name="Global Backlog") backlog.ticket_types = [Type.REQUIREMENT] backlog.save() # Create some tickets and add them to the Backlog b = self.bmm.get(name="Global Backlog") t1 = self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '3000'}) t_no = self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_POINTS: '13'}) t2 = self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '1200'}) b1 = self.bmm.get(name="Global Backlog") # Test that a belonging ticket is really belonging self.assert_contains(t2, b1) # Test if the external ticket, has been loaded into the Backlog self.assert_contains(t1, b1) # Test that the t_no, User Story is also not in the Backlog self.assert_not_contains(t_no, b1) def testBacklogWithHierarchicalItems(self): """Tests the Backlog with multiple hierarchical types""" # Create 2 requirements and link 2 stories each r1 = self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '2000'}) self.assert_true( r1.link_to( self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_PRIORITY: 'Linear'}))) self.assert_true( r1.link_to( self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_PRIORITY: 'Mandatory'}))) r2 = self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '3000'}) self.assert_true( r2.link_to( self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_PRIORITY: 'Exciter'}))) self.assert_true( r2.link_to( self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_PRIORITY: 'Linear'}))) # Now create a Backlog with both type and lets' verify that the tickets are there backlog = BacklogConfiguration(self.env, name="Global Backlog") backlog.ticket_types = [Type.REQUIREMENT, Type.USER_STORY] backlog.save() b = self.bmm.get(name="Global Backlog") self.assert_equals(6, len(b)) self.assert_contains(r1, b) for at in r1.get_outgoing(): self.assert_contains(at, b) self.assert_contains(r1, b) for at in r2.get_outgoing(): self.assert_contains(at, b) def testBacklogForSprint(self): """Tests a Backlog associated to a Sprint""" # Creates a Milestone m = Milestone(self.env) m.name = "Milestone 1" m.insert() # Create a Sprint sprint = self.teh.create_sprint(name="Sprint 1", start=to_datetime(t=None), duration=20, milestone=m.name) # Create some tickets # s1(s) -> t1(s) # -> t2(s) # -> t3 # s2 -> t4(s) # -> t5 s1 = self.teh.create_ticket(Type.USER_STORY, props={ Key.STORY_POINTS: '3', Key.SPRINT: sprint.name }) self.assert_equals(s1[Key.SPRINT], sprint.name) self.assert_true( s1.link_to( self.teh.create_ticket(Type.TASK, props={ Key.REMAINING_TIME: '4', Key.SPRINT: sprint.name }))) self.assert_true( s1.link_to( self.teh.create_ticket(Type.TASK, props={ Key.REMAINING_TIME: '8', Key.SPRINT: sprint.name }))) self.assert_true( s1.link_to( self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '4'}))) s2 = self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_POINTS: '5'}) self.assert_true( s2.link_to( self.teh.create_ticket(Type.TASK, props={ Key.REMAINING_TIME: '2', Key.SPRINT: sprint.name }))) self.assert_true( s2.link_to( self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '3'}))) # Creates the Backlog bound to the Sprint backlog = BacklogConfiguration(self.env, name="Sprint-Backlog", type=BacklogType.SPRINT) backlog.ticket_types = [Type.USER_STORY, Type.TASK] backlog.save() # The Backlog should contains only the items planned for the Sprint, and with parents # planned for the Sprint too backlog = self.bmm.get(name="Sprint-Backlog", scope=sprint.name) self.assert_length(5, backlog) def testBacklogForMultipleSprint(self): """Tests a Backlog associated to a Sprint with multiple sprints""" # Creates a Milestone m = Milestone(self.env) m.name = "Milestone 1" m.insert() # Create 2 Sprints sprint1 = self.teh.create_sprint(name="Sprint 1", start=to_datetime(t=None), duration=20, milestone=m.name) sprint2 = self.teh.create_sprint(name="Sprint 2", start=to_datetime(t=None), duration=20, milestone=m.name) # Create some tickets s1 = self.teh.create_ticket(Type.USER_STORY, props={ Key.STORY_POINTS: '3', Key.SPRINT: sprint1.name }) self.assert_true( s1.link_to( self.teh.create_ticket(Type.TASK, props={ Key.REMAINING_TIME: '4', Key.SPRINT: sprint1.name }))) self.assert_true( s1.link_to( self.teh.create_ticket(Type.TASK, props={ Key.REMAINING_TIME: '8', Key.SPRINT: sprint1.name }))) self.assert_true( s1.link_to( self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '4'}))) s2 = self.teh.create_ticket(Type.USER_STORY, props={ Key.STORY_POINTS: '5', Key.SPRINT: sprint2.name }) self.assert_true( s2.link_to( self.teh.create_ticket(Type.TASK, props={ Key.REMAINING_TIME: '2', Key.SPRINT: sprint2.name }))) self.assert_true( s2.link_to( self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '3'}))) # Creates the Backlog bound to the Sprint backlog = BacklogConfiguration(self.env, name="Sprint-Backlog", type=BacklogType.SPRINT) backlog.ticket_types = [Type.USER_STORY, Type.TASK] backlog.save() # The Backlog should contains only the items planned for the Sprint, and with parents # planned for the Sprint too backlog1 = self.bmm.get(name="Sprint-Backlog", scope=sprint1.name) self.assert_length(3, backlog1) backlog2 = self.bmm.get(name="Sprint-Backlog", scope=sprint2.name) self.assert_length(2, backlog2) def testGlobalBacklogWithStrictOption(self): """Tests a global backlog with the Strict option""" backlog = BacklogConfiguration(self.env, name="Bug-Backlog") backlog.ticket_types = [Type.BUG, Type.TASK] backlog.save() # Build a hierarchy of Bug tasks b1 = self.teh.create_ticket(Type.BUG) t1 = self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '3'}) t2 = self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '7'}) # Link the Bug only with one task self.assert_true(b1.link_to(t1)) self.assert_equals('', b1[Key.SPRINT]) # Standard trac fields must not be None (see property change rendering # for ticket preview) self.assert_equals('', b1[Key.MILESTONE]) self.assert_equals(Type.BUG, b1[Key.TYPE]) self.assert_equals('', t1[Key.SPRINT]) self.assert_equals('', t1[Key.MILESTONE]) self.assert_equals('', t2[Key.SPRINT]) self.assert_equals('', t2[Key.MILESTONE]) # Now load the backlog, and check that even with strict # a global backlog shows all the tickets b = self.bmm.get(name="Bug-Backlog") if len(b) != 3: print_backlog(b) self.fail("Backlog count wrong! %s != 3" % \ len(b)) # Now links also the second task self.assert_true(b1.link_to(t2)) # Now reload the backlog and check if the second task is there too self.assert_length(3, b) # Now plan the a task for a sprint so that should disappear from the # backlog s = self.teh.create_sprint("Test") t1[Key.SPRINT] = s.name self.assert_true(t1.save_changes('Tester', 'Planned...')) self.assert_length(2, b) def testScopedBacklogWithClosedTicket(self): """Tests if a scoped backlog loads also closed tickets""" sprint1 = self.teh.create_sprint("Sprint Scoped") sprint1.save() # Creates the Backlog bound to a scope (Sprint) backlog = BacklogConfiguration(self.env, name="Scoped-Backlog", type=BacklogType.SPRINT) backlog.ticket_types = [Type.USER_STORY, Type.TASK] backlog.save() # Create 1 ticket task = self.teh.create_ticket(Type.TASK, props={ Key.REMAINING_TIME: '12', Key.SPRINT: sprint1.name }) # Force reload backlog = self.bmm.get(name="Scoped-Backlog", scope=sprint1.name) self.assert_true(task in backlog) self.assert_equals(len(backlog), 1) task[Key.STATUS] = Status.CLOSED task.save_changes('tester', 'Changed Status') # Now should still be there even if closed, because the backlog is scoped self.assert_true(task in backlog) self.assert_equals(len(backlog), 1) def testDeleteBacklog(self): """Tests the deletion of a Backlog""" backlog = BacklogConfiguration(self.env, name="Delete-Backlog") backlog.ticket_types = [Type.USER_STORY, Type.TASK] backlog.save() # Test that the backlog exists try: b2 = self.bmm.get(name="Delete-Backlog") self.assert_true(b2.delete()) except Exception, e: print "Error: %s" % unicode(e) self.fail("Not able to load backlog!!!") try: b2 = self.bmm.get(self.env, "Delete-Backlog") self.fail("The Backlog was not deleted!!!") except: self.assert_true(True)
class TestBacklog(AgiloTestCase): """Tests for the Backlog class""" def setUp(self): self.super() self.bmm = BacklogModelManager(self.env) # Creates and It's me backlog its_me = self.teh.create_sprint("It's me") self.assert_true(its_me.exists) def _create_sprint_backlog(self): """Creates stories and tasks for a Sprint Backlog and returns the Backlog""" sprint = self.teh.create_sprint("Test") s1 = self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_POINTS: '3', Key.SPRINT: sprint.name}) self.assert_true(s1.link_to(self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '4', Key.SPRINT: sprint.name}))) self.assert_true(s1.link_to(self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '8', Key.SPRINT: sprint.name}))) self.assert_true(s1.link_to(self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '4'}))) s2 = self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_POINTS: '5', Key.SPRINT: sprint.name}) self.assert_true(s2.link_to(self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '2', Key.SPRINT: sprint.name}))) self.assert_true(s2.link_to(self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '3'}))) sprint_backlog = self.bmm.get(name="Sprint Backlog", scope=sprint.name) self.assert_contains(s1, sprint_backlog) self.assert_contains(s2, sprint_backlog) self.assert_length(5, sprint_backlog) return sprint_backlog def _create_product_backlog(self): """Creates Requirements and Stories for a Product Backlog and returns the Backlog""" def _create_story(props): """Creates a ticket of type story and returns it""" return self.teh.create_ticket(Type.USER_STORY, props=props) r1 = self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '3000'}) self.assert_true(r1.link_to(_create_story({Key.STORY_PRIORITY: 'Linear'}))) self.assert_true(r1.link_to(_create_story({Key.STORY_PRIORITY: 'Exciter'}))) self.assert_true(r1.link_to(_create_story({Key.STORY_PRIORITY: 'Mandatory'}))) r2 = self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '1200'}) self.assert_true(r2.link_to(_create_story({Key.STORY_PRIORITY: 'Mandatory'}))) self.assert_true(r2.link_to(_create_story({Key.STORY_PRIORITY: 'Exciter'}))) r3 = self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '2000'}) self.assert_true(r3.link_to(_create_story({Key.STORY_PRIORITY: 'Mandatory'}))) r4 = self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '800'}) self.assert_true(r4.link_to(_create_story({Key.STORY_PRIORITY: 'Linear'}))) r5 = self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '3000'}) self.assert_true(r5.link_to(_create_story({Key.STORY_PRIORITY: 'Exciter'}))) self.assert_true(r5.link_to(_create_story({Key.STORY_PRIORITY: 'Mandatory'}))) product_backlog = self.bmm.get(name="Product Backlog") self.assert_equals(len(product_backlog), 14) return product_backlog def testBacklogAsDictDecorator(self): """Tests that the Backlog car return itself with the Dict Decorator""" def testBacklogCreation(self): """Tests the creation of a Backlog""" global_backlog = BacklogConfiguration(self.env, name="Global Backlog") global_backlog.ticket_types = [Type.REQUIREMENT] global_backlog.save() # Now reload the same backlog and check that the type and order are kept b1 = self.bmm.get(name="Global Backlog") self.assert_equals(b1.ticket_types, [Type.REQUIREMENT]) def testProductBacklogItems(self): """Tests the creation of a Global Backlog and add some Items to it""" backlog = BacklogConfiguration(self.env, name="Global Backlog") backlog.ticket_types = [Type.REQUIREMENT] backlog.save() # Create some tickets and add them to the Backlog b = self.bmm.get(name="Global Backlog") b.add(self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '3000'})) b.add(self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '1200'})) b.add(self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '2000'})) b.add(self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '800'})) b.add(self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '3000'})) # Now test that the ticket are sorted by the defined Key ref = 3000 self.assert_equals(5, len(b), 'Wrong number of tickets in this (%s) Backlog!' % \ len(b)) # Now load it again, and verify that the order is still ok b1 = self.bmm.get(name="Global Backlog") self.assert_true(len(b1) > 0, 'There is no ticket associated to this Backlog!') def testMoveItemInBacklog(self): """Test the movement of an item into the backlog, change the position""" backlog = BacklogConfiguration(self.env, name="Global Backlog") backlog.ticket_types=[Type.REQUIREMENT] backlog.save() # Create some tickets and add them to the Backlog b = self.bmm.get(name="Global Backlog") b.add(self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '3000'})) b.add(self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '1200'})) b.add(self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '2000'})) b.add(self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '800'})) b.add(self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '3000'})) b1 = self.bmm.get(name="Global Backlog") t2000 = None for b in b1: #print "b: %s" % type(b) if int(b.ticket[Key.BUSINESS_VALUE]) == 2000: t2000 = b break self.assert_not_none(t2000) new_pos = b1.insert(0, t2000) self.assert_equals(new_pos, 0) # Now try to move a normal ticket and not a BacklogItem t2000 = self.teh.load_ticket(t_id=t2000.ticket.id) b1.insert(1, t2000) self.assert_equals(t2000, b1[1].ticket) def testBacklogPositionPersistence(self): """Tests the Backlog position persistence of items, after being saved and reloaded""" backlog = BacklogConfiguration(self.env, name="Global Backlog") backlog.ticket_types=[Type.REQUIREMENT] backlog.save() # Create some tickets and add them to the Backlog b = self.bmm.get(name="Global Backlog") b.add(self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '3000'})) b.add(self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '1200'})) b.add(self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '2000'})) # Now reload the backlog, move the item in pos 2 to 1, save and reload b1 = self.bmm.get(name="Global Backlog") self.assert_equals(3, len(b1)) t1200 = b1[1] b1.insert(0, t1200) # reload the backlgo and verify that the item is in position 0 b2 = self.bmm.get(name='Global Backlog') self.assert_equals(t1200.ticket.id, b2[0].ticket.id) self.assert_equals(0, b2[0].pos) def testBacklogWithItemNotAdded(self): """Tests the Backlog with Items that have not been explicitly added""" backlog = BacklogConfiguration(self.env, name="Global Backlog") backlog.ticket_types=[Type.REQUIREMENT] backlog.save() # Create some tickets and add them to the Backlog b = self.bmm.get(name="Global Backlog") t1 = self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '3000'}) t_no = self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_POINTS: '13'}) t2 = self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '1200'}) b1 = self.bmm.get(name="Global Backlog") # Test that a belonging ticket is really belonging self.assert_contains(t2, b1) # Test if the external ticket, has been loaded into the Backlog self.assert_contains(t1, b1) # Test that the t_no, User Story is also not in the Backlog self.assert_not_contains(t_no, b1) def testBacklogWithHierarchicalItems(self): """Tests the Backlog with multiple hierarchical types""" # Create 2 requirements and link 2 stories each r1 = self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '2000'}) self.assert_true(r1.link_to(self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_PRIORITY: 'Linear'}))) self.assert_true(r1.link_to(self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_PRIORITY: 'Mandatory'}))) r2 = self.teh.create_ticket(Type.REQUIREMENT, props={Key.BUSINESS_VALUE: '3000'}) self.assert_true(r2.link_to(self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_PRIORITY: 'Exciter'}))) self.assert_true(r2.link_to(self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_PRIORITY: 'Linear'}))) # Now create a Backlog with both type and lets' verify that the tickets are there backlog = BacklogConfiguration(self.env, name="Global Backlog") backlog.ticket_types=[Type.REQUIREMENT, Type.USER_STORY] backlog.save() b = self.bmm.get(name="Global Backlog") self.assert_equals(6, len(b)) self.assert_contains(r1, b) for at in r1.get_outgoing(): self.assert_contains(at, b) self.assert_contains(r1, b) for at in r2.get_outgoing(): self.assert_contains(at, b) def testBacklogForSprint(self): """Tests a Backlog associated to a Sprint""" # Creates a Milestone m = Milestone(self.env) m.name = "Milestone 1" m.insert() # Create a Sprint sprint = self.teh.create_sprint( name="Sprint 1", start=to_datetime(t=None), duration=20, milestone=m.name) # Create some tickets # s1(s) -> t1(s) # -> t2(s) # -> t3 # s2 -> t4(s) # -> t5 s1 = self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_POINTS: '3', Key.SPRINT: sprint.name}) self.assert_equals(s1[Key.SPRINT], sprint.name) self.assert_true(s1.link_to(self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '4', Key.SPRINT: sprint.name}))) self.assert_true(s1.link_to(self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '8', Key.SPRINT: sprint.name}))) self.assert_true(s1.link_to(self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '4'}))) s2 = self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_POINTS: '5'}) self.assert_true(s2.link_to(self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '2', Key.SPRINT: sprint.name}))) self.assert_true(s2.link_to(self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '3'}))) # Creates the Backlog bound to the Sprint backlog = BacklogConfiguration(self.env, name="Sprint-Backlog", type=BacklogType.SPRINT) backlog.ticket_types=[Type.USER_STORY, Type.TASK] backlog.save() # The Backlog should contains only the items planned for the Sprint, and with parents # planned for the Sprint too backlog = self.bmm.get(name="Sprint-Backlog", scope=sprint.name) self.assert_length(5, backlog) def testBacklogForMultipleSprint(self): """Tests a Backlog associated to a Sprint with multiple sprints""" # Creates a Milestone m = Milestone(self.env) m.name = "Milestone 1" m.insert() # Create 2 Sprints sprint1 = self.teh.create_sprint( name="Sprint 1", start=to_datetime(t=None), duration=20, milestone=m.name) sprint2 = self.teh.create_sprint( name="Sprint 2", start=to_datetime(t=None), duration=20, milestone=m.name) # Create some tickets s1 = self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_POINTS: '3', Key.SPRINT: sprint1.name}) self.assert_true(s1.link_to(self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '4', Key.SPRINT: sprint1.name}))) self.assert_true(s1.link_to(self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '8', Key.SPRINT: sprint1.name}))) self.assert_true(s1.link_to(self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '4'}))) s2 = self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_POINTS: '5', Key.SPRINT: sprint2.name}) self.assert_true(s2.link_to(self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '2', Key.SPRINT: sprint2.name}))) self.assert_true(s2.link_to(self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '3'}))) # Creates the Backlog bound to the Sprint backlog = BacklogConfiguration(self.env, name="Sprint-Backlog", type=BacklogType.SPRINT) backlog.ticket_types = [Type.USER_STORY, Type.TASK] backlog.save() # The Backlog should contains only the items planned for the Sprint, and with parents # planned for the Sprint too backlog1 = self.bmm.get(name="Sprint-Backlog", scope=sprint1.name) self.assert_length(3, backlog1) backlog2 = self.bmm.get(name="Sprint-Backlog", scope=sprint2.name) self.assert_length(2, backlog2) def testGlobalBacklogWithStrictOption(self): """Tests a global backlog with the Strict option""" backlog = BacklogConfiguration(self.env, name="Bug-Backlog") backlog.ticket_types=[Type.BUG, Type.TASK] backlog.save() # Build a hierarchy of Bug tasks b1 = self.teh.create_ticket(Type.BUG) t1 = self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '3'}) t2 = self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '7'}) # Link the Bug only with one task self.assert_true(b1.link_to(t1)) self.assert_equals('', b1[Key.SPRINT]) # Standard trac fields must not be None (see property change rendering # for ticket preview) self.assert_equals('', b1[Key.MILESTONE]) self.assert_equals(Type.BUG, b1[Key.TYPE]) self.assert_equals('', t1[Key.SPRINT]) self.assert_equals('', t1[Key.MILESTONE]) self.assert_equals('', t2[Key.SPRINT]) self.assert_equals('', t2[Key.MILESTONE]) # Now load the backlog, and check that even with strict # a global backlog shows all the tickets b = self.bmm.get(name="Bug-Backlog") if len(b) != 3: print_backlog(b) self.fail("Backlog count wrong! %s != 3" % \ len(b)) # Now links also the second task self.assert_true(b1.link_to(t2)) # Now reload the backlog and check if the second task is there too self.assert_length(3, b) # Now plan the a task for a sprint so that should disappear from the # backlog s = self.teh.create_sprint("Test") t1[Key.SPRINT] = s.name self.assert_true(t1.save_changes('Tester', 'Planned...')) self.assert_length(2, b) def testScopedBacklogWithClosedTicket(self): """Tests if a scoped backlog loads also closed tickets""" sprint1 = self.teh.create_sprint("Sprint Scoped") sprint1.save() # Creates the Backlog bound to a scope (Sprint) backlog = BacklogConfiguration(self.env, name="Scoped-Backlog", type=BacklogType.SPRINT) backlog.ticket_types = [Type.USER_STORY, Type.TASK] backlog.save() # Create 1 ticket task = self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '12', Key.SPRINT: sprint1.name}) # Force reload backlog = self.bmm.get(name="Scoped-Backlog", scope=sprint1.name) self.assert_true(task in backlog) self.assert_equals(len(backlog), 1) task[Key.STATUS] = Status.CLOSED task.save_changes('tester', 'Changed Status') # Now should still be there even if closed, because the backlog is scoped self.assert_true(task in backlog) self.assert_equals(len(backlog), 1) def testDeleteBacklog(self): """Tests the deletion of a Backlog""" backlog = BacklogConfiguration(self.env, name="Delete-Backlog") backlog.ticket_types=[Type.USER_STORY, Type.TASK] backlog.save() # Test that the backlog exists try: b2 = self.bmm.get(name="Delete-Backlog") self.assert_true(b2.delete()) except Exception, e: print "Error: %s" % unicode(e) self.fail("Not able to load backlog!!!") try: b2 = self.bmm.get(self.env, "Delete-Backlog") self.fail("The Backlog was not deleted!!!") except: self.assert_true(True)
def backlog(self): from agilo.scrum.backlog.model import BacklogModelManager return BacklogModelManager(self.env).get(name=self.name, scope=Key.SPRINT)