Merge lp:~bigkevmcd/offspring/add-queue-wait-time into lp:offspring
- add-queue-wait-time
- Merge into trunk
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 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Guilherme Salgado | Approve | ||
Offspring Committers | Pending | ||
Review via email: mp+85489@code.launchpad.net |
Commit message
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).
- 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.
- 131. By Kevin McDermott
-
Merge trunk.
- 132. By Kevin McDermott
-
Update factory.
make_build_ result to allow started_ at/finished_ at etc.
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_
> It'd be nicer if you changed the factory method to take
> requested_
> 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_
"""
Create a BuildResult with the given project or a newly created one if
none is given.
"""
if name is None:
name = self.get_
if project is None:
project = self.make_project()
# requested_at is auto_now_add, so we can't pass it into the object
# creation function.
if requested_at:
return build_result
Preview Diff
1 | === modified file 'lib/offspring/web/queuemanager/management/commands/build_metrics.py' |
2 | --- lib/offspring/web/queuemanager/management/commands/build_metrics.py 2011-12-14 07:32:32 +0000 |
3 | +++ lib/offspring/web/queuemanager/management/commands/build_metrics.py 2012-01-12 08:35:33 +0000 |
4 | @@ -10,5 +10,6 @@ |
5 | |
6 | def handle_noargs(self, **options): |
7 | metrics = get_build_result_metrics() |
8 | - for item, value in metrics.iteritems(): |
9 | + |
10 | + for item, value in metrics: |
11 | self.stdout.write("%s = %s\n" % (item, value)) |
12 | |
13 | === modified file 'lib/offspring/web/queuemanager/management/commands/tests/test_build_metrics.py' |
14 | --- lib/offspring/web/queuemanager/management/commands/tests/test_build_metrics.py 2011-12-14 08:44:40 +0000 |
15 | +++ lib/offspring/web/queuemanager/management/commands/tests/test_build_metrics.py 2012-01-12 08:35:33 +0000 |
16 | @@ -17,7 +17,7 @@ |
17 | """ |
18 | build_result_metrics_mock = self.mocker.replace(get_build_result_metrics) |
19 | build_result_metrics_mock() |
20 | - self.mocker.result({"Description of value": 200}) |
21 | + self.mocker.result([("Description of value", 200)]) |
22 | self.mocker.replay() |
23 | |
24 | command = Command() |
25 | |
26 | === modified file 'lib/offspring/web/queuemanager/metrics.py' |
27 | --- lib/offspring/web/queuemanager/metrics.py 2011-12-14 17:21:33 +0000 |
28 | +++ lib/offspring/web/queuemanager/metrics.py 2012-01-12 08:35:33 +0000 |
29 | @@ -4,13 +4,18 @@ |
30 | from offspring.enums import ProjectBuildStates |
31 | |
32 | |
33 | -def get_average_build_time(project=None, automated=None, period=None): |
34 | +def get_average_time(query_params, columns, project=None, automated=None): |
35 | + |
36 | """ |
37 | - Return the average time taken between BuildResult.started_at and |
38 | - BuildResult.finished_at in seconds for all BuildResults associated with the |
39 | - provided Project. |
40 | - |
41 | - If no Project is supplied, average the build times across all projects. |
42 | + Return the average time between the two named columns. |
43 | + |
44 | + The columns must be listed as the start_time and finish_time for the |
45 | + metric. |
46 | + |
47 | + If no Project is supplied, average the times across all projects. |
48 | + |
49 | + query_params: A dictionary of Djanqo query filters. |
50 | + columns: Columns to be queried, must be start_time, end_time. |
51 | |
52 | project: A Project to filter BuildResults with, if none supplied, will use |
53 | all Projects |
54 | @@ -23,54 +28,86 @@ |
55 | # don't run using PostgreSQL... |
56 | # FIXME: This code should migrate to a manager in order to do the heavy |
57 | # lifting https://bugs.launchpad.net/offspring/+bug/904334 |
58 | - def total_seconds(delta): |
59 | + def delta_to_seconds(delta): |
60 | """ |
61 | Return the total amount of time represented by a timedelta. |
62 | """ |
63 | - if delta: |
64 | - return ((delta.microseconds + (delta.seconds + delta.days * |
65 | - 24 * 3600) |
66 | - * 10 ** 6) / 10 ** 6) |
67 | - else: |
68 | - return 0.0 |
69 | - |
70 | - query_params = {"finished_at__isnull": False, |
71 | - "result__exact": ProjectBuildStates.SUCCESS} |
72 | + return ((delta.microseconds + (delta.seconds + delta.days |
73 | + * 24 * 3600) |
74 | + * 10 ** 6) / 10 ** 6) |
75 | if project is not None: |
76 | query_params["project"] = project |
77 | |
78 | if automated is not None: |
79 | query_params["requestor__isnull"] = automated |
80 | - if period is not None: |
81 | - query_params["finished_at__range"] = period |
82 | - |
83 | build_results = BuildResult.objects.filter(**query_params) |
84 | - time_stamps = build_results.values_list("started_at", "finished_at") |
85 | + time_stamps = build_results.values_list(*columns) |
86 | if not time_stamps: |
87 | return 0.0 |
88 | - times = [total_seconds(finished_at - started_at) |
89 | - for (started_at, finished_at) in time_stamps] |
90 | + times = [delta_to_seconds(end_time - start_time) |
91 | + for (start_time, end_time) in time_stamps] |
92 | return float(sum(times)) / len(time_stamps) |
93 | |
94 | |
95 | +def get_average_build_time(project=None, automated=None, period=None): |
96 | + """ |
97 | + Return the average time taken between BuildResult.started_at and |
98 | + BuildResult.finished_at in seconds for all BuildResults associated with the |
99 | + provided Project. |
100 | + |
101 | + period: A tuple of datetime objects (start_time, end_time) |
102 | + |
103 | + See get_average_time for the project and automated parameters. |
104 | + """ |
105 | + query_params = {"finished_at__isnull": False, |
106 | + "result__exact": ProjectBuildStates.SUCCESS} |
107 | + if period is not None: |
108 | + query_params["finished_at__range"] = period |
109 | + return get_average_time(query_params, ("started_at", "finished_at"), |
110 | + project=project, automated=automated) |
111 | + |
112 | + |
113 | +def get_average_queue_time(project=None, automated=None, period=None): |
114 | + """ |
115 | + Return the average time taken between BuildResult.requested_at and |
116 | + BuildResult.dispatched_at in seconds for all BuildResults associated with the |
117 | + provided Project. |
118 | + |
119 | + period: A tuple of datetime objects (start_time, end_time) |
120 | + |
121 | + See get_average_time for the project and automated parameters. |
122 | + """ |
123 | + query_params = {} |
124 | + if period is not None: |
125 | + query_params["dispatched_at__range"] = period |
126 | + return get_average_time(query_params, ("requested_at", "dispatched_at"), |
127 | + project=project, automated=automated) |
128 | + |
129 | + |
130 | def get_build_result_metrics(): |
131 | """ |
132 | Return some simple metrics, in a format suitable for iterating over and |
133 | displaying in a command-line tool. |
134 | """ |
135 | - results = {} |
136 | + results = [] |
137 | start_date = datetime.utcnow() |
138 | |
139 | seven_days = (start_date - timedelta(days=7), start_date) |
140 | - results["Average scheduled build time (7 days)"] = get_average_build_time( |
141 | - period=seven_days, automated=True) |
142 | - |
143 | thirty_days = (start_date - timedelta(days=30), start_date) |
144 | - results["Average scheduled build time (30 days)"] = get_average_build_time( |
145 | - period=thirty_days, automated=True) |
146 | - |
147 | ninety_days = (start_date - timedelta(days=90), start_date) |
148 | - results["Average scheduled build time (90 days)"] = get_average_build_time( |
149 | - period=ninety_days, automated=True) |
150 | + |
151 | + |
152 | + results.append(("Average scheduled build time (7 days)", |
153 | + get_average_build_time(period=seven_days, automated=True))) |
154 | + results.append(("Average scheduled build time (30 days)", |
155 | + get_average_build_time(period=thirty_days, automated=True))) |
156 | + results.append(("Average scheduled build time (90 days)", |
157 | + get_average_build_time(period=ninety_days, automated=True))) |
158 | + results.append(("Average scheduled queue time (7 days)", |
159 | + get_average_queue_time(period=seven_days, automated=True))) |
160 | + results.append(("Average scheduled queue time (30 days)", |
161 | + get_average_queue_time(period=thirty_days, automated=True))) |
162 | + results.append(("Average scheduled queue time (90 days)", |
163 | + get_average_queue_time(period=ninety_days, automated=True))) |
164 | |
165 | return results |
166 | |
167 | === modified file 'lib/offspring/web/queuemanager/models.py' |
168 | --- lib/offspring/web/queuemanager/models.py 2011-12-14 14:44:27 +0000 |
169 | +++ lib/offspring/web/queuemanager/models.py 2012-01-12 08:35:33 +0000 |
170 | @@ -1,17 +1,8 @@ |
171 | # Copyright 2010 Canonical Ltd. This software is licensed under the |
172 | # GNU Affero General Public License version 3 (see the file LICENSE). |
173 | |
174 | -__all__ = ["Project", "ProjectGroup", "Lexbuilder", "BuildRequest", |
175 | - "BuildResult", "DailyBuildOrder", "LaunchpadProject", |
176 | - "LaunchpadProjectMilestone", "ProjectNotificationSubscription", |
177 | - "Release"] |
178 | - |
179 | -from datetime import ( |
180 | - date, |
181 | - datetime, |
182 | - timedelta |
183 | -) |
184 | import math |
185 | +from datetime import date, datetime, timedelta |
186 | |
187 | from django.contrib.auth.models import AnonymousUser, User |
188 | from django.db import ( |
189 | @@ -26,6 +17,10 @@ |
190 | from offspring.config import get_configuration |
191 | from offspring.enums import ProjectBuildStates |
192 | |
193 | +__all__ = ["Project", "ProjectGroup", "Lexbuilder", "BuildRequest", |
194 | + "BuildResult", "DailyBuildOrder", "LaunchpadProject", |
195 | + "LaunchpadProjectMilestone", "ProjectNotificationSubscription", |
196 | + "Release"] |
197 | |
198 | config = get_configuration() |
199 | |
200 | @@ -85,7 +80,7 @@ |
201 | project_group=self) |
202 | |
203 | @property |
204 | - def builder(self): |
205 | + def builder(self): |
206 | return None |
207 | |
208 | @property |
209 | @@ -389,7 +384,7 @@ |
210 | requestor = models.ForeignKey(User, db_column="requestor_id", blank=True, null=True, editable=False) |
211 | reason = models.CharField('request reason', blank=True, null=True, max_length=200, editable=False) |
212 | requested_at = models.DateTimeField('date created', auto_now_add=True, blank=True, null=True, editable=False) |
213 | - dispatched_at = models.DateTimeField('date dispatched', editable=False, null=True, blank=True) |
214 | + dispatched_at = models.DateTimeField('date dispatched', editable=False, null=True, blank=True) |
215 | notes = models.CharField(max_length=200, null=True, blank=True) |
216 | |
217 | access_relation = 'project' |
218 | |
219 | === modified file 'lib/offspring/web/queuemanager/tests/factory.py' |
220 | --- lib/offspring/web/queuemanager/tests/factory.py 2011-12-16 10:08:55 +0000 |
221 | +++ lib/offspring/web/queuemanager/tests/factory.py 2012-01-12 08:35:33 +0000 |
222 | @@ -73,7 +73,7 @@ |
223 | return ProjectGroup.objects.create(name=name, title=title) |
224 | |
225 | def make_build_result(self, project=None, name=None, result=None, |
226 | - builder=None, requestor=None): |
227 | + builder=None, requestor=None, **kwargs): |
228 | """ |
229 | Create a BuildResult with the given project or a newly created one if |
230 | none is given. |
231 | @@ -82,9 +82,16 @@ |
232 | name = self.get_unique_string() |
233 | if project is None: |
234 | project = self.make_project() |
235 | - return BuildResult.objects.create( |
236 | + requested_at = kwargs.pop("requested_at", None) |
237 | + build_result = BuildResult.objects.create( |
238 | project=project, name=name, result=result, builder=builder, |
239 | - requestor=requestor) |
240 | + requestor=requestor, **kwargs) |
241 | + # requested_at is auto_now_add, so we can't pass it into the object |
242 | + # creation function. |
243 | + if requested_at: |
244 | + build_result.requested_at = requested_at |
245 | + build_result.save() |
246 | + return build_result |
247 | |
248 | def make_release(self, build=None, name=None, creator=None): |
249 | """ |
250 | |
251 | === modified file 'lib/offspring/web/queuemanager/tests/test_metrics.py' |
252 | --- lib/offspring/web/queuemanager/tests/test_metrics.py 2011-12-14 17:38:39 +0000 |
253 | +++ lib/offspring/web/queuemanager/tests/test_metrics.py 2012-01-12 08:35:33 +0000 |
254 | @@ -5,7 +5,8 @@ |
255 | from offspring.enums import ProjectBuildStates |
256 | from offspring.web.queuemanager.models import User |
257 | from offspring.web.queuemanager.metrics import ( |
258 | - get_average_build_time, get_build_result_metrics) |
259 | + get_average_build_time, get_average_queue_time, |
260 | + get_build_result_metrics) |
261 | |
262 | from offspring.web.queuemanager.tests.factory import factory |
263 | |
264 | @@ -23,10 +24,25 @@ |
265 | finished_at = datetime.combine(build_date, time()) |
266 | for minutes in durations: |
267 | build_result = factory.make_build_result( |
268 | - project=project, requestor=requestor, result=result) |
269 | - build_result.finished_at = finished_at |
270 | - build_result.started_at = finished_at - timedelta(minutes=minutes) |
271 | - build_result.save() |
272 | + project=project, requestor=requestor, result=result, |
273 | + started_at=finished_at - timedelta(minutes=minutes), |
274 | + finished_at=finished_at) |
275 | + |
276 | + |
277 | +def create_build_results_with_queue_times(project, queue_times, requestor=None, |
278 | + build_date=date.today()): |
279 | + """ |
280 | + Create BuildResults with queue times specified. |
281 | + |
282 | + project: The Project to associate the BuildResults with. |
283 | + queue_times: A sequence of time periods in minutes. |
284 | + """ |
285 | + dispatched_at = datetime.combine(build_date, time()) |
286 | + for minutes in queue_times: |
287 | + build_result = factory.make_build_result( |
288 | + project=project, requestor=requestor, |
289 | + requested_at=dispatched_at - timedelta(minutes=minutes), |
290 | + dispatched_at=dispatched_at) |
291 | |
292 | |
293 | class BuildResultMetricsTests(TestCase): |
294 | @@ -39,13 +55,12 @@ |
295 | get_average_build_time should return the average time taken to build a |
296 | project. |
297 | """ |
298 | + finished_at = datetime.utcnow() |
299 | build_result = factory.make_build_result( |
300 | - project=self.project, result=ProjectBuildStates.SUCCESS) |
301 | - finished_at = datetime.now() |
302 | - build_result.finished_at = finished_at |
303 | - build_result.started_at = finished_at - timedelta(minutes=10) |
304 | - build_result.save() |
305 | - self.assertEqual(600, get_average_build_time(self.project)) |
306 | + project=self.project, result=ProjectBuildStates.SUCCESS, |
307 | + finished_at=finished_at, |
308 | + started_at=finished_at - timedelta(minutes=10)) |
309 | + self.assertEqual(10*60, get_average_build_time(self.project)) |
310 | |
311 | def test_get_average_build_time_only_includes_completed_builds(self): |
312 | """ |
313 | @@ -72,9 +87,9 @@ |
314 | If a build has started, but not yet finished, this we should get 0.0 |
315 | for the average for this entry. |
316 | """ |
317 | - build_result = factory.make_build_result(project=self.project) |
318 | - build_result.started_at = datetime.now() - timedelta(minutes=20) |
319 | - build_result.save() |
320 | + started_at = datetime.utcnow() - timedelta(minutes=20) |
321 | + build_result = factory.make_build_result(project=self.project, |
322 | + started_at=started_at) |
323 | self.assertEqual(0.0, get_average_build_time(self.project)) |
324 | |
325 | def test_get_average_build_time_multiple_builds(self): |
326 | @@ -82,7 +97,7 @@ |
327 | The time for each BuildResult should be averaged together. |
328 | """ |
329 | create_build_results_with_durations(self.project, [10, 20]) |
330 | - self.assertEqual(15 * 60.0, get_average_build_time(self.project)) |
331 | + self.assertEqual(15*60, get_average_build_time(self.project)) |
332 | |
333 | def test_get_average_build_time_multiple_builds_ignores_unfinished(self): |
334 | """ |
335 | @@ -91,11 +106,11 @@ |
336 | create_build_results_with_durations(self.project, [10, 20]) |
337 | |
338 | # Create an additional unfinished build. |
339 | - build_result = factory.make_build_result(project=self.project) |
340 | - build_result.started_at = datetime.now() - timedelta(minutes=20) |
341 | - build_result.save() |
342 | + started_at = datetime.utcnow() - timedelta(minutes=20) |
343 | + build_result = factory.make_build_result(project=self.project, |
344 | + started_at=started_at) |
345 | |
346 | - self.assertEqual(15 * 60.0, get_average_build_time(self.project)) |
347 | + self.assertEqual(15*60, get_average_build_time(self.project)) |
348 | |
349 | def test_get_average_build_time_ignores_other_projects(self): |
350 | """ |
351 | @@ -104,8 +119,7 @@ |
352 | """ |
353 | create_build_results_with_durations(self.project, [10, 20]) |
354 | create_build_results_with_durations(factory.make_project(), [50, 100]) |
355 | - |
356 | - self.assertEqual(15 * 60.0, get_average_build_time(self.project)) |
357 | + self.assertEqual(15*60, get_average_build_time(self.project)) |
358 | |
359 | def test_get_average_build_time_no_project(self): |
360 | """ |
361 | @@ -116,7 +130,7 @@ |
362 | create_build_results_with_durations( |
363 | factory.make_project(), [50, 100]) |
364 | # 10 + 20 + 50 + 100 = 180 / 4 = 45 minutes... |
365 | - self.assertEqual(45 * 60.0, get_average_build_time()) |
366 | + self.assertEqual(45*60, get_average_build_time()) |
367 | |
368 | def test_get_average_build_time_with_automated_flag(self): |
369 | """ |
370 | @@ -168,8 +182,7 @@ |
371 | |
372 | # From the day after we create our builds 'til today. |
373 | time_period = (build_date + timedelta(days=1), datetime.utcnow()) |
374 | - self.assertEqual(75 * 60.0, |
375 | - get_average_build_time(period=time_period)) |
376 | + self.assertEqual(75*60, get_average_build_time(period=time_period)) |
377 | |
378 | def test_get_average_build_time_filters_by_date_and_automated(self): |
379 | """ |
380 | @@ -189,34 +202,95 @@ |
381 | |
382 | # From the day after we create our builds 'til today. |
383 | time_period = (build_date + timedelta(days=1), datetime.utcnow()) |
384 | - self.assertEqual(40 * 60.0, |
385 | + self.assertEqual(40*60, |
386 | get_average_build_time(period=time_period, |
387 | automated=True)) |
388 | |
389 | + |
390 | +class QueueTimeMetricsTests(TestCase): |
391 | + |
392 | + def setUp(self): |
393 | + self.project = factory.make_project() |
394 | + |
395 | + def test_average_queue_time_single_build(self): |
396 | + """ |
397 | + get_average_queue_time should return the average time a build waits |
398 | + before being dispatched. |
399 | + """ |
400 | + dispatched_at = datetime.utcnow() |
401 | + build_result = factory.make_build_result( |
402 | + project=self.project, dispatched_at=dispatched_at, |
403 | + requested_at=dispatched_at - timedelta(minutes=30)) |
404 | + self.assertEqual(30*60, get_average_queue_time(self.project)) |
405 | + |
406 | + def test_average_queue_time_no_builds(self): |
407 | + """ |
408 | + If there are no builds, we should get an average of 0.0. |
409 | + """ |
410 | + self.assertEqual(0.0*60, get_average_queue_time(self.project)) |
411 | + |
412 | + def test_average_queue_time_includes_by_date(self): |
413 | + """ |
414 | + It should be possible to restrict the date queried to a specific time |
415 | + frame, specifying a period should only include those BuildResults |
416 | + within that period. |
417 | + """ |
418 | + build_date = datetime.utcnow() - timedelta(days=30) |
419 | + create_build_results_with_queue_times( |
420 | + self.project, [10, 20], build_date=build_date) |
421 | + |
422 | + create_build_results_with_queue_times( |
423 | + factory.make_project(), [50, 100], |
424 | + build_date=build_date + timedelta(days=2)) |
425 | + |
426 | + # From the day after we create our builds 'til today. |
427 | + time_period = (build_date + timedelta(days=1), datetime.utcnow()) |
428 | + self.assertEqual(75*60, |
429 | + get_average_queue_time(period=time_period)) |
430 | + |
431 | + |
432 | +class GetBuildResultsTests(TestCase): |
433 | + |
434 | + def setUp(self): |
435 | + self.project = factory.make_project() |
436 | + |
437 | def test_get_build_result_metrics(self): |
438 | """ |
439 | - get_build_result_metrics should return a dictionary with the following: |
440 | - |
441 | - "Average scheduled build time (7 days)": value, |
442 | - "Average scheduled build time (30 days)": value, |
443 | - "Average scheduled build time (90 days)": value |
444 | + get_build_result_metrics should return a list of tuples with the metric |
445 | + being measured, and the time in minutes. |
446 | """ |
447 | start_date = datetime.utcnow() |
448 | # Two this week, average = 10 + 20/2 = 15 |
449 | create_build_results_with_durations( |
450 | self.project, [10, 20], build_date=start_date) |
451 | |
452 | + # Two this week, average = 30 + 18/2 = 24.0 |
453 | + create_build_results_with_queue_times( |
454 | + self.project, [30, 18], build_date=start_date) |
455 | + |
456 | last_week = start_date - timedelta(days=8) |
457 | # Two last week, 10 + 10 + 10 + 20/4 = 12.5 |
458 | create_build_results_with_durations( |
459 | self.project, [10, 10], build_date=last_week) |
460 | |
461 | + # Two last week, average = 30 + 18 + 14 11/4 = 73 |
462 | + create_build_results_with_queue_times( |
463 | + self.project, [14, 11], build_date=last_week) |
464 | + |
465 | last_month = start_date - timedelta(days=35) |
466 | # Two last month, 10 + 10 + 10 + 20 + 30 + 40/6 = 20 |
467 | create_build_results_with_durations( |
468 | self.project, [30, 40], build_date=last_month) |
469 | |
470 | - self.assertEqual({"Average scheduled build time (7 days)": 900, |
471 | - "Average scheduled build time (30 days)": 750, |
472 | - "Average scheduled build time (90 days)": 1200}, |
473 | - get_build_result_metrics()) |
474 | + # Two last month, average = 30 + 18 + 14 11 + 30 + 20/6 = 82 |
475 | + create_build_results_with_queue_times( |
476 | + self.project, [30, 20], build_date=last_month) |
477 | + |
478 | + self.assertEqual( |
479 | + [("Average scheduled build time (7 days)", 15.0*60), |
480 | + ("Average scheduled build time (30 days)", 12.5*60), |
481 | + ("Average scheduled build time (90 days)", 20.0*60), |
482 | + ("Average scheduled queue time (7 days)", 24.0*60), |
483 | + ("Average scheduled queue time (30 days)", 18.25*60), |
484 | + ("Average scheduled queue time (90 days)", 20.5*60)], |
485 | + get_build_result_metrics()) |
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.