Commit 9a5de9cd authored by Enrico Zini's avatar Enrico Zini
Browse files

Initial test for process_show

parent 4e579e95
...@@ -180,6 +180,28 @@ class TestBase(object): ...@@ -180,6 +180,28 @@ class TestBase(object):
if match.search(errmsg): return if match.search(errmsg): return
self.fail("{} dit not match any in {}".format(regex, repr(errors))) self.fail("{} dit not match any in {}".format(regex, repr(errors)))
def assertContainsElements(self, response, elements, *names):
"""
Check that the response contains only the elements in `names` from PageElements `elements`
"""
want = set(names)
extras = want - set(elements.keys())
if extras: raise RuntimeError("Wanted elements not found in the list of possible ones: {}".format(", ".join(extras)))
should_have = []
should_not_have = []
content = response.content.decode("utf-8")
for name, regex in elements.items():
if name in want:
if not regex.search(content):
should_have.append(name)
else:
if regex.search(content):
should_not_have.append(name)
if should_have or should_not_have:
msg = []
if should_have: msg.append("should have element(s) {}".format(", ".join(should_have)))
if should_not_have: msg.append("should not have element(s) {}".format(", ".join(should_not_have)))
self.fail("page " + " and ".join(msg))
class BaseFixtureMixin(TestBase): class BaseFixtureMixin(TestBase):
@classmethod @classmethod
......
...@@ -105,42 +105,40 @@ class RequirementVisitorPermissions(ProcessVisitorPermissions): ...@@ -105,42 +105,40 @@ class RequirementVisitorPermissions(ProcessVisitorPermissions):
class ProcessManager(models.Manager): class ProcessManager(models.Manager):
def compute_requirements(self, person, applying_for): def compute_requirements(self, status, applying_for):
""" """
Compute the process requirements for person applying for applying_for Compute the process requirements for person applying for applying_for
""" """
if person.status == applying_for: if status == applying_for:
raise RuntimeError("Invalid applying_for value {} for a person with status {}".format(applying_for, person.status)) raise RuntimeError("Invalid applying_for value {} for a person with status {}".format(applying_for, status))
if person.pending: if status == const.STATUS_DD_U:
raise RuntimeError("Invalid applying_for value {} for a person whose account is still pending".format(applying_for)) raise RuntimeError("Invalid applying_for value {} for a person with status {}".format(applying_for, status))
if person.status == const.STATUS_DD_U:
raise RuntimeError("Invalid applying_for value {} for a person with status {}".format(applying_for, person.status))
requirements = ["intent", "sc_dmup"] requirements = ["intent", "sc_dmup"]
if applying_for == const.STATUS_DC_GA: if applying_for == const.STATUS_DC_GA:
if person.status != const.STATUS_DC: if status != const.STATUS_DC:
raise RuntimeError("Invalid applying_for value {} for a person with status {}".format(applying_for, person.status)) raise RuntimeError("Invalid applying_for value {} for a person with status {}".format(applying_for, status))
requirements.append("advocate") requirements.append("advocate")
elif applying_for == const.STATUS_DM: elif applying_for == const.STATUS_DM:
if person.status != const.STATUS_DC: if status != const.STATUS_DC:
raise RuntimeError("Invalid applying_for value {} for a person with status {}".format(applying_for, person.status)) raise RuntimeError("Invalid applying_for value {} for a person with status {}".format(applying_for, status))
requirements.append("advocate") requirements.append("advocate")
requirements.append("keycheck") requirements.append("keycheck")
elif applying_for == const.STATUS_DM_GA: elif applying_for == const.STATUS_DM_GA:
if person.status == const.STATUS_DC_GA: if status == const.STATUS_DC_GA:
requirements.append("advocate") requirements.append("advocate")
requirements.append("keycheck") requirements.append("keycheck")
elif person.status == const.STATUS_DM: elif status == const.STATUS_DM:
# No extra requirement: the declaration of intents is # No extra requirement: the declaration of intents is
# sufficient # sufficient
pass pass
else: else:
raise RuntimeError("Invalid applying_for value {} for a person with status {}".format(applying_for, person.status)) raise RuntimeError("Invalid applying_for value {} for a person with status {}".format(applying_for, status))
elif applying_for in (const.STATUS_DD_U, const.STATUS_DD_NU): elif applying_for in (const.STATUS_DD_U, const.STATUS_DD_NU):
if person.status != const.STATUS_DD_NU: if status != const.STATUS_DD_NU:
requirements.append("keycheck") requirements.append("keycheck")
requirements.append("am_ok") requirements.append("am_ok")
if person.status not in (const.STATUS_EMERITUS_DD, const.STATUS_REMOVED_DD): if status not in (const.STATUS_EMERITUS_DD, const.STATUS_REMOVED_DD):
requirements.append("advocate") requirements.append("advocate")
else: else:
raise RuntimeError("Invalid applying_for value {}".format(applying_for)) raise RuntimeError("Invalid applying_for value {}".format(applying_for))
...@@ -152,12 +150,16 @@ class ProcessManager(models.Manager): ...@@ -152,12 +150,16 @@ class ProcessManager(models.Manager):
""" """
Create a new process and all its requirements Create a new process and all its requirements
""" """
# Forbid pending persons to start processes
if person.pending:
raise RuntimeError("Invalid applying_for value {} for a person whose account is still pending".format(applying_for))
# Check that no active process of the same kind exists # Check that no active process of the same kind exists
if self.filter(person=person, applying_for=applying_for, closed__isnull=True).exists(): if self.filter(person=person, applying_for=applying_for, closed__isnull=True).exists():
raise RuntimeError("there is already an active process for {} to become {}".format(person, applying_for)) raise RuntimeError("there is already an active process for {} to become {}".format(person, applying_for))
# Compute requirements # Compute requirements
requirements = self.compute_requirements(person, applying_for) requirements = self.compute_requirements(person.status, applying_for)
# Create the new process # Create the new process
res = self.model(person=person, applying_for=applying_for) res = self.model(person=person, applying_for=applying_for)
...@@ -231,13 +233,15 @@ class Process(models.Model): ...@@ -231,13 +233,15 @@ class Process(models.Model):
for s in adv.statements.all(): for s in adv.statements.all():
advocates.add(s.uploaded_by) advocates.add(s.uploaded_by)
log = self.log.order_by("logdate")
return { return {
"requirements": requirements, "requirements": requirements,
"requirements_sorted": sorted(requirements.values(), key=lambda x: REQUIREMENT_TYPES_DICT[x.type].sort_order), "requirements_sorted": sorted(requirements.values(), key=lambda x: REQUIREMENT_TYPES_DICT[x.type].sort_order),
"requirements_ok": sorted(rok, key=lambda x: REQUIREMENT_TYPES_DICT[x.type].sort_order), "requirements_ok": sorted(rok, key=lambda x: REQUIREMENT_TYPES_DICT[x.type].sort_order),
"requirements_missing": sorted(rnok, key=lambda x: REQUIREMENT_TYPES_DICT[x.type].sort_order), "requirements_missing": sorted(rnok, key=lambda x: REQUIREMENT_TYPES_DICT[x.type].sort_order),
"log_first": self.log.order_by("logdate")[0], "log_first": log[0] if log else None,
"log_last": self.log.order_by("-logdate")[0], "log_last": log[-1] if log else None,
"advocates": sorted(advocates), "advocates": sorted(advocates),
} }
......
...@@ -10,27 +10,27 @@ ...@@ -10,27 +10,27 @@
<br/> <br/>
<textarea name="logtext" rows="3" cols="80" placeholder="vacation notice / remark about the process / status update / ..."></textarea> <textarea name="logtext" rows="3" cols="80" placeholder="vacation notice / remark about the process / status update / ..."></textarea>
<br/> <br/>
<button type="submit" name="add_action" value="log_public">Comment</button> <button id="log_public" type="submit" name="add_action" value="log_public">Comment</button>
<button type="submit" name="add_action" value="log_private">Comment (confidential)</button> <button id="log_private" type="submit" name="add_action" value="log_private">Comment (confidential)</button>
{% if requirement %} {% if requirement %}
{% if requirement.approved_by %} {% if requirement.approved_by %}
<button type="submit" name="add_action" value="req_unapprove">Unapprove</button> <button id="req_unapprove" type="submit" name="add_action" value="req_unapprove">Unapprove</button>
{% else %} {% else %}
<button type="submit" name="add_action" value="req_approve">Approve</button> <button id="req_approve" type="submit" name="add_action" value="req_approve">Approve</button>
{% endif %} {% endif %}
{% else %} {% else %}
{% if not process.frozen_by %} {% if not process.frozen_by %}
{% if not process.approved_by %} {% if not process.approved_by %}
<button type="submit" name="add_action" value="proc_freeze">Freeze for review</button> <button id="proc_freeze" type="submit" name="add_action" value="proc_freeze">Freeze for review</button>
{% else %} {% else %}
{# no button to show here: this case should not happen and should get a warning by nightly maintenance #} {# no button to show here: this case should not happen and should get a warning by nightly maintenance #}
{% endif %} {% endif %}
{% else %} {% else %}
{% if not process.approved_by %} {% if not process.approved_by %}
<button type="submit" name="add_action" value="proc_unfreeze">Unfreeze for further work</button> <button id="proc_unfreeze" type="submit" name="add_action" value="proc_unfreeze">Unfreeze for further work</button>
<button type="submit" name="add_action" value="proc_approve">Approve process</button> <button id="proc_approve" type="submit" name="add_action" value="proc_approve">Approve process</button>
{% else %} {% else %}
<button type="submit" name="add_action" value="proc_unapprove">Unapprove process</button> <button id="proc_unapprove" type="submit" name="add_action" value="proc_unapprove">Unapprove process</button>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% endif %} {% endif %}
......
...@@ -103,11 +103,11 @@ ...@@ -103,11 +103,11 @@
</tr> </tr>
{% if visitor.is_admin and process.fd_comment %} {% if visitor.is_admin and process.fd_comment %}
<tr><th>FD comments</th><td>{{process.fd_comment}}</td></tr> <tr id="view_fd_comment"><th>FD comments</th><td>{{process.fd_comment}}</td></tr>
{% endif %} {% endif %}
{% if "view_mbox" in visit_perms %} {% if "view_mbox" in visit_perms %}
<tr> <tr id="view_mbox">
<th>Mail archive</th> <th>Mail archive</th>
<td> <td>
<tt><a href="mailto:{{process.archive_email}}">{{process.archive_email}}</a></tt> <tt><a href="mailto:{{process.archive_email}}">{{process.archive_email}}</a></tt>
......
...@@ -61,7 +61,7 @@ def get_all_process_types(): ...@@ -61,7 +61,7 @@ def get_all_process_types():
Generate all valid (source_status, applying_for) pairs for all possible Generate all valid (source_status, applying_for) pairs for all possible
processes. processes.
""" """
for src, tgts in bmodels.Process._new_status_table: for src, tgts in bmodels.Person._new_status_table.items():
for tgt in tgts: for tgt in tgts:
yield src, tgt yield src, tgt
......
...@@ -10,21 +10,17 @@ from process import models as pmodels ...@@ -10,21 +10,17 @@ from process import models as pmodels
from backend.unittest import BaseFixtureMixin, PersonFixtureMixin from backend.unittest import BaseFixtureMixin, PersonFixtureMixin
class TestRequirements(PersonFixtureMixin, TestCase): class TestRequirements(PersonFixtureMixin, TestCase):
def assertRequirements(self, person, applying_for, expected): def assertRequirements(self, status, applying_for, expected):
computed = pmodels.Process.objects.compute_requirements(self.persons[person], applying_for) computed = pmodels.Process.objects.compute_requirements(status, applying_for)
self.assertItemsEqual(computed, expected) self.assertItemsEqual(computed, expected)
def assertInvalid(self, person, applying_for): def assertInvalid(self, status, applying_for):
with self.assertRaises(RuntimeError) as re: with self.assertRaises(RuntimeError) as re:
pmodels.Process.objects.compute_requirements(self.persons[person], applying_for) pmodels.Process.objects.compute_requirements(status, applying_for)
def test_requirements(self): def test_requirements(self):
all_statuses = {s.tag for s in const.ALL_STATUS} all_statuses = {s.tag for s in const.ALL_STATUS}
# Pending users cannot apply for anything yet
for dest in all_statuses:
self.assertInvalid("pending", dest)
for dest in all_statuses - { const.STATUS_DC_GA, const.STATUS_DM, const.STATUS_DD_NU, const.STATUS_DD_U }: for dest in all_statuses - { const.STATUS_DC_GA, const.STATUS_DM, const.STATUS_DD_NU, const.STATUS_DD_U }:
self.assertInvalid("dc", dest) self.assertInvalid("dc", dest)
self.assertRequirements("dc", const.STATUS_DC_GA, ["intent", "sc_dmup", "advocate"]) self.assertRequirements("dc", const.STATUS_DC_GA, ["intent", "sc_dmup", "advocate"])
......
...@@ -8,7 +8,7 @@ from django.core.urlresolvers import reverse ...@@ -8,7 +8,7 @@ from django.core.urlresolvers import reverse
from django.utils.timezone import now from django.utils.timezone import now
from backend import const from backend import const
from backend import models as bmodels from backend import models as bmodels
from backend.unittest import BaseFixtureMixin, PersonFixtureMixin, ExpectedSets, NamedObjects, TestSet from backend.unittest import PersonFixtureMixin, ExpectedSets, TestSet
import process.models as pmodels import process.models as pmodels
from .common import ProcessFixtureMixin from .common import ProcessFixtureMixin
......
# coding: utf8
from __future__ import print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from django.test import TestCase
from django.core.urlresolvers import reverse
from django.utils.timezone import now
from backend import const
from backend import models as bmodels
from backend.unittest import PersonFixtureMixin, ExpectedSets, TestSet, PageElements
import process.models as pmodels
from .common import ProcessFixtureMixin, get_all_process_types
class TestProcessShow(ProcessFixtureMixin, TestCase):
@classmethod
def __add_extra_tests__(cls):
for src, tgt in get_all_process_types():
want_am = "am_ok" in pmodels.Process.objects.compute_requirements(src, tgt)
visitors = [None, "pending", "dc", "dc_ga", "dm", "dm_ga", "dd_nu", "dd_u", "dd_e", "dd_r", "activeam", "fd", "dam", "app"]
if want_am: visitors.append("am")
for visitor in visitors:
if want_am:
cls._add_method(cls._test_perms, src, tgt, visitor, am="dd_nu")
cls._add_method(cls._test_perms, src, tgt, visitor, am="dd_u")
else:
cls._add_method(cls._test_perms, src, tgt, visitor)
@classmethod
def setUpClass(cls):
super(TestProcessShow, cls).setUpClass()
cls.page_elements = PageElements()
cls.page_elements.add_id("view_fd_comment")
cls.page_elements.add_id("view_mbox")
cls.page_elements.add_id("log_public")
cls.page_elements.add_id("log_private")
cls.page_elements.add_id("proc_freeze")
cls.page_elements.add_id("proc_unfreeze")
cls.page_elements.add_id("proc_approve")
cls.page_elements.add_id("proc_unapprove")
def assertPageElements(self, response, visit_perms):
# Check page elements based on visit_perms
wanted = []
if visit_perms.visitor.is_admin:
wanted.append("view_fd_comment")
if "add_log" in visit_perms:
wanted += ["log_public", "log_private"]
for el in ("view_mbox", "proc_freeze", "proc_unfreeze", "proc_approve", "proc_unapprove"):
if el in visit_perms: wanted.append(el)
self.assertContainsElements(response, self.page_elements, *wanted)
def _test_perms(self, src, tgt, visitor, am=None):
self.persons.create("app", status=src)
self.processes.create("app", person=self.persons.app, applying_for=tgt)
if am is not None:
self.persons.create("am", status=am)
self.ams.create("am", person=self.persons.am)
client = self.make_test_client(visitor)
response = client.get(reverse("process_show", args=[self.processes.app.pk]))
self.assertEqual(response.status_code, 200)
visit_perms = self.processes.app.permissions_of(self.persons[visitor])
self.assertPageElements(response, visit_perms)
# Assign am and repeat visit
if am:
pmodels.AMAssignment.objects.create(process=self.processes.app, am=self.ams.am, assigned_by=self.persons["fd"], assigned_time=now())
response = client.get(reverse("process_show", args=[self.processes.app.pk]))
self.assertEqual(response.status_code, 200)
visit_perms = self.processes.app.permissions_of(self.persons[visitor])
self.assertPageElements(response, visit_perms)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment