Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

POST form data #194

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion pyresttest/binding.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import logging

import datetime
import types

"""
Expand Down Expand Up @@ -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()
34 changes: 31 additions & 3 deletions pyresttest/contenthandling.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from collections import OrderedDict

import os
import sys

import pycurl
from . import parsing
from .parsing import *

Expand All @@ -20,19 +22,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? """
Expand All @@ -54,6 +59,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())
Expand All @@ -70,7 +85,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")
Expand All @@ -80,6 +95,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):
Expand All @@ -100,6 +116,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!
Expand Down Expand Up @@ -145,4 +162,15 @@ def parse_content(node):
is_done = False
break

elif key == 'form':
output.is_template_content = is_template_content
output.content = OrderedDict()
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.")
25 changes: 17 additions & 8 deletions pyresttest/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand All @@ -327,25 +327,34 @@ 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':
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':
Expand Down
1 change: 1 addition & 0 deletions pyresttest/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down