From 150735360f2047322c89618d91b0b570c816efcc Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Sat, 2 Jul 2016 18:44:13 +0200 Subject: [PATCH] wscalls: implement PUT, PATCH and DELETE verbs (#12416) --- tests/test_workflows.py | 39 +++++++++++++++++++++++++++++++++++++-- tests/test_wscall.py | 32 +++++++++++++++++++++++++++++++- wcs/wf/wscall.py | 10 ++++++++-- wcs/wscalls.py | 21 +++++++++++++++------ 4 files changed, 91 insertions(+), 11 deletions(-) diff --git a/tests/test_workflows.py b/tests/test_workflows.py index 0bc525e85..7cb5015fa 100644 --- a/tests/test_workflows.py +++ b/tests/test_workflows.py @@ -1482,6 +1482,40 @@ def test_webservice_call(http_requests, pub): assert qs['ezt'] == [formdata.get_display_id()] assert qs['str'] == ['abcd'] + item = WebserviceCallStatusItem() + item.method = 'DELETE' + item.post = False + item.url = 'http://remote.example.net/json' + pub.substitutions.feed(formdata) + item.perform(formdata) + assert http_requests.get_last('method') == 'DELETE' + + item = WebserviceCallStatusItem() + item.url = 'http://remote.example.net' + item.method = 'PUT' + item.post = False + item.post_data = {'str': 'abcd', 'one': '=1', + 'evalme': '=form_number', 'error':'=1=3'} + pub.substitutions.feed(formdata) + item.perform(formdata) + assert http_requests.get_last('url') == 'http://remote.example.net' + assert http_requests.get_last('method') == 'PUT' + payload = json.loads(http_requests.get_last('body')) + assert payload == {'one': 1, 'str': 'abcd', 'evalme': formdata.get_display_id()} + + item = WebserviceCallStatusItem() + item.url = 'http://remote.example.net' + item.method = 'PATCH' + item.post = False + item.post_data = {'str': 'abcd', 'one': '=1', + 'evalme': '=form_number', 'error':'=1=3'} + pub.substitutions.feed(formdata) + item.perform(formdata) + assert http_requests.get_last('url') == 'http://remote.example.net' + assert http_requests.get_last('method') == 'PATCH' + payload = json.loads(http_requests.get_last('body')) + assert payload == {'one': 1, 'str': 'abcd', 'evalme': formdata.get_display_id()} + def test_webservice_waitpoint(pub): item = WebserviceCallStatusItem() assert item.waitpoint @@ -1994,10 +2028,11 @@ def test_sms_with_passerelle(pub): item.body = 'my message' with mock.patch('wcs.wscalls.get_secret_and_orig') as mocked_secret_and_orig: mocked_secret_and_orig.return_value = ('secret', 'localhost') - with mock.patch('qommon.misc.http_post_request') as mocked_http_post: + with mock.patch('qommon.misc._http_request') as mocked_http_post: mocked_http_post.return_value = ('response', '200', 'data', 'headers') item.perform(formdata) - url, payload = mocked_http_post.call_args[0] + url = mocked_http_post.call_args[0][0] + payload = mocked_http_post.call_args[1]['body'] assert 'http://passerelle.example.com' in url assert '?nostop=1' in url assert 'orig=localhost' in url diff --git a/tests/test_wscall.py b/tests/test_wscall.py index feebf24bd..442f0ec4e 100644 --- a/tests/test_wscall.py +++ b/tests/test_wscall.py @@ -1,5 +1,4 @@ import json -import mock import pytest from StringIO import StringIO @@ -19,6 +18,7 @@ def pub(): pub.load_site_options() return pub + def teardown_module(module): clean_temporary_pub() @@ -135,3 +135,33 @@ def test_wscall_ezt(http_requests, pub): assert template.render(variables) == '

' template = Template('

[webservice.hello.foo]

') assert template.render(variables) == '

[webservice.hello.foo]

' + +def test_webservice_post_put_patch(http_requests, pub): + NamedWsCall.wipe() + + for method in ('POST', 'PUT', 'PATCH'): + wscall = NamedWsCall() + wscall.name = 'Hello world' + wscall.request = {'method': 'PUT', 'post_data': {'toto': 'coin'}, + 'url': 'http://remote.example.net/json'} + try: + wscall.call() + except: + pass + assert http_requests.get_last('url') == wscall.request['url'] + assert http_requests.get_last('method') == wscall.request['method'] + assert json.loads(http_requests.get_last('body')) == wscall.request['post_data'] + +def test_webservice_delete(http_requests, pub): + NamedWsCall.wipe() + + wscall = NamedWsCall() + wscall.name = 'Hello world' + wscall.request = {'method': 'DELETE', 'post_data': {'toto': 'coin'}, + 'url': 'http://remote.example.net/json'} + try: + wscall.call() + except: + pass + assert http_requests.get_last('url') == wscall.request['url'] + assert http_requests.get_last('method') == 'DELETE' diff --git a/wcs/wf/wscall.py b/wcs/wf/wscall.py index 013a8a3a7..2eb78b42c 100644 --- a/wcs/wf/wscall.py +++ b/wcs/wf/wscall.py @@ -127,7 +127,7 @@ class WebserviceCallStatusItem(WorkflowStatusItem): @property def method(self): - if self._method in ('GET', 'POST'): + if self._method in ('GET', 'POST', 'PUT', 'PATCH', 'DELETE'): return self._method if self.post or self.post_data: return 'POST' @@ -174,7 +174,13 @@ class WebserviceCallStatusItem(WorkflowStatusItem): value=self.qs_data or {}, element_value_type=ComputedExpressionWidget) methods = collections.OrderedDict( - [('GET', _('GET')), ('POST', _('POST (JSON)'))]) + [ + ('GET', _('GET')), + ('POST', _('POST (JSON)')), + ('PUT', _('PUT (JSON)')), + ('PATCH', _('PATCH (JSON)')), + ('DELETE', _('DELETE')), + ]) if 'method' in parameters: form.add(RadiobuttonsWidget, '%smethod' % prefix, title=_('Method'), diff --git a/wcs/wscalls.py b/wcs/wscalls.py index b3aaefe73..fce9232c5 100644 --- a/wcs/wscalls.py +++ b/wcs/wscalls.py @@ -86,7 +86,7 @@ def call_webservice(url, qs_data=None, request_signature_key=None, payload = None # if post_data exists, payload is a dict built from it - if method == 'POST' and post_data: + if method in ('PATCH', 'PUT', 'POST') and post_data: payload = {} for (key, value) in post_data.items(): try: @@ -96,20 +96,23 @@ def call_webservice(url, qs_data=None, request_signature_key=None, # if formdata has to be sent, it's the payload. If post_data exists, # it's added in formdata['extra'] - if method == 'POST' and post_formdata: + if method in ('PATCH', 'PUT', 'POST') and post_formdata: if formdata: formdata_dict = formdata.get_json_export_dict() if payload is not None: formdata_dict['extra'] = payload payload = formdata_dict - if method == 'POST': + if method in ('PATCH', 'PUT', 'POST'): if payload: headers['Content-type'] = 'application/json' payload = json.dumps(payload, cls=JSONEncoder, encoding=get_publisher().site_charset) - response, status, data, auth_header = qommon.misc.http_post_request( - url, payload, headers=headers) + response, status, data, auth_header = qommon.misc._http_request( + url, method=method, body=payload, headers=headers) + elif method == 'DELETE': + response, status, data, auth_header = qommon.misc._http_request( + url, method='DELETE', headers=headers) else: response, status, data, auth_header = qommon.misc.http_get_page( url, headers=headers) @@ -223,7 +226,13 @@ class WsCallRequestWidget(CompositeWidget): value=value.get('qs_data') or {}, element_value_type=ComputedExpressionWidget) methods = collections.OrderedDict( - [('GET', _('GET')), ('POST', _('POST (JSON)'))]) + [ + ('GET', _('GET')), + ('POST', _('POST (JSON)')), + ('PUT', _('PUT (JSON)')), + ('PATCH', _('PATCH (JSON)')), + ('DELETE', _('DELETE')), + ]) self.add(RadiobuttonsWidget, 'method', title=_('Method'), options=methods.items(), -- 2.18.0