From aaff0c1a5abc850db49dc72a79abb581be8cfcfc Mon Sep 17 00:00:00 2001 From: Sean Date: Tue, 3 Mar 2020 10:54:20 -0500 Subject: Fixed a few bugs for the stats functions and created a few tests. Signed-off-by: Sean Change-Id: I2e4598811bddabe5b7447c3a92d39d16acb77a03 Signed-off-by: Sean --- src/booking/stats.py | 70 +++++++++++++++++------------------ src/booking/tests/test_stats.py | 59 +++++++++++++++++++++++++++++ src/templates/base/booking/stats.html | 15 ++++++-- 3 files changed, 104 insertions(+), 40 deletions(-) create mode 100644 src/booking/tests/test_stats.py (limited to 'src') diff --git a/src/booking/stats.py b/src/booking/stats.py index 47de80b..bdb478a 100644 --- a/src/booking/stats.py +++ b/src/booking/stats.py @@ -1,5 +1,5 @@ ############################################################################## -# Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, and others. +# Copyright (c) 2020 Parker Berberian, Sawyer Bergeron, Sean Smith and others. # # All rights reserved. This program and the accompanying materials # are made available under the terms of the Apache License, Version 2.0 @@ -7,7 +7,7 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## from booking.models import Booking -import datetime +from datetime import datetime, timedelta import pytz @@ -18,43 +18,41 @@ class StatisticsManager(object): """ Calculate Booking usage data points. - Will return a dictionary of names and 2-D array of x and y data points. - e.g. {"plot1": [["x1", "x2", "x3"],["y1", "y2", "y3]]} - x values will be dates in string - every change (booking start / end) will be reflected, - instead of one data point per day - y values are the integer number of bookings/users active at - some point in the given date span is the number of days to plot. - The last x value will always be the current time + Gathers all active bookings that fall in interval [(now - span), (now + 1 week)]. + x data points are every 12 hours + y values are the integer number of bookings/users active at time """ - data = [] + x = [] y = [] users = [] - now = datetime.datetime.now(pytz.utc) - delta = datetime.timedelta(days=span) - end = now - delta - bookings = Booking.objects.filter(start__lte=now, end__gte=end).prefetch_related("collaborators") - for booking in bookings: # collect data from each booking - user_list = [u.pk for u in booking.collaborators.all()] - user_list.append(booking.owner.pk) - data.append((booking.start, 1, user_list)) - data.append((booking.end, -1, user_list)) - - # sort based on time - data.sort(key=lambda i: i[0]) - - # collect data - count = 0 - active_users = {} - for datum in data: - x.append(str(datum[0])) # time - count += datum[1] # booking count - y.append(count) - for pk in datum[2]: # maintain count of each user's active bookings - active_users[pk] = active_users.setdefault(pk, 0) + datum[1] - if active_users[pk] == 0: - del active_users[pk] - users.append(len([x for x in active_users.values() if x > 0])) + + now = datetime.now(pytz.utc) + delta = timedelta(days=span) + start = now - delta + end = now + timedelta(weeks=1) + + bookings = Booking.objects.filter( + start__lte=end, + end__gte=start + ).prefetch_related("collaborators") + + # get data + while start <= end: + active_users = 0 + + books = bookings.filter( + start__lte=start, + end__gte=start + ).prefetch_related("collaborators") + + for booking in books: + active_users += booking.collaborators.all().count() + 1 + + x.append(str(start)) + y.append(books.count()) + users.append(active_users) + + start += timedelta(hours=12) return {"booking": [x, y], "user": [x, users]} diff --git a/src/booking/tests/test_stats.py b/src/booking/tests/test_stats.py new file mode 100644 index 0000000..5501355 --- /dev/null +++ b/src/booking/tests/test_stats.py @@ -0,0 +1,59 @@ +############################################################################# +# Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, Sean Smith, and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import pytz +from datetime import timedelta, datetime + +from django.test import TestCase + +from booking.models import Booking +from booking.stats import StatisticsManager as sm +from dashboard.testing_utils import make_user + + +class StatsTestCases(TestCase): + + def test_no_booking_outside_span(self): + now = datetime.now(pytz.utc) + + bad_date = now + timedelta(days=1200) + Booking.objects.create(start=now, end=bad_date, owner=make_user(username='jj')) + + actual = sm.getContinuousBookingTimeSeries() + dates = actual['booking'][0] + + for date in dates: + self.assertNotEqual(date, bad_date) + + def check_booking_and_user_counts(self): + now = datetime.now(pytz.utc) + + for i in range(20): + Booking.objects.create( + start=now, + end=now + timedelta(weeks=3), + owner=make_user(username='a')) + + for i in range(30): + Booking.objects.create( + start=now + timedelta(days=5), + end=now + timedelta(weeks=3, days=5), + owner=make_user(username='a')) + + for i in range(120): + Booking.objects.create( + start=now + timedelta(weeks=1), + end=now + timedelta(weeks=4), + owner=make_user(username='a')) + + dates = [[now, 20], [now + timedelta(days=5), 30], [now + timedelta(weeks=1), 120]] + actual = sm.getContinuousBookingTimeSeries() + + for date in dates: + self.assertEqual(date[1], actual['booking'][date[0]]) + self.assertEqual(date[1], actual['booking'][date[1]]) diff --git a/src/templates/base/booking/stats.html b/src/templates/base/booking/stats.html index a78f793..4c06b71 100644 --- a/src/templates/base/booking/stats.html +++ b/src/templates/base/booking/stats.html @@ -5,20 +5,26 @@ {{ block.super }} {% endblock %} -- cgit 1.2.3-korg