From a1c67cdfe74ed6739ff832ed502864c5fe8af951 Mon Sep 17 00:00:00 2001 From: Matias Bordese Date: Tue, 13 Aug 2024 17:51:18 -0300 Subject: [PATCH] Address deprecation warnings in tests (#4681) Related to https://github.com/grafana/oncall/issues/4496 [No warnings](https://github.com/grafana/oncall/actions/runs/10359091611/job/28674729718?pr=4681#step:5:305)! --- .github/workflows/linting-and-tests.yml | 1 + engine/apps/api/tests/conftest.py | 10 +++--- engine/apps/api/tests/test_alert_group.py | 35 +++++++++---------- .../apps/api/views/alert_receive_channel.py | 2 +- engine/apps/api/views/shift_swap.py | 4 ++- engine/apps/email/tests/test_inbound_email.py | 6 +++- .../public_api/serializers/on_call_shifts.py | 5 ++- .../tests/tasks/test_refresh_ical_files.py | 3 +- engine/apps/slack/utils.py | 4 +-- .../telegram/tests/test_update_handlers.py | 6 ++-- engine/common/api_helpers/filters.py | 15 ++++++-- engine/common/tests/test_ordered_model.py | 4 +-- engine/engine/middlewares.py | 2 +- engine/requirements.in | 4 +-- engine/requirements.txt | 5 +-- engine/settings/base.py | 2 -- engine/tox.ini | 6 ++++ 17 files changed, 68 insertions(+), 46 deletions(-) diff --git a/.github/workflows/linting-and-tests.yml b/.github/workflows/linting-and-tests.yml index 4c7449b3b3..0063e8baba 100644 --- a/.github/workflows/linting-and-tests.yml +++ b/.github/workflows/linting-and-tests.yml @@ -5,6 +5,7 @@ on: env: DJANGO_SETTINGS_MODULE: settings.ci_test + SKIP_SLACK_SDK_WARNING: True DATABASE_HOST: localhost RABBITMQ_URI: amqp://rabbitmq:rabbitmq@localhost:5672 SLACK_CLIENT_OAUTH_ID: 1 diff --git a/engine/apps/api/tests/conftest.py b/engine/apps/api/tests/conftest.py index 8c67999b9c..cfd3ddafd0 100644 --- a/engine/apps/api/tests/conftest.py +++ b/engine/apps/api/tests/conftest.py @@ -1,5 +1,3 @@ -from datetime import timedelta - import pytest from django.utils import timezone @@ -29,8 +27,8 @@ def _make_alert_groups_all_statuses(alert_receive_channel, channel_filter, alert resolved_alert_group = make_alert_group( alert_receive_channel, channel_filter=channel_filter, - acknowledged_at=timezone.now() + timedelta(hours=1), - resolved_at=timezone.now() + timedelta(hours=2), + acknowledged_at=timezone.now() + timezone.timedelta(hours=1), + resolved_at=timezone.now() + timezone.timedelta(hours=2), resolved=True, acknowledged=True, ) @@ -39,7 +37,7 @@ def _make_alert_groups_all_statuses(alert_receive_channel, channel_filter, alert ack_alert_group = make_alert_group( alert_receive_channel, channel_filter=channel_filter, - acknowledged_at=timezone.now() + timedelta(hours=1), + acknowledged_at=timezone.now() + timezone.timedelta(hours=1), acknowledged=True, ) make_alert(alert_group=ack_alert_group, raw_request_data=alert_raw_request_data) @@ -51,7 +49,7 @@ def _make_alert_groups_all_statuses(alert_receive_channel, channel_filter, alert alert_receive_channel, channel_filter=channel_filter, silenced=True, - silenced_at=timezone.now() + timedelta(hours=1), + silenced_at=timezone.now() + timezone.timedelta(hours=1), ) make_alert(alert_group=silenced_alert_group, raw_request_data=alert_raw_request_data) diff --git a/engine/apps/api/tests/test_alert_group.py b/engine/apps/api/tests/test_alert_group.py index 85a9af0988..e9564b86c9 100644 --- a/engine/apps/api/tests/test_alert_group.py +++ b/engine/apps/api/tests/test_alert_group.py @@ -1,4 +1,3 @@ -import datetime from unittest.mock import Mock, patch import pytest @@ -250,8 +249,8 @@ def test_get_filter_resolved_by( resolved_alert_group = make_alert_group( alert_receive_channel, channel_filter=default_channel_filter, - acknowledged_at=timezone.now() + datetime.timedelta(hours=1), - resolved_at=timezone.now() + datetime.timedelta(hours=2), + acknowledged_at=timezone.now() + timezone.timedelta(hours=1), + resolved_at=timezone.now() + timezone.timedelta(hours=2), resolved=True, acknowledged=True, resolved_by_user=first_user, @@ -302,8 +301,8 @@ def make_resolved_by_user_alert_group(user): resolved_alert_group = make_alert_group( alert_receive_channel, channel_filter=default_channel_filter, - acknowledged_at=timezone.now() + datetime.timedelta(hours=1), - resolved_at=timezone.now() + datetime.timedelta(hours=2), + acknowledged_at=timezone.now() + timezone.timedelta(hours=1), + resolved_at=timezone.now() + timezone.timedelta(hours=2), resolved=True, acknowledged=True, resolved_by_user=user, @@ -348,8 +347,8 @@ def test_get_filter_acknowledged_by( acknowledged_alert_group = make_alert_group( alert_receive_channel, channel_filter=default_channel_filter, - acknowledged_at=timezone.now() + datetime.timedelta(hours=1), - resolved_at=timezone.now() + datetime.timedelta(hours=2), + acknowledged_at=timezone.now() + timezone.timedelta(hours=1), + resolved_at=timezone.now() + timezone.timedelta(hours=2), acknowledged=True, acknowledged_by_user=first_user, ) @@ -398,8 +397,8 @@ def make_acknowledged_by_user_alert_group(user): acknowledged_alert_group = make_alert_group( alert_receive_channel, channel_filter=default_channel_filter, - acknowledged_at=timezone.now() + datetime.timedelta(hours=1), - resolved_at=timezone.now() + datetime.timedelta(hours=2), + acknowledged_at=timezone.now() + timezone.timedelta(hours=1), + resolved_at=timezone.now() + timezone.timedelta(hours=2), acknowledged=True, acknowledged_by_user=user, ) @@ -442,7 +441,7 @@ def test_get_filter_silenced_by( silenced_alert_group = make_alert_group( alert_receive_channel, channel_filter=default_channel_filter, - silenced_at=timezone.now() + datetime.timedelta(hours=1), + silenced_at=timezone.now() + timezone.timedelta(hours=1), silenced=True, silenced_by_user=first_user, ) @@ -491,7 +490,7 @@ def make_silenced_by_user_alert_group(user): acknowledged_alert_group = make_alert_group( alert_receive_channel, channel_filter=default_channel_filter, - silenced_at=timezone.now() + datetime.timedelta(hours=1), + silenced_at=timezone.now() + timezone.timedelta(hours=1), silenced=True, silenced_by_user=user, ) @@ -670,8 +669,8 @@ def test_get_filter_mine( acknowledged_alert_group = make_alert_group( alert_receive_channel, channel_filter=default_channel_filter, - acknowledged_at=timezone.now() + datetime.timedelta(hours=1), - resolved_at=timezone.now() + datetime.timedelta(hours=2), + acknowledged_at=timezone.now() + timezone.timedelta(hours=1), + resolved_at=timezone.now() + timezone.timedelta(hours=2), acknowledged=True, acknowledged_by_user=first_user, ) @@ -724,8 +723,8 @@ def test_get_filter_involved_users( acknowledged_alert_group = make_alert_group( alert_receive_channel, channel_filter=default_channel_filter, - acknowledged_at=timezone.now() + datetime.timedelta(hours=1), - resolved_at=timezone.now() + datetime.timedelta(hours=2), + acknowledged_at=timezone.now() + timezone.timedelta(hours=1), + resolved_at=timezone.now() + timezone.timedelta(hours=2), acknowledged=True, acknowledged_by_user=first_user, ) @@ -999,7 +998,7 @@ def test_get_title_search( alert_receive_channel, channel_filter=channel_filter, web_title_cache=f"testing {i+1}" ) # alert groups starting every months going back - alert_group.started_at = timezone.now() - datetime.timedelta(days=10 + 30 * i) + alert_group.started_at = timezone.now() - timezone.timedelta(days=10 + 30 * i) alert_group.save(update_fields=["started_at"]) make_alert(alert_group=alert_group, raw_request_data=alert_raw_request_data) alert_groups.append(alert_group) @@ -1021,8 +1020,8 @@ def test_get_title_search( response = client.get( url + "?search=testing&started_at={}_{}".format( - (timezone.now() - datetime.timedelta(days=500)).strftime(DateRangeFilterMixin.DATE_FORMAT), - (timezone.now() - datetime.timedelta(days=30)).strftime(DateRangeFilterMixin.DATE_FORMAT), + (timezone.now() - timezone.timedelta(days=500)).strftime(DateRangeFilterMixin.DATE_FORMAT), + (timezone.now() - timezone.timedelta(days=30)).strftime(DateRangeFilterMixin.DATE_FORMAT), ), format="json", **make_user_auth_headers(user, token), diff --git a/engine/apps/api/views/alert_receive_channel.py b/engine/apps/api/views/alert_receive_channel.py index c4103e9d2d..e70be14290 100644 --- a/engine/apps/api/views/alert_receive_channel.py +++ b/engine/apps/api/views/alert_receive_channel.py @@ -242,7 +242,7 @@ def get_queryset(self, eager=True, ignore_filtering_by_available_teams=False): ) # distinct to remove duplicates after alert_receive_channels X labels join - queryset = queryset.distinct() + queryset = queryset.distinct().order_by("id") return queryset diff --git a/engine/apps/api/views/shift_swap.py b/engine/apps/api/views/shift_swap.py index 6bad0b2820..bbc674efae 100644 --- a/engine/apps/api/views/shift_swap.py +++ b/engine/apps/api/views/shift_swap.py @@ -65,7 +65,9 @@ def get_serializer_class(self): return ShiftSwapRequestListSerializer if self.action == "list" else super().get_serializer_class() def get_queryset(self): - queryset = ShiftSwapRequest.objects.filter(schedule__organization=self.request.auth.organization) + queryset = ShiftSwapRequest.objects.filter(schedule__organization=self.request.auth.organization).order_by( + "-created_at" + ) return self.serializer_class.setup_eager_loading(queryset) def perform_destroy(self, instance: ShiftSwapRequest) -> None: diff --git a/engine/apps/email/tests/test_inbound_email.py b/engine/apps/email/tests/test_inbound_email.py index bf6ae5ae57..81a76e923a 100644 --- a/engine/apps/email/tests/test_inbound_email.py +++ b/engine/apps/email/tests/test_inbound_email.py @@ -20,6 +20,7 @@ ], ) @pytest.mark.django_db +@pytest.mark.filterwarnings("ignore:::anymail.*") # ignore missing WEBHOOK_SECRET in amazon ses test setup def test_amazon_ses_provider_load( settings, make_organization_and_user_with_token, make_alert_receive_channel, recipients, expected ): @@ -128,7 +129,10 @@ def test_mailgun_provider_load( "sender_value,expected_result", [ ("'Alex Smith' ", "test@example.com"), - ("'Alex Smith' via [TEST] mail ", "'Alex Smith' via [TEST] mail "), + # double quotes required when including special characters + ("\"'Alex Smith' via [TEST] mail\" ", "test@example.com"), + # missing double quotes + ("'Alex Smith' via [TEST] mail ", "\"'Alex Smith' via\""), ], ) def test_get_sender_from_email_message(sender_value, expected_result): diff --git a/engine/apps/public_api/serializers/on_call_shifts.py b/engine/apps/public_api/serializers/on_call_shifts.py index d1b840251a..7e0ec725fa 100644 --- a/engine/apps/public_api/serializers/on_call_shifts.py +++ b/engine/apps/public_api/serializers/on_call_shifts.py @@ -1,3 +1,4 @@ +import datetime import time from rest_framework import fields, serializers @@ -345,7 +346,9 @@ def _correct_validated_data(self, event_type, validated_data): if isinstance(validated_data.get(field), list) and len(validated_data[field]) == 0: validated_data[field] = None if validated_data.get("start") is not None: - validated_data["start"] = validated_data["start"].replace(tzinfo=None) + # store start date as UTC, TZ is really given by the time_zone field + # (see apps/schedules/models/custom_on_call_shift.py::convert_dt_to_schedule_timezone) + validated_data["start"] = validated_data["start"].replace(tzinfo=datetime.timezone.utc) if validated_data.get("frequency") is not None and "interval" not in validated_data: # if there is frequency but no interval is given, default to 1 validated_data["interval"] = 1 diff --git a/engine/apps/schedules/tests/tasks/test_refresh_ical_files.py b/engine/apps/schedules/tests/tasks/test_refresh_ical_files.py index fdbbec3673..63e1b34ebc 100644 --- a/engine/apps/schedules/tests/tasks/test_refresh_ical_files.py +++ b/engine/apps/schedules/tests/tasks/test_refresh_ical_files.py @@ -1,4 +1,3 @@ -import datetime from unittest.mock import patch import pytest @@ -69,7 +68,7 @@ def test_refresh_ical_files_filter_orgs( make_schedule, ): organization = make_organization() - deleted_organization = make_organization(deleted_at=datetime.datetime.now()) + deleted_organization = make_organization(deleted_at=timezone.now()) schedule_from_deleted_org = make_schedule(deleted_organization, schedule_class=OnCallScheduleWeb) schedule = make_schedule(organization, schedule_class=OnCallScheduleWeb) diff --git a/engine/apps/slack/utils.py b/engine/apps/slack/utils.py index f24cb702a0..8b3515ba30 100644 --- a/engine/apps/slack/utils.py +++ b/engine/apps/slack/utils.py @@ -1,6 +1,6 @@ +import datetime import enum import typing -from datetime import datetime from apps.slack.client import SlackClient from apps.slack.errors import ( @@ -83,7 +83,7 @@ def post_message_to_channel(organization: "Organization", channel_id: str, text: def _format_datetime_to_slack(timestamp: float, format: str) -> str: - fallback = datetime.utcfromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M (UTC)") + fallback = datetime.datetime.fromtimestamp(timestamp, datetime.UTC).strftime("%Y-%m-%d %H:%M (UTC)") return f"" diff --git a/engine/apps/telegram/tests/test_update_handlers.py b/engine/apps/telegram/tests/test_update_handlers.py index bb8b799408..35a047d208 100644 --- a/engine/apps/telegram/tests/test_update_handlers.py +++ b/engine/apps/telegram/tests/test_update_handlers.py @@ -136,9 +136,11 @@ def test_button_press_handler_non_existing_alert_group( make_telegram_user_connector(user_1, telegram_chat_id=chat_id) update = generate_button_press_ack_message(chat_id, 1234) + update_data = update.callback_query.data handler = ButtonPressHandler(update=update) - with patch.object(update.callback_query, "answer") as mock_answer: + with patch.object(update, "callback_query", autospec=True) as mock_callback_query: + mock_callback_query.data = update_data handler.process_update() - mock_answer.assert_called_once_with(NOT_FOUND_ERROR, show_alert=True) + mock_callback_query.answer.assert_called_once_with(NOT_FOUND_ERROR, show_alert=True) diff --git a/engine/common/api_helpers/filters.py b/engine/common/api_helpers/filters.py index 6c904618ce..f3423e0cb0 100644 --- a/engine/common/api_helpers/filters.py +++ b/engine/common/api_helpers/filters.py @@ -1,8 +1,9 @@ from datetime import datetime +from django.conf import settings from django.db.models import Q +from django.utils import timezone from django_filters import rest_framework as filters -from django_filters.utils import handle_timezone from drf_spectacular.utils import extend_schema_field from rest_framework import serializers @@ -12,6 +13,14 @@ NO_TEAM_VALUE = "null" +def _handle_timezone(value): + if settings.USE_TZ and timezone.is_naive(value): + return timezone.make_aware(value, timezone.get_current_timezone()) + elif not settings.USE_TZ and timezone.is_aware(value): + return timezone.make_naive(value, timezone.utc) + return value + + class DateRangeFilterMixin: DATE_FORMAT = "%Y-%m-%dT%H:%M:%S" @@ -44,8 +53,8 @@ def parse_custom_datetime_range(cls, value): if start_date > end_date: raise BadRequest(detail="Invalid range value") - start_date = handle_timezone(start_date, False) - end_date = handle_timezone(end_date, False) + start_date = _handle_timezone(start_date) + end_date = _handle_timezone(end_date) return start_date, end_date diff --git a/engine/common/tests/test_ordered_model.py b/engine/common/tests/test_ordered_model.py index 77a58051b1..de579ffa27 100644 --- a/engine/common/tests/test_ordered_model.py +++ b/engine/common/tests/test_ordered_model.py @@ -439,7 +439,7 @@ def delete(idx): assert list(TestOrderedModel.objects.values_list("extra_field", flat=True)) == expected_extra_field_values -class TestOrderedModelSerializer(OrderedModelSerializer): +class OrderedModelSerializerForTests(OrderedModelSerializer): class Meta: model = TestOrderedModel fields = OrderedModelSerializer.Meta.fields + ["test_field", "extra_field"] @@ -461,7 +461,7 @@ def test_ordered_model_swap_all_to_zero_via_serializer(): def update_order_to_zero(idx): try: instance = instances[idx] - serializer = TestOrderedModelSerializer(instance, data={"order": 0, "extra_field": idx}, partial=True) + serializer = OrderedModelSerializerForTests(instance, data={"order": 0, "extra_field": idx}, partial=True) serializer.is_valid(raise_exception=True) serializer.save() instance.swap(positions[idx]) diff --git a/engine/engine/middlewares.py b/engine/engine/middlewares.py index b19db2d48b..c3da3c4c2b 100644 --- a/engine/engine/middlewares.py +++ b/engine/engine/middlewares.py @@ -10,7 +10,7 @@ class RequestTimeLoggingMiddleware(MiddlewareMixin): @staticmethod def log_message(request, response, tag, message=""): - dt = datetime.datetime.utcnow() + dt = datetime.datetime.now(datetime.UTC) if not hasattr(request, "_logging_start_dt"): request._logging_start_dt = dt if request.path.startswith("/integrations/v1"): diff --git a/engine/requirements.in b/engine/requirements.in index 9a0d217780..a872ac6d39 100644 --- a/engine/requirements.in +++ b/engine/requirements.in @@ -5,7 +5,7 @@ cryptography==42.0.8 django==4.2.15 django-add-default-value==0.10.0 django-amazon-ses==4.0.1 -django-anymail==8.6 +django-anymail==11.1 django-cors-headers==3.7.0 # pyroscope-io==0.8.1 django-dbconn-retry==0.1.7 @@ -32,7 +32,7 @@ emoji==2.4.0 grpcio==1.64.1 fcm-django @ https://github.com/grafana/fcm-django/archive/refs/tags/v1.0.12r1.tar.gz#sha256=7ec7cd9d353fc9edf19a4acd4fa14090a31d83d02ac986c5e5e081dea29f564f hiredis==2.2.3 -humanize==0.5.1 +humanize==4.10.0 icalendar==5.0.10 lxml==5.2.2 markdown2==2.4.10 diff --git a/engine/requirements.txt b/engine/requirements.txt index f39d41065d..89a6ae2cb9 100644 --- a/engine/requirements.txt +++ b/engine/requirements.txt @@ -100,7 +100,7 @@ django-add-default-value==0.10.0 # via -r requirements.in django-amazon-ses==4.0.1 # via -r requirements.in -django-anymail==8.6 +django-anymail==11.1 # via -r requirements.in django-cors-headers==3.7.0 # via -r requirements.in @@ -217,7 +217,7 @@ httplib2==0.22.0 # via # google-api-python-client # google-auth-httplib2 -humanize==0.5.1 +humanize==4.10.0 # via -r requirements.in icalendar==5.0.10 # via @@ -458,6 +458,7 @@ urllib3==1.26.19 # via # -r requirements.in # botocore + # django-anymail # requests uwsgi==2.0.26 # via -r requirements.in diff --git a/engine/settings/base.py b/engine/settings/base.py index 9aace2dfb0..e19be7840e 100644 --- a/engine/settings/base.py +++ b/engine/settings/base.py @@ -468,8 +468,6 @@ class DatabaseTypes: USE_I18N = True -USE_L10N = True - USE_TZ = True # Static files (CSS, JavaScript, Images) diff --git a/engine/tox.ini b/engine/tox.ini index 5707e1dfe9..908559ba5e 100644 --- a/engine/tox.ini +++ b/engine/tox.ini @@ -17,3 +17,9 @@ banned-modules = addopts = --dist no --no-migrations --color=yes --showlocals # https://pytest-django.readthedocs.io/en/latest/faq.html#my-tests-are-not-being-found-why python_files = tests.py test_*.py *_tests.py + +filterwarnings = + ignore:::django_filters.* + ignore:::httpretty.* + ignore:::polymorphic.* + ignore:::telegram.*