Compare commits
9 Commits
a9f810689b
...
17ac728f78
Author | SHA1 | Date |
---|---|---|
Pierre Ducroquet | 17ac728f78 | |
Frédéric Péters | ab38410f34 | |
Frédéric Péters | 2eb29089a1 | |
Valentin Deniaud | f418c515f5 | |
Valentin Deniaud | d784acba07 | |
Valentin Deniaud | d9267a79ca | |
Frédéric Péters | 9cf2aae477 | |
Frédéric Péters | d10392f0fe | |
Valentin Deniaud | 7dfc90a1e5 |
|
@ -2,6 +2,7 @@ import os
|
|||
|
||||
import pytest
|
||||
|
||||
from wcs.formdef import FormDef
|
||||
from wcs.qommon.http_request import HTTPRequest
|
||||
from wcs.qommon.ident.password_accounts import PasswordAccount
|
||||
|
||||
|
@ -86,6 +87,10 @@ def test_admin_for_all(pub):
|
|||
user = create_superuser(pub)
|
||||
role = create_role(pub)
|
||||
|
||||
formdef = FormDef()
|
||||
formdef.name = 'test'
|
||||
formdef.store()
|
||||
|
||||
try:
|
||||
with open(os.path.join(pub.app_dir, 'ADMIN_FOR_ALL'), 'w'):
|
||||
pass # create empty file
|
||||
|
|
|
@ -1369,6 +1369,7 @@ def test_tests_webservice_response(pub):
|
|||
resp = resp.click('Test response')
|
||||
resp.form['url'] = 'http://example.com/'
|
||||
resp.form['payload'] = '{"a": "b"}'
|
||||
resp.form['status_code'] = '400'
|
||||
resp.form['qs_data$element0key'] = 'foo'
|
||||
resp.form['method'] = 'POST (JSON)'
|
||||
resp.form['post_data$element0key'] = 'bar'
|
||||
|
@ -1381,6 +1382,7 @@ def test_tests_webservice_response(pub):
|
|||
assert response.name == 'Test response'
|
||||
assert response.url == 'http://example.com/'
|
||||
assert response.payload == '{"a": "b"}'
|
||||
assert response.status_code == 400
|
||||
assert response.qs_data == {'foo': ''}
|
||||
assert response.method == 'POST'
|
||||
assert response.post_data == {'bar': ''}
|
||||
|
|
|
@ -3789,8 +3789,16 @@ def test_workflows_wscall_options(pub, value):
|
|||
baz_status.add_action('webservice_call')
|
||||
workflow.store()
|
||||
|
||||
pub.cfg['debug'] = {}
|
||||
pub.write_cfg()
|
||||
|
||||
app = login(get_app(pub))
|
||||
resp = app.get('/backoffice/workflows/%s/status/%s/items/1/' % (workflow.id, baz_status.id))
|
||||
assert 'notify_on_errors' not in resp.form.fields
|
||||
|
||||
pub.cfg['debug'] = {'error_email': 'test@localhost'}
|
||||
pub.write_cfg()
|
||||
resp = app.get('/backoffice/workflows/%s/status/%s/items/1/' % (workflow.id, baz_status.id))
|
||||
assert resp.form['notify_on_errors'].value is None
|
||||
assert resp.form['record_on_errors'].value == 'yes'
|
||||
resp.form['notify_on_errors'] = value
|
||||
|
|
|
@ -429,6 +429,9 @@ def test_backoffice_submission_formdef_list_search(pub, local_user, access, auth
|
|||
resp = get_url('/api/formdefs/?backoffice-submission=on&q=test')
|
||||
assert len(resp.json['data']) == 2
|
||||
|
||||
resp = get_url('/api/formdefs/?backoffice-submission=on&q=tes')
|
||||
assert len(resp.json['data']) == 2
|
||||
|
||||
resp = get_url('/api/formdefs/?backoffice-submission=on&q=xyz')
|
||||
assert len(resp.json['data']) == 0
|
||||
|
||||
|
|
|
@ -64,6 +64,32 @@ def test_workflow_tests_ignore_unsupported_items(pub, monkeypatch):
|
|||
assert str(excinfo.value) == 'Form should be in status "End status" but is in status "New status".'
|
||||
|
||||
|
||||
def test_workflow_tests_no_actions(pub):
|
||||
user = pub.user_class(name='test user')
|
||||
user.store()
|
||||
|
||||
workflow = Workflow(name='Workflow One')
|
||||
workflow.add_status(name='New status')
|
||||
|
||||
workflow.store()
|
||||
|
||||
formdef = FormDef()
|
||||
formdef.name = 'test title'
|
||||
formdef.workflow_id = workflow.id
|
||||
formdef.store()
|
||||
|
||||
formdata = formdef.data_class()()
|
||||
formdata.just_created()
|
||||
|
||||
testdef = TestDef.create_from_formdata(formdef, formdata)
|
||||
testdef.agent_id = user.id
|
||||
testdef.workflow_tests.actions = []
|
||||
|
||||
with mock.patch('wcs.workflow_tests.WorkflowTests.run') as mocked_run:
|
||||
testdef.run(formdef)
|
||||
mocked_run.assert_not_called()
|
||||
|
||||
|
||||
def test_workflow_tests_button_click(pub):
|
||||
role = pub.role_class(name='test role')
|
||||
role.store()
|
||||
|
@ -316,7 +342,9 @@ def test_workflow_tests_sendmail(mocked_send_email, pub):
|
|||
testdef = TestDef.create_from_formdata(formdef, formdata)
|
||||
testdef.agent_id = user.id
|
||||
testdef.workflow_tests.actions = [
|
||||
workflow_tests.AssertEmail(subject_strings=['In new status'], body_strings=['xxx']),
|
||||
workflow_tests.AssertEmail(
|
||||
addresses=['test@example.org'], subject_strings=['In new status'], body_strings=['xxx']
|
||||
),
|
||||
workflow_tests.ButtonClick(button_name='Go to end status'),
|
||||
workflow_tests.AssertStatus(status_name='End status'),
|
||||
workflow_tests.AssertEmail(subject_strings=['end status'], body_strings=['yyy']),
|
||||
|
@ -347,6 +375,15 @@ def test_workflow_tests_sendmail(mocked_send_email, pub):
|
|||
testdef.run(formdef)
|
||||
assert str(excinfo.value) == 'Email body does not contain "bli".'
|
||||
|
||||
testdef.workflow_tests.actions = [
|
||||
workflow_tests.AssertEmail(addresses=['test@example.org', 'other@example.org']),
|
||||
]
|
||||
|
||||
with pytest.raises(WorkflowTestError) as excinfo:
|
||||
testdef.run(formdef)
|
||||
assert str(excinfo.value) == 'Email was not sent to address "other@example.org".'
|
||||
assert 'Email addresses: test@example.org' in excinfo.value.details
|
||||
|
||||
testdef.workflow_tests.actions = [
|
||||
workflow_tests.ButtonClick(button_name='Go to end status'),
|
||||
workflow_tests.AssertEmail(subject_strings=['In new status'], body_strings=['xxx']),
|
||||
|
@ -506,3 +543,53 @@ def test_workflow_tests_webservice(pub):
|
|||
with pytest.raises(WorkflowTestError) as excinfo:
|
||||
testdef.run(formdef)
|
||||
assert str(excinfo.value) == 'Webservice response Fake response was used 0 times (instead of 1).'
|
||||
|
||||
|
||||
def test_workflow_tests_webservice_status_jump(pub):
|
||||
user = pub.user_class(name='test user')
|
||||
user.store()
|
||||
|
||||
workflow = Workflow(name='Workflow One')
|
||||
new_status = workflow.add_status(name='New status')
|
||||
end_status = workflow.add_status(name='Error status')
|
||||
|
||||
wscall = new_status.add_action('webservice_call')
|
||||
wscall.url = 'http://example.com/json'
|
||||
wscall.varname = 'test_webservice'
|
||||
wscall.action_on_4xx = end_status.id
|
||||
|
||||
workflow.store()
|
||||
|
||||
formdef = FormDef()
|
||||
formdef.name = 'test title'
|
||||
formdef.workflow_id = workflow.id
|
||||
formdef.store()
|
||||
|
||||
formdata = formdef.data_class()()
|
||||
formdata.just_created()
|
||||
|
||||
testdef = TestDef.create_from_formdata(formdef, formdata)
|
||||
testdef.agent_id = user.id
|
||||
testdef.store()
|
||||
|
||||
response = WebserviceResponse()
|
||||
response.testdef_id = testdef.id
|
||||
response.name = 'Fake response'
|
||||
response.url = 'http://example.com/json'
|
||||
response.payload = '{"foo": "foo"}'
|
||||
response.store()
|
||||
|
||||
testdef.workflow_tests.actions = [
|
||||
workflow_tests.AssertStatus(status_name='New status'),
|
||||
workflow_tests.AssertWebserviceCall(webservice_response_id=response.id, call_count=1),
|
||||
]
|
||||
|
||||
testdef.run(formdef)
|
||||
|
||||
response.status_code = 400
|
||||
response.store()
|
||||
|
||||
testdef.workflow_tests.actions = [
|
||||
workflow_tests.AssertStatus(status_name='End status'),
|
||||
workflow_tests.AssertWebserviceCall(webservice_response_id=response.id, call_count=1),
|
||||
]
|
||||
|
|
|
@ -754,6 +754,16 @@ class WebserviceResponsePage(Directory):
|
|||
validation_function=validate_json,
|
||||
)
|
||||
|
||||
form.add(
|
||||
RadiobuttonsWidget,
|
||||
'status_code',
|
||||
title=_('Response status code'),
|
||||
required=True,
|
||||
options=[200, 204, 400, 401, 403, 404, 500, 502, 503],
|
||||
value=self.webservice_response.status_code,
|
||||
extra_css_class='widget-inline-radio',
|
||||
)
|
||||
|
||||
form.add(
|
||||
WidgetDict,
|
||||
'qs_data',
|
||||
|
@ -820,6 +830,7 @@ class WebserviceResponsePage(Directory):
|
|||
self.webservice_response.name = form.get_widget('name').parse()
|
||||
self.webservice_response.payload = form.get_widget('payload').parse()
|
||||
self.webservice_response.url = form.get_widget('url').parse()
|
||||
self.webservice_response.status_code = form.get_widget('status_code').parse()
|
||||
self.webservice_response.qs_data = form.get_widget('qs_data').parse()
|
||||
self.webservice_response.method = form.get_widget('method').parse()
|
||||
self.webservice_response.post_data = form.get_widget('post_data').parse()
|
||||
|
|
|
@ -4,8 +4,8 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: wcs 0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-03-01 17:03+0100\n"
|
||||
"PO-Revision-Date: 2024-03-01 17:03+0100\n"
|
||||
"POT-Creation-Date: 2024-03-04 17:49+0100\n"
|
||||
"PO-Revision-Date: 2024-03-04 17:49+0100\n"
|
||||
"Last-Translator: Thomas Noël <tnoel@entrouvert.com>\n"
|
||||
"Language-Team: french\n"
|
||||
"Language: fr\n"
|
||||
|
@ -725,11 +725,11 @@ msgstr "Attribut du texte (text)"
|
|||
msgid "Name of the attribute containing the label of an entry (default: text)"
|
||||
msgstr "Nom de l’attribut contenant le texte d’une donnée (par défaut : text)"
|
||||
|
||||
#: admin/data_sources.py admin/wscalls.py wf/wscall.py
|
||||
#: admin/data_sources.py admin/wscalls.py
|
||||
msgid "Notify on errors"
|
||||
msgstr "Notifier en cas d’erreur"
|
||||
|
||||
#: admin/data_sources.py admin/wscalls.py wf/wscall.py
|
||||
#: admin/data_sources.py admin/wscalls.py
|
||||
msgid "Record on errors"
|
||||
msgstr "Enregistrer les erreurs"
|
||||
|
||||
|
@ -2628,6 +2628,10 @@ msgstr "JSON invalide : %s"
|
|||
msgid "Response payload (JSON)"
|
||||
msgstr "Contenu de la réponse (JSON)"
|
||||
|
||||
#: admin/tests.py
|
||||
msgid "Response status code"
|
||||
msgstr "Code de statut de la réponse"
|
||||
|
||||
#: admin/tests.py
|
||||
msgid "Restrict to query string data"
|
||||
msgstr "Limiter aux paramètres de l’URL"
|
||||
|
@ -11936,8 +11940,26 @@ msgid "Action on network errors"
|
|||
msgstr "Action en cas d’erreur réseau"
|
||||
|
||||
#: wf/wscall.py
|
||||
msgid "Record errors in the log"
|
||||
msgstr "Enregistrer les erreurs dans l’historique"
|
||||
msgid "Notify errors by email"
|
||||
msgstr "Notifier les erreurs par courriel "
|
||||
|
||||
#: wf/wscall.py
|
||||
#, python-format
|
||||
msgid "Error traces will be sent to %s"
|
||||
msgstr "Les traces des erreurs seront envoyées à %s."
|
||||
|
||||
#: wf/wscall.py
|
||||
msgid ""
|
||||
"Record errors in the central error screen, for management by administrators"
|
||||
msgstr ""
|
||||
" Enregistrer les erreurs dans l’écran de centralisation des erreurs, pour "
|
||||
"traitement par l’équipe d’administration"
|
||||
|
||||
#: wf/wscall.py
|
||||
msgid "Record errors in card/form history log, for agents"
|
||||
msgstr ""
|
||||
"Enregistrer les erreurs dans l’historique de la demande ou fiche, pour "
|
||||
"visualisation par les agents"
|
||||
|
||||
#: wf/wscall.py
|
||||
msgctxt "wscall-parameter"
|
||||
|
@ -12029,10 +12051,25 @@ msgstr "Nom du statut"
|
|||
msgid "Assert email is sent"
|
||||
msgstr "Vérifier l’envoi d’un courriel"
|
||||
|
||||
#: workflow_tests.py
|
||||
#, python-format
|
||||
msgid "Email to \"%s\""
|
||||
msgstr "Courriel vers « %s »"
|
||||
|
||||
#: workflow_tests.py
|
||||
msgid "No email was sent."
|
||||
msgstr "Aucun courriel envoyé."
|
||||
|
||||
#: workflow_tests.py
|
||||
#, python-format
|
||||
msgid "Email addresses: %s"
|
||||
msgstr "Adresses de courriel : %s"
|
||||
|
||||
#: workflow_tests.py
|
||||
#, python-format
|
||||
msgid "Email was not sent to address \"%s\"."
|
||||
msgstr "Le courriel n’a pas été envoyé vers l’adresse « %s »."
|
||||
|
||||
#: workflow_tests.py
|
||||
#, python-format
|
||||
msgid "Email subject: %s"
|
||||
|
@ -12053,6 +12090,14 @@ msgstr "Corps du courriel : %s"
|
|||
msgid "Email body does not contain \"%s\"."
|
||||
msgstr "Le corps du courriel ne contient pas « %s »."
|
||||
|
||||
#: workflow_tests.py
|
||||
msgid "Email addresses"
|
||||
msgstr "Adresses de courriel"
|
||||
|
||||
#: workflow_tests.py
|
||||
msgid "Add address"
|
||||
msgstr "Ajouter une adresse"
|
||||
|
||||
#: workflow_tests.py
|
||||
msgid "Subject must contain"
|
||||
msgstr "Le sujet doit contenir"
|
||||
|
|
|
@ -1281,7 +1281,7 @@ def intcomma(value):
|
|||
|
||||
@register.filter
|
||||
def get_preference(user, pref_name):
|
||||
return user.get_preference(pref_name)
|
||||
return user.get_preference(pref_name) if user else None
|
||||
|
||||
|
||||
@register.simple_tag(takes_context=True)
|
||||
|
|
|
@ -287,7 +287,7 @@ class TestDef(sql.TestDef):
|
|||
|
||||
def _run(self, objectdef):
|
||||
formdata = self.run_form_fill(objectdef)
|
||||
if self.agent_id:
|
||||
if self.agent_id and self.workflow_tests.actions:
|
||||
agent_user = get_publisher().user_class.get(self.agent_id)
|
||||
self.workflow_tests.run(formdata, agent_user)
|
||||
|
||||
|
@ -640,7 +640,7 @@ class MockWebserviceResponseAdapter(requests.adapters.HTTPAdapter):
|
|||
}
|
||||
|
||||
raw_response = HTTPResponse(
|
||||
status=200,
|
||||
status=response.status_code,
|
||||
body=io.BytesIO(response.payload.encode()),
|
||||
headers=headers,
|
||||
original_response=self.make_original_response(headers),
|
||||
|
@ -669,6 +669,7 @@ class WebserviceResponse(XmlStorableObject):
|
|||
name = ''
|
||||
payload = None
|
||||
url = None
|
||||
status_code = 200
|
||||
qs_data = None
|
||||
method = ''
|
||||
post_data = None
|
||||
|
@ -678,6 +679,7 @@ class WebserviceResponse(XmlStorableObject):
|
|||
('name', 'str'),
|
||||
('payload', 'str'),
|
||||
('url', 'str'),
|
||||
('status_code', 'int'),
|
||||
('qs_data', 'kv_data'),
|
||||
('method', 'str'),
|
||||
('post_data', 'kv_data'),
|
||||
|
|
|
@ -185,9 +185,9 @@ class WebserviceCallStatusItem(WorkflowStatusItem):
|
|||
'action_on_5xx',
|
||||
'action_on_bad_data',
|
||||
'action_on_network_errors',
|
||||
'notify_on_errors',
|
||||
'record_on_errors',
|
||||
'record_errors',
|
||||
'record_on_errors',
|
||||
'notify_on_errors',
|
||||
'condition',
|
||||
'set_marker_on_status',
|
||||
)
|
||||
|
@ -378,11 +378,12 @@ class WebserviceCallStatusItem(WorkflowStatusItem):
|
|||
default_value=getattr(self.__class__, attribute),
|
||||
)
|
||||
|
||||
if 'notify_on_errors' in parameters:
|
||||
if 'notify_on_errors' in parameters and get_publisher().logger.error_email:
|
||||
form.add(
|
||||
CheckboxWidget,
|
||||
'%snotify_on_errors' % prefix,
|
||||
title=_('Notify on errors'),
|
||||
title=_('Notify errors by email'),
|
||||
hint=_('Error traces will be sent to %s') % get_publisher().logger.error_email,
|
||||
value=self.notify_on_errors,
|
||||
tab=('error', _('Error Handling')),
|
||||
)
|
||||
|
@ -391,7 +392,7 @@ class WebserviceCallStatusItem(WorkflowStatusItem):
|
|||
form.add(
|
||||
CheckboxWidget,
|
||||
'%srecord_on_errors' % prefix,
|
||||
title=_('Record on errors'),
|
||||
title=_('Record errors in the central error screen, for management by administrators'),
|
||||
value=self.record_on_errors,
|
||||
tab=('error', _('Error Handling')),
|
||||
default_value=self.__class__.record_on_errors,
|
||||
|
@ -401,7 +402,7 @@ class WebserviceCallStatusItem(WorkflowStatusItem):
|
|||
form.add(
|
||||
CheckboxWidget,
|
||||
'%srecord_errors' % prefix,
|
||||
title=_('Record errors in the log'),
|
||||
title=_('Record errors in card/form history log, for agents'),
|
||||
value=self.record_errors,
|
||||
tab=('error', _('Error Handling')),
|
||||
)
|
||||
|
|
|
@ -19,7 +19,7 @@ import uuid
|
|||
|
||||
from wcs import wf
|
||||
from wcs.qommon import _
|
||||
from wcs.qommon.form import IntWidget, SingleSelectWidget, StringWidget, WidgetList
|
||||
from wcs.qommon.form import EmailWidget, IntWidget, SingleSelectWidget, StringWidget, WidgetList
|
||||
from wcs.qommon.humantime import humanduration2seconds, seconds2humanduration, timewords
|
||||
from wcs.qommon.xml_storage import XmlStorableObject
|
||||
from wcs.testdef import TestError, WebserviceResponse
|
||||
|
@ -268,24 +268,35 @@ class AssertEmail(WorkflowTestAction):
|
|||
label = _('Assert email is sent')
|
||||
|
||||
key = 'assert-email'
|
||||
addresses = None
|
||||
subject_strings = None
|
||||
body_strings = None
|
||||
|
||||
optional_fields = ['subject_strings', 'body_strings']
|
||||
optional_fields = ['addresses', 'subject_strings', 'body_strings']
|
||||
|
||||
XML_NODES = WorkflowTestAction.XML_NODES + [
|
||||
('addresses', 'str_list'),
|
||||
('subject_strings', 'str_list'),
|
||||
('body_strings', 'str_list'),
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.addresses = self.addresses or []
|
||||
self.subject_strings = self.subject_strings or []
|
||||
self.body_strings = self.body_strings or []
|
||||
|
||||
@property
|
||||
def details_label(self):
|
||||
return ''
|
||||
if not self.addresses:
|
||||
return ''
|
||||
|
||||
label = _('Email to "%s"') % self.addresses[0]
|
||||
|
||||
if len(self.addresses) > 1:
|
||||
label = '%s (+%s)' % (label, len(self.addresses) - 1)
|
||||
|
||||
return label
|
||||
|
||||
def perform(self, formdata, user):
|
||||
try:
|
||||
|
@ -293,6 +304,11 @@ class AssertEmail(WorkflowTestAction):
|
|||
except IndexError:
|
||||
raise WorkflowTestError(_('No email was sent.'))
|
||||
|
||||
for address in self.addresses:
|
||||
details = [_('Email addresses: %s') % ', '.join(email.email_msg.to)]
|
||||
if address not in email.email_msg.to:
|
||||
raise WorkflowTestError(_('Email was not sent to address "%s".') % address, details=details)
|
||||
|
||||
for subject in self.subject_strings:
|
||||
details = [_('Email subject: %s') % email.email_msg.subject]
|
||||
if subject not in email.email_msg.subject:
|
||||
|
@ -304,6 +320,15 @@ class AssertEmail(WorkflowTestAction):
|
|||
raise WorkflowTestError(_('Email body does not contain "%s".') % body, details=details)
|
||||
|
||||
def fill_admin_form(self, form, formdef):
|
||||
form.add(
|
||||
WidgetList,
|
||||
'addresses',
|
||||
element_type=EmailWidget,
|
||||
title=_('Email addresses'),
|
||||
value=self.addresses,
|
||||
add_element_label=_('Add address'),
|
||||
element_kwargs={'render_br': False, 'size': 50},
|
||||
)
|
||||
form.add(
|
||||
WidgetList,
|
||||
'subject_strings',
|
||||
|
|
Loading…
Reference in New Issue