Skip to content
Snippets Groups Projects
Commit 5722c5e0 authored by Todd Dembrey's avatar Todd Dembrey
Browse files

Update the tests for the new FSM approach

parent 4fe0087c
No related branches found
No related tags found
No related merge requests found
......@@ -2,11 +2,8 @@ from . import models
from .models import * # noqa
from . import blocks
from .blocks import * # noqa
# from . import workflows
# from .workflows import * # noqa
__all__ = []
__all__.extend(blocks.__all__)
__all__.extend(models.__all__)
# __all__.extend(workflows.__all__)
......@@ -45,7 +45,7 @@ def build_form(data, prefix=''):
extras[field][attr] = value
form_fields = {}
for i, field in enumerate(blocks.CustomFormFieldsFactory.factories.keys()):
for i, field in enumerate(blocks.CustomFormFieldsFactory.factories):
form_fields[f'{prefix}form_fields__{i}__{field}__'] = ''
for attr, value in extras[field].items():
form_fields[f'{prefix}form_fields__{i}__{field}__{attr}'] = value
......@@ -139,7 +139,7 @@ class LabFactory(wagtail_factories.PageFactory):
def forms(self, create, extracted, **kwargs):
if create:
fields = build_form(kwargs, prefix='form')
for _ in range(len(self.workflow_class.stage_classes)):
for _ in get_stages(self.workflow):
# Generate a form based on all defined fields on the model
LabFormFactory(
lab=self,
......
import factory
from opentech.apply.funds.workflow import Action, Phase, Stage, Workflow
__all__ = [
'ActionFactory',
'PhaseFactory',
'StageFactory',
'WorkflowFactory',
]
class ListSubFactory(factory.SubFactory):
def __init__(self, *args, count=0, **kwargs):
self.count = count
super().__init__(*args, **kwargs)
def evaluate(self, *args, **kwargs):
if isinstance(self.count, factory.declarations.BaseDeclaration):
self.evaluated_count = self.count.evaluate(*args, **kwargs)
else:
self.evaluated_count = self.count
return super().evaluate(*args, **kwargs)
def generate(self, step, params):
subfactory = self.get_factory()
force_sequence = step.sequence if self.FORCE_SEQUENCE else None
return [
step.recurse(subfactory, params, force_sequence=force_sequence)
for _ in range(self.evaluated_count)
]
class ActionFactory(factory.Factory):
class Meta:
model = Action
name = factory.Faker('word')
class PhaseFactory(factory.Factory):
class Meta:
model = Phase
class Params:
num_actions = factory.Faker('random_int', min=1, max=5)
name = factory.Faker('word')
actions = ListSubFactory(ActionFactory, count=factory.SelfAttribute('num_actions'))
stage = factory.PostGeneration(
lambda obj, create, extracted, **kwargs: StageFactory.build(phases=[obj])
)
@classmethod
def _create(cls, model_class, *args, **kwargs):
actions = kwargs.pop('actions')
new_class = type(model_class.__name__, (model_class,), {'actions': actions})
return new_class(*args, **kwargs)
@classmethod
def _build(cls, model_class, *args, **kwargs):
# defer to create because parent uses build
return cls._create(model_class, *args, **kwargs)
class StageFactory(factory.Factory):
class Meta:
model = Stage
class Params:
num_phases = factory.Faker('random_int', min=1, max=3)
name = factory.Faker('word')
phases = ListSubFactory(PhaseFactory, count=factory.SelfAttribute('num_phases'))
@classmethod
def _create(cls, model_class, *args, **kwargs):
# Returns a new class
phases = kwargs.pop('phases')
name = kwargs.pop('name')
return type(model_class.__name__, (model_class,), {'phases': phases, 'name': name})
@classmethod
def _build(cls, model_class, *args, **kwargs):
# returns an instance of the stage class
phases = kwargs.pop('phases')
name = kwargs.pop('name')
new_class = type(model_class.__name__, (model_class,), {'phases': phases, 'name': name})
# Pretend we have a workflow object, only used for __le__
kwargs['workflow'] = None
return new_class(*args, **kwargs)
class WorkflowFactory(factory.Factory):
class Meta:
model = Workflow
rename = {'stages': 'stage_classes'}
class Params:
num_stages = factory.Faker('random_int', min=1, max=3)
name = factory.Faker('word')
stages = ListSubFactory(StageFactory, count=factory.SelfAttribute('num_stages'))
@classmethod
def _create(cls, model_class, *args, **kwargs):
name = kwargs.pop('name')
stages = kwargs.pop('stage_classes')
new_class = type(model_class.__name__, (model_class,), {'name': name, 'stage_classes': stages})
return new_class(*args, **kwargs)
......@@ -33,7 +33,7 @@ class TestFundModel(TestCase):
def test_can_access_workflow_class(self):
self.assertEqual(self.fund.workflow_name, 'single')
self.assertEqual(self.fund.workflow_class, SingleStage)
self.assertEqual(self.fund.workflow, SingleStage)
def test_no_open_rounds(self):
self.assertIsNone(self.fund.open_round)
......@@ -201,32 +201,33 @@ class TestFormSubmission(TestCase):
page = page or self.round_page
fields = page.get_form_fields()
data = {k: v for k, v in zip(fields, ['project', email, name])}
data = {k: v for k, v in zip(fields, ['project', 0, email, name])}
request = self.request_factory.post('', data)
request.user = user
request.site = self.site
try:
return page.get_parent().serve(request)
response = page.get_parent().serve(request)
except AttributeError:
return page.serve(request)
response = page.serve(request)
self.assertNotContains(response, 'There where some errors with your form')
return response
def test_workflow_and_status_assigned(self):
self.submit_form()
submission = ApplicationSubmission.objects.first()
first_phase = self.round_page.workflow.first()
self.assertEqual(submission.workflow_name, self.round_page.workflow_name)
self.assertEqual(submission.status, str(first_phase))
self.assertEqual(submission.status_name, first_phase.name)
first_phase = list(self.round_page.workflow.keys())[0]
self.assertEqual(submission.workflow, self.round_page.workflow)
self.assertEqual(submission.status, first_phase)
def test_workflow_and_status_assigned_lab(self):
self.submit_form(page=self.lab_page)
submission = ApplicationSubmission.objects.first()
first_phase = self.lab_page.workflow.first()
self.assertEqual(submission.workflow_name, self.lab_page.workflow_name)
self.assertEqual(submission.status, str(first_phase))
self.assertEqual(submission.status_name, first_phase.name)
first_phase = list(self.lab_page.workflow.keys())[0]
self.assertEqual(submission.workflow, self.lab_page.workflow)
self.assertEqual(submission.status, first_phase)
def test_can_submit_if_new(self):
self.submit_form()
......@@ -363,24 +364,3 @@ class TestApplicationSubmission(TestCase):
submission = self.make_submission(form_data__image__filename=filename)
save_path = os.path.join(settings.MEDIA_ROOT, submission.save_path(filename))
self.assertTrue(os.path.isfile(save_path))
class TestApplicationProgression(TestCase):
def test_new_submission_created(self):
submission = ApplicationSubmissionFactory(workflow_name='double')
self.assertEqual(ApplicationSubmission.objects.count(), 1)
old_id = submission.id
# Update the status to the accepted phase of the current stage
submission.status = str(submission.workflow.stages[0].phases[-2])
submission.save()
old_submission = ApplicationSubmission.objects.get(id=old_id)
self.assertEqual(ApplicationSubmission.objects.count(), 2)
self.assertEqual(submission.previous, old_submission)
self.assertEqual(old_submission.next, submission)
form_fields = submission.round.forms.all()[1].fields
self.assertEqual(submission.form_fields, form_fields)
from django.test import SimpleTestCase
from opentech.apply.funds.workflow import (
Action,
ChangePhaseAction,
NextPhaseAction,
Phase,
Stage,
Workflow,
)
from .factories import ActionFactory, PhaseFactory, StageFactory, WorkflowFactory
class TestWorkflowCreation(SimpleTestCase):
def test_can_create_workflow(self):
stage = StageFactory()
class NewWorkflow(Workflow):
name = 'single_stage'
stage_classes = [stage]
workflow = NewWorkflow()
self.assertEqual(workflow.name, NewWorkflow.name)
self.assertEqual(len(workflow.stages), 1)
def test_returns_first_phase_if_no_arg(self):
workflow = WorkflowFactory(num_stages=1, stages__num_phases=1)
self.assertEqual(workflow.next(), workflow.stages[0].phases[0])
def test_can_get_the_current_phase(self):
workflow = WorkflowFactory(num_stages=1, stages__num_phases=2)
phase = workflow.stages[0].phases[0]
self.assertEqual(workflow.current(str(phase)), phase)
def test_returns_next_stage(self):
workflow = WorkflowFactory(num_stages=2, stages__num_phases=1)
self.assertEqual(workflow.next_stage(workflow.stages[0]), workflow.stages[1])
def test_returns_none_if_no_next(self):
workflow = WorkflowFactory(num_stages=1, stages__num_phases=1)
self.assertEqual(workflow.next(workflow.stages[0].phases[0]), None)
def test_returns_next_phase(self):
workflow = WorkflowFactory(num_stages=2, stages__num_phases=1)
self.assertEqual(workflow.next(workflow.stages[0].phases[0]), workflow.stages[1].phases[0])
def test_returns_next_phase_shared_name(self):
workflow = WorkflowFactory(num_stages=1, stages__num_phases=3, stages__phases__name='the_same')
self.assertEqual(workflow.next(workflow.stages[0].phases[0]), workflow.stages[0].phases[1])
class TestStageCreation(SimpleTestCase):
def test_can_create_stage(self):
name = 'the_stage'
stage = Stage(None, name=name)
self.assertEqual(stage.name, name)
def test_can_create_with_multi_phase_step(self):
first_phase, second_phase = Phase(name='first'), Phase(name='second')
change_first = ChangePhaseAction(first_phase, 'first')
change_second = ChangePhaseAction(second_phase, 'second')
class PhaseSwitch(Phase):
actions = [change_first, change_second]
class MultiPhaseStep(Stage):
name = 'stage'
phases = [
PhaseSwitch(),
[first_phase, second_phase],
]
stage = MultiPhaseStep(None)
self.assertEqual(stage.steps, 2)
current_phase = stage.phases[0]
self.assertEqual(current_phase.process(change_first.name), stage.phases[1]) # type: ignore
self.assertEqual(current_phase.process(change_second.name), stage.phases[2]) # type: ignore
def test_can_get_next_phase(self):
stage = StageFactory.build(num_phases=2)
self.assertEqual(stage.next(stage.phases[0]), stage.phases[1])
def test_get_none_if_no_next_phase(self):
stage = StageFactory.build(num_phases=1)
self.assertEqual(stage.next(stage.phases[0]), None)
class TestPhaseCreation(SimpleTestCase):
def test_can_create_phase(self):
name = 'the_phase'
phase = Phase(name)
self.assertEqual(phase.name, name)
def test_can_get_action_from_phase(self):
actions = ActionFactory.create_batch(3)
action = actions[1]
phase = PhaseFactory(actions=actions)
self.assertEqual(phase[action.name], action)
def test_uses_name_if_no_public(self):
phase = Phase('Phase Name')
self.assertEqual(phase.public_name, phase.name)
def test_uses_public_if_provided(self):
public_name = 'Public Name'
phase = Phase('Phase Name', public_name=public_name)
self.assertEqual(phase.public_name, public_name)
self.assertNotEqual(phase.public_name, phase.name)
def test_uses_public_if_provided_on_class(self):
class NewPhase(Phase):
public_name = 'Public Name'
phase = NewPhase('Phase Name')
self.assertEqual(phase.public_name, NewPhase.public_name)
self.assertNotEqual(phase.public_name, phase.name)
class TestActions(SimpleTestCase):
def test_can_create_action(self):
name = 'action stations'
action = Action(name)
self.assertEqual(action.name, name)
def test_calling_processes_the_action(self):
action = ActionFactory()
with self.assertRaises(NotImplementedError):
action.process('')
class TestCustomActions(SimpleTestCase):
def test_next_phase_action_returns_none_if_no_next(self):
action = NextPhaseAction('the next!')
phase = PhaseFactory(actions=[action])
self.assertEqual(phase.process(action.name), None)
def test_next_phase_action_returns_next_phase(self):
action = NextPhaseAction('the next!')
stage = StageFactory.build(num_phases=2, phases__actions=[action])
self.assertEqual(stage.phases[0].process(action.name), stage.phases[1])
def test_change_phase_will_skip_phase(self):
target_phase = PhaseFactory()
action = ChangePhaseAction(target_phase.name, 'skip!')
other_phases = PhaseFactory.create_batch(2, actions=[action])
stage = StageFactory.build(phases=[*other_phases, target_phase])
self.assertEqual(stage.phases[0].process(action.name), stage.phases[2])
self.assertEqual(stage.phases[1].process(action.name), stage.phases[2])
......@@ -196,7 +196,7 @@ class SubmissionEditView(UpdateView):
def dispatch(self, request, *args, **kwargs):
if request.user != self.get_object().user:
raise PermissionDenied
if not self.get_object().phase.has_perm(request.user, 'edit'):
if not self.get_object().phase.permissions.can_edit(request.user):
raise PermissionDenied
return super().dispatch(request, *args, **kwargs)
......
......@@ -177,7 +177,7 @@ DoubleStageDefinition = {
},
'display': 'Invited for Proposal',
'stage': Proposal,
'permissions': Permission(),
'permissions': CanEditPermission(),
'step': 4,
},
'proposal_discussion': {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment