Repository: learningequality/kolibri

Issue:
CSV Report generation API tests fail when the current date in the active timezone is different to the UTC date
## Observed behavior
When running the tests in `kolibri/plugins/facility/test/test_api.py` 2 tests can sometimes fail - the ones to do with generating a CSV Summary Log or Session Log report.

This occurs when the date as reported on the local machine in the currently set timezone is different to the current date according to UTC. In my specific case, the tests would fail when I ran them after 4pm PST (UTC - 8). I have not tested, but would assume that a similar issue would occur running the tests at say 7am in (UTC + 8) timezone.

## Errors and logs
```
kolibri/plugins/facility/test/test_api.py F..F.....                                                                                                                                                         [100%]

==================================================================================================== FAILURES =====================================================================================================
_____________________________________________________________________ ContentSummaryLogCSVExportTestCase.test_csv_download_admin_permissions ______________________________________________________________________

self = <kolibri.plugins.facility.test.test_api.ContentSummaryLogCSVExportTestCase testMethod=test_csv_download_admin_permissions>, mock_enqueue = <MagicMock name='enqueue' id='140268344491728'>

    @mock.patch.object(log_exports_cleanup, "enqueue", return_value=None)
    def test_csv_download_admin_permissions(self, mock_enqueue):
        call_command(
            "exportlogs",
            log_type="summary",
            output_file=output_filename(
                "summary",
                self.facility,
                start_date=self.start_date,
                end_date=self.end_date,
            ),
            overwrite=True,
            start_date=self.start_date,
            end_date=self.end_date,
        )
        self.client.login(
            username=self.admin.username,
            password=DUMMY_PASSWORD,
            facility=self.facility,
        )
        response = self.client.get(
            reverse(
                "kolibri:kolibri.plugins.facility:download_csv_file",
                kwargs={"csv_type": "summary", "facility_id": self.facility.id},
            )
        )
>       self.assertEqual(response.status_code, 200)
E       AssertionError: 404 != 200

kolibri/plugins/facility/test/test_api.py:149: AssertionError
---------------------------------------------------------------------------------------------- Captured stdout setup ----------------------------------------------------------------------------------------------
Installed 2 object(s) from 1 fixture(s)
---------------------------------------------------------------------------------------------- Captured stdout call -----------------------------------------------------------------------------------------------
INFO     2024-03-01 16:58:51,322 Creating csv file /home/richard/github/kolibri/.pytest_kolibri_home/log_export/Rock N' Roll High School #0_0f6e_content_summary_logs_from_2020-10-21_to_2024-03-01.csv
INFO     2024-03-01 16:58:51,327 Created csv file /home/richard/github/kolibri/.pytest_kolibri_home/log_export/Rock N' Roll High School #0_0f6e_content_summary_logs_from_2020-10-21_to_2024-03-01.csv with 3 lines
INFO     2024-03-01 16:58:51,504 127.0.0.1 - - "GET /facility/api/downloadcsvfile/summary/0f6ee14289d0447dbb105688560eee29/" 404 0 "" "unknown"
WARNING  2024-03-01 16:58:51,504 Not Found: /facility/api/downloadcsvfile/summary/0f6ee14289d0447dbb105688560eee29/
------------------------------------------------------------------------------------------------ Captured log call ------------------------------------------------------------------------------------------------
csv_export.py              186 INFO     Creating csv file /home/richard/github/kolibri/.pytest_kolibri_home/log_export/Rock N' Roll High School #0_0f6e_content_summary_logs_from_2020-10-21_to_2024-03-01.csv
exportlogs.py              159 INFO     Created csv file /home/richard/github/kolibri/.pytest_kolibri_home/log_export/Rock N' Roll High School #0_0f6e_content_summary_logs_from_2020-10-21_to_2024-03-01.csv with 3 lines
log.py                     224 WARNING  Not Found: /facility/api/downloadcsvfile/summary/0f6ee14289d0447dbb105688560eee29/
_____________________________________________________________________ ContentSessionLogCSVExportTestCase.test_csv_download_admin_permissions ______________________________________________________________________

self = <kolibri.plugins.facility.test.test_api.ContentSessionLogCSVExportTestCase testMethod=test_csv_download_admin_permissions>, mock_enqueue = <MagicMock name='enqueue' id='140268351318224'>

    @mock.patch.object(log_exports_cleanup, "enqueue", return_value=None)
    def test_csv_download_admin_permissions(self, mock_enqueue):
        call_command(
            "exportlogs",
            log_type="session",
            output_file=output_filename(
                "session",
                self.facility,
                start_date=self.start_date,
                end_date=self.end_date,
            ),
            overwrite=True,
            start_date=self.start_date,
            end_date=self.end_date,
        )
        self.client.login(
            username=self.admin.username,
            password=DUMMY_PASSWORD,
            facility=self.facility,
        )
        response = self.client.get(
            reverse(
                "kolibri:kolibri.plugins.facility:download_csv_file",
                kwargs={"csv_type": "session", "facility_id": self.facility.id},
            )
        )
>       self.assertEqual(response.status_code, 200)
E       AssertionError: 404 != 200

kolibri/plugins/facility/test/test_api.py:252: AssertionError
---------------------------------------------------------------------------------------------- Captured stdout setup ----------------------------------------------------------------------------------------------
Installed 2 object(s) from 1 fixture(s)
---------------------------------------------------------------------------------------------- Captured stdout call -----------------------------------------------------------------------------------------------
INFO     2024-03-01 16:58:52,079 Creating csv file /home/richard/github/kolibri/.pytest_kolibri_home/log_export/Rock N' Roll High School #1_207d_content_session_logs_from_2020-10-21_to_2024-03-01.csv
INFO     2024-03-01 16:58:52,084 Created csv file /home/richard/github/kolibri/.pytest_kolibri_home/log_export/Rock N' Roll High School #1_207d_content_session_logs_from_2020-10-21_to_2024-03-01.csv with 3 lines
INFO     2024-03-01 16:58:52,177 127.0.0.1 - - "GET /facility/api/downloadcsvfile/session/207d21f8516da5fad0659fc6488359d3/" 404 0 "" "unknown"
WARNING  2024-03-01 16:58:52,177 Not Found: /facility/api/downloadcsvfile/session/207d21f8516da5fad0659fc6488359d3/
------------------------------------------------------------------------------------------------ Captured log call ------------------------------------------------------------------------------------------------
csv_export.py              186 INFO     Creating csv file /home/richard/github/kolibri/.pytest_kolibri_home/log_export/Rock N' Roll High School #1_207d_content_session_logs_from_2020-10-21_to_2024-03-01.csv
exportlogs.py              159 INFO     Created csv file /home/richard/github/kolibri/.pytest_kolibri_home/log_export/Rock N' Roll High School #1_207d_content_session_logs_from_2020-10-21_to_2024-03-01.csv with 3 lines
log.py                     224 WARNING  Not Found: /facility/api/downloadcsvfile/session/207d21f8516da5fad0659fc6488359d3/
======================================================================================= 2 failed, 7 passed in 13.86 seconds =======================================================================================
```

Note - I did a test of the actual functionality that relies on this in the Facility plugin, and observed no issues, so this seems at the moment to be purely a testing artifact.

## Expected behavior
Tests should pass regardless of time of day or timezone!

## User-facing consequences
I think none - but would be good to work out why this is happening to be sure.

## Steps to reproduce
Set your system timezone to PST.
Set your system time to after 4pm.
Run the test suite above with pytest.

## Context

Noticed in the develop branch, but also extant on release-v0.16.x



Discussion:
Hey 👋🏽 
I would like to be assigned to this :) 

Resolving patch:
diff --git a/kolibri/utils/time_utils.py b/kolibri/utils/time_utils.py
--- a/kolibri/utils/time_utils.py
+++ b/kolibri/utils/time_utils.py
@@ -2,8 +2,18 @@
 
 
 def local_now():
+    """
+    Returns the current time in the local timezone.
+    """
     return timezone.localtime(timezone.now())
 
 
+def utc_now():
+    """
+    Returns the current time in the UTC timezone.
+    """
+    return timezone.now()
+
+
 def naive_utc_datetime(dt):
     return timezone.make_naive(dt, timezone=timezone.utc)


Test patch:
diff --git a/kolibri/plugins/facility/test/test_api.py b/kolibri/plugins/facility/test/test_api.py
--- a/kolibri/plugins/facility/test/test_api.py
+++ b/kolibri/plugins/facility/test/test_api.py
@@ -22,7 +22,7 @@
 from kolibri.core.logger.test.factory_logger import FacilityUserFactory
 from kolibri.plugins.facility.views import CSV_EXPORT_FILENAMES
 from kolibri.utils import conf
-from kolibri.utils.time_utils import local_now
+from kolibri.utils.time_utils import utc_now
 
 
 def output_filename(log_type, facility, **kwargs):
@@ -67,7 +67,7 @@ def setUpTestData(cls):
         ]
         cls.facility.add_admin(cls.admin)
         cls.start_date = datetime.datetime(2020, 10, 21, tzinfo=pytz.UTC).isoformat()
-        cls.end_date = local_now().isoformat()
+        cls.end_date = utc_now().isoformat()
 
     @mock.patch.object(log_exports_cleanup, "enqueue", return_value=None)
     def test_csv_download_anonymous_permissions(self, mock_enqueue):
@@ -170,7 +170,7 @@ def setUpTestData(cls):
         ]
         cls.facility.add_admin(cls.admin)
         cls.start_date = datetime.datetime(2020, 10, 21, tzinfo=pytz.UTC).isoformat()
-        cls.end_date = local_now().isoformat()
+        cls.end_date = utc_now().isoformat()
 
     @mock.patch.object(log_exports_cleanup, "enqueue", return_value=None)
     def test_csv_download_anonymous_permissions(self, mock_enqueue):