Пример #1
0
 def testVelocityForSprint(self):
     """Tests the set velocity for a sprint as a team metric"""
     test_team = self.tm.create(name="Team#1")
     self.assert_true(test_team.save())
     self.tmm.create(name="Member#1", team=test_team).save()
     self.tmm.create(name="Member#2", team=test_team).save()
     self.tmm.create(name="Member#3", team=test_team).save()
     sprint = self.teh.create_sprint("TestSprint", team=test_team)
     us1 = self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_POINTS: '5',
                                                          Key.SPRINT: sprint.name})
     us2 = self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_POINTS: '8',
                                                          Key.SPRINT: sprint.name})
     us3 = self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_POINTS: '13',
                                                          Key.SPRINT: sprint.name})
     # we have to use the TeamController here
     cmd_store = TeamController.StoreTeamVelocityCommand(self.env,
                                                         sprint=sprint,
                                                         team=test_team,
                                                         estimated=True)
     self.assert_equals(26, self.controller.process_command(cmd_store))
     # Now close a story and check the actual velocity
     cmd_get = TeamController.GetStoredTeamVelocityCommand(self.env,
                                                           sprint=sprint.name,
                                                           team=test_team,
                                                           estimated=True)
     us3[Key.STATUS] = Status.CLOSED
     us3.save_changes('tester', 'closed US3')
     self.assert_equals(26, self.controller.process_command(cmd_get))
     cmd_store.estimated = False
     self.assert_equals(13, self.controller.process_command(cmd_store))
     cmd_get.estimated = False
     self.assert_equals(13, self.controller.process_command(cmd_get))
 def _metric(self, sprint, team, metric):
     cmd = TeamController.GetTeamMetricCommand(self.env,
                                               sprint=sprint,
                                               team=team,
                                               metric=metric)
     result = TeamController(self.env).process_command(cmd)
     return result
Пример #3
0
    def testGetTeamCommandReturnsMembersAsDict(self):
        team = self.teh.create_team('Testteam')
        self.teh.create_member('foo', team)
        cmd = TeamController.GetTeamCommand(self.env, team=team.name)
        value_team = TeamController(self.env).process_command(cmd)

        members = value_team.members
        self.assert_equals(1, len(members))
        self.assert_true(isinstance(members[0], ValueObject))
Пример #4
0
 def test_summed_capacity_for_team_command_returns_zero_array_if_no_capacity_is_there(
         self):
     """Tests the calculation of the Daily capacity of a team for a Sprint"""
     cmd_daily_capacity = TeamController.CalculateSummedCapacityCommand(
         self.env, sprint=self.sprint)
     capacity = self.controller.process_command(cmd_daily_capacity)
     self.assert_equals(0, capacity)
Пример #5
0
 def _store_commitment(self, commitment):
     cmd_class = TeamController.StoreTeamMetricCommand
     cmd = cmd_class(self.env,
                     sprint=self.sprint,
                     team=self.sprint.team,
                     metric=Key.COMMITMENT,
                     value=commitment)
     TeamController(self.env).process_command(cmd)
Пример #6
0
 def test_team_commitment(self):
     """Tests store and retrieval of the team commitment of a sprint"""
     test_team = self.tm.create(name="Team#1")
     sprint = self.teh.create_sprint("TestSprint", team=test_team)
     self.assert_true(test_team.exists)
     # Set the initial USP/RT ratio to 2
     tm = TeamMetrics(self.env, sprint, test_team)
     tm[Key.RT_USP_RATIO] = 2
     tm.save()
     
     tm1 = self.tmm.create(name="Member#1", team=test_team)
     self.tmm.create(name="Member#2", team=test_team)
     self.tmm.create(name="Member#3", team=test_team)
     us1 = self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_POINTS: '5',
                                                          Key.SPRINT: sprint.name})
     us2 = self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_POINTS: '8',
                                                          Key.SPRINT: sprint.name})
     t1 = self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '12',
                                                   Key.OWNER: tm1.name,
                                                   Key.SPRINT: sprint.name})
     # This task is not explicitly planned for the sprint, but because it is
     # linked should be calculated
     t2 = self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '8',
                                                   Key.OWNER: tm1.name})
     # Make sure there is a remaining time entry on the first day of the sprint
     RemainingTime(self.env, t1).set_remaining_time(t1[Key.REMAINING_TIME], 
                                                    sprint.start)
     RemainingTime(self.env, t2).set_remaining_time(t2[Key.REMAINING_TIME], 
                                                    sprint.start)
     us1.link_to(t1)
     us1.link_to(t2)
     us2 = self.teh.load_ticket(ticket=us2)
     self.assert_equals(Type.USER_STORY, us2.get_type())
     self.assert_not_none(us2._calculated)
     # check the estimated remaining time for us2
     self.assert_equals(8 * 2, us2[Key.ESTIMATED_REMAINING_TIME])
     
     cmd_class = TeamController.CalculateAndStoreTeamCommitmentCommand
     cmd_store_commitment = cmd_class(self.env, sprint=sprint, team=test_team)
     commitment = TeamController(self.env).process_command(cmd_store_commitment)
     self.assert_equals(12 + 8 * 2, commitment)
     cmd_get_commitment = TeamController.GetTeamCommitmentCommand(self.env,
                                                                  sprint=sprint,
                                                                  team=test_team)
     self.assert_equals(commitment, 
                      self.controller.process_command(cmd_get_commitment))
Пример #7
0
 def test_confirm_commitment_uses_current_remaining_time(self):
     self.sprint.start = now() - timedelta(hours=2)
     self.sprint.save()
     task_properties = {Key.REMAINING_TIME: '7', Key.SPRINT: self.sprint.name}
     self.teh.create_ticket(Type.TASK, props=task_properties)
     
     commitment = TeamController.confirm_commitment_for_sprint(self.env, self.sprint)
     self.assert_equals(7, commitment)
Пример #8
0
    def test_can_sum_capacity_for_team(self):
        self.sprints_can_start_and_end_anytime()
        self.sprint.start = datetime(2009, 8, 1, 00, 00, tzinfo=utc)
        self.sprint.end = datetime(2009, 8, 10, 23, 59, tzinfo=utc)
        self.sprint.save()
        self.teh.create_member('Foo', self.sprint.team)

        cmd_daily_capacity = TeamController.CalculateSummedCapacityCommand(
            self.env, sprint=self.sprint, team=self.sprint.team)
        capacity_per_day = self.controller.process_command(cmd_daily_capacity)
        self.assert_almost_equals(36, capacity_per_day, max_delta=.01)
Пример #9
0
 def testStoreAndRetriveVelocityCommands(self):
     """Tests the store and retrive of the team velocity from the metrics"""
     self.assert_equals('A-Team', self.sprint.team.name)
     cmd_store_velocity = TeamController.StoreTeamVelocityCommand(
         self.env, sprint=self.sprint)
     velocity = self.controller.process_command(cmd_store_velocity)
     self.assert_equals(13, velocity)
     # now check if it has been stored
     cmd_get_velocity = TeamController.GetStoredTeamVelocityCommand(
         self.env, sprint=self.sprint)
     metrics_velocity = self.controller.process_command(cmd_get_velocity)
     self.assert_equals(velocity, metrics_velocity)
     # now the estimated
     cmd_store_velocity.estimated = True
     cmd_get_velocity.estimated = True
     est_velocity = self.controller.process_command(cmd_store_velocity)
     self.assert_equals(39, est_velocity)
     metrics_est_velocity = self.controller.process_command(
         cmd_get_velocity)
     self.assert_equals(est_velocity, metrics_est_velocity)
Пример #10
0
 def testCalculateVelocityCommand(self):
     """Tests the calculate velocity command"""
     cmd_calc_velocity = TeamController.CalculateTeamVelocityCommand(
         self.env, sprint=self.sprint)
     velocity = self.controller.process_command(cmd_calc_velocity)
     # Now velocity is the actual, so should be 13 only the closed story
     self.assert_equals(13, velocity)
     # Now check the estimated velocity, setting estimated to true in the command
     cmd_calc_velocity.estimated = True
     est_velocity = self.controller.process_command(cmd_calc_velocity)
     self.assert_equals(39, est_velocity)
Пример #11
0
 def setUp(self):
     """initalize and environment, and a controller instance"""
     self.super()
     self.controller = TeamController(self.teh.get_env())
     self.sprint = self.teh.create_sprint('TestSprint', team='A-Team')
     self.s1 = self.teh.create_ticket(Type.USER_STORY,
                                      props={
                                          Key.STORY_POINTS: '13',
                                          Key.SPRINT: 'TestSprint'
                                      })
     self.s2 = self.teh.create_ticket(Type.USER_STORY,
                                      props={
                                          Key.STORY_POINTS: '13',
                                          Key.SPRINT: 'TestSprint'
                                      })
     self.s3 = self.teh.create_ticket(Type.USER_STORY,
                                      props={
                                          Key.STORY_POINTS: '13',
                                          Key.SPRINT: 'TestSprint',
                                          Key.STATUS: 'closed'
                                      })
Пример #12
0
    def test_confirm_commitment_uses_current_remaining_time(self):
        self.sprint.start = now() - timedelta(hours=2)
        self.sprint.save()
        task_properties = {
            Key.REMAINING_TIME: '7',
            Key.SPRINT: self.sprint.name
        }
        self.teh.create_ticket(Type.TASK, props=task_properties)

        commitment = TeamController.confirm_commitment_for_sprint(
            self.env, self.sprint)
        self.assert_equals(7, commitment)
Пример #13
0
 def setUp(self):
     """initalize and environment, and a controller instance"""
     self.super()
     self.controller = TeamController(self.teh.get_env())
     self.sprint = self.teh.create_sprint('TestSprint', team='A-Team')
     self.s1 = self.teh.create_ticket(Type.USER_STORY, 
                                      props={Key.STORY_POINTS: '13',
                                             Key.SPRINT: 'TestSprint'})
     self.s2 = self.teh.create_ticket(Type.USER_STORY, 
                                      props={Key.STORY_POINTS: '13',
                                             Key.SPRINT: 'TestSprint'})
     self.s3 = self.teh.create_ticket(Type.USER_STORY, 
                                      props={Key.STORY_POINTS: '13',
                                             Key.SPRINT: 'TestSprint',
                                             Key.STATUS: 'closed'})
Пример #14
0
class TeamControllerTest(AgiloTestCase):
    """Tests the TeamController and all the Commands in it"""
    def setUp(self):
        """initalize and environment, and a controller instance"""
        self.super()
        self.controller = TeamController(self.teh.get_env())
        self.sprint = self.teh.create_sprint('TestSprint', team='A-Team')
        self.s1 = self.teh.create_ticket(Type.USER_STORY, 
                                         props={Key.STORY_POINTS: '13',
                                                Key.SPRINT: 'TestSprint'})
        self.s2 = self.teh.create_ticket(Type.USER_STORY, 
                                         props={Key.STORY_POINTS: '13',
                                                Key.SPRINT: 'TestSprint'})
        self.s3 = self.teh.create_ticket(Type.USER_STORY, 
                                         props={Key.STORY_POINTS: '13',
                                                Key.SPRINT: 'TestSprint',
                                                Key.STATUS: 'closed'})
        
    def testCalculateVelocityCommand(self):
        """Tests the calculate velocity command"""
        cmd_calc_velocity = TeamController.CalculateTeamVelocityCommand(self.env,
                                                                        sprint=self.sprint)
        velocity = self.controller.process_command(cmd_calc_velocity)
        # Now velocity is the actual, so should be 13 only the closed story
        self.assert_equals(13, velocity)
        # Now check the estimated velocity, setting estimated to true in the command
        cmd_calc_velocity.estimated = True
        est_velocity = self.controller.process_command(cmd_calc_velocity)
        self.assert_equals(39, est_velocity)
    
    def testStoreAndRetriveVelocityCommands(self):
        """Tests the store and retrive of the team velocity from the metrics"""
        self.assert_equals('A-Team', self.sprint.team.name)
        cmd_store_velocity = TeamController.StoreTeamVelocityCommand(self.env,
                                                                     sprint=self.sprint)
        velocity = self.controller.process_command(cmd_store_velocity)
        self.assert_equals(13, velocity)
        # now check if it has been stored
        cmd_get_velocity = TeamController.GetStoredTeamVelocityCommand(self.env,
                                                                       sprint=self.sprint)
        metrics_velocity = self.controller.process_command(cmd_get_velocity)
        self.assert_equals(velocity, metrics_velocity)
        # now the estimated
        cmd_store_velocity.estimated = True
        cmd_get_velocity.estimated = True
        est_velocity = self.controller.process_command(cmd_store_velocity)
        self.assert_equals(39, est_velocity)
        metrics_est_velocity = self.controller.process_command(cmd_get_velocity)
        self.assert_equals(est_velocity, metrics_est_velocity)
    
    def test_summed_capacity_for_team_command_returns_zero_array_if_no_capacity_is_there(self):
        """Tests the calculation of the Daily capacity of a team for a Sprint"""
        cmd_daily_capacity = TeamController.CalculateSummedCapacityCommand(self.env, sprint=self.sprint)
        capacity = self.controller.process_command(cmd_daily_capacity)
        self.assert_equals(0, capacity)
    
    def test_can_sum_capacity_for_team(self):
        self.sprints_can_start_and_end_anytime()
        self.sprint.start = datetime(2009, 8, 1, 00, 00, tzinfo=utc)
        self.sprint.end = datetime(2009, 8, 10, 23, 59, tzinfo=utc)
        self.sprint.save()
        self.teh.create_member('Foo', self.sprint.team)
        
        cmd_daily_capacity = TeamController.CalculateSummedCapacityCommand(self.env, sprint=self.sprint, team=self.sprint.team)
        capacity_per_day = self.controller.process_command(cmd_daily_capacity)
        self.assert_almost_equals(36, capacity_per_day, max_delta=.01)
    
    def test_can_subtract_contingents_from_team_capacity(self):
        self.sprints_can_start_and_end_anytime()
        self.sprint.start = datetime(2009, 8, 1, 00, 00, tzinfo=utc)
        self.sprint.end = datetime(2009, 8, 10, 23, 59, tzinfo=utc)
        self.sprint.save()
        self.teh.create_member('Foo', self.sprint.team)
        self.teh.add_contingent_to_sprint('Bar', 12, self.sprint)
        
        cmd_daily_capacity = TeamController.CalculateSummedCapacityCommand(self.env, sprint=self.sprint, team=self.sprint.team)
        capacity_per_day = self.controller.process_command(cmd_daily_capacity)
        self.assert_almost_equals(36 - 12, capacity_per_day, max_delta=.01)
    
    def sprints_can_start_and_end_anytime(self):
        config = AgiloConfig(self.env)
        config.change_option('sprints_can_start_or_end_on_weekends', True, section='agilo-general')
        config.save()
        
    def testGetTeamCommandReturnsMembersAsDict(self):
        team = self.teh.create_team('Testteam')
        self.teh.create_member('foo', team)
        cmd = TeamController.GetTeamCommand(self.env, team=team.name)
        value_team = TeamController(self.env).process_command(cmd)
        
        members = value_team.members
        self.assert_equals(1, len(members))
        self.assert_true(isinstance(members[0], ValueObject))
    
    def test_confirm_commitment_uses_current_remaining_time(self):
        self.sprint.start = now() - timedelta(hours=2)
        self.sprint.save()
        task_properties = {Key.REMAINING_TIME: '7', Key.SPRINT: self.sprint.name}
        self.teh.create_ticket(Type.TASK, props=task_properties)
        
        commitment = TeamController.confirm_commitment_for_sprint(self.env, self.sprint)
        self.assert_equals(7, commitment)
    
    def allowZeroDotFiveStoryPoints(self):
        AgiloConfig(self.env).change_option('rd_points.options', '|0|0.5|1|2|3|5|8|13|20|40|100', section='ticket-custom')
    
    def test_confirm_commitment_can_cope_with_float_story_points(self):
        self.allowZeroDotFiveStoryPoints()
        self.s1[Key.STORY_POINTS] = '0.5'
        self.s1.save_changes('', '')
        TeamController.confirm_commitment_for_sprint(self.env, self.sprint)
    
    def test_store_team_velocity_can_cope_with_float_story_points(self):
        self.allowZeroDotFiveStoryPoints()
        self.s1[Key.STORY_POINTS] = '0.5'
        self.s1.save_changes('', '')
        TeamController.store_team_velocity(self.env, self.sprint, True)
 def _commitment(self, sprint, team):
     cmd = TeamController.GetTeamCommitmentCommand(self.env,
                                                   sprint=sprint,
                                                   team=team)
     commitment = TeamController(self.env).process_command(cmd)
     return commitment
Пример #16
0
 def test_confirm_commitment_can_cope_with_float_story_points(self):
     self.allowZeroDotFiveStoryPoints()
     self.s1[Key.STORY_POINTS] = '0.5'
     self.s1.save_changes('', '')
     TeamController.confirm_commitment_for_sprint(self.env, self.sprint)
Пример #17
0
 def test_store_team_velocity_can_cope_with_float_story_points(self):
     self.allowZeroDotFiveStoryPoints()
     self.s1[Key.STORY_POINTS] = '0.5'
     self.s1.save_changes('', '')
     TeamController.store_team_velocity(self.env, self.sprint, True)
Пример #18
0
 def setUp(self):
     self.super()
     self.tm = TeamModelManager(self.env)
     self.tmm = TeamMemberModelManager(self.env)
     self.controller = TeamController(self.env)
Пример #19
0
 def test_confirm_commitment_can_cope_with_float_story_points(self):
     self.allowZeroDotFiveStoryPoints()
     self.s1[Key.STORY_POINTS] = '0.5'
     self.s1.save_changes('', '')
     TeamController.confirm_commitment_for_sprint(self.env, self.sprint)
Пример #20
0
class TestTeam(AgiloTestCase):
    """Tests for the team model class Team"""
    
    def setUp(self):
        self.super()
        self.tm = TeamModelManager(self.env)
        self.tmm = TeamMemberModelManager(self.env)
        self.controller = TeamController(self.env)
    
    def set_hours_for_day_on_team_member(self, hours, day, team_member):
        calendar = team_member.calendar
        calendar.set_hours_for_day(hours, day)
        calendar.save()
    
    def team_with_no_member(self):
        team = self.tm.create(name="Team#1")
        return team

    def team_with_one_member(self):
        team = self.team_with_no_member()
        member = self._add_member_to_team('Member#1', team)
        return team, member
    
    def team_with_two_members(self):
        team, member1 = self.team_with_one_member()
        member2 = self._add_member_to_team('Member#2', team)
        return team, member1, member2
    
    def _add_member_to_team(self, name, team):
        member = self.tmm.create(name=name, team=team)
        # just to make sure we have  a capacity, 1h/1h for ease of calculating test data
        member.capacity = [9] * 7
        member.save()
        return member
    
    
    def testCapacityHours(self):
        """Test the get_capacity_hours() method"""
        test_team = self.tm.create(name="Team#1")
        self.assert_true(test_team.exists)
        test_members = (self.tmm.create(name="Member#1", team=test_team),
                        self.tmm.create(name="Member#2", team=test_team, 
                                              default_capacity=[4,4,4,0,0,0,0]),
                        self.tmm.create(name="Member#3", team=test_team, 
                                              default_capacity=[0,0,0,2,2,0,0]))
        for tm in test_members:
            self.assert_not_none(tm.team)
            self.assert_equals(test_team, tm.team)
        
        # test the default constructor
        start_date = parse_date("2008-09-08T08:00:00")
        test_sprint =  self.teh.create_sprint(name="TestSprint", start=start_date, 
                                              duration=10)
        
        # test save and restore
        for member in test_members:
            self.assert_true(self.tmm.save(member))
        
        test_sprint.team = test_team
        test_sprint.save()
        
        weekly_hours = (5 * 6) + (4 + 4 + 4) + (2 + 2)
        self.assert_equals(weekly_hours, test_team.capacity().default_hours_of_capacity_per_week())
        
        sprint_hours = 2 * weekly_hours
        actual = test_team.capacity().hourly_capacities_in_sprint(test_sprint)
        capacity = sum(map(lambda each: each.capacity, actual))
        self.assert_almost_equals(sprint_hours, capacity, max_delta=.01)
    
    def testVelocityForSprint(self):
        """Tests the set velocity for a sprint as a team metric"""
        test_team = self.tm.create(name="Team#1")
        self.assert_true(test_team.save())
        self.tmm.create(name="Member#1", team=test_team).save()
        self.tmm.create(name="Member#2", team=test_team).save()
        self.tmm.create(name="Member#3", team=test_team).save()
        sprint = self.teh.create_sprint("TestSprint", team=test_team)
        us1 = self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_POINTS: '5',
                                                             Key.SPRINT: sprint.name})
        us2 = self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_POINTS: '8',
                                                             Key.SPRINT: sprint.name})
        us3 = self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_POINTS: '13',
                                                             Key.SPRINT: sprint.name})
        # we have to use the TeamController here
        cmd_store = TeamController.StoreTeamVelocityCommand(self.env,
                                                            sprint=sprint,
                                                            team=test_team,
                                                            estimated=True)
        self.assert_equals(26, self.controller.process_command(cmd_store))
        # Now close a story and check the actual velocity
        cmd_get = TeamController.GetStoredTeamVelocityCommand(self.env,
                                                              sprint=sprint.name,
                                                              team=test_team,
                                                              estimated=True)
        us3[Key.STATUS] = Status.CLOSED
        us3.save_changes('tester', 'closed US3')
        self.assert_equals(26, self.controller.process_command(cmd_get))
        cmd_store.estimated = False
        self.assert_equals(13, self.controller.process_command(cmd_store))
        cmd_get.estimated = False
        self.assert_equals(13, self.controller.process_command(cmd_get))
    
    def test_team_commitment(self):
        """Tests store and retrieval of the team commitment of a sprint"""
        test_team = self.tm.create(name="Team#1")
        sprint = self.teh.create_sprint("TestSprint", team=test_team)
        self.assert_true(test_team.exists)
        # Set the initial USP/RT ratio to 2
        tm = TeamMetrics(self.env, sprint, test_team)
        tm[Key.RT_USP_RATIO] = 2
        tm.save()
        
        tm1 = self.tmm.create(name="Member#1", team=test_team)
        self.tmm.create(name="Member#2", team=test_team)
        self.tmm.create(name="Member#3", team=test_team)
        us1 = self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_POINTS: '5',
                                                             Key.SPRINT: sprint.name})
        us2 = self.teh.create_ticket(Type.USER_STORY, props={Key.STORY_POINTS: '8',
                                                             Key.SPRINT: sprint.name})
        t1 = self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '12',
                                                      Key.OWNER: tm1.name,
                                                      Key.SPRINT: sprint.name})
        # This task is not explicitly planned for the sprint, but because it is
        # linked should be calculated
        t2 = self.teh.create_ticket(Type.TASK, props={Key.REMAINING_TIME: '8',
                                                      Key.OWNER: tm1.name})
        # Make sure there is a remaining time entry on the first day of the sprint
        RemainingTime(self.env, t1).set_remaining_time(t1[Key.REMAINING_TIME], 
                                                       sprint.start)
        RemainingTime(self.env, t2).set_remaining_time(t2[Key.REMAINING_TIME], 
                                                       sprint.start)
        us1.link_to(t1)
        us1.link_to(t2)
        us2 = self.teh.load_ticket(ticket=us2)
        self.assert_equals(Type.USER_STORY, us2.get_type())
        self.assert_not_none(us2._calculated)
        # check the estimated remaining time for us2
        self.assert_equals(8 * 2, us2[Key.ESTIMATED_REMAINING_TIME])
        
        cmd_class = TeamController.CalculateAndStoreTeamCommitmentCommand
        cmd_store_commitment = cmd_class(self.env, sprint=sprint, team=test_team)
        commitment = TeamController(self.env).process_command(cmd_store_commitment)
        self.assert_equals(12 + 8 * 2, commitment)
        cmd_get_commitment = TeamController.GetTeamCommitmentCommand(self.env,
                                                                     sprint=sprint,
                                                                     team=test_team)
        self.assert_equals(commitment, 
                         self.controller.process_command(cmd_get_commitment))
    
    def test_get_team_metrics_command_returns_none_if_no_team_given(self):
        sprint_without_team = self.teh.create_sprint('FooSprint')
        cmd = TeamController.GetTeamCommitmentCommand(self.env, sprint=sprint_without_team)
        commitment = TeamController(self.env).process_command(cmd)
        self.assert_none(commitment)
    
    def test_can_return_hourly_capacity_on_specific_day(self):
        team, member1, member2 = self.team_with_two_members()
        
        capacities = team.capacity(member1.timezone()).hourly_capacities_for_day(today())
        self.assert_length(10, capacities)
        for capacity in capacities[:-1]:
            self.assert_equals(2, capacity.capacity)
    
    def test_last_entry_of_hourly_capacity_is_zero(self):
        team, member1, member2 = self.team_with_two_members()
        
        capacities = team.capacity(member1.timezone()).hourly_capacities_for_day(today())
        self.assert_equals(0, capacities[-1].capacity)
        
    
    def test_can_return_empty_list_if_no_capacity_is_there(self):
        team, member1, member2 = self.team_with_two_members()
        self.set_hours_for_day_on_team_member(0, today(), member1)
        self.set_hours_for_day_on_team_member(0, today(), member2)
        
        capacities = team.capacity(member1.timezone()).hourly_capacities_for_day(today())
        self.assert_length(0, capacities)
    
    def test_can_combine_different_timezones(self):
        team, member1, member2 = self.team_with_two_members()
        set_user_attribute_in_session(self.env, 'tz', 'GMT', member1.name)
        set_user_attribute_in_session(self.env, 'tz', 'GMT +1:00', member2.name)
        
        capacities = team.capacity(member1.timezone()).hourly_capacities_for_day(today())
        self.assert_length(11, capacities)
        self.assert_equals(1, capacities[0].capacity)
        self.assert_equals(1, capacities[-2].capacity)
    
    def test_can_cut_off_times_that_would_be_on_next_day(self):
        team, member1, member2 = self.team_with_two_members()
        set_user_attribute_in_session(self.env, 'tz', 'GMT', member1.name)
        set_user_attribute_in_session(self.env, 'tz', 'GMT -8:00', member2.name)
        viewer_timezone = member1.timezone()
        self.set_hours_for_day_on_team_member(0, yesterday(viewer_timezone), member2)
        # 15:00 at his place is 23:00 here, so two values should be lost
        
        day = today(tz=member1.timezone())
        capacities = team.capacity(viewer_timezone).hourly_capacities_for_day(day)
        self.assert_length(16, capacities)
        self.assert_equals(1, capacities[0].capacity)
        self.assert_equals(1, capacities[-2].capacity)
        last_hour_of_member1 = datetime.combine(day, time(23, tzinfo=member1.timezone()))
        self.assert_equals(last_hour_of_member1, capacities[-2].when)
    
    def test_cuts_off_times_that_would_be_on_previous_day(self):
        team, member1, member2 = self.team_with_two_members()
        set_user_attribute_in_session(self.env, 'tz', 'GMT', member1.name)
        set_user_attribute_in_session(self.env, 'tz', 'GMT +11:00', member2.name)
        
        viewer_timezone = utc
        # don't want to get values from tomorrow
        self.set_hours_for_day_on_team_member(0, tomorrow(viewer_timezone), member2)
        # 11:00 at his place is 0:00 here, so two values should be lost
        
        capacities = team.capacity(viewer_timezone).hourly_capacities_for_day(today())
        self.assert_length(17, capacities)
        self.assert_equals(1, capacities[0].capacity)
        self.assert_equals(1, capacities[-2].capacity)
        start_of_day_for_member1 = midnight(now(tz=viewer_timezone))
        self.assert_equals(start_of_day_for_member1, capacities[0].when)
    
    def test_cuts_off_times_that_would_be_on_previous_day_for_the_viewer(self):
        team, member1 = self.team_with_one_member()
        set_user_attribute_in_session(self.env, 'tz', 'GMT +11:00', member1.name)
        
        viewer_timezone = utc
        # don't want to get values from tomorrow
        self.set_hours_for_day_on_team_member(0, tomorrow(viewer_timezone), member1)
        # 11:00 at his place is 0:00 here, so two values should be lost
        
        capacities = team.capacity(viewer_timezone).hourly_capacities_for_day(today())
        self.assert_length(8, capacities)
        self.assert_equals(1, capacities[0].capacity)
        self.assert_equals(1, capacities[-2].capacity)
        start_of_day_for_member1 = midnight(now(tz=viewer_timezone))
        self.assert_equals(start_of_day_for_member1, capacities[0].when)
    
    def test_includes_times_from_previous_day_that_get_shifted_to_today_through_the_timezone_difference(self):
        team, member1, member2 = self.team_with_two_members()
        set_user_attribute_in_session(self.env, 'tz', 'GMT', member1.name)
        set_user_attribute_in_session(self.env, 'tz', 'GMT -7:00', member2.name)
        
        day = today(tz=member1.timezone())
        yesterday = day - timedelta(days=1)
        self.set_hours_for_day_on_team_member(9, yesterday, member2)
        # member2s last hour of yesterday should happen on today for member1
        capacities = team.capacity(member1.timezone()).hourly_capacities_for_day(day)
        member1_midnight = datetime.combine(day, time(0, tzinfo=member1.timezone()))
        self.assert_equals(member1_midnight, capacities[0].when)
        self.assert_equals(1, capacities[0].capacity)
    
    def test_includes_times_from_next_day_that_get_shifted_to_today_through_the_timezone_difference(self):
        team, member1, member2 = self.team_with_two_members()
        set_user_attribute_in_session(self.env, 'tz', 'GMT', member1.name)
        set_user_attribute_in_session(self.env, 'tz', 'GMT +10:00', member2.name)
        
        day = today(tz=member1.timezone())
        tomorrow = day + timedelta(days=1)
        self.set_hours_for_day_on_team_member(9, tomorrow, member2)
        # member2s first hour of tomorrow should happen on today for member1
        capacities = team.capacity(member1.timezone()).hourly_capacities_for_day(day)
        member1_last_hour = datetime.combine(day, time(23, tzinfo=member1.timezone()))
        self.assert_equals(member1_last_hour, capacities[-2].when)
        self.assert_equals(1, capacities[-2].capacity)
    
    def test_team_with_capacity_on_every_day_has_no_empty_days(self):
        team, member1 = self.team_with_one_member()
        member1.capacity = [1] * 7
        member1.save()
        start = now() - timedelta(days=7)
        end = now()
        self.assert_length(0, team.capacity().days_without_capacity_in_interval(start, end))
    
    def _create_team_with_weekends_off(self):
        team, member1 = self.team_with_one_member()
        member1.capacity = [1] * 5 + [0, 0]
        member1.save()
        return team
    
    def test_team_not_working_on_weekends_has_no_capacity_on_weekends(self):
        team = self._create_team_with_weekends_off()
        # exactly one week so we're sure that this interval covers two non-working days
        start = now() - timedelta(days=7)
        end = now()
        days_without_capacity = team.capacity().days_without_capacity_in_interval(start, end)
        self.assert_length(2, days_without_capacity)
        self.assert_equals(0, days_without_capacity[0].hour)
        self.assert_equals(0, days_without_capacity[0].minute)
    
    def test_days_without_capacity_respect_given_timestamp(self):
        team = self._create_team_with_weekends_off()
        end = now(utc)
        start = end - timedelta(days=7)
        bangkok_tz = get_timezone('GMT +7:00')
        days_without_capacity = team.capacity(bangkok_tz).days_without_capacity_in_interval(start, end)
        self.assert_equals(bangkok_tz, days_without_capacity[0].tzinfo)
    
    def test_days_without_capacity_include_last_day(self):
        team = self._create_team_with_weekends_off()
        end = datetime(2010, 5, 23, 3, 0, 0, tzinfo=localtz) # sunday
        start = end - timedelta(days=3)
        days_without_capacity = team.capacity().days_without_capacity_in_interval(start, end)
        self.assert_length(2, days_without_capacity)
    
    def _set_default_capacity_for_member(self, default_capacity, member):
        member.capacity = [default_capacity] * 7
        member.save()
    
    def test_can_return_capacity_series_for_interval(self):
        team, member1 = self.team_with_one_member()
        self._set_default_capacity_for_member(1, member1)
        # tomorrow -> date -> 0:00 on date -> removes everything on that day
        self.assert_length(2*9 + 2, team.capacity().hourly_capacities_in_interval(yesterday(), tomorrow()))
    
    def test_return_capacity_information_until_end_of_sprint_even_if_last_values_are_zero(self):
        self.teh.disable_sprint_date_normalization()
        team, member = self.team_with_one_member()
        self._set_default_capacity_for_member(0, member)
        sprint = self.teh.create_sprint('Foo Sprint')
        sprint.start = midnight(yesterday())
        sprint.end = midnight(day_after_tomorrow())
        
        capacities = team.capacity().hourly_capacities_in_sprint(sprint)
        # +1 because the last item is from 22:00-23:00
        self.assert_length(24*3+1, capacities)
    
    def test_can_sum_remaining_capacities_in_sprint(self):
        self.teh.disable_sprint_date_normalization()
        team, member = self.team_with_one_member()
        self._set_default_capacity_for_member(9*2, member)
        
        sprint =  self.teh.create_sprint(name="SprintWithContingent", team=team,
                                         start=midnight(yesterday()), 
                                         end=midnight(tomorrow()))
        summed = team.capacity().summed_hourly_capacities_in_sprint(sprint)
        # 2*9 (no. working hours), +8 (additional hours after zero), +1 (00:00-01:00 on the last day)
        self.assert_length(9*2+8+1, summed)
        self.assert_equals(2*(9*2), summed[0].capacity)
        self.assert_equals(0, summed[-1].capacity)
    
    def test_capacity_can_take_timezone_parameter(self):
        team, member = self.team_with_one_member()
        self._set_default_capacity_for_member(0, member)
        set_user_attribute_in_session(self.env, 'tz', 'GMT', member.name)
        self.set_hours_for_day_on_team_member(9, today(member.timezone()), member)
        
        viewer_timezone = get_timezone('GMT -12:00')
        capacitator = team.capacity(viewer_timezone)
        # Need to take the member timezone for start and end, to make sure that we really cut off all
        # workhours he has on the previous day - even though they would be on the current day when
        # viewed from the viewers timezone.
        hourly_capacities = capacitator.hourly_capacities_in_interval(today(tz=member.timezone()), tomorrow(tz=member.timezone()))
        self.assert_length(7, hourly_capacities)
    
    def test_contingents_are_removed_from_capacity(self):
        team, member = self.team_with_one_member()
        start = parse_date("2008-09-08T08:00:00")
        sprint =  self.teh.create_sprint(name="SprintWithContingent", start=start, duration=10, team=team)
        self.teh.add_contingent_to_sprint('Contingent', 100, sprint)
        self._set_default_capacity_for_member(9, member)
        
        capacities = team.capacity().hourly_capacities_in_sprint(sprint)
        capacity = sum(map(lambda each: each.capacity, capacities))
        self.assert_almost_equals(108 - 100, capacity, max_delta=.01)


    def test_will_contain_second_team_member_after_invalidating(self):
        team, member = self.team_with_one_member()
        self.assert_contains(member, team.members)
        member2 = self._add_member_to_team("member2", team)
        self.assert_not_contains(member2, team.members)
        team.invalidate_team_member_cache()
        self.assert_contains(member2, team.members)

    def test_can_invalidate_empty_cache(self):
        team = self.team_with_no_member()
        team.invalidate_team_member_cache()
        self.assert_length(0, team.members)
Пример #21
0
 def test_get_team_metrics_command_returns_none_if_no_team_given(self):
     sprint_without_team = self.teh.create_sprint('FooSprint')
     cmd = TeamController.GetTeamCommitmentCommand(self.env, sprint=sprint_without_team)
     commitment = TeamController(self.env).process_command(cmd)
     self.assert_none(commitment)
Пример #22
0
 def test_store_team_velocity_can_cope_with_float_story_points(self):
     self.allowZeroDotFiveStoryPoints()
     self.s1[Key.STORY_POINTS] = '0.5'
     self.s1.save_changes('', '')
     TeamController.store_team_velocity(self.env, self.sprint, True)
Пример #23
0
class TeamControllerTest(AgiloTestCase):
    """Tests the TeamController and all the Commands in it"""
    def setUp(self):
        """initalize and environment, and a controller instance"""
        self.super()
        self.controller = TeamController(self.teh.get_env())
        self.sprint = self.teh.create_sprint('TestSprint', team='A-Team')
        self.s1 = self.teh.create_ticket(Type.USER_STORY,
                                         props={
                                             Key.STORY_POINTS: '13',
                                             Key.SPRINT: 'TestSprint'
                                         })
        self.s2 = self.teh.create_ticket(Type.USER_STORY,
                                         props={
                                             Key.STORY_POINTS: '13',
                                             Key.SPRINT: 'TestSprint'
                                         })
        self.s3 = self.teh.create_ticket(Type.USER_STORY,
                                         props={
                                             Key.STORY_POINTS: '13',
                                             Key.SPRINT: 'TestSprint',
                                             Key.STATUS: 'closed'
                                         })

    def testCalculateVelocityCommand(self):
        """Tests the calculate velocity command"""
        cmd_calc_velocity = TeamController.CalculateTeamVelocityCommand(
            self.env, sprint=self.sprint)
        velocity = self.controller.process_command(cmd_calc_velocity)
        # Now velocity is the actual, so should be 13 only the closed story
        self.assert_equals(13, velocity)
        # Now check the estimated velocity, setting estimated to true in the command
        cmd_calc_velocity.estimated = True
        est_velocity = self.controller.process_command(cmd_calc_velocity)
        self.assert_equals(39, est_velocity)

    def testStoreAndRetriveVelocityCommands(self):
        """Tests the store and retrive of the team velocity from the metrics"""
        self.assert_equals('A-Team', self.sprint.team.name)
        cmd_store_velocity = TeamController.StoreTeamVelocityCommand(
            self.env, sprint=self.sprint)
        velocity = self.controller.process_command(cmd_store_velocity)
        self.assert_equals(13, velocity)
        # now check if it has been stored
        cmd_get_velocity = TeamController.GetStoredTeamVelocityCommand(
            self.env, sprint=self.sprint)
        metrics_velocity = self.controller.process_command(cmd_get_velocity)
        self.assert_equals(velocity, metrics_velocity)
        # now the estimated
        cmd_store_velocity.estimated = True
        cmd_get_velocity.estimated = True
        est_velocity = self.controller.process_command(cmd_store_velocity)
        self.assert_equals(39, est_velocity)
        metrics_est_velocity = self.controller.process_command(
            cmd_get_velocity)
        self.assert_equals(est_velocity, metrics_est_velocity)

    def test_summed_capacity_for_team_command_returns_zero_array_if_no_capacity_is_there(
            self):
        """Tests the calculation of the Daily capacity of a team for a Sprint"""
        cmd_daily_capacity = TeamController.CalculateSummedCapacityCommand(
            self.env, sprint=self.sprint)
        capacity = self.controller.process_command(cmd_daily_capacity)
        self.assert_equals(0, capacity)

    def test_can_sum_capacity_for_team(self):
        self.sprints_can_start_and_end_anytime()
        self.sprint.start = datetime(2009, 8, 1, 00, 00, tzinfo=utc)
        self.sprint.end = datetime(2009, 8, 10, 23, 59, tzinfo=utc)
        self.sprint.save()
        self.teh.create_member('Foo', self.sprint.team)

        cmd_daily_capacity = TeamController.CalculateSummedCapacityCommand(
            self.env, sprint=self.sprint, team=self.sprint.team)
        capacity_per_day = self.controller.process_command(cmd_daily_capacity)
        self.assert_almost_equals(36, capacity_per_day, max_delta=.01)

    def test_can_subtract_contingents_from_team_capacity(self):
        self.sprints_can_start_and_end_anytime()
        self.sprint.start = datetime(2009, 8, 1, 00, 00, tzinfo=utc)
        self.sprint.end = datetime(2009, 8, 10, 23, 59, tzinfo=utc)
        self.sprint.save()
        self.teh.create_member('Foo', self.sprint.team)
        self.teh.add_contingent_to_sprint('Bar', 12, self.sprint)

        cmd_daily_capacity = TeamController.CalculateSummedCapacityCommand(
            self.env, sprint=self.sprint, team=self.sprint.team)
        capacity_per_day = self.controller.process_command(cmd_daily_capacity)
        self.assert_almost_equals(36 - 12, capacity_per_day, max_delta=.01)

    def sprints_can_start_and_end_anytime(self):
        config = AgiloConfig(self.env)
        config.change_option('sprints_can_start_or_end_on_weekends',
                             True,
                             section='agilo-general')
        config.save()

    def testGetTeamCommandReturnsMembersAsDict(self):
        team = self.teh.create_team('Testteam')
        self.teh.create_member('foo', team)
        cmd = TeamController.GetTeamCommand(self.env, team=team.name)
        value_team = TeamController(self.env).process_command(cmd)

        members = value_team.members
        self.assert_equals(1, len(members))
        self.assert_true(isinstance(members[0], ValueObject))

    def test_confirm_commitment_uses_current_remaining_time(self):
        self.sprint.start = now() - timedelta(hours=2)
        self.sprint.save()
        task_properties = {
            Key.REMAINING_TIME: '7',
            Key.SPRINT: self.sprint.name
        }
        self.teh.create_ticket(Type.TASK, props=task_properties)

        commitment = TeamController.confirm_commitment_for_sprint(
            self.env, self.sprint)
        self.assert_equals(7, commitment)

    def allowZeroDotFiveStoryPoints(self):
        AgiloConfig(self.env).change_option('rd_points.options',
                                            '|0|0.5|1|2|3|5|8|13|20|40|100',
                                            section='ticket-custom')

    def test_confirm_commitment_can_cope_with_float_story_points(self):
        self.allowZeroDotFiveStoryPoints()
        self.s1[Key.STORY_POINTS] = '0.5'
        self.s1.save_changes('', '')
        TeamController.confirm_commitment_for_sprint(self.env, self.sprint)

    def test_store_team_velocity_can_cope_with_float_story_points(self):
        self.allowZeroDotFiveStoryPoints()
        self.s1[Key.STORY_POINTS] = '0.5'
        self.s1.save_changes('', '')
        TeamController.store_team_velocity(self.env, self.sprint, True)
Пример #24
0
 def get_commitment(self, team, sprint):
     cmd = TeamController.GetTeamCommitmentCommand(self.env,
                                                   sprint=sprint,
                                                   team=team)
     return TeamController(self.env).process_command(cmd)