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)
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)
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)