Merge lp:~bigkevmcd/offspring/add-queue-wait-time into lp:offspring

Proposed by Kevin McDermott
Status: Merged
Merge reported by: Kevin McDermott
Merged at revision: not available
Proposed branch: lp:~bigkevmcd/offspring/add-queue-wait-time
Merge into: lp:offspring
Prerequisite: lp:~bigkevmcd/offspring/add-queue-metrics
Diff against target: 485 lines (+196/-82)
6 files modified
lib/offspring/web/queuemanager/management/commands/build_metrics.py (+2/-1)
lib/offspring/web/queuemanager/management/commands/tests/test_build_metrics.py (+1/-1)
lib/offspring/web/queuemanager/metrics.py (+68/-31)
lib/offspring/web/queuemanager/models.py (+7/-12)
lib/offspring/web/queuemanager/tests/factory.py (+10/-3)
lib/offspring/web/queuemanager/tests/test_metrics.py (+108/-34)
To merge this branch: bzr merge lp:~bigkevmcd/offspring/add-queue-wait-time
Reviewer Review Type Date Requested Status
Guilherme Salgado Approve
Offspring Committers Pending
Review via email: mp+85489@code.launchpad.net

Description of the change

This refactors the metric calculation logic and adds support for the average queue time.

Still to do...non-scheduled builds (involves adding logic to exclude specific types from the reason).

To post a comment you must log in.
119. By Kevin McDermott

Merge forward with changes to automated request lookups.

120. By Kevin McDermott

Update clarified docstring.

121. By Kevin McDermott

Merge forward.

122. By Kevin McDermott

Merge forward.

123. By Kevin McDermott

Update docstring, and removed some unused code.

124. By Kevin McDermott

Merge forward.

125. By Kevin McDermott

Fix command test to reflect new properties.

126. By Kevin McDermott

Merge forward.

127. By Kevin McDermott

Merge forward.

128. By Kevin McDermott

Merge forward.

129. By Kevin McDermott

Merge forward.

130. By Kevin McDermott

Merge trunk.

Revision history for this message
Guilherme Salgado (salgado) wrote :

This looks quite neat! I was hoping there'd be some template tag in Django to convert a timedetal into a human readable string but I couldn't find anything. I guess you've probably searched for one as well before rolling your own?

Also, in a couple places you create a build result using the object factory, set the requested_at/dispatched_at attributes and then save the object again. It'd be nicer if you changed the factory method to take requested_at/dispatched_at as optional arguments to avoid duplicating it in even more places in the future.

review: Approve
131. By Kevin McDermott

Merge trunk.

132. By Kevin McDermott

Update factory.make_build_result to allow started_at/finished_at etc.

Revision history for this message
Kevin McDermott (bigkevmcd) wrote :

> This looks quite neat! I was hoping there'd be some template tag in Django to
> convert a timedetal into a human readable string but I couldn't find anything.
> I guess you've probably searched for one as well before rolling your own?
Yeah...the normal time one doesn't understand timedeltas (I guess it's relatively rare).

> Also, in a couple places you create a build result using the object factory,
> set the requested_at/dispatched_at attributes and then save the object again.
> It'd be nicer if you changed the factory method to take
> requested_at/dispatched_at as optional arguments to avoid duplicating it in
> even more places in the future.

It's a bit icky...but it works...

I added **kwargs because it would just keep growing...if there are specific things we want to check for, then it's good to move them to the list of named args, otherwise...

    def make_build_result(self, project=None, name=None, result=None,
                          builder=None, requestor=None, **kwargs):
        """
        Create a BuildResult with the given project or a newly created one if
        none is given.
        """
        if name is None:
            name = self.get_unique_string()
        if project is None:
            project = self.make_project()
        requested_at = kwargs.pop("requested_at", None)
        build_result = BuildResult.objects.create(
            project=project, name=name, result=result, builder=builder,
            requestor=requestor, **kwargs)
        # requested_at is auto_now_add, so we can't pass it into the object
        # creation function.
        if requested_at:
            build_result.requested_at = requested_at
            build_result.save()
        return build_result

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/offspring/web/queuemanager/management/commands/build_metrics.py'
--- lib/offspring/web/queuemanager/management/commands/build_metrics.py 2011-12-14 07:32:32 +0000
+++ lib/offspring/web/queuemanager/management/commands/build_metrics.py 2012-01-12 08:35:33 +0000
@@ -10,5 +10,6 @@
1010
11 def handle_noargs(self, **options):11 def handle_noargs(self, **options):
12 metrics = get_build_result_metrics()12 metrics = get_build_result_metrics()
13 for item, value in metrics.iteritems():13
14 for item, value in metrics:
14 self.stdout.write("%s = %s\n" % (item, value))15 self.stdout.write("%s = %s\n" % (item, value))
1516
=== modified file 'lib/offspring/web/queuemanager/management/commands/tests/test_build_metrics.py'
--- lib/offspring/web/queuemanager/management/commands/tests/test_build_metrics.py 2011-12-14 08:44:40 +0000
+++ lib/offspring/web/queuemanager/management/commands/tests/test_build_metrics.py 2012-01-12 08:35:33 +0000
@@ -17,7 +17,7 @@
17 """17 """
18 build_result_metrics_mock = self.mocker.replace(get_build_result_metrics)18 build_result_metrics_mock = self.mocker.replace(get_build_result_metrics)
19 build_result_metrics_mock()19 build_result_metrics_mock()
20 self.mocker.result({"Description of value": 200})20 self.mocker.result([("Description of value", 200)])
21 self.mocker.replay()21 self.mocker.replay()
2222
23 command = Command()23 command = Command()
2424
=== modified file 'lib/offspring/web/queuemanager/metrics.py'
--- lib/offspring/web/queuemanager/metrics.py 2011-12-14 17:21:33 +0000
+++ lib/offspring/web/queuemanager/metrics.py 2012-01-12 08:35:33 +0000
@@ -4,13 +4,18 @@
4from offspring.enums import ProjectBuildStates4from offspring.enums import ProjectBuildStates
55
66
7def get_average_build_time(project=None, automated=None, period=None):7def get_average_time(query_params, columns, project=None, automated=None):
8
8 """9 """
9 Return the average time taken between BuildResult.started_at and10 Return the average time between the two named columns.
10 BuildResult.finished_at in seconds for all BuildResults associated with the11
11 provided Project.12 The columns must be listed as the start_time and finish_time for the
1213 metric.
13 If no Project is supplied, average the build times across all projects.14
15 If no Project is supplied, average the times across all projects.
16
17 query_params: A dictionary of Djanqo query filters.
18 columns: Columns to be queried, must be start_time, end_time.
1419
15 project: A Project to filter BuildResults with, if none supplied, will use20 project: A Project to filter BuildResults with, if none supplied, will use
16 all Projects21 all Projects
@@ -23,54 +28,86 @@
23 # don't run using PostgreSQL...28 # don't run using PostgreSQL...
24 # FIXME: This code should migrate to a manager in order to do the heavy29 # FIXME: This code should migrate to a manager in order to do the heavy
25 # lifting https://bugs.launchpad.net/offspring/+bug/90433430 # lifting https://bugs.launchpad.net/offspring/+bug/904334
26 def total_seconds(delta):31 def delta_to_seconds(delta):
27 """32 """
28 Return the total amount of time represented by a timedelta.33 Return the total amount of time represented by a timedelta.
29 """34 """
30 if delta:35 return ((delta.microseconds + (delta.seconds + delta.days
31 return ((delta.microseconds + (delta.seconds + delta.days *36 * 24 * 3600)
32 24 * 3600)37 * 10 ** 6) / 10 ** 6)
33 * 10 ** 6) / 10 ** 6)
34 else:
35 return 0.0
36
37 query_params = {"finished_at__isnull": False,
38 "result__exact": ProjectBuildStates.SUCCESS}
39 if project is not None:38 if project is not None:
40 query_params["project"] = project39 query_params["project"] = project
4140
42 if automated is not None:41 if automated is not None:
43 query_params["requestor__isnull"] = automated42 query_params["requestor__isnull"] = automated
44 if period is not None:
45 query_params["finished_at__range"] = period
46
47 build_results = BuildResult.objects.filter(**query_params)43 build_results = BuildResult.objects.filter(**query_params)
48 time_stamps = build_results.values_list("started_at", "finished_at")44 time_stamps = build_results.values_list(*columns)
49 if not time_stamps:45 if not time_stamps:
50 return 0.046 return 0.0
51 times = [total_seconds(finished_at - started_at)47 times = [delta_to_seconds(end_time - start_time)
52 for (started_at, finished_at) in time_stamps]48 for (start_time, end_time) in time_stamps]
53 return float(sum(times)) / len(time_stamps)49 return float(sum(times)) / len(time_stamps)
5450
5551
52def get_average_build_time(project=None, automated=None, period=None):
53 """
54 Return the average time taken between BuildResult.started_at and
55 BuildResult.finished_at in seconds for all BuildResults associated with the
56 provided Project.
57
58 period: A tuple of datetime objects (start_time, end_time)
59
60 See get_average_time for the project and automated parameters.
61 """
62 query_params = {"finished_at__isnull": False,
63 "result__exact": ProjectBuildStates.SUCCESS}
64 if period is not None:
65 query_params["finished_at__range"] = period
66 return get_average_time(query_params, ("started_at", "finished_at"),
67 project=project, automated=automated)
68
69
70def get_average_queue_time(project=None, automated=None, period=None):
71 """
72 Return the average time taken between BuildResult.requested_at and
73 BuildResult.dispatched_at in seconds for all BuildResults associated with the
74 provided Project.
75
76 period: A tuple of datetime objects (start_time, end_time)
77
78 See get_average_time for the project and automated parameters.
79 """
80 query_params = {}
81 if period is not None:
82 query_params["dispatched_at__range"] = period
83 return get_average_time(query_params, ("requested_at", "dispatched_at"),
84 project=project, automated=automated)
85
86
56def get_build_result_metrics():87def get_build_result_metrics():
57 """88 """
58 Return some simple metrics, in a format suitable for iterating over and89 Return some simple metrics, in a format suitable for iterating over and
59 displaying in a command-line tool.90 displaying in a command-line tool.
60 """91 """
61 results = {}92 results = []
62 start_date = datetime.utcnow()93 start_date = datetime.utcnow()
6394
64 seven_days = (start_date - timedelta(days=7), start_date)95 seven_days = (start_date - timedelta(days=7), start_date)
65 results["Average scheduled build time (7 days)"] = get_average_build_time(
66 period=seven_days, automated=True)
67
68 thirty_days = (start_date - timedelta(days=30), start_date)96 thirty_days = (start_date - timedelta(days=30), start_date)
69 results["Average scheduled build time (30 days)"] = get_average_build_time(
70 period=thirty_days, automated=True)
71
72 ninety_days = (start_date - timedelta(days=90), start_date)97 ninety_days = (start_date - timedelta(days=90), start_date)
73 results["Average scheduled build time (90 days)"] = get_average_build_time(98
74 period=ninety_days, automated=True)99
100 results.append(("Average scheduled build time (7 days)",
101 get_average_build_time(period=seven_days, automated=True)))
102 results.append(("Average scheduled build time (30 days)",
103 get_average_build_time(period=thirty_days, automated=True)))
104 results.append(("Average scheduled build time (90 days)",
105 get_average_build_time(period=ninety_days, automated=True)))
106 results.append(("Average scheduled queue time (7 days)",
107 get_average_queue_time(period=seven_days, automated=True)))
108 results.append(("Average scheduled queue time (30 days)",
109 get_average_queue_time(period=thirty_days, automated=True)))
110 results.append(("Average scheduled queue time (90 days)",
111 get_average_queue_time(period=ninety_days, automated=True)))
75112
76 return results113 return results
77114
=== modified file 'lib/offspring/web/queuemanager/models.py'
--- lib/offspring/web/queuemanager/models.py 2011-12-14 14:44:27 +0000
+++ lib/offspring/web/queuemanager/models.py 2012-01-12 08:35:33 +0000
@@ -1,17 +1,8 @@
1# Copyright 2010 Canonical Ltd. This software is licensed under the1# Copyright 2010 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4__all__ = ["Project", "ProjectGroup", "Lexbuilder", "BuildRequest",
5 "BuildResult", "DailyBuildOrder", "LaunchpadProject",
6 "LaunchpadProjectMilestone", "ProjectNotificationSubscription",
7 "Release"]
8
9from datetime import (
10 date,
11 datetime,
12 timedelta
13)
14import math4import math
5from datetime import date, datetime, timedelta
156
16from django.contrib.auth.models import AnonymousUser, User7from django.contrib.auth.models import AnonymousUser, User
17from django.db import (8from django.db import (
@@ -26,6 +17,10 @@
26from offspring.config import get_configuration17from offspring.config import get_configuration
27from offspring.enums import ProjectBuildStates18from offspring.enums import ProjectBuildStates
2819
20__all__ = ["Project", "ProjectGroup", "Lexbuilder", "BuildRequest",
21 "BuildResult", "DailyBuildOrder", "LaunchpadProject",
22 "LaunchpadProjectMilestone", "ProjectNotificationSubscription",
23 "Release"]
2924
30config = get_configuration()25config = get_configuration()
3126
@@ -85,7 +80,7 @@
85 project_group=self)80 project_group=self)
8681
87 @property82 @property
88 def builder(self): 83 def builder(self):
89 return None84 return None
9085
91 @property86 @property
@@ -389,7 +384,7 @@
389 requestor = models.ForeignKey(User, db_column="requestor_id", blank=True, null=True, editable=False)384 requestor = models.ForeignKey(User, db_column="requestor_id", blank=True, null=True, editable=False)
390 reason = models.CharField('request reason', blank=True, null=True, max_length=200, editable=False)385 reason = models.CharField('request reason', blank=True, null=True, max_length=200, editable=False)
391 requested_at = models.DateTimeField('date created', auto_now_add=True, blank=True, null=True, editable=False)386 requested_at = models.DateTimeField('date created', auto_now_add=True, blank=True, null=True, editable=False)
392 dispatched_at = models.DateTimeField('date dispatched', editable=False, null=True, blank=True) 387 dispatched_at = models.DateTimeField('date dispatched', editable=False, null=True, blank=True)
393 notes = models.CharField(max_length=200, null=True, blank=True)388 notes = models.CharField(max_length=200, null=True, blank=True)
394389
395 access_relation = 'project'390 access_relation = 'project'
396391
=== modified file 'lib/offspring/web/queuemanager/tests/factory.py'
--- lib/offspring/web/queuemanager/tests/factory.py 2011-12-16 10:08:55 +0000
+++ lib/offspring/web/queuemanager/tests/factory.py 2012-01-12 08:35:33 +0000
@@ -73,7 +73,7 @@
73 return ProjectGroup.objects.create(name=name, title=title)73 return ProjectGroup.objects.create(name=name, title=title)
7474
75 def make_build_result(self, project=None, name=None, result=None,75 def make_build_result(self, project=None, name=None, result=None,
76 builder=None, requestor=None):76 builder=None, requestor=None, **kwargs):
77 """77 """
78 Create a BuildResult with the given project or a newly created one if78 Create a BuildResult with the given project or a newly created one if
79 none is given.79 none is given.
@@ -82,9 +82,16 @@
82 name = self.get_unique_string()82 name = self.get_unique_string()
83 if project is None:83 if project is None:
84 project = self.make_project()84 project = self.make_project()
85 return BuildResult.objects.create(85 requested_at = kwargs.pop("requested_at", None)
86 build_result = BuildResult.objects.create(
86 project=project, name=name, result=result, builder=builder,87 project=project, name=name, result=result, builder=builder,
87 requestor=requestor)88 requestor=requestor, **kwargs)
89 # requested_at is auto_now_add, so we can't pass it into the object
90 # creation function.
91 if requested_at:
92 build_result.requested_at = requested_at
93 build_result.save()
94 return build_result
8895
89 def make_release(self, build=None, name=None, creator=None):96 def make_release(self, build=None, name=None, creator=None):
90 """97 """
9198
=== modified file 'lib/offspring/web/queuemanager/tests/test_metrics.py'
--- lib/offspring/web/queuemanager/tests/test_metrics.py 2011-12-14 17:38:39 +0000
+++ lib/offspring/web/queuemanager/tests/test_metrics.py 2012-01-12 08:35:33 +0000
@@ -5,7 +5,8 @@
5from offspring.enums import ProjectBuildStates5from offspring.enums import ProjectBuildStates
6from offspring.web.queuemanager.models import User6from offspring.web.queuemanager.models import User
7from offspring.web.queuemanager.metrics import (7from offspring.web.queuemanager.metrics import (
8 get_average_build_time, get_build_result_metrics)8 get_average_build_time, get_average_queue_time,
9 get_build_result_metrics)
910
10from offspring.web.queuemanager.tests.factory import factory11from offspring.web.queuemanager.tests.factory import factory
1112
@@ -23,10 +24,25 @@
23 finished_at = datetime.combine(build_date, time())24 finished_at = datetime.combine(build_date, time())
24 for minutes in durations:25 for minutes in durations:
25 build_result = factory.make_build_result(26 build_result = factory.make_build_result(
26 project=project, requestor=requestor, result=result)27 project=project, requestor=requestor, result=result,
27 build_result.finished_at = finished_at28 started_at=finished_at - timedelta(minutes=minutes),
28 build_result.started_at = finished_at - timedelta(minutes=minutes)29 finished_at=finished_at)
29 build_result.save()30
31
32def create_build_results_with_queue_times(project, queue_times, requestor=None,
33 build_date=date.today()):
34 """
35 Create BuildResults with queue times specified.
36
37 project: The Project to associate the BuildResults with.
38 queue_times: A sequence of time periods in minutes.
39 """
40 dispatched_at = datetime.combine(build_date, time())
41 for minutes in queue_times:
42 build_result = factory.make_build_result(
43 project=project, requestor=requestor,
44 requested_at=dispatched_at - timedelta(minutes=minutes),
45 dispatched_at=dispatched_at)
3046
3147
32class BuildResultMetricsTests(TestCase):48class BuildResultMetricsTests(TestCase):
@@ -39,13 +55,12 @@
39 get_average_build_time should return the average time taken to build a55 get_average_build_time should return the average time taken to build a
40 project.56 project.
41 """57 """
58 finished_at = datetime.utcnow()
42 build_result = factory.make_build_result(59 build_result = factory.make_build_result(
43 project=self.project, result=ProjectBuildStates.SUCCESS)60 project=self.project, result=ProjectBuildStates.SUCCESS,
44 finished_at = datetime.now()61 finished_at=finished_at,
45 build_result.finished_at = finished_at62 started_at=finished_at - timedelta(minutes=10))
46 build_result.started_at = finished_at - timedelta(minutes=10)63 self.assertEqual(10*60, get_average_build_time(self.project))
47 build_result.save()
48 self.assertEqual(600, get_average_build_time(self.project))
4964
50 def test_get_average_build_time_only_includes_completed_builds(self):65 def test_get_average_build_time_only_includes_completed_builds(self):
51 """66 """
@@ -72,9 +87,9 @@
72 If a build has started, but not yet finished, this we should get 0.087 If a build has started, but not yet finished, this we should get 0.0
73 for the average for this entry.88 for the average for this entry.
74 """89 """
75 build_result = factory.make_build_result(project=self.project)90 started_at = datetime.utcnow() - timedelta(minutes=20)
76 build_result.started_at = datetime.now() - timedelta(minutes=20)91 build_result = factory.make_build_result(project=self.project,
77 build_result.save()92 started_at=started_at)
78 self.assertEqual(0.0, get_average_build_time(self.project))93 self.assertEqual(0.0, get_average_build_time(self.project))
7994
80 def test_get_average_build_time_multiple_builds(self):95 def test_get_average_build_time_multiple_builds(self):
@@ -82,7 +97,7 @@
82 The time for each BuildResult should be averaged together.97 The time for each BuildResult should be averaged together.
83 """98 """
84 create_build_results_with_durations(self.project, [10, 20])99 create_build_results_with_durations(self.project, [10, 20])
85 self.assertEqual(15 * 60.0, get_average_build_time(self.project))100 self.assertEqual(15*60, get_average_build_time(self.project))
86101
87 def test_get_average_build_time_multiple_builds_ignores_unfinished(self):102 def test_get_average_build_time_multiple_builds_ignores_unfinished(self):
88 """103 """
@@ -91,11 +106,11 @@
91 create_build_results_with_durations(self.project, [10, 20])106 create_build_results_with_durations(self.project, [10, 20])
92107
93 # Create an additional unfinished build.108 # Create an additional unfinished build.
94 build_result = factory.make_build_result(project=self.project)109 started_at = datetime.utcnow() - timedelta(minutes=20)
95 build_result.started_at = datetime.now() - timedelta(minutes=20)110 build_result = factory.make_build_result(project=self.project,
96 build_result.save()111 started_at=started_at)
97112
98 self.assertEqual(15 * 60.0, get_average_build_time(self.project))113 self.assertEqual(15*60, get_average_build_time(self.project))
99114
100 def test_get_average_build_time_ignores_other_projects(self):115 def test_get_average_build_time_ignores_other_projects(self):
101 """116 """
@@ -104,8 +119,7 @@
104 """119 """
105 create_build_results_with_durations(self.project, [10, 20])120 create_build_results_with_durations(self.project, [10, 20])
106 create_build_results_with_durations(factory.make_project(), [50, 100])121 create_build_results_with_durations(factory.make_project(), [50, 100])
107122 self.assertEqual(15*60, get_average_build_time(self.project))
108 self.assertEqual(15 * 60.0, get_average_build_time(self.project))
109123
110 def test_get_average_build_time_no_project(self):124 def test_get_average_build_time_no_project(self):
111 """125 """
@@ -116,7 +130,7 @@
116 create_build_results_with_durations(130 create_build_results_with_durations(
117 factory.make_project(), [50, 100])131 factory.make_project(), [50, 100])
118 # 10 + 20 + 50 + 100 = 180 / 4 = 45 minutes...132 # 10 + 20 + 50 + 100 = 180 / 4 = 45 minutes...
119 self.assertEqual(45 * 60.0, get_average_build_time())133 self.assertEqual(45*60, get_average_build_time())
120134
121 def test_get_average_build_time_with_automated_flag(self):135 def test_get_average_build_time_with_automated_flag(self):
122 """136 """
@@ -168,8 +182,7 @@
168182
169 # From the day after we create our builds 'til today.183 # From the day after we create our builds 'til today.
170 time_period = (build_date + timedelta(days=1), datetime.utcnow())184 time_period = (build_date + timedelta(days=1), datetime.utcnow())
171 self.assertEqual(75 * 60.0,185 self.assertEqual(75*60, get_average_build_time(period=time_period))
172 get_average_build_time(period=time_period))
173186
174 def test_get_average_build_time_filters_by_date_and_automated(self):187 def test_get_average_build_time_filters_by_date_and_automated(self):
175 """188 """
@@ -189,34 +202,95 @@
189202
190 # From the day after we create our builds 'til today.203 # From the day after we create our builds 'til today.
191 time_period = (build_date + timedelta(days=1), datetime.utcnow())204 time_period = (build_date + timedelta(days=1), datetime.utcnow())
192 self.assertEqual(40 * 60.0,205 self.assertEqual(40*60,
193 get_average_build_time(period=time_period,206 get_average_build_time(period=time_period,
194 automated=True))207 automated=True))
195208
209
210class QueueTimeMetricsTests(TestCase):
211
212 def setUp(self):
213 self.project = factory.make_project()
214
215 def test_average_queue_time_single_build(self):
216 """
217 get_average_queue_time should return the average time a build waits
218 before being dispatched.
219 """
220 dispatched_at = datetime.utcnow()
221 build_result = factory.make_build_result(
222 project=self.project, dispatched_at=dispatched_at,
223 requested_at=dispatched_at - timedelta(minutes=30))
224 self.assertEqual(30*60, get_average_queue_time(self.project))
225
226 def test_average_queue_time_no_builds(self):
227 """
228 If there are no builds, we should get an average of 0.0.
229 """
230 self.assertEqual(0.0*60, get_average_queue_time(self.project))
231
232 def test_average_queue_time_includes_by_date(self):
233 """
234 It should be possible to restrict the date queried to a specific time
235 frame, specifying a period should only include those BuildResults
236 within that period.
237 """
238 build_date = datetime.utcnow() - timedelta(days=30)
239 create_build_results_with_queue_times(
240 self.project, [10, 20], build_date=build_date)
241
242 create_build_results_with_queue_times(
243 factory.make_project(), [50, 100],
244 build_date=build_date + timedelta(days=2))
245
246 # From the day after we create our builds 'til today.
247 time_period = (build_date + timedelta(days=1), datetime.utcnow())
248 self.assertEqual(75*60,
249 get_average_queue_time(period=time_period))
250
251
252class GetBuildResultsTests(TestCase):
253
254 def setUp(self):
255 self.project = factory.make_project()
256
196 def test_get_build_result_metrics(self):257 def test_get_build_result_metrics(self):
197 """258 """
198 get_build_result_metrics should return a dictionary with the following:259 get_build_result_metrics should return a list of tuples with the metric
199260 being measured, and the time in minutes.
200 "Average scheduled build time (7 days)": value,
201 "Average scheduled build time (30 days)": value,
202 "Average scheduled build time (90 days)": value
203 """261 """
204 start_date = datetime.utcnow()262 start_date = datetime.utcnow()
205 # Two this week, average = 10 + 20/2 = 15263 # Two this week, average = 10 + 20/2 = 15
206 create_build_results_with_durations(264 create_build_results_with_durations(
207 self.project, [10, 20], build_date=start_date)265 self.project, [10, 20], build_date=start_date)
208266
267 # Two this week, average = 30 + 18/2 = 24.0
268 create_build_results_with_queue_times(
269 self.project, [30, 18], build_date=start_date)
270
209 last_week = start_date - timedelta(days=8)271 last_week = start_date - timedelta(days=8)
210 # Two last week, 10 + 10 + 10 + 20/4 = 12.5272 # Two last week, 10 + 10 + 10 + 20/4 = 12.5
211 create_build_results_with_durations(273 create_build_results_with_durations(
212 self.project, [10, 10], build_date=last_week)274 self.project, [10, 10], build_date=last_week)
213275
276 # Two last week, average = 30 + 18 + 14 11/4 = 73
277 create_build_results_with_queue_times(
278 self.project, [14, 11], build_date=last_week)
279
214 last_month = start_date - timedelta(days=35)280 last_month = start_date - timedelta(days=35)
215 # Two last month, 10 + 10 + 10 + 20 + 30 + 40/6 = 20281 # Two last month, 10 + 10 + 10 + 20 + 30 + 40/6 = 20
216 create_build_results_with_durations(282 create_build_results_with_durations(
217 self.project, [30, 40], build_date=last_month)283 self.project, [30, 40], build_date=last_month)
218284
219 self.assertEqual({"Average scheduled build time (7 days)": 900,285 # Two last month, average = 30 + 18 + 14 11 + 30 + 20/6 = 82
220 "Average scheduled build time (30 days)": 750,286 create_build_results_with_queue_times(
221 "Average scheduled build time (90 days)": 1200},287 self.project, [30, 20], build_date=last_month)
222 get_build_result_metrics())288
289 self.assertEqual(
290 [("Average scheduled build time (7 days)", 15.0*60),
291 ("Average scheduled build time (30 days)", 12.5*60),
292 ("Average scheduled build time (90 days)", 20.0*60),
293 ("Average scheduled queue time (7 days)", 24.0*60),
294 ("Average scheduled queue time (30 days)", 18.25*60),
295 ("Average scheduled queue time (90 days)", 20.5*60)],
296 get_build_result_metrics())

Subscribers

People subscribed via source and target branches