import os import shutil import calendar import json import datetime from pyquery import PyQuery import debug # pyflakes:ignore from django.conf import settings from django.core.urlresolvers import reverse as urlreverse from ietf.doc.models import Document, DocAlias, DocEvent, State from ietf.group.models import Group, GroupEvent, GroupMilestone, GroupStateTransitions, MilestoneGroupEvent from ietf.group.utils import save_group_in_history from ietf.name.models import DocTagName, GroupStateName from ietf.person.models import Person, Email from ietf.utils.test_utils import TestCase from ietf.utils.mail import outbox from ietf.utils.test_data import make_test_data from ietf.utils.test_utils import login_testing_unauthorized from ietf.wginfo.mails import ( email_milestone_review_reminder, email_milestones_due, email_milestones_overdue, groups_needing_milestones_due_reminder, groups_needing_milestones_overdue_reminder, groups_with_milestones_needing_review ) class GroupPagesTests(TestCase): def setUp(self): self.charter_dir = os.path.abspath("tmp-charter-dir") os.mkdir(self.charter_dir) settings.CHARTER_PATH = self.charter_dir def tearDown(self): shutil.rmtree(self.charter_dir) def test_active_wgs(self): draft = make_test_data() group = draft.group url = urlreverse('ietf.wginfo.views.active_wgs') r = self.client.get(url) self.assertEqual(r.status_code, 200) self.assertTrue(group.parent.name in r.content) self.assertTrue(group.acronym in r.content) self.assertTrue(group.name in r.content) self.assertTrue(group.ad.plain_name() in r.content) def test_wg_summaries(self): draft = make_test_data() group = draft.group chair = Email.objects.filter(role__group=group, role__name="chair")[0] with open(os.path.join(self.charter_dir, "%s-%s.txt" % (group.charter.canonical_name(), group.charter.rev)), "w") as f: f.write("This is a charter.") url = urlreverse('ietf.wginfo.views.wg_summary_area') r = self.client.get(url) self.assertEqual(r.status_code, 200) self.assertTrue(group.parent.name in r.content) self.assertTrue(group.acronym in r.content) self.assertTrue(group.name in r.content) self.assertTrue(chair.address in r.content) url = urlreverse('ietf.wginfo.views.wg_summary_acronym') r = self.client.get(url) self.assertEqual(r.status_code, 200) self.assertTrue(group.acronym in r.content) self.assertTrue(group.name in r.content) self.assertTrue(chair.address in r.content) url = urlreverse('ietf.wginfo.views.wg_charters') r = self.client.get(url) self.assertEqual(r.status_code, 200) self.assertTrue(group.acronym in r.content) self.assertTrue(group.name in r.content) self.assertTrue(group.ad.plain_name() in r.content) self.assertTrue(chair.address in r.content) self.assertTrue("This is a charter." in r.content) url = urlreverse('ietf.wginfo.views.wg_charters_by_acronym') r = self.client.get(url) self.assertEqual(r.status_code, 200) self.assertTrue(group.acronym in r.content) self.assertTrue(group.name in r.content) self.assertTrue(group.ad.plain_name() in r.content) self.assertTrue(chair.address in r.content) self.assertTrue("This is a charter." in r.content) def test_chartering_wgs(self): draft = make_test_data() group = draft.group group.charter.set_state(State.objects.get(used=True, type="charter", slug="intrev")) url = urlreverse('ietf.wginfo.views.chartering_wgs') r = self.client.get(url) self.assertEqual(r.status_code, 200) q = PyQuery(r.content) self.assertEqual(len(q('table.ietf-doctable td.acronym a:contains("%s")' % group.acronym)), 1) def test_bofs(self): draft = make_test_data() group = draft.group group.state_id = "bof" group.save() url = urlreverse('ietf.wginfo.views.bofs') r = self.client.get(url) self.assertEqual(r.status_code, 200) q = PyQuery(r.content) self.assertEqual(len(q('table.ietf-doctable td.acronym a:contains("%s")' % group.acronym)), 1) def test_group_documents(self): draft = make_test_data() group = draft.group draft2 = Document.objects.create( name="draft-somebody-mars-test", time=datetime.datetime.now(), type_id="draft", title="Test By Somebody", stream_id="ietf", group=Group.objects.get(type="individ"), abstract="Abstract.", rev="01", pages=2, intended_std_level_id="ps", shepherd=None, ad=None, expires=datetime.datetime.now() + datetime.timedelta(days=10), notify="", note="", ) draft2.set_state(State.objects.get(used=True, type="draft", slug="active")) DocAlias.objects.create( document=draft2, name=draft2.name, ) url = urlreverse('ietf.wginfo.views.group_documents', kwargs=dict(acronym=group.acronym)) r = self.client.get(url) self.assertEqual(r.status_code, 200) self.assertTrue(draft.name in r.content) self.assertTrue(group.name in r.content) self.assertTrue(group.acronym in r.content) self.assertTrue(draft2.name in r.content) # test the txt version too while we're at it url = urlreverse('ietf.wginfo.views.group_documents_txt', kwargs=dict(acronym=group.acronym)) r = self.client.get(url) self.assertEqual(r.status_code, 200) self.assertTrue(draft.name in r.content) self.assertTrue(draft2.name in r.content) def test_group_charter(self): draft = make_test_data() group = draft.group with open(os.path.join(self.charter_dir, "%s-%s.txt" % (group.charter.canonical_name(), group.charter.rev)), "w") as f: f.write("This is a charter.") milestone = GroupMilestone.objects.create( group=group, state_id="active", desc="Get Work Done", due=datetime.date.today() + datetime.timedelta(days=100)) milestone.docs.add(draft) url = urlreverse('ietf.wginfo.views.group_charter', kwargs=dict(acronym=group.acronym)) r = self.client.get(url) self.assertEqual(r.status_code, 200) self.assertTrue(group.name in r.content) self.assertTrue(group.acronym in r.content) self.assertTrue("This is a charter." in r.content) self.assertTrue(milestone.desc in r.content) self.assertTrue(milestone.docs.all()[0].name in r.content) def test_history(self): draft = make_test_data() group = draft.group e = GroupEvent.objects.create( group=group, desc="Something happened.", type="added_comment", by=Person.objects.get(name="(System)")) url = urlreverse('ietf.wginfo.views.history', kwargs=dict(acronym=group.acronym)) r = self.client.get(url) self.assertEqual(r.status_code, 200) self.assertTrue(e.desc in r.content) def test_feed(self): draft = make_test_data() group = draft.group ge = GroupEvent.objects.create( group=group, desc="Something happened.", type="added_comment", by=Person.objects.get(name="(System)")) de = DocEvent.objects.create( doc=group.charter, desc="Something else happened.", type="added_comment", by=Person.objects.get(name="(System)")) r = self.client.get("/feed/group-changes/%s/" % group.acronym) self.assertEqual(r.status_code, 200) self.assertTrue(ge.desc in r.content) self.assertTrue(de.desc in r.content) class GroupEditTests(TestCase): def setUp(self): self.charter_dir = os.path.abspath("tmp-charter-dir") os.mkdir(self.charter_dir) settings.CHARTER_PATH = self.charter_dir def tearDown(self): shutil.rmtree(self.charter_dir) def test_create(self): make_test_data() url = urlreverse('wg_create') login_testing_unauthorized(self, "secretary", url) num_wgs = len(Group.objects.filter(type="wg")) bof_state = GroupStateName.objects.get(slug="bof") # normal get r = self.client.get(url) self.assertEqual(r.status_code, 200) q = PyQuery(r.content) self.assertEqual(len(q('form input[name=acronym]')), 1) # faulty post r = self.client.post(url, dict(acronym="foobarbaz")) # No name self.assertEqual(r.status_code, 200) q = PyQuery(r.content) self.assertTrue(len(q('form ul.errorlist')) > 0) self.assertEqual(len(Group.objects.filter(type="wg")), num_wgs) # acronym contains non-alphanumeric r = self.client.post(url, dict(acronym="test...", name="Testing WG", state=bof_state.pk)) self.assertEqual(r.status_code, 200) # acronym contains hyphen r = self.client.post(url, dict(acronym="test-wg", name="Testing WG", state=bof_state.pk)) self.assertEqual(r.status_code, 200) # acronym too short r = self.client.post(url, dict(acronym="t", name="Testing WG", state=bof_state.pk)) self.assertEqual(r.status_code, 200) # acronym doesn't start with an alpha character r = self.client.post(url, dict(acronym="1startwithalpha", name="Testing WG", state=bof_state.pk)) self.assertEqual(r.status_code, 200) # creation r = self.client.post(url, dict(acronym="testwg", name="Testing WG", state=bof_state.pk)) self.assertEqual(r.status_code, 302) self.assertEqual(len(Group.objects.filter(type="wg")), num_wgs + 1) group = Group.objects.get(acronym="testwg") self.assertEqual(group.name, "Testing WG") self.assertEqual(group.charter.name, "charter-ietf-testwg") self.assertEqual(group.charter.rev, "00-00") def test_create_based_on_existing(self): make_test_data() url = urlreverse('wg_create') login_testing_unauthorized(self, "secretary", url) group = Group.objects.get(acronym="mars") # try hijacking area - faulty r = self.client.post(url, dict(name="Test", acronym=group.parent.acronym)) self.assertEqual(r.status_code, 200) q = PyQuery(r.content) self.assertTrue(len(q('form ul.errorlist')) > 0) self.assertEqual(len(q('form input[name="confirmed"]')), 0) # can't confirm us out of this # try elevating BoF to WG group.state_id = "bof" group.save() r = self.client.post(url, dict(name="Test", acronym=group.acronym)) self.assertEqual(r.status_code, 200) q = PyQuery(r.content) self.assertTrue(len(q('form ul.errorlist')) > 0) self.assertEqual(len(q('form input[name="confirmed"]')), 1) self.assertEqual(Group.objects.get(acronym=group.acronym).state_id, "bof") # confirm elevation state = GroupStateName.objects.get(slug="proposed") r = self.client.post(url, dict(name="Test", acronym=group.acronym, confirmed="1",state=state.pk)) self.assertEqual(r.status_code, 302) self.assertEqual(Group.objects.get(acronym=group.acronym).state_id, "proposed") self.assertEqual(Group.objects.get(acronym=group.acronym).name, "Test") def test_edit_info(self): make_test_data() group = Group.objects.get(acronym="mars") url = urlreverse('group_edit', kwargs=dict(acronym=group.acronym)) login_testing_unauthorized(self, "secretary", url) # normal get r = self.client.get(url) self.assertEqual(r.status_code, 200) q = PyQuery(r.content) self.assertEqual(len(q('form select[name=parent]')), 1) self.assertEqual(len(q('form input[name=acronym]')), 1) # faulty post Group.objects.create(name="Collision Test Group", acronym="collide") r = self.client.post(url, dict(acronym="collide")) self.assertEqual(r.status_code, 200) q = PyQuery(r.content) self.assertTrue(len(q('form ul.errorlist')) > 0) # create old acronym group.acronym = "oldmars" group.save() save_group_in_history(group) group.acronym = "mars" group.save() # post with warning r = self.client.post(url, dict(acronym="oldmars")) self.assertEqual(r.status_code, 200) q = PyQuery(r.content) self.assertTrue(len(q('form ul.errorlist')) > 0) # edit info with open(os.path.join(self.charter_dir, "%s-%s.txt" % (group.charter.canonical_name(), group.charter.rev)), "w") as f: f.write("This is a charter.") area = group.parent ad = Person.objects.get(name="Aread Irector") state = GroupStateName.objects.get(slug="bof") r = self.client.post(url, dict(name="Mars Not Special Interest Group", acronym="mars", parent=area.pk, ad=ad.pk, state=state.pk, chairs="aread@ietf.org, ad1@ietf.org", secretaries="aread@ietf.org, ad1@ietf.org, ad2@ietf.org", techadv="aread@ietf.org", delegates="ad2@ietf.org", list_email="mars@mail", list_subscribe="subscribe.mars", list_archive="archive.mars", urls="http://mars.mars (MARS site)" )) self.assertEqual(r.status_code, 302) group = Group.objects.get(acronym="mars") self.assertEqual(group.name, "Mars Not Special Interest Group") self.assertEqual(group.parent, area) self.assertEqual(group.ad, ad) for k in ("chair", "secr", "techadv"): self.assertTrue(group.role_set.filter(name=k, email__address="aread@ietf.org")) self.assertTrue(group.role_set.filter(name="delegate", email__address="ad2@ietf.org")) self.assertEqual(group.list_email, "mars@mail") self.assertEqual(group.list_subscribe, "subscribe.mars") self.assertEqual(group.list_archive, "archive.mars") self.assertEqual(group.groupurl_set.all()[0].url, "http://mars.mars") self.assertEqual(group.groupurl_set.all()[0].name, "MARS site") self.assertTrue(os.path.exists(os.path.join(self.charter_dir, "%s-%s.txt" % (group.charter.canonical_name(), group.charter.rev)))) def test_conclude(self): make_test_data() group = Group.objects.get(acronym="mars") url = urlreverse('wg_conclude', kwargs=dict(acronym=group.acronym)) login_testing_unauthorized(self, "secretary", url) # normal get r = self.client.get(url) self.assertEqual(r.status_code, 200) q = PyQuery(r.content) self.assertEqual(len(q('form textarea[name=instructions]')), 1) # faulty post r = self.client.post(url, dict(instructions="")) # No instructions self.assertEqual(r.status_code, 200) q = PyQuery(r.content) self.assertTrue(len(q('form ul.errorlist')) > 0) # request conclusion mailbox_before = len(outbox) r = self.client.post(url, dict(instructions="Test instructions")) self.assertEqual(r.status_code, 302) self.assertEqual(len(outbox), mailbox_before + 1) # the WG remains active until the Secretariat takes action group = Group.objects.get(acronym=group.acronym) self.assertEqual(group.state_id, "active") class MilestoneTests(TestCase): def create_test_milestones(self): draft = make_test_data() group = Group.objects.get(acronym="mars") m1 = GroupMilestone.objects.create(id=1, group=group, desc="Test 1", due=datetime.date.today(), resolved="", state_id="active") m1.docs = [draft] m2 = GroupMilestone.objects.create(id=2, group=group, desc="Test 2", due=datetime.date.today(), resolved="", state_id="charter") m2.docs = [draft] return (m1, m2, group) def last_day_of_month(self, d): return datetime.date(d.year, d.month, calendar.monthrange(d.year, d.month)[1]) def test_milestone_sets(self): m1, m2, group = self.create_test_milestones() url = urlreverse('wg_edit_milestones', kwargs=dict(acronym=group.acronym)) login_testing_unauthorized(self, "secretary", url) r = self.client.get(url) self.assertEqual(r.status_code, 200) self.assertTrue(m1.desc in r.content) self.assertTrue(m2.desc not in r.content) url = urlreverse('wg_edit_charter_milestones', kwargs=dict(acronym=group.acronym)) r = self.client.get(url) self.assertEqual(r.status_code, 200) self.assertTrue(m1.desc not in r.content) self.assertTrue(m2.desc in r.content) def test_add_milestone(self): m1, m2, group = self.create_test_milestones() url = urlreverse('wg_edit_milestones', kwargs=dict(acronym=group.acronym)) login_testing_unauthorized(self, "secretary", url) # normal get r = self.client.get(url) self.assertEqual(r.status_code, 200) milestones_before = GroupMilestone.objects.count() events_before = group.groupevent_set.count() docs = Document.objects.filter(type="draft").values_list("name", flat=True) due = self.last_day_of_month(datetime.date.today() + datetime.timedelta(days=365)) # faulty post r = self.client.post(url, { 'prefix': "m-1", 'm-1-id': "-1", 'm-1-desc': "", # no description 'm-1-due_month': str(due.month), 'm-1-due_year': str(due.year), 'm-1-resolved': "", 'm-1-docs': ",".join(docs), 'action': "save", }) self.assertEqual(r.status_code, 200) q = PyQuery(r.content) self.assertTrue(len(q('form ul.errorlist')) > 0) self.assertEqual(GroupMilestone.objects.count(), milestones_before) # add r = self.client.post(url, { 'prefix': "m-1", 'm-1-id': "-1", 'm-1-desc': "Test 3", 'm-1-due_month': str(due.month), 'm-1-due_year': str(due.year), 'm-1-resolved': "", 'm-1-docs': ",".join(docs), 'action': "save", }) self.assertEqual(r.status_code, 302) self.assertEqual(GroupMilestone.objects.count(), milestones_before + 1) self.assertEqual(group.groupevent_set.count(), events_before + 1) m = GroupMilestone.objects.get(desc="Test 3") self.assertEqual(m.state_id, "active") self.assertEqual(m.due, due) self.assertEqual(m.resolved, "") self.assertEqual(set(m.docs.values_list("name", flat=True)), set(docs)) self.assertTrue("Added milestone" in m.milestonegroupevent_set.all()[0].desc) def test_add_milestone_as_chair(self): m1, m2, group = self.create_test_milestones() url = urlreverse('wg_edit_milestones', kwargs=dict(acronym=group.acronym)) login_testing_unauthorized(self, "marschairman", url) # normal get r = self.client.get(url) self.assertEqual(r.status_code, 200) milestones_before = GroupMilestone.objects.count() events_before = group.groupevent_set.count() due = self.last_day_of_month(datetime.date.today() + datetime.timedelta(days=365)) # add r = self.client.post(url, { 'prefix': "m-1", 'm-1-id': -1, 'm-1-desc': "Test 3", 'm-1-due_month': str(due.month), 'm-1-due_year': str(due.year), 'm-1-resolved': "", 'm-1-docs': "", 'action': "save", }) self.assertEqual(r.status_code, 302) self.assertEqual(GroupMilestone.objects.count(), milestones_before + 1) m = GroupMilestone.objects.get(desc="Test 3") self.assertEqual(m.state_id, "review") self.assertEqual(group.groupevent_set.count(), events_before + 1) self.assertTrue("for review" in m.milestonegroupevent_set.all()[0].desc) def test_accept_milestone(self): m1, m2, group = self.create_test_milestones() m1.state_id = "review" m1.save() url = urlreverse('wg_edit_milestones', kwargs=dict(acronym=group.acronym)) login_testing_unauthorized(self, "ad", url) # normal get r = self.client.get(url) self.assertEqual(r.status_code, 200) events_before = group.groupevent_set.count() # add r = self.client.post(url, { 'prefix': "m1", 'm1-id': m1.id, 'm1-desc': m1.desc, 'm1-due_month': str(m1.due.month), 'm1-due_year': str(m1.due.year), 'm1-resolved': m1.resolved, 'm1-docs': ",".join(m1.docs.values_list("name", flat=True)), 'm1-accept': "accept", 'action': "save", }) self.assertEqual(r.status_code, 302) m = GroupMilestone.objects.get(pk=m1.pk) self.assertEqual(m.state_id, "active") self.assertEqual(group.groupevent_set.count(), events_before + 1) self.assertTrue("to active from review" in m.milestonegroupevent_set.all()[0].desc) def test_delete_milestone(self): m1, m2, group = self.create_test_milestones() url = urlreverse('wg_edit_milestones', kwargs=dict(acronym=group.acronym)) login_testing_unauthorized(self, "secretary", url) milestones_before = GroupMilestone.objects.count() events_before = group.groupevent_set.count() # delete r = self.client.post(url, { 'prefix': "m1", 'm1-id': m1.id, 'm1-desc': m1.desc, 'm1-due_month': str(m1.due.month), 'm1-due_year': str(m1.due.year), 'm1-resolved': "", 'm1-docs': ",".join(m1.docs.values_list("name", flat=True)), 'm1-delete': "checked", 'action': "save", }) self.assertEqual(r.status_code, 302) self.assertEqual(GroupMilestone.objects.count(), milestones_before) self.assertEqual(group.groupevent_set.count(), events_before + 1) m = GroupMilestone.objects.get(pk=m1.pk) self.assertEqual(m.state_id, "deleted") self.assertTrue("Deleted milestone" in m.milestonegroupevent_set.all()[0].desc) def test_edit_milestone(self): m1, m2, group = self.create_test_milestones() url = urlreverse('wg_edit_milestones', kwargs=dict(acronym=group.acronym)) login_testing_unauthorized(self, "secretary", url) milestones_before = GroupMilestone.objects.count() events_before = group.groupevent_set.count() docs = Document.objects.filter(type="draft").values_list("name", flat=True) due = self.last_day_of_month(datetime.date.today() + datetime.timedelta(days=365)) # faulty post r = self.client.post(url, { 'prefix': "m1", 'm1-id': m1.id, 'm1-desc': "", # no description 'm1-due_month': str(due.month), 'm1-due_year': str(due.year), 'm1-resolved': "", 'm1-docs': ",".join(docs), 'action': "save", }) self.assertEqual(r.status_code, 200) q = PyQuery(r.content) self.assertTrue(len(q('form ul.errorlist')) > 0) m = GroupMilestone.objects.get(pk=m1.pk) self.assertEqual(GroupMilestone.objects.count(), milestones_before) self.assertEqual(m.due, m1.due) # edit mailbox_before = len(outbox) r = self.client.post(url, { 'prefix': "m1", 'm1-id': m1.id, 'm1-desc': "Test 2 - changed", 'm1-due_month': str(due.month), 'm1-due_year': str(due.year), 'm1-resolved': "Done", 'm1-resolved_checkbox': "checked", 'm1-docs': ",".join(docs), 'action': "save", }) self.assertEqual(r.status_code, 302) self.assertEqual(GroupMilestone.objects.count(), milestones_before) self.assertEqual(group.groupevent_set.count(), events_before + 1) m = GroupMilestone.objects.get(pk=m1.pk) self.assertEqual(m.state_id, "active") self.assertEqual(m.due, due) self.assertEqual(m.resolved, "Done") self.assertEqual(set(m.docs.values_list("name", flat=True)), set(docs)) self.assertTrue("Changed milestone" in m.milestonegroupevent_set.all()[0].desc) self.assertEqual(len(outbox), mailbox_before + 2) self.assertTrue("Milestones changed" in outbox[-2]["Subject"]) self.assertTrue(group.ad.role_email("ad").address in str(outbox[-2])) self.assertTrue("Milestones changed" in outbox[-1]["Subject"]) self.assertTrue(group.list_email in str(outbox[-1])) def test_reset_charter_milestones(self): m1, m2, group = self.create_test_milestones() url = urlreverse('wg_reset_charter_milestones', kwargs=dict(acronym=group.acronym)) login_testing_unauthorized(self, "secretary", url) # normal get r = self.client.get(url) self.assertEqual(r.status_code, 200) q = PyQuery(r.content) self.assertEqual(q('input[name=milestone]').val(), str(m1.pk)) events_before = group.charter.docevent_set.count() # reset r = self.client.post(url, dict(milestone=[str(m1.pk)])) self.assertEqual(r.status_code, 302) self.assertEqual(GroupMilestone.objects.get(pk=m1.pk).state_id, "active") self.assertEqual(GroupMilestone.objects.get(pk=m2.pk).state_id, "deleted") self.assertEqual(GroupMilestone.objects.filter(due=m1.due, desc=m1.desc, state="charter").count(), 1) self.assertEqual(group.charter.docevent_set.count(), events_before + 2) # 1 delete, 1 add def test_send_review_needed_reminders(self): make_test_data() group = Group.objects.get(acronym="mars") person = Person.objects.get(user__username="marschairman") m1 = GroupMilestone.objects.create(group=group, desc="Test 1", due=datetime.date.today(), resolved="", state_id="review") MilestoneGroupEvent.objects.create( group=group, type="changed_milestone", by=person, desc='Added milestone "%s"' % m1.desc, milestone=m1, time=datetime.datetime.now() - datetime.timedelta(seconds=60)) # send mailbox_before = len(outbox) for g in groups_with_milestones_needing_review(): email_milestone_review_reminder(g) self.assertEqual(len(outbox), mailbox_before) # too early to send reminder # add earlier added milestone m2 = GroupMilestone.objects.create(group=group, desc="Test 2", due=datetime.date.today(), resolved="", state_id="review") MilestoneGroupEvent.objects.create( group=group, type="changed_milestone", by=person, desc='Added milestone "%s"' % m2.desc, milestone=m2, time=datetime.datetime.now() - datetime.timedelta(days=10)) # send mailbox_before = len(outbox) for g in groups_with_milestones_needing_review(): email_milestone_review_reminder(g) self.assertEqual(len(outbox), mailbox_before + 1) self.assertTrue(group.acronym in outbox[-1]["Subject"]) self.assertTrue(m1.desc in unicode(outbox[-1])) self.assertTrue(m2.desc in unicode(outbox[-1])) def test_send_milestones_due_reminders(self): make_test_data() group = Group.objects.get(acronym="mars") early_warning_days = 30 # due dates here aren't aligned on the last day of the month, # but everything should still work m1 = GroupMilestone.objects.create(group=group, desc="Test 1", due=datetime.date.today(), resolved="Done", state_id="active") m2 = GroupMilestone.objects.create(group=group, desc="Test 2", due=datetime.date.today() + datetime.timedelta(days=early_warning_days - 10), resolved="", state_id="active") # send mailbox_before = len(outbox) for g in groups_needing_milestones_due_reminder(early_warning_days): email_milestones_due(g, early_warning_days) self.assertEqual(len(outbox), mailbox_before) # none found m1.resolved = "" m1.save() m2.due = datetime.date.today() + datetime.timedelta(days=early_warning_days) m2.save() # send mailbox_before = len(outbox) for g in groups_needing_milestones_due_reminder(early_warning_days): email_milestones_due(g, early_warning_days) self.assertEqual(len(outbox), mailbox_before + 1) self.assertTrue(group.acronym in outbox[-1]["Subject"]) self.assertTrue(m1.desc in unicode(outbox[-1])) self.assertTrue(m2.desc in unicode(outbox[-1])) def test_send_milestones_overdue_reminders(self): make_test_data() group = Group.objects.get(acronym="mars") # due dates here aren't aligned on the last day of the month, # but everything should still work m1 = GroupMilestone.objects.create(group=group, desc="Test 1", due=datetime.date.today() - datetime.timedelta(days=200), resolved="Done", state_id="active") m2 = GroupMilestone.objects.create(group=group, desc="Test 2", due=datetime.date.today() - datetime.timedelta(days=10), resolved="", state_id="active") # send mailbox_before = len(outbox) for g in groups_needing_milestones_overdue_reminder(grace_period=30): email_milestones_overdue(g) self.assertEqual(len(outbox), mailbox_before) # none found m1.resolved = "" m1.save() m2.due = self.last_day_of_month(datetime.date.today() - datetime.timedelta(days=300)) m2.save() # send mailbox_before = len(outbox) for g in groups_needing_milestones_overdue_reminder(grace_period=30): email_milestones_overdue(g) self.assertEqual(len(outbox), mailbox_before + 1) self.assertTrue(group.acronym in outbox[-1]["Subject"]) self.assertTrue(m1.desc in unicode(outbox[-1])) self.assertTrue(m2.desc in unicode(outbox[-1])) def test_ajax_search_docs(self): draft = make_test_data() r = self.client.get(urlreverse("wg_ajax_search_docs", kwargs=dict(acronym=draft.group.acronym)), dict(q=draft.name)) self.assertEqual(r.status_code, 200) data = json.loads(r.content) self.assertTrue(data[0]["id"], draft.name) class CustomizeWorkflowTests(TestCase): def test_customize_workflow(self): make_test_data() group = Group.objects.get(acronym="mars") url = urlreverse('ietf.wginfo.edit.customize_workflow', kwargs=dict(acronym=group.acronym)) login_testing_unauthorized(self, "secretary", url) state = State.objects.get(used=True, type="draft-stream-ietf", slug="wg-lc") self.assertTrue(state not in group.unused_states.all()) # get r = self.client.get(url) self.assertEqual(r.status_code, 200) q = PyQuery(r.content) self.assertEqual(len(q("form.set-state").find("input[name=state][value='%s']" % state.pk).parents("form").find("input[name=active][value='0']")), 1) # deactivate state r = self.client.post(url, dict(action="setstateactive", state=state.pk, active="0")) self.assertEqual(r.status_code, 302) r = self.client.get(url) q = PyQuery(r.content) self.assertEqual(len(q("form.set-state").find("input[name=state][value='%s']" % state.pk).parents("form").find("input[name=active][value='1']")), 1) group = Group.objects.get(acronym=group.acronym) self.assertTrue(state in group.unused_states.all()) # change next states state = State.objects.get(used=True, type="draft-stream-ietf", slug="wg-doc") next_states = State.objects.filter(used=True, type=b"draft-stream-ietf", slug__in=["parked", "dead", "wait-wgw", 'sub-pub']).values_list('pk', flat=True) r = self.client.post(url, dict(action="setnextstates", state=state.pk, next_states=next_states)) self.assertEqual(r.status_code, 302) r = self.client.get(url) q = PyQuery(r.content) self.assertEqual(len(q("form.set-next-states").find("input[name=state][value='%s']" % state.pk).parents('form').find("input[name=next_states][checked=checked]")), len(next_states)) transitions = GroupStateTransitions.objects.filter(group=group, state=state) self.assertEqual(len(transitions), 1) self.assertEqual(set(transitions[0].next_states.values_list("pk", flat=True)), set(next_states)) # change them back to default next_states = state.next_states.values_list("pk", flat=True) r = self.client.post(url, dict(action="setnextstates", state=state.pk, next_states=next_states)) self.assertEqual(r.status_code, 302) r = self.client.get(url) q = PyQuery(r.content) transitions = GroupStateTransitions.objects.filter(group=group, state=state) self.assertEqual(len(transitions), 0) # deactivate tag tag = DocTagName.objects.get(slug="w-expert") r = self.client.post(url, dict(action="settagactive", tag=tag.pk, active="0")) self.assertEqual(r.status_code, 302) r = self.client.get(url) q = PyQuery(r.content) self.assertEqual(len(q('form').find('input[name=tag][value="%s"]' % tag.pk).parents("form").find("input[name=active]")), 1) group = Group.objects.get(acronym=group.acronym) self.assertTrue(tag in group.unused_tags.all())