From ccde0cd5886469b3f8310b5a64c972a349647c95 Mon Sep 17 00:00:00 2001 From: Alexey Baranov Date: Thu, 21 Apr 2016 11:43:01 +0300 Subject: [PATCH 1/6] POST form data --- pyresttest/contenthandling.py | 33 ++++++++++++++++++++++++++++++--- pyresttest/tests.py | 10 ++++++---- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/pyresttest/contenthandling.py b/pyresttest/contenthandling.py index 52e35598..45ec1064 100644 --- a/pyresttest/contenthandling.py +++ b/pyresttest/contenthandling.py @@ -1,6 +1,7 @@ import os import sys - +import base64 +import pycurl from . import parsing from .parsing import * @@ -20,19 +21,22 @@ class ContentHandler: Also creates pixie dust and unicorn farts on demand This is pulled out because logic gets complex rather fast - Covers 6 states: + Covers 8 states: - Inline body content, no templating - Inline body content, with templating - File path to content, NO templating - File path to content, content gets templated - Templated path to file content (path itself is templated), file content UNtemplated - Templated path to file content (path itself is templated), file content TEMPLATED + - Form data content, no templating + - Form data content, with templating """ content = None # Inline content is_file = False is_template_path = False is_template_content = False + is_form = False def is_dynamic(self): """ Is templating used? """ @@ -54,6 +58,16 @@ def get_content(self, context=None): return string.Template(data).safe_substitute(context.get_values()) else: return data + elif self.is_form: + content = [] + for k, v in self.content.items(): + content_row = [safe_substitute_unicode_template(k, context.get_values())] + if isinstance(v, (list, tuple)): + content_row.append([v[0], safe_substitute_unicode_template(v[1], context.get_values())]) + else: + content_row.append(safe_substitute_unicode_template(v, context.get_values())) + content.append(content_row) + return content else: if self.is_template_content and context: return safe_substitute_unicode_template(self.content, context.get_values()) @@ -70,7 +84,7 @@ def create_noread_version(self): output.content = f.read() return output - def setup(self, input, is_file=False, is_template_path=False, is_template_content=False): + def setup(self, input, is_file=False, is_template_path=False, is_template_content=False, is_form=False): """ Self explanatory, input is inline content or file path. """ if not isinstance(input, basestring): raise TypeError("Input is not a string") @@ -80,6 +94,7 @@ def setup(self, input, is_file=False, is_template_path=False, is_template_conten self.is_file = is_file self.is_template_path = is_template_path self.is_template_content = is_template_content + self.is_form = is_form @staticmethod def parse_content(node): @@ -100,6 +115,7 @@ def parse_content(node): is_template_content = False is_file = False is_done = False + is_form = False while (node and not is_done): # Dive through the configuration tree # Finally we've found the value! @@ -145,4 +161,15 @@ def parse_content(node): is_done = False break + elif key == 'form': + output.is_template_content = is_template_content + output.content = {} + for k, v in value.items(): + if isinstance(v, basestring) and v.startswith('@'): + v = (pycurl.FORM_FILE, v[1:]) + output.content[k] = v + output.is_form = True + is_form = True + return output + raise Exception("Invalid configuration for content.") diff --git a/pyresttest/tests.py b/pyresttest/tests.py index 56365fce..cd8560c6 100644 --- a/pyresttest/tests.py +++ b/pyresttest/tests.py @@ -157,7 +157,7 @@ def get_body(self, context=None): """ Read body from file, applying template if pertinent """ if self._body is None: return None - elif isinstance(self._body, basestring): + elif isinstance(self._body, (basestring, list, tuple)): return self._body else: return self._body.get_content(context=context) @@ -315,7 +315,7 @@ def configure_curl(self, timeout=DEFAULT_TIMEOUT, context=None, curl_handle=None is_unicoded = True # Set read function for post/put bodies - if bod and len(bod) > 0: + if bod and isinstance(bod, basestring) and len(bod) > 0: curl.setopt(curl.READFUNCTION, MyIO(bod).read) if self.auth_username and self.auth_password: @@ -327,9 +327,11 @@ def configure_curl(self, timeout=DEFAULT_TIMEOUT, context=None, curl_handle=None if self.method == u'POST': curl.setopt(HTTP_METHODS[u'POST'], 1) - # Required for some servers if bod is not None: - curl.setopt(pycurl.POSTFIELDSIZE, len(bod)) + if isinstance(bod, (list, tuple)): + curl.setopt(pycurl.HTTPPOST, bod) + else: + curl.setopt(pycurl.POSTFIELDSIZE, len(bod)) else: curl.setopt(pycurl.POSTFIELDSIZE, 0) elif self.method == u'PUT': From 581c2898ec251a3d23b9df8350c7d84b9399646f Mon Sep 17 00:00:00 2001 From: Alexey Baranov Date: Thu, 21 Apr 2016 11:45:31 +0300 Subject: [PATCH 2/6] rm import base64 --- pyresttest/contenthandling.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pyresttest/contenthandling.py b/pyresttest/contenthandling.py index 45ec1064..89652f8a 100644 --- a/pyresttest/contenthandling.py +++ b/pyresttest/contenthandling.py @@ -1,6 +1,5 @@ import os import sys -import base64 import pycurl from . import parsing from .parsing import * From 8eee0a096c4142057ca0c16bfe63760a6c273282 Mon Sep 17 00:00:00 2001 From: Alexey Baranov Date: Thu, 21 Apr 2016 12:17:20 +0300 Subject: [PATCH 3/6] PUT|PATCH form data --- pyresttest/tests.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/pyresttest/tests.py b/pyresttest/tests.py index cd8560c6..050fe1d9 100644 --- a/pyresttest/tests.py +++ b/pyresttest/tests.py @@ -335,19 +335,26 @@ def configure_curl(self, timeout=DEFAULT_TIMEOUT, context=None, curl_handle=None else: curl.setopt(pycurl.POSTFIELDSIZE, 0) elif self.method == u'PUT': - curl.setopt(HTTP_METHODS[u'PUT'], 1) # Required for some servers + curl.setopt(HTTP_METHODS[u'POST'], 1) + curl.setopt(pycurl.CUSTOMREQUEST, 'PUT') if bod is not None: - curl.setopt(pycurl.INFILESIZE, len(bod)) + if isinstance(bod, (list, tuple)): + curl.setopt(pycurl.HTTPPOST, bod) + else: + curl.setopt(pycurl.POSTFIELDSIZE, len(bod)) else: curl.setopt(pycurl.INFILESIZE, 0) elif self.method == u'PATCH': - curl.setopt(curl.POSTFIELDS, bod) + curl.setopt(HTTP_METHODS[u'POST'], 1) curl.setopt(curl.CUSTOMREQUEST, 'PATCH') # Required for some servers # I wonder: how compatible will this be? It worked with Django but feels iffy. if bod is not None: - curl.setopt(pycurl.INFILESIZE, len(bod)) + if isinstance(bod, (list, tuple)): + curl.setopt(pycurl.HTTPPOST, bod) + else: + curl.setopt(pycurl.POSTFIELDSIZE, len(bod)) else: curl.setopt(pycurl.INFILESIZE, 0) elif self.method == u'DELETE': From 5c89aa30cb8715d41c795a77a01f0f664e7e30d5 Mon Sep 17 00:00:00 2001 From: Alexey Baranov Date: Mon, 25 Apr 2016 11:05:03 +0300 Subject: [PATCH 4/6] multipart forms --- pyresttest/contenthandling.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyresttest/contenthandling.py b/pyresttest/contenthandling.py index 89652f8a..32c3c01f 100644 --- a/pyresttest/contenthandling.py +++ b/pyresttest/contenthandling.py @@ -1,3 +1,5 @@ +from collections import OrderedDict + import os import sys import pycurl @@ -162,7 +164,7 @@ def parse_content(node): elif key == 'form': output.is_template_content = is_template_content - output.content = {} + output.content = OrderedDict() for k, v in value.items(): if isinstance(v, basestring) and v.startswith('@'): v = (pycurl.FORM_FILE, v[1:]) From a9a86105aa0102a3d4ac2af4ee9f1e03302074a0 Mon Sep 17 00:00:00 2001 From: Alexey Baranov Date: Mon, 25 Apr 2016 11:20:43 +0300 Subject: [PATCH 5/6] add testset_datetime variable --- pyresttest/binding.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyresttest/binding.py b/pyresttest/binding.py index 1f1a033c..34e532e0 100644 --- a/pyresttest/binding.py +++ b/pyresttest/binding.py @@ -1,4 +1,6 @@ import logging + +import datetime import types """ @@ -68,5 +70,5 @@ def get_generator(self, generator_name): return self.generators.get(str(generator_name)) def __init__(self): - self.variables = dict() + self.variables = dict(testset_datetime=datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%S')) self.generators = dict() From bdf56357ebc440dd391450515692987336ce5401 Mon Sep 17 00:00:00 2001 From: Alexey Baranov Date: Mon, 25 Apr 2016 15:03:48 +0300 Subject: [PATCH 6/6] comparator str_not_eq --- pyresttest/validators.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyresttest/validators.py b/pyresttest/validators.py index d59cbbea..97231a79 100644 --- a/pyresttest/validators.py +++ b/pyresttest/validators.py @@ -53,6 +53,7 @@ 'eq': operator.eq, 'equals': operator.eq, 'str_eq': lambda x, y: operator.eq(str(x), str(y)), + 'str_not_eq': lambda x, y: operator.ne(str(x), str(y)), 'ne': operator.ne, 'not_equals': operator.ne, 'ge': operator.ge,