Skip to content

Commit 235ac8b

Browse files
refactor: idnits2 mgmt cmds -> tasks (ietf-tools#7421)
* feat: tasks for generate_idnits2_rfc* mgmt cmds * chore: create periodic tasks * chore: remove mgmt cmds from bin/hourly * test: test new tasks * chore: remove now-unused scripts * refactor: unitize Idnits2SupportTests
1 parent c0a12fa commit 235ac8b

7 files changed

Lines changed: 101 additions & 62 deletions

File tree

bin/hourly

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@ ID=/a/ietfdata/doc/draft/repository
2424
DERIVED=/a/ietfdata/derived
2525
DOWNLOAD=/a/www/www6s/download
2626

27-
$DTDIR/ietf/manage.py generate_idnits2_rfc_status
28-
$DTDIR/ietf/manage.py generate_idnits2_rfcs_obsoleted
29-
3027
CHARTER=/a/www/ietf-ftp/charter
3128
wget -q https://datatracker.ietf.org/wg/1wg-charters-by-acronym.txt -O $CHARTER/1wg-charters-by-acronym.txt
3229
wget -q https://datatracker.ietf.org/wg/1wg-charters.txt -O $CHARTER/1wg-charters.txt

ietf/doc/management/commands/generate_idnits2_rfc_status.py

Lines changed: 0 additions & 23 deletions
This file was deleted.

ietf/doc/management/commands/generate_idnits2_rfcs_obsoleted.py

Lines changed: 0 additions & 23 deletions
This file was deleted.

ietf/doc/tasks.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
import debug # pyflakes:ignore
77

88
from celery import shared_task
9+
from pathlib import Path
10+
11+
from django.conf import settings
912

1013
from ietf.utils import log
1114
from ietf.utils.timezone import datetime_today
@@ -21,6 +24,7 @@
2124
send_expire_warning_for_draft,
2225
)
2326
from .models import Document
27+
from .utils import generate_idnits2_rfc_status, generate_idnits2_rfcs_obsoleted
2428

2529

2630
@shared_task
@@ -54,3 +58,23 @@ def expire_ids_task():
5458
def notify_expirations_task(notify_days=14):
5559
for doc in get_soon_to_expire_drafts(notify_days):
5660
send_expire_warning_for_draft(doc)
61+
62+
63+
@shared_task
64+
def generate_idnits2_rfc_status_task():
65+
outpath = Path(settings.DERIVED_DIR) / "idnits2-rfc-status"
66+
blob = generate_idnits2_rfc_status()
67+
try:
68+
outpath.write_text(blob, encoding="utf8")
69+
except Exception as e:
70+
log.log(f"failed to write idnits2-rfc-status: {e}")
71+
72+
73+
@shared_task
74+
def generate_idnits2_rfcs_obsoleted_task():
75+
outpath = Path(settings.DERIVED_DIR) / "idnits2-rfcs-obsoleted"
76+
blob = generate_idnits2_rfcs_obsoleted()
77+
try:
78+
outpath.write_text(blob, encoding="utf8")
79+
except Exception as e:
80+
log.log(f"failed to write idnits2-rfcs-obsoleted: {e}")

ietf/doc/tests.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
from collections import defaultdict
2121
from zoneinfo import ZoneInfo
2222

23-
from django.core.management import call_command
2423
from django.urls import reverse as urlreverse
2524
from django.conf import settings
2625
from django.forms import Form
@@ -45,7 +44,14 @@
4544
StatusChangeFactory, DocExtResourceFactory, RgDraftFactory, BcpFactory)
4645
from ietf.doc.forms import NotifyForm
4746
from ietf.doc.fields import SearchableDocumentsField
48-
from ietf.doc.utils import create_ballot_if_not_open, investigate_fragment, uppercase_std_abbreviated_name, DraftAliasGenerator
47+
from ietf.doc.utils import (
48+
create_ballot_if_not_open,
49+
investigate_fragment,
50+
uppercase_std_abbreviated_name,
51+
DraftAliasGenerator,
52+
generate_idnits2_rfc_status,
53+
generate_idnits2_rfcs_obsoleted,
54+
)
4955
from ietf.group.models import Group, Role
5056
from ietf.group.factories import GroupFactory, RoleFactory
5157
from ietf.ipr.factories import HolderIprDisclosureFactory
@@ -2831,32 +2837,40 @@ def test_markdown_and_text(self):
28312837
class Idnits2SupportTests(TestCase):
28322838
settings_temp_path_overrides = TestCase.settings_temp_path_overrides + ['DERIVED_DIR']
28332839

2834-
def test_obsoleted(self):
2840+
def test_generate_idnits2_rfcs_obsoleted(self):
28352841
rfc = WgRfcFactory(rfc_number=1001)
28362842
WgRfcFactory(rfc_number=1003,relations=[('obs',rfc)])
28372843
rfc = WgRfcFactory(rfc_number=1005)
28382844
WgRfcFactory(rfc_number=1007,relations=[('obs',rfc)])
2845+
blob = generate_idnits2_rfcs_obsoleted()
2846+
self.assertEqual(blob, b'1001 1003\n1005 1007\n'.decode("utf8"))
28392847

2848+
def test_obsoleted(self):
28402849
url = urlreverse('ietf.doc.views_doc.idnits2_rfcs_obsoleted')
28412850
r = self.client.get(url)
28422851
self.assertEqual(r.status_code, 404)
2843-
call_command('generate_idnits2_rfcs_obsoleted')
2852+
# value written is arbitrary, expect it to be passed through
2853+
(Path(settings.DERIVED_DIR) / "idnits2-rfcs-obsoleted").write_bytes(b'1001 1003\n1005 1007\n')
28442854
url = urlreverse('ietf.doc.views_doc.idnits2_rfcs_obsoleted')
28452855
r = self.client.get(url)
28462856
self.assertEqual(r.status_code, 200)
28472857
self.assertEqual(r.content, b'1001 1003\n1005 1007\n')
28482858

2849-
def test_rfc_status(self):
2859+
def test_generate_idnits2_rfc_status(self):
28502860
for slug in ('bcp', 'ds', 'exp', 'hist', 'inf', 'std', 'ps', 'unkn'):
28512861
WgRfcFactory(std_level_id=slug)
2862+
blob = generate_idnits2_rfc_status().replace("\n", "")
2863+
self.assertEqual(blob[6312-1], "O")
2864+
2865+
def test_rfc_status(self):
28522866
url = urlreverse('ietf.doc.views_doc.idnits2_rfc_status')
28532867
r = self.client.get(url)
28542868
self.assertEqual(r.status_code,404)
2855-
call_command('generate_idnits2_rfc_status')
2869+
# value written is arbitrary, expect it to be passed through
2870+
(Path(settings.DERIVED_DIR) / "idnits2-rfc-status").write_bytes(b'1001 1003\n1005 1007\n')
28562871
r = self.client.get(url)
28572872
self.assertEqual(r.status_code,200)
2858-
blob = unicontent(r).replace('\n','')
2859-
self.assertEqual(blob[6312-1],'O')
2873+
self.assertEqual(r.content, b'1001 1003\n1005 1007\n')
28602874

28612875
def test_idnits2_state(self):
28622876
rfc = WgRfcFactory()

ietf/doc/tests_tasks.py

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
11
# Copyright The IETF Trust 2024, All Rights Reserved
22
import mock
33

4+
from pathlib import Path
5+
6+
from django.conf import settings
7+
48
from ietf.utils.test_utils import TestCase
59
from ietf.utils.timezone import datetime_today
610

711
from .factories import DocumentFactory
812
from .models import Document
9-
from .tasks import expire_ids_task, notify_expirations_task
10-
13+
from .tasks import (
14+
expire_ids_task,
15+
generate_idnits2_rfcs_obsoleted_task,
16+
generate_idnits2_rfc_status_task,
17+
notify_expirations_task,
18+
)
1119

1220
class TaskTests(TestCase):
21+
settings_temp_path_overrides = TestCase.settings_temp_path_overrides + ["DERIVED_DIR"]
1322

1423
@mock.patch("ietf.doc.tasks.in_draft_expire_freeze")
1524
@mock.patch("ietf.doc.tasks.get_expired_drafts")
@@ -35,10 +44,10 @@ def test_expire_ids_task(
3544
Document.objects.filter(pk=doc.pk),
3645
Document.objects.filter(pk=other_doc.pk),
3746
]
38-
47+
3948
# call task
4049
expire_ids_task()
41-
50+
4251
# check results
4352
self.assertTrue(in_draft_expire_freeze_mock.called)
4453
self.assertEqual(expirable_drafts_mock.call_count, 2)
@@ -50,7 +59,7 @@ def test_expire_ids_task(
5059

5160
# test that an exception is raised
5261
in_draft_expire_freeze_mock.side_effect = RuntimeError
53-
with self.assertRaises(RuntimeError):(
62+
with self.assertRaises(RuntimeError): (
5463
expire_ids_task())
5564

5665
@mock.patch("ietf.doc.tasks.send_expire_warning_for_draft")
@@ -61,3 +70,24 @@ def test_notify_expirations_task(self, get_drafts_mock, send_warning_mock):
6170
notify_expirations_task()
6271
self.assertEqual(send_warning_mock.call_count, 1)
6372
self.assertEqual(send_warning_mock.call_args[0], ("sentinel",))
73+
74+
@mock.patch("ietf.doc.tasks.generate_idnits2_rfc_status")
75+
def test_generate_idnits2_rfc_status_task(self, mock_generate):
76+
mock_generate.return_value = "dåtå"
77+
generate_idnits2_rfc_status_task()
78+
self.assertEqual(mock_generate.call_count, 1)
79+
self.assertEqual(
80+
"dåtå".encode("utf8"),
81+
(Path(settings.DERIVED_DIR) / "idnits2-rfc-status").read_bytes(),
82+
)
83+
84+
@mock.patch("ietf.doc.tasks.generate_idnits2_rfcs_obsoleted")
85+
def test_generate_idnits2_rfcs_obsoleted_task(self, mock_generate):
86+
mock_generate.return_value = "dåtå"
87+
generate_idnits2_rfcs_obsoleted_task()
88+
self.assertEqual(mock_generate.call_count, 1)
89+
self.assertEqual(
90+
"dåtå".encode("utf8"),
91+
(Path(settings.DERIVED_DIR) / "idnits2-rfcs-obsoleted").read_bytes(),
92+
)
93+

ietf/utils/management/commands/periodic_tasks.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,26 @@ def create_default_tasks(self):
181181
)
182182
)
183183

184+
PeriodicTask.objects.get_or_create(
185+
name="Generate idnits2 rfcs-obsoleted blob",
186+
task="ietf.doc.tasks.generate_idnits2_rfcs_obsoleted_task",
187+
defaults=dict(
188+
enabled=False,
189+
crontab=self.crontabs["hourly"],
190+
description="Generate the rfcs-obsoleted file used by idnits",
191+
),
192+
)
193+
194+
PeriodicTask.objects.get_or_create(
195+
name="Generate idnits2 rfc-status blob",
196+
task="ietf.doc.tasks.generate_idnits2_rfc_status_task",
197+
defaults=dict(
198+
enabled=False,
199+
crontab=self.crontabs["hourly"],
200+
description="Generate the rfc_status blob used by idnits",
201+
),
202+
)
203+
184204
def show_tasks(self):
185205
for label, crontab in self.crontabs.items():
186206
tasks = PeriodicTask.objects.filter(crontab=crontab).order_by(

0 commit comments

Comments
 (0)