wbcore 2.2.1__py2.py3-none-any.whl → 2.2.4__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. wbcore/contrib/agenda/locale/de/LC_MESSAGES/django.po +113 -0
  2. wbcore/contrib/agenda/static/agenda/markdown/documentation/building.md +11 -0
  3. wbcore/contrib/agenda/static/agenda/markdown/documentation/conferenceroom.md +20 -0
  4. wbcore/contrib/authentication/fixtures/authentication.json +62 -0
  5. wbcore/contrib/authentication/locale/de/LC_MESSAGES/django.po +610 -0
  6. wbcore/contrib/authentication/templates/activate_confirm.html +12 -0
  7. wbcore/contrib/authentication/templates/base.html +135 -0
  8. wbcore/contrib/authentication/templates/email_base_template.html +335 -0
  9. wbcore/contrib/authentication/templates/password_reset_done.html +13 -0
  10. wbcore/contrib/authentication/templates/password_reset_email.html +11 -0
  11. wbcore/contrib/authentication/templates/password_reset_email_html.html +43 -0
  12. wbcore/contrib/authentication/templates/password_reset_form.html +23 -0
  13. wbcore/contrib/authentication/templates/password_reset_sent.html +11 -0
  14. wbcore/contrib/authentication/templates/reset_password.html +15 -0
  15. wbcore/contrib/authentication/templates/user_registration_email.html +37 -0
  16. wbcore/contrib/color/admin.py +28 -0
  17. wbcore/contrib/color/apps.py +5 -0
  18. wbcore/contrib/color/enums.py +17 -0
  19. wbcore/contrib/color/factories.py +10 -0
  20. wbcore/contrib/color/fields.py +29 -0
  21. wbcore/contrib/color/forms.py +13 -0
  22. wbcore/contrib/color/models.py +62 -0
  23. wbcore/contrib/color/tests/conftest.py +10 -0
  24. wbcore/contrib/color/tests/test_color_models.py +61 -0
  25. wbcore/contrib/color/tests/test_fields.py +25 -0
  26. wbcore/contrib/currency/fixtures/currency.yaml +1014 -0
  27. wbcore/contrib/currency/fixtures/currency_fx_rate.yaml +73585 -0
  28. wbcore/contrib/directory/fixtures/directory.json +3924 -0
  29. wbcore/contrib/directory/locale/de/LC_MESSAGES/django.po +1686 -0
  30. wbcore/contrib/directory/static/directory/markdown/documentation/address.md +38 -0
  31. wbcore/contrib/directory/static/directory/markdown/documentation/banking.md +54 -0
  32. wbcore/contrib/directory/static/directory/markdown/documentation/bankingentry.md +38 -0
  33. wbcore/contrib/directory/static/directory/markdown/documentation/clientmanagerrelationship.md +42 -0
  34. wbcore/contrib/directory/static/directory/markdown/documentation/company.md +52 -0
  35. wbcore/contrib/directory/static/directory/markdown/documentation/companytype.md +2 -0
  36. wbcore/contrib/directory/static/directory/markdown/documentation/customerstatus.md +2 -0
  37. wbcore/contrib/directory/static/directory/markdown/documentation/email.md +20 -0
  38. wbcore/contrib/directory/static/directory/markdown/documentation/employeecompany.md +34 -0
  39. wbcore/contrib/directory/static/directory/markdown/documentation/employerperson.md +43 -0
  40. wbcore/contrib/directory/static/directory/markdown/documentation/person.md +61 -0
  41. wbcore/contrib/directory/static/directory/markdown/documentation/position.md +2 -0
  42. wbcore/contrib/directory/static/directory/markdown/documentation/relationshiptype.md +2 -0
  43. wbcore/contrib/directory/static/directory/markdown/documentation/socialmedia.md +23 -0
  44. wbcore/contrib/directory/static/directory/markdown/documentation/specialization.md +2 -0
  45. wbcore/contrib/directory/static/directory/markdown/documentation/systememployee.md +31 -0
  46. wbcore/contrib/directory/static/directory/markdown/documentation/telephone.md +23 -0
  47. wbcore/contrib/directory/static/directory/markdown/documentation/telephonesearch.md +26 -0
  48. wbcore/contrib/directory/static/directory/markdown/documentation/userisclient.md +14 -0
  49. wbcore/contrib/directory/static/directory/markdown/documentation/userismanager.md +28 -0
  50. wbcore/contrib/directory/static/directory/markdown/documentation/website.md +20 -0
  51. wbcore/contrib/documents/fixtures/docments.json +135 -0
  52. wbcore/contrib/documents/locale/de/LC_MESSAGES/django.po +272 -0
  53. wbcore/contrib/documents/static/documents/markdown/documentation/document_types.md +21 -0
  54. wbcore/contrib/documents/static/documents/markdown/documentation/documents.md +18 -0
  55. wbcore/contrib/documents/static/documents/markdown/documentation/shareablelink.md +28 -0
  56. wbcore/contrib/documents/static/documents/markdown/documentation/shareablelinkaccess.md +20 -0
  57. wbcore/contrib/documents/tests/conftest.py +30 -0
  58. wbcore/contrib/documents/tests/test_models.py +144 -0
  59. wbcore/contrib/example_app/fixtures/example_app.json +7425 -0
  60. wbcore/contrib/example_app/tests/test_models/test_event.py +87 -0
  61. wbcore/contrib/example_app/tests/test_models/test_match.py +210 -0
  62. wbcore/contrib/example_app/tests/test_models/test_others.py +159 -0
  63. wbcore/contrib/example_app/tests/test_serializers/test_league_serializer.py +34 -0
  64. wbcore/contrib/example_app/tests/test_serializers/test_match_serializer.py +134 -0
  65. wbcore/contrib/example_app/tests/test_serializers/test_role_serializer.py +13 -0
  66. wbcore/contrib/example_app/tests/test_serializers/test_sport_serializer.py +14 -0
  67. wbcore/contrib/example_app/tests/test_serializers/test_stadium_serializer.py +14 -0
  68. wbcore/contrib/example_app/tests/test_serializers/test_team_result_serializer.py +30 -0
  69. wbcore/contrib/example_app/tests/test_serializers/test_team_serializer.py +70 -0
  70. wbcore/contrib/example_app/tests/test_viewsets/test_event_viewset.py +162 -0
  71. wbcore/contrib/example_app/tests/test_viewsets/test_league_viewset.py +84 -0
  72. wbcore/contrib/example_app/tests/test_viewsets/test_match_viewset.py +65 -0
  73. wbcore/contrib/example_app/tests/test_viewsets/test_person_viewset.py +166 -0
  74. wbcore/contrib/example_app/tests/test_viewsets/test_role_viewset.py +75 -0
  75. wbcore/contrib/example_app/tests/test_viewsets/test_sport_viewset.py +75 -0
  76. wbcore/contrib/example_app/tests/test_viewsets/test_stadium_viewset.py +75 -0
  77. wbcore/contrib/example_app/tests/test_viewsets/test_team_viewset.py +92 -0
  78. wbcore/contrib/example_app/tests/test_viewsets/test_teamresult_viewset.py +58 -0
  79. wbcore/contrib/example_app/tests/test_viewsets/test_utils_viewsets.py +124 -0
  80. wbcore/contrib/geography/fixtures/geography.json +13454 -0
  81. wbcore/contrib/geography/static/geography/markdown/documentation/geography.md +16 -0
  82. wbcore/contrib/guardian/apps.py +6 -0
  83. wbcore/contrib/guardian/configurations.py +3 -0
  84. wbcore/contrib/guardian/filters.py +21 -0
  85. wbcore/contrib/guardian/tasks.py +10 -0
  86. wbcore/contrib/guardian/urls.py +12 -0
  87. wbcore/contrib/guardian/utils.py +124 -0
  88. wbcore/contrib/io/fixtures/io.json +145 -0
  89. wbcore/contrib/io/locale/de/LC_MESSAGES/django.po +52 -0
  90. wbcore/contrib/notifications/locale/de/LC_MESSAGES/django.po +60 -0
  91. wbcore/contrib/notifications/static/notifications/service-worker.js +1 -0
  92. wbcore/contrib/notifications/templates/notifications/notification_template.html +43 -0
  93. wbcore/contrib/notifications/viewsets/configs/notification_types.py +27 -0
  94. wbcore/contrib/notifications/viewsets/configs/notifications.py +85 -0
  95. wbcore/contrib/workflow/fixtures/workflow.json +612 -0
  96. wbcore/contrib/workflow/locale/de/LC_MESSAGES/django.po +1289 -0
  97. wbcore/contrib/workflow/static/workflow/markdown/documentation/assignedprocessstep.md +33 -0
  98. wbcore/contrib/workflow/static/workflow/markdown/documentation/condition.md +24 -0
  99. wbcore/contrib/workflow/static/workflow/markdown/documentation/decisionstep.md +30 -0
  100. wbcore/contrib/workflow/static/workflow/markdown/documentation/emailstep.md +45 -0
  101. wbcore/contrib/workflow/static/workflow/markdown/documentation/finishstep.md +33 -0
  102. wbcore/contrib/workflow/static/workflow/markdown/documentation/joinstep.md +33 -0
  103. wbcore/contrib/workflow/static/workflow/markdown/documentation/process.md +33 -0
  104. wbcore/contrib/workflow/static/workflow/markdown/documentation/processstep.md +51 -0
  105. wbcore/contrib/workflow/static/workflow/markdown/documentation/scriptstep.md +33 -0
  106. wbcore/contrib/workflow/static/workflow/markdown/documentation/splitstep.md +30 -0
  107. wbcore/contrib/workflow/static/workflow/markdown/documentation/startstep.md +27 -0
  108. wbcore/contrib/workflow/static/workflow/markdown/documentation/transition.md +27 -0
  109. wbcore/contrib/workflow/static/workflow/markdown/documentation/userstep.md +42 -0
  110. wbcore/contrib/workflow/static/workflow/markdown/documentation/workflow.md +32 -0
  111. wbcore/contrib/workflow/templates/Test_Templates.txt +25 -0
  112. wbcore/contrib/workflow/tests/test_models/step/test_decision_step.py +79 -0
  113. wbcore/contrib/workflow/tests/test_models/step/test_email_step.py +45 -0
  114. wbcore/contrib/workflow/tests/test_models/step/test_finish_step.py +105 -0
  115. wbcore/contrib/workflow/tests/test_models/step/test_join_step.py +127 -0
  116. wbcore/contrib/workflow/tests/test_models/step/test_script_step.py +24 -0
  117. wbcore/contrib/workflow/tests/test_models/step/test_split_step.py +49 -0
  118. wbcore/contrib/workflow/tests/test_models/step/test_step.py +621 -0
  119. wbcore/contrib/workflow/tests/test_models/step/test_user_step.py +225 -0
  120. wbcore/contrib/workflow/tests/test_models/test_condition.py +103 -0
  121. wbcore/contrib/workflow/tests/test_models/test_data.py +134 -0
  122. wbcore/contrib/workflow/tests/test_models/test_process.py +98 -0
  123. wbcore/contrib/workflow/tests/test_models/test_transition.py +128 -0
  124. wbcore/contrib/workflow/tests/test_models/test_workflow.py +358 -0
  125. wbcore/locale/de/LC_MESSAGES/django.po +667 -0
  126. wbcore/templates/errors/404.html +134 -0
  127. wbcore/templates/errors/500.html +138 -0
  128. wbcore/templates/errors/503.html +132 -0
  129. wbcore/templates/errors/custom.html +132 -0
  130. wbcore/templates/forms.py +0 -0
  131. wbcore/templates/notifications/email_template.html +43 -0
  132. wbcore/templates/wbcore/admin/change_list.html +8 -0
  133. wbcore/templates/wbcore/admin/csv_form.html +15 -0
  134. wbcore/templates/wbcore/dynamic_color_array.html +29 -0
  135. wbcore/templates/wbcore/email_base_template.html +335 -0
  136. wbcore/templates/wbcore/email_notification_template.html +10 -0
  137. wbcore/templates/wbcore/frontend.html +51 -0
  138. wbcore/test/e2e_helpers_methods/e2e_checks.py +121 -0
  139. wbcore/test/e2e_helpers_methods/e2e_helper_methods.py +395 -0
  140. wbcore/tests/test_permissions/test_backend.py +29 -0
  141. {wbcore-2.2.1.dist-info → wbcore-2.2.4.dist-info}/METADATA +1 -1
  142. {wbcore-2.2.1.dist-info → wbcore-2.2.4.dist-info}/RECORD +143 -3
  143. {wbcore-2.2.1.dist-info → wbcore-2.2.4.dist-info}/WHEEL +0 -0
@@ -0,0 +1,621 @@
1
+ from unittest.mock import patch
2
+
3
+ import pytest
4
+ from wbcore.contrib.authentication.factories import GroupFactory, UserFactory
5
+ from wbcore.contrib.authentication.models import Permission
6
+ from wbcore.contrib.directory.factories import PersonFactory
7
+ from wbcore.contrib.directory.models import Person
8
+ from wbcore.contrib.workflow.factories import (
9
+ FinishStepFactory,
10
+ JoinStepFactory,
11
+ UserStepFactory,
12
+ )
13
+ from wbcore.contrib.workflow.models import Condition, ProcessStep, Step
14
+ from wbcore.contrib.workflow.models.step import activate_step, process_can_finish
15
+ from wbcore.test.utils import get_or_create_superuser
16
+
17
+
18
+ @pytest.mark.django_db
19
+ class TestStep:
20
+ @patch("wbcore.contrib.workflow.models.step.Step.run")
21
+ def test_activate_step_no_status(self, mock_run, step_factory, process_factory):
22
+ step = step_factory(status=None)
23
+ process = process_factory(workflow=step.workflow)
24
+ activate_step(step.pk, process.pk)
25
+ process_step_qs = ProcessStep.objects.filter(
26
+ state=ProcessStep.StepState.ACTIVE, process=process, step=step, status=step.status
27
+ )
28
+ assert process_step_qs.count() == 1
29
+ assert mock_run.call_args.args == (process_step_qs.first(),)
30
+
31
+ @patch("wbcore.contrib.workflow.models.step.Step.run")
32
+ def test_activate_step_no_instance(self, mock_run, step_factory, process_factory):
33
+ step = step_factory()
34
+ process = process_factory(workflow=step.workflow, instance=None, instance_id=None)
35
+ activate_step(step.pk, process.pk)
36
+ process_step_qs = ProcessStep.objects.filter(
37
+ state=ProcessStep.StepState.ACTIVE, process=process, step=step, status=step.status
38
+ )
39
+ assert process_step_qs.count() == 1
40
+ assert mock_run.call_args.args == (process_step_qs.first(),)
41
+
42
+ @patch("wbcore.contrib.workflow.models.step.Step.run")
43
+ def test_activate_step_wrong_status_field(self, mock_run, step_factory, process_factory):
44
+ step = step_factory(workflow__status_field="test")
45
+ process = process_factory(workflow=step.workflow)
46
+ activate_step(step.pk, process.pk)
47
+ process_step_qs = ProcessStep.objects.filter(
48
+ state=ProcessStep.StepState.ACTIVE, process=process, step=step, status=step.status
49
+ )
50
+ assert process_step_qs.count() == 1
51
+ assert mock_run.call_args.args == (process_step_qs.first(),)
52
+
53
+ @patch("wbcore.contrib.workflow.models.step.Step.run")
54
+ def test_activate_step_wrong_status_field_type(self, mock_run, step_factory, process_factory):
55
+ step = step_factory(workflow__status_field="birthday")
56
+ process = process_factory(workflow=step.workflow)
57
+ activate_step(step.pk, process.pk)
58
+ process_step_qs = ProcessStep.objects.filter(
59
+ state=ProcessStep.StepState.ACTIVE,
60
+ process=process,
61
+ step=step,
62
+ status=step.status,
63
+ )
64
+ assert process_step_qs.count() == 1
65
+ assert Person.objects.get(id=process.instance.pk).birthday == process.instance.birthday
66
+ assert mock_run.call_args.args == (process_step_qs.first(),)
67
+
68
+ @patch("wbcore.contrib.workflow.models.step.UserStep.run")
69
+ def test_activate_user_step(self, mock_run, user_step_factory, process_factory):
70
+ step = user_step_factory(permission=Permission.objects.last())
71
+ process = process_factory(workflow=step.workflow)
72
+ activate_step(step.pk, process.pk)
73
+ process_step_qs = ProcessStep.objects.filter(
74
+ state=ProcessStep.StepState.ACTIVE,
75
+ process=process,
76
+ step=step,
77
+ permission=step.permission,
78
+ status=step.status,
79
+ group=step.group,
80
+ )
81
+ assert process_step_qs.count() == 1
82
+ assert Person.objects.get(id=process.instance.pk).first_name == step.status
83
+ assert mock_run.call_args.args == (process_step_qs.first(),)
84
+
85
+ @patch("wbcore.contrib.workflow.models.step.DecisionStep.run")
86
+ def test_activate_decision_step(self, mock_run, decision_step_factory, process_factory):
87
+ step = decision_step_factory()
88
+ process = process_factory(workflow=step.workflow)
89
+ activate_step(step.pk, process.pk)
90
+ process_step_qs = ProcessStep.objects.filter(
91
+ state=ProcessStep.StepState.ACTIVE, process=process, step=step, status=step.status
92
+ )
93
+ assert process_step_qs.count() == 1
94
+ assert Person.objects.get(id=process.instance.pk).first_name == step.status
95
+ assert mock_run.call_args.args == (process_step_qs.first(),)
96
+
97
+ @patch("wbcore.contrib.workflow.models.step.SplitStep.run")
98
+ def test_activate_split_step(self, mock_run, split_step_factory, process_factory):
99
+ step = split_step_factory()
100
+ process = process_factory(workflow=step.workflow)
101
+ activate_step(step.pk, process.pk)
102
+ process_step_qs = ProcessStep.objects.filter(
103
+ state=ProcessStep.StepState.ACTIVE, process=process, step=step, status=step.status
104
+ )
105
+ assert process_step_qs.count() == 1
106
+ assert Person.objects.get(id=process.instance.pk).first_name == step.status
107
+ assert mock_run.call_args.args == (process_step_qs.first(),)
108
+
109
+ @patch("wbcore.contrib.workflow.models.step.ScriptStep.run")
110
+ def test_activate_script_step(self, mock_run, script_step_factory, process_factory):
111
+ step = script_step_factory()
112
+ process = process_factory(workflow=step.workflow)
113
+ activate_step(step.pk, process.pk)
114
+ process_step_qs = ProcessStep.objects.filter(
115
+ state=ProcessStep.StepState.ACTIVE, process=process, step=step, status=step.status
116
+ )
117
+ assert process_step_qs.count() == 1
118
+ assert Person.objects.get(id=process.instance.pk).first_name == step.status
119
+ assert mock_run.call_args.args == (process_step_qs.first(),)
120
+
121
+ @patch("wbcore.contrib.workflow.models.step.EmailStep.run")
122
+ def test_activate_email_step(self, mock_run, email_step_factory, process_factory):
123
+ step = email_step_factory()
124
+ process = process_factory(workflow=step.workflow)
125
+ activate_step(step.pk, process.pk)
126
+ process_step_qs = ProcessStep.objects.filter(
127
+ state=ProcessStep.StepState.ACTIVE, process=process, step=step, status=step.status
128
+ )
129
+ assert process_step_qs.count() == 1
130
+ assert Person.objects.get(id=process.instance.pk).first_name == step.status
131
+ assert mock_run.call_args.args == (process_step_qs.first(),)
132
+
133
+ @patch("wbcore.contrib.workflow.models.step.FinishStep.run")
134
+ def test_activate_finish_step(self, mock_run, finish_step_factory, process_factory):
135
+ step = finish_step_factory()
136
+ process = process_factory(workflow=step.workflow)
137
+ activate_step(step.pk, process.pk)
138
+ process_step_qs = ProcessStep.objects.filter(
139
+ state=ProcessStep.StepState.ACTIVE, process=process, step=step, status=step.status
140
+ )
141
+ assert process_step_qs.count() == 1
142
+ assert Person.objects.get(id=process.instance.pk).first_name == step.status
143
+ assert mock_run.call_args.args == (process_step_qs.first(),)
144
+
145
+ @patch("wbcore.contrib.workflow.models.step.JoinStep.run")
146
+ def test_activate_join_step(self, mock_run, process_step_factory, join_step_factory, process_factory):
147
+ step = join_step_factory()
148
+ process = process_factory(workflow=step.workflow)
149
+ process_step_factory(state=ProcessStep.StepState.WAITING, step=step, status=step.status, process=process)
150
+ process_step_factory(state=ProcessStep.StepState.WAITING, step=step, status=step.status, finished=None)
151
+ process_step_factory()
152
+ activate_step(step.pk, process.pk)
153
+ process_step_qs = ProcessStep.objects.filter(
154
+ state=ProcessStep.StepState.ACTIVE, process=process, step=step, status=step.status
155
+ )
156
+ assert process_step_qs.count() == 1
157
+ assert Person.objects.get(id=process.instance.pk).first_name == step.status
158
+ assert mock_run.call_args.args == (process_step_qs.first(),)
159
+
160
+ @patch("wbcore.contrib.workflow.models.step.JoinStep.run")
161
+ def test_activate_step_too_many_waiting_steps(
162
+ self, mock_run, process_step_factory, join_step_factory, process_factory
163
+ ):
164
+ step = join_step_factory()
165
+ process = process_factory(workflow=step.workflow)
166
+ process_step_factory(
167
+ state=ProcessStep.StepState.WAITING, step=step, status=step.status, process=process, finished=None
168
+ )
169
+ process_step_factory(
170
+ state=ProcessStep.StepState.WAITING, step=step, status=step.status, process=process, finished=None
171
+ )
172
+ process_step_factory()
173
+ activate_step(step.pk, process.pk)
174
+ process_step_qs = ProcessStep.objects.filter(
175
+ state=ProcessStep.StepState.ACTIVE, process=process, step=step, status=step.status
176
+ )
177
+ assert process_step_qs.count() == 1
178
+ assert Person.objects.get(id=process.instance.pk).first_name == step.status
179
+ assert mock_run.call_args.args == (process_step_qs.first(),)
180
+
181
+ @patch("wbcore.contrib.workflow.models.step.JoinStep.run")
182
+ def test_activate_waiting_join_step(self, mock_run, process_step_factory, join_step_factory, process_factory):
183
+ step = join_step_factory()
184
+ process = process_factory(workflow=step.workflow)
185
+ process_step_factory(state=ProcessStep.StepState.WAITING, step=step, status=step.status, process=process)
186
+ waiting_process_step = process_step_factory(
187
+ state=ProcessStep.StepState.WAITING, step=step, status=step.status, process=process, finished=None
188
+ )
189
+ process_step_factory()
190
+ activate_step(step.pk, process.pk)
191
+ assert not ProcessStep.objects.filter(
192
+ state=ProcessStep.StepState.ACTIVE, process=process, step=step, status=step.status
193
+ ).exists()
194
+ assert Person.objects.get(id=process.instance.pk).first_name == step.status
195
+ assert str(mock_run.call_args.args[0].pk) == waiting_process_step.pk
196
+
197
+ def test_get_outgoing_transitions(self, random_child_step_factory, transition_factory):
198
+ step = random_child_step_factory()
199
+ transition = transition_factory(from_step=step)
200
+ transition_factory()
201
+ transition_factory(to_step=step)
202
+ assert list(step.get_outgoing_transitions()) == [transition]
203
+
204
+ def test_get_incoming_transitions(self, random_child_step_factory, transition_factory):
205
+ step = random_child_step_factory()
206
+ transition_factory(from_step=step)
207
+ transition_factory()
208
+ transition = transition_factory(to_step=step)
209
+ assert list(step.get_incoming_transitions()) == [transition]
210
+
211
+ def test_get_previous_steps(self, random_child_step_factory, transition_factory):
212
+ step = random_child_step_factory()
213
+ transition1 = transition_factory(to_step=step)
214
+ transition2 = transition_factory(to_step=step)
215
+ transition_factory(from_step=step)
216
+ transition_factory()
217
+ assert set(step.get_previous_steps()) == {transition1.from_step, transition2.from_step}
218
+
219
+ def test_get_all_valid_outgoing_transitions(
220
+ self, random_child_step_factory, transition_factory, condition_factory, process_step_factory
221
+ ):
222
+ person = PersonFactory()
223
+ step = random_child_step_factory()
224
+ invalid_transition = transition_factory(from_step=step, to_step__workflow=step.workflow)
225
+ condition_factory(
226
+ transition=invalid_transition,
227
+ attribute_name="first_name",
228
+ expected_value=person.first_name,
229
+ operator=Condition.Operator.EQ,
230
+ negate_operator=True,
231
+ )
232
+ condition_factory(
233
+ transition=invalid_transition,
234
+ attribute_name="last_name",
235
+ expected_value=person.last_name,
236
+ operator=Condition.Operator.EQ,
237
+ negate_operator=False,
238
+ )
239
+ valid_transition = transition_factory(from_step=step, to_step__workflow=step.workflow)
240
+ condition_factory(
241
+ transition=valid_transition,
242
+ attribute_name="first_name",
243
+ expected_value=person.first_name,
244
+ operator=Condition.Operator.EQ,
245
+ negate_operator=False,
246
+ )
247
+ valid_transition_without_condition = transition_factory(from_step=step, to_step__workflow=step.workflow)
248
+ process_step = process_step_factory(step=step, process__instance=person)
249
+ transitions = step.get_all_valid_outgoing_transitions(process_step)
250
+ assert set(transitions) == {valid_transition, valid_transition_without_condition}
251
+
252
+ def test_get_assigned_group(self, random_child_step_factory):
253
+ random_step = random_child_step_factory(exclude_factories=[UserStepFactory])
254
+ assert random_step.get_assigned_group() is None
255
+
256
+ def test_get_assigned_user(self, random_child_step_factory):
257
+ random_step = random_child_step_factory(exclude_factories=[UserStepFactory])
258
+ assert random_step.get_assigned_user() is None
259
+
260
+ def test_get_casted_step(self, random_child_step_factory):
261
+ random_step_child = random_child_step_factory()
262
+ parent_step = random_step_child.step_ptr
263
+ assert parent_step.get_casted_step().__class__ == random_step_child.__class__
264
+
265
+ def test_user_can_see_step_user_permission(self, random_child_step_factory):
266
+ step = random_child_step_factory(permission=Permission.objects.last())
267
+ user = UserFactory()
268
+ user.user_permissions.add(step.permission)
269
+ assert step.user_can_see_step(user)
270
+
271
+ def test_user_can_see_step_no_permission(self, random_child_step_factory):
272
+ step = random_child_step_factory()
273
+ user = UserFactory()
274
+ assert step.user_can_see_step(user)
275
+
276
+ def test_user_can_see_step_superuser(self, random_child_step_factory):
277
+ step = random_child_step_factory(permission=Permission.objects.last())
278
+ user = get_or_create_superuser()
279
+ assert step.user_can_see_step(user)
280
+
281
+ def test_user_can_see_step_group_permission(self, random_child_step_factory):
282
+ step = random_child_step_factory(permission=Permission.objects.last())
283
+ group = GroupFactory(permissions=[step.permission])
284
+ user = UserFactory(groups=[group])
285
+ assert step.user_can_see_step(user)
286
+
287
+ def test_user_can_see_step_user_no_permission(self, random_child_step_factory):
288
+ step = random_child_step_factory(permission=Permission.objects.last())
289
+ user = UserFactory()
290
+ assert not step.user_can_see_step(user)
291
+
292
+ @patch("wbcore.contrib.workflow.models.step.Step.finish")
293
+ def test_set_finished(self, mock_finish, process_step_factory, random_child_step_factory):
294
+ step = random_child_step_factory(exclude_factories=[FinishStepFactory])
295
+ process_step = process_step_factory(step=step)
296
+ step.set_finished(process_step)
297
+ assert process_step.state == ProcessStep.StepState.FINISHED
298
+ assert mock_finish.call_args.args == (process_step,)
299
+
300
+ @patch("wbcore.contrib.workflow.models.step.FinishStep.finish")
301
+ def test_set_finished_finish_step(self, mock_finish, process_step_factory, finish_step_factory):
302
+ step = finish_step_factory()
303
+ process_step = process_step_factory(step=step)
304
+ step.set_finished(process_step)
305
+ assert process_step.state == ProcessStep.StepState.FINISHED
306
+ assert mock_finish.call_args.args == (process_step,)
307
+
308
+ @patch("wbcore.contrib.workflow.models.step.process_can_finish.delay")
309
+ def test_set_failed(self, mock_can_finish, process_step_factory, random_child_step_factory):
310
+ step = random_child_step_factory()
311
+ process_step = process_step_factory(step=step, error_message=None)
312
+ error_message = "Error message"
313
+ step.set_failed(process_step, error_message)
314
+ assert process_step.state == ProcessStep.StepState.FAILED
315
+ assert process_step.error_message == error_message
316
+ assert mock_can_finish.call_args.args == (process_step.process.pk,)
317
+
318
+ @patch("wbcore.contrib.workflow.models.step.process_can_finish.delay")
319
+ def test_set_failed_has_error_message(self, mock_can_finish, process_step_factory, random_child_step_factory):
320
+ step = random_child_step_factory()
321
+ error_message = "Error message"
322
+ process_step = process_step_factory(step=step, error_message=error_message)
323
+ step.set_failed(process_step, "Test")
324
+ assert process_step.state == ProcessStep.StepState.FAILED
325
+ assert process_step.error_message == error_message
326
+ assert mock_can_finish.call_args.args == (process_step.process.pk,)
327
+
328
+ @patch("wbcore.contrib.workflow.models.step.Step.finish")
329
+ def test_set_canceled(self, mock_finish, process_step_factory, random_child_step_factory):
330
+ step = random_child_step_factory(exclude_factories=[FinishStepFactory])
331
+ process_step = process_step_factory(step=step)
332
+ step.set_canceled(process_step)
333
+ assert process_step.state == ProcessStep.StepState.CANCELED
334
+ assert mock_finish.call_args.args == (process_step,)
335
+
336
+ @patch("wbcore.contrib.workflow.models.step.FinishStep.finish")
337
+ def test_set_canceled_finish_step(self, mock_finish, process_step_factory, finish_step_factory):
338
+ step = finish_step_factory()
339
+ process_step = process_step_factory(step=step)
340
+ step.set_canceled(process_step)
341
+ assert process_step.state == ProcessStep.StepState.CANCELED
342
+ assert mock_finish.call_args.args == (process_step,)
343
+
344
+ @patch("wbcore.contrib.workflow.models.step.Step.start_next_step")
345
+ def test_execute_single_next_step(
346
+ self, mock_next, process_step_factory, transition_factory, random_child_step_factory
347
+ ):
348
+ step = random_child_step_factory()
349
+ process_step = process_step_factory(step=step)
350
+ transition = transition_factory(from_step=step)
351
+ transition_factory()
352
+ step.execute_single_next_step(process_step)
353
+ assert mock_next.call_args.args == (process_step, transition)
354
+
355
+ @patch("wbcore.contrib.workflow.models.step.Step.set_failed")
356
+ def test_execute_single_next_step_no_transitions(
357
+ self, mock_failed, process_step_factory, transition_factory, random_child_step_factory
358
+ ):
359
+ step = random_child_step_factory(exclude_factories=[UserStepFactory])
360
+ process_step = process_step_factory(step=step)
361
+ transition_factory()
362
+ step.execute_single_next_step(process_step)
363
+ assert mock_failed.call_args.args[0] == process_step
364
+
365
+ @patch("wbcore.contrib.workflow.models.step.Step.set_failed")
366
+ def test_execute_single_next_step_multiple_transitions(
367
+ self, mock_failed, process_step_factory, transition_factory, random_child_step_factory
368
+ ):
369
+ step = random_child_step_factory(exclude_factories=[UserStepFactory])
370
+ process_step = process_step_factory(step=step)
371
+ transition_factory(from_step=step)
372
+ transition_factory(from_step=step)
373
+ step.execute_single_next_step(process_step)
374
+ assert mock_failed.call_args.args[0] == process_step
375
+
376
+ @patch("wbcore.contrib.workflow.models.step.Step.set_finished")
377
+ def test_run(self, mock_finished, process_step_factory):
378
+ process_step = process_step_factory()
379
+ step = process_step.step
380
+ step.run(process_step)
381
+ assert mock_finished.call_args.args == (process_step,)
382
+
383
+ @pytest.mark.parametrize(
384
+ "state, expected",
385
+ [
386
+ ("Finished", True),
387
+ ("Canceled", True),
388
+ ("Active", False),
389
+ ("Waiting", False),
390
+ ("Failed", False),
391
+ ],
392
+ )
393
+ def test_finish(self, state, expected, process_step_factory, random_child_step_factory):
394
+ step = random_child_step_factory(exclude_factories=[FinishStepFactory])
395
+ process_step = process_step_factory(step=step, state=state, finished=None)
396
+ step.finish(process_step)
397
+ assert bool(process_step.finished) is expected
398
+
399
+ @patch("wbcore.contrib.workflow.models.step.activate_step.delay")
400
+ @patch("wbcore.contrib.workflow.models.step.Step.set_finished")
401
+ def test_start_next_step(self, mock_finish, mock_activate, transition_factory, process_step_factory):
402
+ transition = transition_factory()
403
+ process_step = process_step_factory()
404
+ Step.start_next_step(process_step, transition)
405
+ assert mock_finish.call_args.args == (process_step,)
406
+ assert mock_activate.call_args.args == (transition.to_step.pk, process_step.process.pk)
407
+
408
+ @patch("wbcore.contrib.workflow.models.process.Process.set_failed")
409
+ def test_process_can_finish_no_active(self, mock_failed, process_step_factory):
410
+ process_step = process_step_factory(state=ProcessStep.StepState.CANCELED)
411
+ process = process_step.process
412
+ process_step_factory(state=ProcessStep.StepState.FINISHED, process=process)
413
+ process_step_factory(state=ProcessStep.StepState.FAILED, process=process)
414
+ process_step_factory(state=ProcessStep.StepState.ACTIVE)
415
+ process_can_finish(process.pk)
416
+ assert mock_failed.call_count == 1
417
+
418
+ @patch("wbcore.contrib.workflow.models.process.Process.set_failed")
419
+ def test_process_can_finish_no_join_steps(
420
+ self, mock_failed, process_step_factory, random_child_step_factory, process_factory
421
+ ):
422
+ step = random_child_step_factory(exclude_factories=[JoinStepFactory])
423
+ process = process_factory(workflow=step.workflow)
424
+ process_step_factory(step=step, state=ProcessStep.StepState.ACTIVE, process=process)
425
+ process_can_finish(process.pk)
426
+ assert not mock_failed.called
427
+
428
+ # """
429
+ # Test Workflow:
430
+ # 8
431
+ # / \ # noqa: W605
432
+ # 4 - 6 - 7 14
433
+ # / \ / \ # noqa: W605
434
+ # / 9 \ # noqa: W605
435
+ # 1 - 2 - 3 16 - 17
436
+ # \ 12 / # noqa: W605
437
+ # \ / \ / # noqa: W605
438
+ # 5 - 10 - 11 15
439
+ # \ / # noqa: W605
440
+ # 13
441
+ # """
442
+
443
+ @patch("wbcore.contrib.workflow.models.process.Process.set_failed")
444
+ def test_process_can_finish_join_steps_can_be_reached(
445
+ self,
446
+ mock_failed,
447
+ workflow_factory,
448
+ split_step_factory,
449
+ process_factory,
450
+ process_step_factory,
451
+ random_child_step_factory,
452
+ start_step_factory,
453
+ transition_factory,
454
+ join_step_factory,
455
+ finish_step_factory,
456
+ ):
457
+ workflow = workflow_factory()
458
+ step1 = start_step_factory(workflow=workflow)
459
+ step2 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
460
+ transition_factory(from_step=step1, to_step=step2)
461
+ step3 = split_step_factory(workflow=workflow)
462
+ transition_factory(from_step=step2, to_step=step3)
463
+ step4 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
464
+ step5 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
465
+ transition_factory(from_step=step3, to_step=step4)
466
+ transition_factory(from_step=step3, to_step=step5)
467
+ step6 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
468
+ transition_factory(from_step=step4, to_step=step6)
469
+ step7 = split_step_factory(workflow=workflow)
470
+ transition_factory(from_step=step6, to_step=step7)
471
+ step8 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
472
+ step9 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
473
+ transition_factory(from_step=step7, to_step=step8)
474
+ transition_factory(from_step=step7, to_step=step9)
475
+ step10 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
476
+ transition_factory(from_step=step5, to_step=step10)
477
+ step11 = split_step_factory(workflow=workflow)
478
+ transition_factory(from_step=step10, to_step=step11)
479
+ step12 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
480
+ step13 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
481
+ transition_factory(from_step=step11, to_step=step12)
482
+ transition_factory(from_step=step11, to_step=step13)
483
+ step14 = join_step_factory(wait_for_all=True, workflow=workflow)
484
+ transition_factory(from_step=step8, to_step=step14)
485
+ transition_factory(from_step=step9, to_step=step14)
486
+ step15 = join_step_factory(wait_for_all=False, workflow=workflow)
487
+ transition_factory(from_step=step12, to_step=step15)
488
+ transition_factory(from_step=step13, to_step=step15)
489
+ step16 = join_step_factory(wait_for_all=True, workflow=workflow)
490
+ transition_factory(from_step=step14, to_step=step16)
491
+ transition_factory(from_step=step15, to_step=step16)
492
+ step17 = finish_step_factory(workflow=workflow)
493
+ transition_factory(from_step=step16, to_step=step17)
494
+
495
+ process = process_factory(workflow=workflow)
496
+ process_step_factory(step=step12, state=ProcessStep.StepState.FAILED, process=process)
497
+ process_step_factory(step=step11, state=ProcessStep.StepState.ACTIVE, process=process)
498
+ for step in [step1, step2, step3, step4, step5, step6, step7, step8, step9, step10, step14]:
499
+ process_step_factory(step=step, state=ProcessStep.StepState.FINISHED, process=process)
500
+ process_can_finish(process.pk)
501
+ assert not mock_failed.called
502
+
503
+ @patch("wbcore.contrib.workflow.models.process.Process.set_failed")
504
+ def test_process_can_finish_waiting_join_step_one_failed(
505
+ self,
506
+ mock_failed,
507
+ workflow_factory,
508
+ split_step_factory,
509
+ process_factory,
510
+ process_step_factory,
511
+ random_child_step_factory,
512
+ start_step_factory,
513
+ transition_factory,
514
+ join_step_factory,
515
+ finish_step_factory,
516
+ ):
517
+ workflow = workflow_factory()
518
+ step1 = start_step_factory(workflow=workflow)
519
+ step2 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
520
+ transition_factory(from_step=step1, to_step=step2)
521
+ step3 = split_step_factory(workflow=workflow)
522
+ transition_factory(from_step=step2, to_step=step3)
523
+ step4 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
524
+ step5 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
525
+ transition_factory(from_step=step3, to_step=step4)
526
+ transition_factory(from_step=step3, to_step=step5)
527
+ step6 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
528
+ transition_factory(from_step=step4, to_step=step6)
529
+ step7 = split_step_factory(workflow=workflow)
530
+ transition_factory(from_step=step6, to_step=step7)
531
+ step8 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
532
+ step9 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
533
+ transition_factory(from_step=step7, to_step=step8)
534
+ transition_factory(from_step=step7, to_step=step9)
535
+ step10 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
536
+ transition_factory(from_step=step5, to_step=step10)
537
+ step11 = split_step_factory(workflow=workflow)
538
+ transition_factory(from_step=step10, to_step=step11)
539
+ step12 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
540
+ step13 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
541
+ transition_factory(from_step=step11, to_step=step12)
542
+ transition_factory(from_step=step11, to_step=step13)
543
+ step14 = join_step_factory(wait_for_all=True, workflow=workflow)
544
+ transition_factory(from_step=step8, to_step=step14)
545
+ transition_factory(from_step=step9, to_step=step14)
546
+ step15 = join_step_factory(wait_for_all=False, workflow=workflow)
547
+ transition_factory(from_step=step12, to_step=step15)
548
+ transition_factory(from_step=step13, to_step=step15)
549
+ step16 = join_step_factory(wait_for_all=True, workflow=workflow)
550
+ transition_factory(from_step=step14, to_step=step16)
551
+ transition_factory(from_step=step15, to_step=step16)
552
+ step17 = finish_step_factory(workflow=workflow)
553
+ transition_factory(from_step=step16, to_step=step17)
554
+
555
+ process = process_factory(workflow=workflow)
556
+ process_step_factory(step=step8, state=ProcessStep.StepState.FAILED, process=process)
557
+ process_step_factory(step=step14, state=ProcessStep.StepState.WAITING, process=process)
558
+ for step in [step1, step2, step3, step4, step5, step6, step7, step9, step10, step11, step12, step13, step15]:
559
+ process_step_factory(step=step, state=ProcessStep.StepState.FINISHED, process=process)
560
+ process_can_finish(process.pk)
561
+ assert mock_failed.called
562
+
563
+ @patch("wbcore.contrib.workflow.models.process.Process.set_failed")
564
+ def test_process_can_finish_failed_at_beginning(
565
+ self,
566
+ mock_failed,
567
+ workflow_factory,
568
+ split_step_factory,
569
+ process_factory,
570
+ process_step_factory,
571
+ random_child_step_factory,
572
+ start_step_factory,
573
+ transition_factory,
574
+ join_step_factory,
575
+ finish_step_factory,
576
+ ):
577
+ workflow = workflow_factory()
578
+ step1 = start_step_factory(workflow=workflow)
579
+ step2 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
580
+ transition_factory(from_step=step1, to_step=step2)
581
+ step3 = split_step_factory(workflow=workflow)
582
+ transition_factory(from_step=step2, to_step=step3)
583
+ step4 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
584
+ step5 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
585
+ transition_factory(from_step=step3, to_step=step4)
586
+ transition_factory(from_step=step3, to_step=step5)
587
+ step6 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
588
+ transition_factory(from_step=step4, to_step=step6)
589
+ step7 = split_step_factory(workflow=workflow)
590
+ transition_factory(from_step=step6, to_step=step7)
591
+ step8 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
592
+ step9 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
593
+ transition_factory(from_step=step7, to_step=step8)
594
+ transition_factory(from_step=step7, to_step=step9)
595
+ step10 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
596
+ transition_factory(from_step=step5, to_step=step10)
597
+ step11 = split_step_factory(workflow=workflow)
598
+ transition_factory(from_step=step10, to_step=step11)
599
+ step12 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
600
+ step13 = random_child_step_factory(exclude_factories=[JoinStepFactory], workflow=workflow)
601
+ transition_factory(from_step=step11, to_step=step12)
602
+ transition_factory(from_step=step11, to_step=step13)
603
+ step14 = join_step_factory(wait_for_all=True, workflow=workflow)
604
+ transition_factory(from_step=step8, to_step=step14)
605
+ transition_factory(from_step=step9, to_step=step14)
606
+ step15 = join_step_factory(wait_for_all=False, workflow=workflow)
607
+ transition_factory(from_step=step12, to_step=step15)
608
+ transition_factory(from_step=step13, to_step=step15)
609
+ step16 = join_step_factory(wait_for_all=True, workflow=workflow)
610
+ transition_factory(from_step=step14, to_step=step16)
611
+ transition_factory(from_step=step15, to_step=step16)
612
+ step17 = finish_step_factory(workflow=workflow)
613
+ transition_factory(from_step=step16, to_step=step17)
614
+
615
+ process = process_factory(workflow=workflow)
616
+ process_step_factory(step=step6, state=ProcessStep.StepState.FAILED, process=process)
617
+ process_step_factory(step=step15, state=ProcessStep.StepState.ACTIVE, process=process)
618
+ for step in [step1, step2, step3, step4, step5, step10, step11, step12, step13, step15]:
619
+ process_step_factory(step=step, state=ProcessStep.StepState.FINISHED, process=process)
620
+ process_can_finish(process.pk)
621
+ assert mock_failed.called