chore: add task tests; move message task to message app (#6964)
* test: Test send_review_reminders_task * refactor: Move send_scheduled_mail_task to message app * chore: Remove unused import * test: Add Message/SendQueue factories * test: Test send_scheduled_mail_task * test: Reset mocks before reuse * test: Cover error conditions * test: Return non-empty change set * test: Test SMTPException handling * test: Test fetch_attendance_from_meetings() * test: Test RuntimeError handling * test: RFC index sync should populate authors
This commit is contained in:
parent
7438a4e87a
commit
36c43c8520
27
ietf/message/factories.py
Normal file
27
ietf/message/factories.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# Copyright The IETF Trust 2024, All Rights Reserved
|
||||||
|
import factory
|
||||||
|
|
||||||
|
from ietf.person.models import Person
|
||||||
|
from .models import Message, SendQueue
|
||||||
|
|
||||||
|
|
||||||
|
class MessageFactory(factory.django.DjangoModelFactory):
|
||||||
|
class Meta:
|
||||||
|
model = Message
|
||||||
|
|
||||||
|
by = factory.LazyFunction(lambda: Person.objects.get(name="(System)"))
|
||||||
|
subject = factory.Faker("sentence")
|
||||||
|
to = factory.Faker("email")
|
||||||
|
frm = factory.Faker("email")
|
||||||
|
cc = factory.Faker("email")
|
||||||
|
bcc = factory.Faker("email")
|
||||||
|
body = factory.Faker("paragraph")
|
||||||
|
content_type = "text/plain"
|
||||||
|
|
||||||
|
|
||||||
|
class SendQueueFactory(factory.django.DjangoModelFactory):
|
||||||
|
class Meta:
|
||||||
|
model = SendQueue
|
||||||
|
|
||||||
|
by = factory.LazyFunction(lambda: Person.objects.get(name="(System)"))
|
||||||
|
message = factory.SubFactory(MessageFactory)
|
|
@ -1,8 +1,9 @@
|
||||||
# Copyright The IETF Trust 2013-2020, All Rights Reserved
|
# Copyright The IETF Trust 2013-2020, All Rights Reserved
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from smtplib import SMTPException
|
||||||
|
|
||||||
from django.urls import reverse as urlreverse
|
from django.urls import reverse as urlreverse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
@ -10,7 +11,9 @@ from django.utils import timezone
|
||||||
import debug # pyflakes:ignore
|
import debug # pyflakes:ignore
|
||||||
|
|
||||||
from ietf.group.factories import GroupFactory
|
from ietf.group.factories import GroupFactory
|
||||||
|
from ietf.message.factories import SendQueueFactory
|
||||||
from ietf.message.models import Message, SendQueue
|
from ietf.message.models import Message, SendQueue
|
||||||
|
from ietf.message.tasks import send_scheduled_mail_task
|
||||||
from ietf.message.utils import send_scheduled_message_from_send_queue
|
from ietf.message.utils import send_scheduled_message_from_send_queue
|
||||||
from ietf.person.models import Person
|
from ietf.person.models import Person
|
||||||
from ietf.utils.mail import outbox, send_mail_text, send_mail_message, get_payload_text
|
from ietf.utils.mail import outbox, send_mail_text, send_mail_message, get_payload_text
|
||||||
|
@ -128,3 +131,22 @@ class SendScheduledAnnouncementsTests(TestCase):
|
||||||
self.assertTrue("This is a test" in outbox[-1]["Subject"])
|
self.assertTrue("This is a test" in outbox[-1]["Subject"])
|
||||||
self.assertTrue("--NextPart" in outbox[-1].as_string())
|
self.assertTrue("--NextPart" in outbox[-1].as_string())
|
||||||
self.assertTrue(SendQueue.objects.get(id=q.id).sent_at)
|
self.assertTrue(SendQueue.objects.get(id=q.id).sent_at)
|
||||||
|
|
||||||
|
|
||||||
|
class TaskTests(TestCase):
|
||||||
|
@mock.patch("ietf.message.tasks.log_smtp_exception")
|
||||||
|
@mock.patch("ietf.message.tasks.send_scheduled_message_from_send_queue")
|
||||||
|
def test_send_scheduled_mail_task(self, mock_send_message, mock_log_smtp_exception):
|
||||||
|
not_yet_sent = SendQueueFactory()
|
||||||
|
SendQueueFactory(sent_at=timezone.now()) # already sent
|
||||||
|
send_scheduled_mail_task()
|
||||||
|
self.assertEqual(mock_send_message.call_count, 1)
|
||||||
|
self.assertEqual(mock_send_message.call_args[0], (not_yet_sent,))
|
||||||
|
self.assertFalse(mock_log_smtp_exception.called)
|
||||||
|
|
||||||
|
mock_send_message.reset_mock()
|
||||||
|
mock_send_message.side_effect = SMTPException
|
||||||
|
send_scheduled_mail_task()
|
||||||
|
self.assertEqual(mock_send_message.call_count, 1)
|
||||||
|
self.assertEqual(mock_send_message.call_args[0], (not_yet_sent,))
|
||||||
|
self.assertTrue(mock_log_smtp_exception.called)
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
# Copyright The IETF Trust 2019-2020, All Rights Reserved
|
# Copyright The IETF Trust 2019-2020, All Rights Reserved
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import datetime
|
import datetime
|
||||||
|
import mock
|
||||||
import debug # pyflakes:ignore
|
import debug # pyflakes:ignore
|
||||||
|
|
||||||
from pyquery import PyQuery
|
from pyquery import PyQuery
|
||||||
|
|
||||||
from ietf.group.factories import RoleFactory
|
from ietf.group.factories import RoleFactory
|
||||||
from ietf.doc.factories import WgDraftFactory
|
from ietf.doc.factories import WgDraftFactory
|
||||||
from ietf.utils.mail import empty_outbox, get_payload_text, outbox
|
from ietf.utils.mail import empty_outbox, get_payload_text, outbox
|
||||||
|
@ -13,6 +15,7 @@ from ietf.utils.timezone import date_today, datetime_from_date
|
||||||
from .factories import ReviewAssignmentFactory, ReviewRequestFactory, ReviewerSettingsFactory
|
from .factories import ReviewAssignmentFactory, ReviewRequestFactory, ReviewerSettingsFactory
|
||||||
from .mailarch import hash_list_message_id
|
from .mailarch import hash_list_message_id
|
||||||
from .models import ReviewerSettings, ReviewSecretarySettings, ReviewTeamSettings, UnavailablePeriod
|
from .models import ReviewerSettings, ReviewSecretarySettings, ReviewTeamSettings, UnavailablePeriod
|
||||||
|
from .tasks import send_review_reminders_task
|
||||||
from .utils import (email_secretary_reminder, review_assignments_needing_secretary_reminder,
|
from .utils import (email_secretary_reminder, review_assignments_needing_secretary_reminder,
|
||||||
email_reviewer_reminder, review_assignments_needing_reviewer_reminder,
|
email_reviewer_reminder, review_assignments_needing_reviewer_reminder,
|
||||||
send_reminder_unconfirmed_assignments, send_review_reminder_overdue_assignment,
|
send_reminder_unconfirmed_assignments, send_review_reminder_overdue_assignment,
|
||||||
|
@ -550,3 +553,66 @@ class AddReviewCommentTestCase(TestCase):
|
||||||
# But can't have the comment we are goint to add.
|
# But can't have the comment we are goint to add.
|
||||||
self.assertContains(r, 'This is a test.')
|
self.assertContains(r, 'This is a test.')
|
||||||
|
|
||||||
|
|
||||||
|
class TaskTests(TestCase):
|
||||||
|
# hyaaa it's mockzilla
|
||||||
|
@mock.patch("ietf.review.tasks.date_today")
|
||||||
|
@mock.patch("ietf.review.tasks.review_assignments_needing_reviewer_reminder")
|
||||||
|
@mock.patch("ietf.review.tasks.email_reviewer_reminder")
|
||||||
|
@mock.patch("ietf.review.tasks.review_assignments_needing_secretary_reminder")
|
||||||
|
@mock.patch("ietf.review.tasks.email_secretary_reminder")
|
||||||
|
@mock.patch("ietf.review.tasks.send_unavailability_period_ending_reminder")
|
||||||
|
@mock.patch("ietf.review.tasks.send_reminder_all_open_reviews")
|
||||||
|
@mock.patch("ietf.review.tasks.send_review_reminder_overdue_assignment")
|
||||||
|
@mock.patch("ietf.review.tasks.send_reminder_unconfirmed_assignments")
|
||||||
|
def test_send_review_reminders_task(
|
||||||
|
self,
|
||||||
|
mock_send_reminder_unconfirmed_assignments,
|
||||||
|
mock_send_review_reminder_overdue_assignment,
|
||||||
|
mock_send_reminder_all_open_reviews,
|
||||||
|
mock_send_unavailability_period_ending_reminder,
|
||||||
|
mock_email_secretary_reminder,
|
||||||
|
mock_review_assignments_needing_secretary_reminder,
|
||||||
|
mock_email_reviewer_reminder,
|
||||||
|
mock_review_assignments_needing_reviewer_reminder,
|
||||||
|
mock_date_today,
|
||||||
|
):
|
||||||
|
"""Test that send_review_reminders calls functions correctly
|
||||||
|
|
||||||
|
Does not test individual methods, just that they are called as expected.
|
||||||
|
"""
|
||||||
|
mock_today = object()
|
||||||
|
assignment = ReviewAssignmentFactory()
|
||||||
|
secretary_role = RoleFactory(name_id="secr")
|
||||||
|
|
||||||
|
mock_date_today.return_value = mock_today
|
||||||
|
mock_review_assignments_needing_reviewer_reminder.return_value = [assignment]
|
||||||
|
mock_review_assignments_needing_secretary_reminder.return_value = [[assignment, secretary_role]]
|
||||||
|
mock_send_unavailability_period_ending_reminder.return_value = ["pretending I sent a period end reminder"]
|
||||||
|
mock_send_review_reminder_overdue_assignment.return_value = ["pretending I sent an overdue reminder"]
|
||||||
|
mock_send_reminder_all_open_reviews.return_value = ["pretending I sent an open review reminder"]
|
||||||
|
mock_send_reminder_unconfirmed_assignments.return_value = ["pretending I sent an unconfirmed reminder"]
|
||||||
|
|
||||||
|
send_review_reminders_task()
|
||||||
|
|
||||||
|
self.assertEqual(mock_review_assignments_needing_reviewer_reminder.call_count, 1)
|
||||||
|
self.assertEqual(mock_review_assignments_needing_reviewer_reminder.call_args[0], (mock_today,))
|
||||||
|
self.assertEqual(mock_email_reviewer_reminder.call_count, 1)
|
||||||
|
self.assertEqual(mock_email_reviewer_reminder.call_args[0], (assignment,))
|
||||||
|
|
||||||
|
self.assertEqual(mock_review_assignments_needing_secretary_reminder.call_count, 1)
|
||||||
|
self.assertEqual(mock_review_assignments_needing_secretary_reminder.call_args[0], (mock_today,))
|
||||||
|
self.assertEqual(mock_email_secretary_reminder.call_count, 1)
|
||||||
|
self.assertEqual(mock_email_secretary_reminder.call_args[0], (assignment, secretary_role))
|
||||||
|
|
||||||
|
self.assertEqual(mock_send_unavailability_period_ending_reminder.call_count, 1)
|
||||||
|
self.assertEqual(mock_send_unavailability_period_ending_reminder.call_args[0], (mock_today,))
|
||||||
|
|
||||||
|
self.assertEqual(mock_send_review_reminder_overdue_assignment.call_count, 1)
|
||||||
|
self.assertEqual(mock_send_review_reminder_overdue_assignment.call_args[0], (mock_today,))
|
||||||
|
|
||||||
|
self.assertEqual(mock_send_reminder_all_open_reviews.call_count, 1)
|
||||||
|
self.assertEqual(mock_send_reminder_all_open_reviews.call_args[0], (mock_today,))
|
||||||
|
|
||||||
|
self.assertEqual(mock_send_reminder_unconfirmed_assignments.call_count, 1)
|
||||||
|
self.assertEqual(mock_send_reminder_unconfirmed_assignments.call_args[0], (mock_today,))
|
||||||
|
|
|
@ -30,7 +30,7 @@ from ietf.review.factories import ReviewRequestFactory, ReviewerSettingsFactory,
|
||||||
from ietf.stats.models import MeetingRegistration, CountryAlias
|
from ietf.stats.models import MeetingRegistration, CountryAlias
|
||||||
from ietf.stats.factories import MeetingRegistrationFactory
|
from ietf.stats.factories import MeetingRegistrationFactory
|
||||||
from ietf.stats.tasks import fetch_meeting_attendance_task
|
from ietf.stats.tasks import fetch_meeting_attendance_task
|
||||||
from ietf.stats.utils import get_meeting_registration_data, FetchStats
|
from ietf.stats.utils import get_meeting_registration_data, FetchStats, fetch_attendance_from_meetings
|
||||||
from ietf.utils.timezone import date_today
|
from ietf.utils.timezone import date_today
|
||||||
|
|
||||||
|
|
||||||
|
@ -302,6 +302,28 @@ class StatisticsTests(TestCase):
|
||||||
query = MeetingRegistration.objects.all()
|
query = MeetingRegistration.objects.all()
|
||||||
self.assertEqual(query.count(), 2)
|
self.assertEqual(query.count(), 2)
|
||||||
|
|
||||||
|
@patch("ietf.stats.utils.get_meeting_registration_data")
|
||||||
|
def test_fetch_attendance_from_meetings(self, mock_get_mtg_reg_data):
|
||||||
|
mock_meetings = [object(), object(), object()]
|
||||||
|
mock_get_mtg_reg_data.side_effect = (
|
||||||
|
(1, 2, 3),
|
||||||
|
(4, 5, 6),
|
||||||
|
(7, 8, 9),
|
||||||
|
)
|
||||||
|
stats = fetch_attendance_from_meetings(mock_meetings)
|
||||||
|
self.assertEqual(
|
||||||
|
[mock_get_mtg_reg_data.call_args_list[n][0][0] for n in range(3)],
|
||||||
|
mock_meetings,
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
stats,
|
||||||
|
[
|
||||||
|
FetchStats(1, 2, 3),
|
||||||
|
FetchStats(4, 5, 6),
|
||||||
|
FetchStats(7, 8, 9),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TaskTests(TestCase):
|
class TaskTests(TestCase):
|
||||||
@patch("ietf.stats.tasks.fetch_attendance_from_meetings")
|
@patch("ietf.stats.tasks.fetch_attendance_from_meetings")
|
||||||
|
@ -315,6 +337,12 @@ class TaskTests(TestCase):
|
||||||
mock_fetch_attendance.return_value = [FetchStats(1,2,3), FetchStats(1,2,3)]
|
mock_fetch_attendance.return_value = [FetchStats(1,2,3), FetchStats(1,2,3)]
|
||||||
|
|
||||||
fetch_meeting_attendance_task()
|
fetch_meeting_attendance_task()
|
||||||
|
|
||||||
self.assertEqual(mock_fetch_attendance.call_count, 1)
|
self.assertEqual(mock_fetch_attendance.call_count, 1)
|
||||||
self.assertCountEqual(mock_fetch_attendance.call_args[0][0], meetings[0:2])
|
self.assertCountEqual(mock_fetch_attendance.call_args[0][0], meetings[0:2])
|
||||||
|
|
||||||
|
# test handling of RuntimeError
|
||||||
|
mock_fetch_attendance.reset_mock()
|
||||||
|
mock_fetch_attendance.side_effect = RuntimeError
|
||||||
|
fetch_meeting_attendance_task()
|
||||||
|
self.assertTrue(mock_fetch_attendance.called)
|
||||||
|
# Good enough that we got here without raising an exception
|
||||||
|
|
|
@ -8,6 +8,7 @@ import json
|
||||||
import datetime
|
import datetime
|
||||||
import mock
|
import mock
|
||||||
import quopri
|
import quopri
|
||||||
|
import requests
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ from django.test.utils import override_settings
|
||||||
|
|
||||||
import debug # pyflakes:ignore
|
import debug # pyflakes:ignore
|
||||||
|
|
||||||
from ietf.doc.factories import WgDraftFactory, RfcFactory
|
from ietf.doc.factories import WgDraftFactory, RfcFactory, DocumentAuthorFactory
|
||||||
from ietf.doc.models import Document, DocEvent, DeletedEvent, DocTagName, RelatedDocument, State, StateDocEvent
|
from ietf.doc.models import Document, DocEvent, DeletedEvent, DocTagName, RelatedDocument, State, StateDocEvent
|
||||||
from ietf.doc.utils import add_state_change_event
|
from ietf.doc.utils import add_state_change_event
|
||||||
from ietf.group.factories import GroupFactory
|
from ietf.group.factories import GroupFactory
|
||||||
|
@ -238,6 +239,7 @@ class RFCSyncTests(TestCase):
|
||||||
external_url="http://my-external-url.example.com",
|
external_url="http://my-external-url.example.com",
|
||||||
note="this is a note",
|
note="this is a note",
|
||||||
)
|
)
|
||||||
|
DocumentAuthorFactory.create_batch(2, document=draft_doc)
|
||||||
draft_doc.action_holders.add(draft_doc.ad) # not normally set, but add to be sure it's cleared
|
draft_doc.action_holders.add(draft_doc.ad) # not normally set, but add to be sure it's cleared
|
||||||
|
|
||||||
RfcFactory(rfc_number=123)
|
RfcFactory(rfc_number=123)
|
||||||
|
@ -381,6 +383,7 @@ class RFCSyncTests(TestCase):
|
||||||
|
|
||||||
rfc_doc = Document.objects.filter(rfc_number=1234, type_id="rfc").first()
|
rfc_doc = Document.objects.filter(rfc_number=1234, type_id="rfc").first()
|
||||||
self.assertIsNotNone(rfc_doc, "RFC document should have been created")
|
self.assertIsNotNone(rfc_doc, "RFC document should have been created")
|
||||||
|
self.assertEqual(rfc_doc.authors(), draft_doc.authors())
|
||||||
rfc_events = rfc_doc.docevent_set.all()
|
rfc_events = rfc_doc.docevent_set.all()
|
||||||
self.assertEqual(len(rfc_events), 8)
|
self.assertEqual(len(rfc_events), 8)
|
||||||
expected_events = [
|
expected_events = [
|
||||||
|
@ -715,11 +718,14 @@ class TaskTests(TestCase):
|
||||||
errata_response = MockResponse(
|
errata_response = MockResponse(
|
||||||
text="these are the errata", json_length=rfceditor.MIN_ERRATA_RESULTS
|
text="these are the errata", json_length=rfceditor.MIN_ERRATA_RESULTS
|
||||||
)
|
)
|
||||||
|
rfc = RfcFactory()
|
||||||
|
|
||||||
# Test with full_index = False
|
# Test with full_index = False
|
||||||
requests_get_mock.side_effect = (index_response, errata_response) # will step through these
|
requests_get_mock.side_effect = (index_response, errata_response) # will step through these
|
||||||
parse_index_mock.return_value = MockIndexData(length=rfceditor.MIN_INDEX_RESULTS)
|
parse_index_mock.return_value = MockIndexData(length=rfceditor.MIN_INDEX_RESULTS)
|
||||||
update_docs_mock.return_value = [] # not tested
|
update_docs_mock.return_value = (
|
||||||
|
(rfc.rfc_number, ("something changed",), rfc, False),
|
||||||
|
)
|
||||||
|
|
||||||
tasks.rfc_editor_index_update_task(full_index=False)
|
tasks.rfc_editor_index_update_task(full_index=False)
|
||||||
|
|
||||||
|
@ -741,9 +747,10 @@ class TaskTests(TestCase):
|
||||||
self.assertIsNotNone(update_docs_kwargs["skip_older_than_date"])
|
self.assertIsNotNone(update_docs_kwargs["skip_older_than_date"])
|
||||||
|
|
||||||
# Test again with full_index = True
|
# Test again with full_index = True
|
||||||
|
requests_get_mock.reset_mock()
|
||||||
|
parse_index_mock.reset_mock()
|
||||||
|
update_docs_mock.reset_mock()
|
||||||
requests_get_mock.side_effect = (index_response, errata_response) # will step through these
|
requests_get_mock.side_effect = (index_response, errata_response) # will step through these
|
||||||
parse_index_mock.return_value = MockIndexData(length=rfceditor.MIN_INDEX_RESULTS)
|
|
||||||
update_docs_mock.return_value = [] # not tested
|
|
||||||
tasks.rfc_editor_index_update_task(full_index=True)
|
tasks.rfc_editor_index_update_task(full_index=True)
|
||||||
|
|
||||||
# Check parse_index() call
|
# Check parse_index() call
|
||||||
|
@ -762,3 +769,38 @@ class TaskTests(TestCase):
|
||||||
update_docs_args, (parse_index_mock.return_value, errata_response.json())
|
update_docs_args, (parse_index_mock.return_value, errata_response.json())
|
||||||
)
|
)
|
||||||
self.assertIsNone(update_docs_kwargs["skip_older_than_date"])
|
self.assertIsNone(update_docs_kwargs["skip_older_than_date"])
|
||||||
|
|
||||||
|
# Test error handling
|
||||||
|
requests_get_mock.reset_mock()
|
||||||
|
parse_index_mock.reset_mock()
|
||||||
|
update_docs_mock.reset_mock()
|
||||||
|
requests_get_mock.side_effect = requests.Timeout # timeout on every get()
|
||||||
|
tasks.rfc_editor_index_update_task(full_index=False)
|
||||||
|
self.assertFalse(parse_index_mock.called)
|
||||||
|
self.assertFalse(update_docs_mock.called)
|
||||||
|
|
||||||
|
requests_get_mock.reset_mock()
|
||||||
|
parse_index_mock.reset_mock()
|
||||||
|
update_docs_mock.reset_mock()
|
||||||
|
requests_get_mock.side_effect = [index_response, requests.Timeout] # timeout second get()
|
||||||
|
tasks.rfc_editor_index_update_task(full_index=False)
|
||||||
|
self.assertFalse(update_docs_mock.called)
|
||||||
|
|
||||||
|
requests_get_mock.reset_mock()
|
||||||
|
parse_index_mock.reset_mock()
|
||||||
|
update_docs_mock.reset_mock()
|
||||||
|
requests_get_mock.side_effect = [index_response, errata_response]
|
||||||
|
# feed in an index that is too short
|
||||||
|
parse_index_mock.return_value = MockIndexData(length=rfceditor.MIN_INDEX_RESULTS - 1)
|
||||||
|
tasks.rfc_editor_index_update_task(full_index=False)
|
||||||
|
self.assertTrue(parse_index_mock.called)
|
||||||
|
self.assertFalse(update_docs_mock.called)
|
||||||
|
|
||||||
|
requests_get_mock.reset_mock()
|
||||||
|
parse_index_mock.reset_mock()
|
||||||
|
update_docs_mock.reset_mock()
|
||||||
|
requests_get_mock.side_effect = [index_response, errata_response]
|
||||||
|
errata_response.json_length = rfceditor.MIN_ERRATA_RESULTS - 1 # too short
|
||||||
|
parse_index_mock.return_value = MockIndexData(length=rfceditor.MIN_INDEX_RESULTS)
|
||||||
|
tasks.rfc_editor_index_update_task(full_index=False)
|
||||||
|
self.assertFalse(update_docs_mock.called)
|
||||||
|
|
|
@ -56,7 +56,7 @@ class Command(BaseCommand):
|
||||||
def create_default_tasks(self):
|
def create_default_tasks(self):
|
||||||
PeriodicTask.objects.get_or_create(
|
PeriodicTask.objects.get_or_create(
|
||||||
name="Send scheduled mail",
|
name="Send scheduled mail",
|
||||||
task="ietf.utils.tasks.send_scheduled_mail_task",
|
task="ietf.meeting.tasks.send_scheduled_mail_task",
|
||||||
defaults=dict(
|
defaults=dict(
|
||||||
enabled=False,
|
enabled=False,
|
||||||
crontab=self.crontabs["every_15m"],
|
crontab=self.crontabs["every_15m"],
|
||||||
|
|
Loading…
Reference in a new issue